1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-05-31 11:15:31 +03:00
occt/src/D3DHost/D3DHost_View.cxx
Pasukhin Dmitry 1f386af59f
Coding - Update method guards for consistency #333
Apply new regex replacement with method's guards in .cxx
Update GH workflow with style checking
2025-02-03 11:16:00 +00:00

513 lines
15 KiB
C++

// Created on: 2015-06-10
// Created by: Kirill Gavrilov
// Copyright (c) 2015 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <d3d9.h>
#include <D3DHost_View.hxx>
#include <D3DHost_GraphicDriver.hxx>
#include <TCollection_ExtendedString.hxx>
#include <OpenGl_Window.hxx>
#include <Standard_WarningDisableFunctionCast.hxx>
IMPLEMENT_STANDARD_RTTIEXT(D3DHost_View, OpenGl_View)
namespace
{
enum D3DHost_VendorId
{
D3DHost_VendorId_AMD = 0x1002,
D3DHost_VendorId_NVIDIA = 0x10DE,
D3DHost_VendorId_Intel = 0x8086,
};
} // namespace
//=================================================================================================
TCollection_AsciiString D3DHost_View::d3dFormatError(const long theErrCode)
{
switch (theErrCode)
{
case D3D_OK:
return "OK";
case D3DERR_DEVICELOST:
return "Device lost";
case D3DERR_DEVICEREMOVED:
return "Device removed";
case D3DERR_DRIVERINTERNALERROR:
return "Driver internal error";
case D3DERR_OUTOFVIDEOMEMORY:
return "Out of video memory";
case D3DERR_INVALIDCALL:
return "Invalid call";
default:
return TCollection_AsciiString("Error #") + int(theErrCode) + ")";
}
}
//=================================================================================================
D3DHost_View::D3DHost_View(const Handle(Graphic3d_StructureManager)& theMgr,
const Handle(D3DHost_GraphicDriver)& theDriver,
const Handle(OpenGl_Caps)& theCaps,
OpenGl_StateCounter* theCounter)
: OpenGl_View(theMgr, theDriver, theCaps, theCounter),
myD3dLib(NULL),
myD3dDevice(NULL),
myD3dParams(new D3DPRESENT_PARAMETERS()),
myRefreshRate(D3DPRESENT_RATE_DEFAULT),
myIsD3dEx(false)
{
memset(myD3dParams.operator->(), 0, sizeof(D3DPRESENT_PARAMETERS));
myD3dParams->Windowed = TRUE;
myD3dParams->SwapEffect = D3DSWAPEFFECT_DISCARD;
myD3dParams->BackBufferFormat = D3DFMT_X8R8G8B8;
myD3dParams->BackBufferCount = 1;
myD3dParams->BackBufferHeight = 2;
myD3dParams->BackBufferWidth = 2;
myD3dParams->EnableAutoDepthStencil = FALSE;
myD3dParams->AutoDepthStencilFormat = D3DFMT_D16_LOCKABLE;
myD3dParams->FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
myD3dParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
}
//=================================================================================================
D3DHost_View::~D3DHost_View()
{
ReleaseGlResources(NULL);
if (myD3dDevice != NULL)
{
myD3dDevice->Release();
myD3dDevice = NULL;
}
if (myD3dLib != NULL)
{
myD3dLib->Release();
myD3dLib = NULL;
}
}
//=================================================================================================
void D3DHost_View::ReleaseGlResources(const Handle(OpenGl_Context)& theCtx)
{
if (!myD3dWglFbo.IsNull())
{
myD3dWglFbo->Release(theCtx.get());
myD3dWglFbo.Nullify();
}
OpenGl_View::ReleaseGlResources(theCtx);
}
//=================================================================================================
IDirect3DSurface9* D3DHost_View::D3dColorSurface() const
{
return myD3dWglFbo->D3dColorSurface();
}
//=================================================================================================
void D3DHost_View::SetWindow(const Handle(Graphic3d_CView)& theParentVIew,
const Handle(Aspect_Window)& theWindow,
const Aspect_RenderingContext theContext)
{
if (!myD3dWglFbo.IsNull())
{
myD3dWglFbo->Release(myWorkspace->GetGlContext().operator->());
myD3dWglFbo.Nullify();
}
if (myD3dDevice != NULL)
{
myD3dDevice->Release();
myD3dDevice = NULL;
}
OpenGl_View::SetWindow(theParentVIew, theWindow, theContext);
if (!myWindow.IsNull())
{
d3dInit();
d3dCreateRenderTarget();
}
}
//=================================================================================================
void D3DHost_View::DiagnosticInformation(TColStd_IndexedDataMapOfStringString& theDict,
Graphic3d_DiagnosticInfo theFlags) const
{
base_type::DiagnosticInformation(theDict, theFlags);
if (myD3dDevice == NULL)
{
return;
}
D3DCAPS9 aDevCaps;
memset(&aDevCaps, 0, sizeof(aDevCaps));
if (myD3dDevice->GetDeviceCaps(&aDevCaps) < 0)
{
return;
}
const UINT anAdapter = aDevCaps.AdapterOrdinal;
D3DADAPTER_IDENTIFIER9 aDevId;
memset(&aDevId, 0, sizeof(aDevId));
if (myD3dLib->GetAdapterIdentifier(anAdapter, 0, &aDevId) < 0)
{
return;
}
TCollection_AsciiString aVendorId((int)aDevId.VendorId);
switch (aDevId.VendorId)
{
case D3DHost_VendorId_AMD:
aVendorId = "AMD";
break;
case D3DHost_VendorId_NVIDIA:
aVendorId = "NVIDIA";
break;
case D3DHost_VendorId_Intel:
aVendorId = "Intel";
break;
}
theDict.Add("D3Dvendor", aVendorId);
theDict.Add("D3Ddescription", aDevId.Description);
theDict.Add("D3DdeviceName", aDevId.DeviceName);
theDict.Add("D3Ddriver", aDevId.Driver);
theDict.Add("D3DdeviceId", TCollection_AsciiString((int)aDevId.DeviceId));
theDict.Add("D3Dinterop",
myD3dWglFbo.IsNull() || myD3dWglFbo->D3dFallback() ? "Software Fallback"
: "WGL_NV_DX_interop");
}
//=================================================================================================
bool D3DHost_View::d3dInitLib()
{
if (myD3dLib == NULL)
{
IDirect3D9Ex* aD3dLibEx = NULL;
// we link against d3d (using Direct3DCreate9 symbol), thus it should be already loaded
HMODULE aLib = GetModuleHandleW(L"d3d9");
if (aLib != NULL)
{
// retrieve D3D9Ex function dynamically (available only since Vista+)
typedef HRESULT(WINAPI * Direct3DCreate9Ex_t)(UINT, IDirect3D9Ex**);
Direct3DCreate9Ex_t Direct3DCreate9ExProc =
(Direct3DCreate9Ex_t)GetProcAddress(aLib, "Direct3DCreate9Ex");
if (Direct3DCreate9ExProc != NULL)
{
Direct3DCreate9ExProc(D3D_SDK_VERSION, &aD3dLibEx);
}
}
myD3dLib = aD3dLibEx;
myIsD3dEx = aD3dLibEx != NULL;
if (myD3dLib == NULL)
{
myD3dLib = Direct3DCreate9(D3D_SDK_VERSION);
}
}
return myD3dLib != NULL;
}
//=================================================================================================
bool D3DHost_View::d3dInit()
{
if (!d3dInitLib())
{
myWorkspace->GetGlContext()->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"Direct3DCreate9 failed!");
return false;
}
UINT anAdapterId = D3DADAPTER_DEFAULT;
// setup the present parameters
D3DDISPLAYMODE aCurrMode;
memset(&aCurrMode, 0, sizeof(aCurrMode));
if (myD3dLib->GetAdapterDisplayMode(anAdapterId, &aCurrMode) == D3D_OK)
{
myD3dParams->BackBufferFormat = aCurrMode.Format;
myRefreshRate = aCurrMode.RefreshRate;
}
myD3dParams->Windowed = TRUE;
myD3dParams->BackBufferWidth = myWindow->Width();
myD3dParams->BackBufferHeight = myWindow->Height();
myD3dParams->hDeviceWindow = (HWND)myWindow->PlatformWindow()->NativeHandle();
// create the Video Device
HRESULT isOK = myD3dLib->CreateDevice(anAdapterId,
D3DDEVTYPE_HAL,
(HWND)myWindow->PlatformWindow()->NativeHandle(),
D3DCREATE_HARDWARE_VERTEXPROCESSING
| D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
myD3dParams.get(),
&myD3dDevice);
if (isOK < 0)
{
return false;
}
return myD3dDevice != NULL;
}
//=================================================================================================
bool D3DHost_View::d3dReset()
{
if (myD3dDevice == NULL)
{
return false;
}
myD3dParams->Windowed = TRUE;
myD3dParams->BackBufferWidth = myWindow->Width();
myD3dParams->BackBufferHeight = myWindow->Height();
myD3dParams->hDeviceWindow = (HWND)myWindow->PlatformWindow()->NativeHandle();
myD3dParams->FullScreen_RefreshRateInHz = !myD3dParams->Windowed ? myRefreshRate : 0;
HRESULT isOK = myD3dDevice->Reset(myD3dParams.get());
return isOK == D3D_OK;
}
//=================================================================================================
bool D3DHost_View::d3dCreateRenderTarget()
{
bool toD3dFallback = false;
if (myD3dWglFbo.IsNull())
{
myD3dWglFbo = new D3DHost_FrameBuffer();
}
else
{
toD3dFallback = myD3dWglFbo->D3dFallback();
}
if (!toD3dFallback)
{
toD3dFallback =
!myD3dWglFbo->InitD3dInterop(myWorkspace->GetGlContext(),
myD3dDevice,
myIsD3dEx,
myWindow->Width(),
myWindow->Height(),
// clang-format off
0); // do not request depth-stencil attachment since buffer will be flipped using addition FBO (myToFlipOutput)
// clang-format on
}
if (toD3dFallback)
{
if (!myD3dWglFbo->InitD3dFallback(myWorkspace->GetGlContext(),
myD3dDevice,
myIsD3dEx,
myWindow->Width(),
myWindow->Height(),
GL_DEPTH24_STENCIL8))
{
return false;
}
}
myD3dDevice->SetRenderTarget(0, myD3dWglFbo->D3dColorSurface());
return true;
}
//=================================================================================================
void D3DHost_View::d3dBeginRender()
{
if (myD3dDevice == NULL)
{
return;
}
// clear the back buffer
myD3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
myD3dDevice->BeginScene();
}
//=================================================================================================
void D3DHost_View::d3dEndRender()
{
if (myD3dDevice != NULL)
{
myD3dDevice->EndScene();
}
}
//=================================================================================================
bool D3DHost_View::d3dSwap()
{
if (myD3dDevice == NULL)
{
return false;
}
const HRESULT isOK = myD3dDevice->Present(NULL, NULL, NULL, NULL);
if (isOK != D3D_OK && isOK != S_PRESENT_OCCLUDED)
{
myWorkspace->GetGlContext()->PushMessage(
GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
TCollection_AsciiString("Direct3D9, Present device failed, ") + d3dFormatError(isOK));
}
return isOK == D3D_OK;
}
//=================================================================================================
void D3DHost_View::Redraw()
{
if (!myWorkspace->Activate() || myD3dDevice == NULL)
{
return;
}
else if (!myFBO.IsNull())
{
OpenGl_View::Redraw();
return;
}
Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
if (myWindow->PlatformWindow()->IsVirtual() && aCtx->arbFBO == NULL)
{
// do a dirty hack in extreme fallback mode with OpenGL driver not supporting FBO,
// the back buffer of hidden window is used for rendering as offscreen buffer
myTransientDrawToFront = false;
int aWinSizeX = 0, aWinSizeY = 0;
myWindow->PlatformWindow()->Size(aWinSizeX, aWinSizeY);
WINDOWPLACEMENT aPlace;
GetWindowPlacement((HWND)myWindow->PlatformWindow()->NativeHandle(), &aPlace);
if (aPlace.rcNormalPosition.right - aPlace.rcNormalPosition.left != aWinSizeX
|| aPlace.rcNormalPosition.bottom - aPlace.rcNormalPosition.top != aWinSizeY)
{
aPlace.rcNormalPosition.right = aPlace.rcNormalPosition.left + aWinSizeX;
aPlace.rcNormalPosition.bottom = aPlace.rcNormalPosition.top + aWinSizeY;
aPlace.showCmd = SW_HIDE;
SetWindowPlacement((HWND)myWindow->PlatformWindow()->NativeHandle(), &aPlace);
}
}
myD3dWglFbo->LockSurface(aCtx);
if (myD3dWglFbo->IsValid())
{
myToFlipOutput = Standard_True;
myFBO = myD3dWglFbo;
}
OpenGl_View::Redraw();
myFBO.Nullify();
myD3dWglFbo->UnlockSurface(aCtx);
myToFlipOutput = Standard_False;
if (aCtx->caps->buffersNoSwap)
{
return;
}
// blit result to the D3D back buffer and swap
d3dBeginRender();
IDirect3DSurface9* aBackbuffer = NULL;
myD3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
myD3dDevice->StretchRect(myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
aBackbuffer->Release();
d3dEndRender();
d3dSwap();
}
//=================================================================================================
void D3DHost_View::RedrawImmediate()
{
Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
if (!myTransientDrawToFront || !myBackBufferRestored
|| (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
{
Redraw();
return;
}
else if (!myWorkspace->Activate() || myD3dDevice == NULL)
{
return;
}
else if (!myFBO.IsNull())
{
OpenGl_View::Redraw();
return;
}
myD3dWglFbo->LockSurface(aCtx);
if (myD3dWglFbo->IsValid())
{
myToFlipOutput = Standard_True;
myFBO = myD3dWglFbo;
}
OpenGl_View::RedrawImmediate();
myFBO.Nullify();
myD3dWglFbo->UnlockSurface(aCtx);
myToFlipOutput = Standard_False;
if (aCtx->caps->buffersNoSwap)
{
return;
}
// blit result to the D3D back buffer and swap
d3dBeginRender();
IDirect3DSurface9* aBackbuffer = NULL;
myD3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
myD3dDevice->StretchRect(myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
aBackbuffer->Release();
d3dEndRender();
d3dSwap();
}
//=================================================================================================
void D3DHost_View::Resized()
{
const Standard_Integer aWidthOld = myWindow->Width();
const Standard_Integer aHeightOld = myWindow->Height();
OpenGl_View::Resized();
if (aWidthOld == myWindow->Width() && aHeightOld == myWindow->Height())
{
return;
}
if (!myD3dWglFbo.IsNull())
{
myD3dWglFbo->Release(myWorkspace->GetGlContext().operator->());
}
if (!myWorkspace->GetGlContext()->caps->buffersNoSwap)
{
d3dReset();
}
d3dCreateRenderTarget();
}