1 // Created on: 2015-06-10
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2015 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
18 #include <D3DHost_View.hxx>
20 #include <D3DHost_GraphicDriver.hxx>
21 #include <TCollection_ExtendedString.hxx>
23 #include <Standard_WarningDisableFunctionCast.hxx>
25 IMPLEMENT_STANDARD_RTTIEXT(D3DHost_View,OpenGl_View)
31 D3DHost_VendorId_AMD = 0x1002,
32 D3DHost_VendorId_NVIDIA = 0x10DE,
33 D3DHost_VendorId_Intel = 0x8086,
37 // =======================================================================
38 // function : d3dFormatError
40 // =======================================================================
41 TCollection_AsciiString D3DHost_View::d3dFormatError (const long theErrCode)
45 case D3D_OK: return "OK";
46 case D3DERR_DEVICELOST: return "Device lost";
47 case D3DERR_DEVICEREMOVED: return "Device removed";
48 case D3DERR_DRIVERINTERNALERROR: return "Driver internal error";
49 case D3DERR_OUTOFVIDEOMEMORY: return "Out of video memory";
50 case D3DERR_INVALIDCALL: return "Invalid call";
51 default: return TCollection_AsciiString ("Error #") + int(theErrCode) + ")";
55 // =======================================================================
56 // function : D3DHost_View
58 // =======================================================================
59 D3DHost_View::D3DHost_View (const Handle(Graphic3d_StructureManager)& theMgr,
60 const Handle(D3DHost_GraphicDriver)& theDriver,
61 const Handle(OpenGl_Caps)& theCaps,
62 OpenGl_StateCounter* theCounter)
63 : OpenGl_View (theMgr, theDriver, theCaps, theCounter),
66 myD3dParams (new D3DPRESENT_PARAMETERS()),
67 myRefreshRate (D3DPRESENT_RATE_DEFAULT),
70 memset(myD3dParams.operator->(), 0, sizeof(D3DPRESENT_PARAMETERS));
72 myD3dParams->Windowed = TRUE;
73 myD3dParams->SwapEffect = D3DSWAPEFFECT_DISCARD;
74 myD3dParams->BackBufferFormat = D3DFMT_X8R8G8B8;
75 myD3dParams->BackBufferCount = 1;
76 myD3dParams->BackBufferHeight = 2;
77 myD3dParams->BackBufferWidth = 2;
78 myD3dParams->EnableAutoDepthStencil = FALSE;
79 myD3dParams->AutoDepthStencilFormat = D3DFMT_D16_LOCKABLE;
80 myD3dParams->FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
81 myD3dParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
84 // =======================================================================
85 // function : ~D3DHost_View
87 // =======================================================================
88 D3DHost_View::~D3DHost_View()
90 ReleaseGlResources (NULL);
91 if (myD3dDevice != NULL)
93 myD3dDevice->Release();
103 // =======================================================================
104 // function : ReleaseGlResources
106 // =======================================================================
107 void D3DHost_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx)
109 if (!myD3dWglFbo.IsNull())
111 myD3dWglFbo->Release (theCtx.get());
112 myD3dWglFbo.Nullify();
114 OpenGl_View::ReleaseGlResources (theCtx);
117 // =======================================================================
118 // function : D3dColorSurface
120 // =======================================================================
121 IDirect3DSurface9* D3DHost_View::D3dColorSurface() const
123 return myD3dWglFbo->D3dColorSurface();
126 // =======================================================================
127 // function : SetWindow
129 // =======================================================================
130 void D3DHost_View::SetWindow (const Handle(Aspect_Window)& theWindow,
131 const Aspect_RenderingContext theContext)
133 if (!myD3dWglFbo.IsNull())
135 myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
136 myD3dWglFbo.Nullify();
138 if (myD3dDevice != NULL)
140 myD3dDevice->Release();
144 OpenGl_View::SetWindow (theWindow, theContext);
146 if (!myWindow.IsNull())
149 d3dCreateRenderTarget();
153 // =======================================================================
154 // function : DiagnosticInformation
156 // =======================================================================
157 void D3DHost_View::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
158 Graphic3d_DiagnosticInfo theFlags) const
160 base_type::DiagnosticInformation (theDict, theFlags);
161 if (myD3dDevice == NULL)
167 memset (&aDevCaps, 0, sizeof(aDevCaps));
168 if (myD3dDevice->GetDeviceCaps (&aDevCaps) < 0)
173 const UINT anAdapter = aDevCaps.AdapterOrdinal;
174 D3DADAPTER_IDENTIFIER9 aDevId;
175 memset (&aDevId, 0, sizeof(aDevId));
176 if (myD3dLib->GetAdapterIdentifier (anAdapter, 0, &aDevId) < 0)
181 TCollection_AsciiString aVendorId ((int )aDevId.VendorId);
182 switch (aDevId.VendorId)
184 case D3DHost_VendorId_AMD: aVendorId = "AMD"; break;
185 case D3DHost_VendorId_NVIDIA: aVendorId = "NVIDIA"; break;
186 case D3DHost_VendorId_Intel: aVendorId = "Intel"; break;
188 theDict.Add ("D3Dvendor", aVendorId);
189 theDict.Add ("D3Ddescription", aDevId.Description);
190 theDict.Add ("D3DdeviceName", aDevId.DeviceName);
191 theDict.Add ("D3Ddriver", aDevId.Driver);
192 theDict.Add ("D3DdeviceId", TCollection_AsciiString((int )aDevId.DeviceId));
193 theDict.Add ("D3Dinterop", myD3dWglFbo.IsNull() || myD3dWglFbo->D3dFallback()
194 ? "Software Fallback"
195 : "WGL_NV_DX_interop");
198 // =======================================================================
199 // function : d3dInitLib
201 // =======================================================================
202 bool D3DHost_View::d3dInitLib()
204 if (myD3dLib == NULL)
206 IDirect3D9Ex* aD3dLibEx = NULL;
207 // we link against d3d (using Direct3DCreate9 symbol), thus it should be already loaded
208 HMODULE aLib = GetModuleHandleW (L"d3d9");
211 // retrieve D3D9Ex function dynamically (available only since Vista+)
212 typedef HRESULT (WINAPI* Direct3DCreate9Ex_t)(UINT , IDirect3D9Ex** );
213 Direct3DCreate9Ex_t Direct3DCreate9ExProc = (Direct3DCreate9Ex_t )GetProcAddress (aLib, "Direct3DCreate9Ex");
214 if (Direct3DCreate9ExProc != NULL)
216 Direct3DCreate9ExProc(D3D_SDK_VERSION, &aD3dLibEx);
219 myD3dLib = aD3dLibEx;
220 myIsD3dEx = aD3dLibEx != NULL;
221 if (myD3dLib == NULL)
223 myD3dLib = Direct3DCreate9 (D3D_SDK_VERSION);
226 return myD3dLib != NULL;
229 // =======================================================================
230 // function : d3dInit
232 // =======================================================================
233 bool D3DHost_View::d3dInit()
237 myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Direct3DCreate9 failed!");
241 UINT anAdapterId = D3DADAPTER_DEFAULT;
243 // setup the present parameters
244 D3DDISPLAYMODE aCurrMode;
245 memset(&aCurrMode, 0, sizeof(aCurrMode));
246 if (myD3dLib->GetAdapterDisplayMode (anAdapterId, &aCurrMode) == D3D_OK)
248 myD3dParams->BackBufferFormat = aCurrMode.Format;
249 myRefreshRate = aCurrMode.RefreshRate;
251 myD3dParams->Windowed = TRUE;
252 myD3dParams->BackBufferWidth = myWindow->Width();
253 myD3dParams->BackBufferHeight = myWindow->Height();
254 myD3dParams->hDeviceWindow = (HWND )myWindow->PlatformWindow()->NativeHandle();
256 // create the Video Device
257 HRESULT isOK = myD3dLib->CreateDevice (anAdapterId, D3DDEVTYPE_HAL,
258 (HWND )myWindow->PlatformWindow()->NativeHandle(),
259 D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
260 myD3dParams.get(), &myD3dDevice);
266 return myD3dDevice != NULL;
269 // =======================================================================
270 // function : d3dReset
272 // =======================================================================
273 bool D3DHost_View::d3dReset()
275 if (myD3dDevice == NULL)
280 myD3dParams->Windowed = TRUE;
281 myD3dParams->BackBufferWidth = myWindow->Width();
282 myD3dParams->BackBufferHeight = myWindow->Height();
283 myD3dParams->hDeviceWindow = (HWND )myWindow->PlatformWindow()->NativeHandle();
284 myD3dParams->FullScreen_RefreshRateInHz = !myD3dParams->Windowed ? myRefreshRate : 0;
286 HRESULT isOK = myD3dDevice->Reset(myD3dParams.get());
287 return isOK == D3D_OK;
290 // =======================================================================
291 // function : d3dCreateRenderTarget
293 // =======================================================================
294 bool D3DHost_View::d3dCreateRenderTarget()
296 bool toD3dFallback = false;
297 if (myD3dWglFbo.IsNull())
299 myD3dWglFbo = new D3DHost_FrameBuffer();
303 toD3dFallback = myD3dWglFbo->D3dFallback();
308 toD3dFallback = !myD3dWglFbo->InitD3dInterop (myWorkspace->GetGlContext(),
313 0); // do not request depth-stencil attachment since buffer will be flipped using addition FBO (myToFlipOutput)
317 if (!myD3dWglFbo->InitD3dFallback (myWorkspace->GetGlContext(),
322 GL_DEPTH24_STENCIL8))
328 myD3dDevice->SetRenderTarget (0, myD3dWglFbo->D3dColorSurface());
332 // =======================================================================
333 // function : d3dBeginRender
335 // =======================================================================
336 void D3DHost_View::d3dBeginRender()
338 if (myD3dDevice == NULL)
343 // clear the back buffer
344 myD3dDevice->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
345 myD3dDevice->BeginScene();
348 // =======================================================================
349 // function : d3dEndRender
351 // =======================================================================
352 void D3DHost_View::d3dEndRender()
354 if (myD3dDevice != NULL)
356 myD3dDevice->EndScene();
360 // =======================================================================
361 // function : d3dSwap
363 // =======================================================================
364 bool D3DHost_View::d3dSwap()
366 if (myD3dDevice == NULL)
371 const HRESULT isOK = myD3dDevice->Present (NULL, NULL, NULL, NULL);
374 myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
375 TCollection_AsciiString("Direct3D9, Present device failed, ") + d3dFormatError (isOK));
377 return isOK == D3D_OK;
380 // =======================================================================
383 // =======================================================================
384 void D3DHost_View::Redraw()
386 if (!myWorkspace->Activate()
387 || myD3dDevice == NULL)
391 else if (!myFBO.IsNull())
393 OpenGl_View::Redraw();
397 Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
398 if (myWindow->PlatformWindow()->IsVirtual()
399 && aCtx->arbFBO == NULL)
401 // do a dirty hack in extreme fallback mode with OpenGL driver not supporting FBO,
402 // the back buffer of hidden window is used for rendering as offscreen buffer
403 myTransientDrawToFront = false;
404 int aWinSizeX = 0, aWinSizeY = 0;
405 myWindow->PlatformWindow()->Size (aWinSizeX, aWinSizeY);
406 WINDOWPLACEMENT aPlace;
407 GetWindowPlacement ((HWND )myWindow->PlatformWindow()->NativeHandle(), &aPlace);
408 if (aPlace.rcNormalPosition.right - aPlace.rcNormalPosition.left != aWinSizeX
409 || aPlace.rcNormalPosition.bottom - aPlace.rcNormalPosition.top != aWinSizeY)
411 aPlace.rcNormalPosition.right = aPlace.rcNormalPosition.left + aWinSizeX;
412 aPlace.rcNormalPosition.bottom = aPlace.rcNormalPosition.top + aWinSizeY;
413 aPlace.showCmd = SW_HIDE;
414 SetWindowPlacement ((HWND )myWindow->PlatformWindow()->NativeHandle(), &aPlace);
418 myD3dWglFbo->LockSurface (aCtx);
419 if (myD3dWglFbo->IsValid())
421 myToFlipOutput = Standard_True;
424 OpenGl_View::Redraw();
426 myD3dWglFbo->UnlockSurface (aCtx);
427 myToFlipOutput = Standard_False;
428 if (aCtx->caps->buffersNoSwap)
433 // blit result to the D3D back buffer and swap
436 IDirect3DSurface9* aBackbuffer = NULL;
437 myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
438 myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
439 aBackbuffer->Release();
445 // =======================================================================
446 // function : RedrawImmediate
448 // =======================================================================
449 void D3DHost_View::RedrawImmediate()
451 Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
452 if (!myTransientDrawToFront
453 || !myBackBufferRestored
454 || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
459 else if (!myWorkspace->Activate()
460 || myD3dDevice == NULL)
464 else if (!myFBO.IsNull())
466 OpenGl_View::Redraw();
470 myD3dWglFbo->LockSurface (aCtx);
471 if (myD3dWglFbo->IsValid())
473 myToFlipOutput = Standard_True;
476 OpenGl_View::RedrawImmediate();
478 myD3dWglFbo->UnlockSurface (aCtx);
479 myToFlipOutput = Standard_False;
480 if (aCtx->caps->buffersNoSwap)
485 // blit result to the D3D back buffer and swap
488 IDirect3DSurface9* aBackbuffer = NULL;
489 myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
490 myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
491 aBackbuffer->Release();
497 // =======================================================================
500 // =======================================================================
501 void D3DHost_View::Resized()
503 const Standard_Integer aWidthOld = myWindow->Width();
504 const Standard_Integer aHeightOld = myWindow->Height();
505 OpenGl_View::Resized();
506 if (aWidthOld == myWindow->Width()
507 && aHeightOld == myWindow->Height())
512 if (!myD3dWglFbo.IsNull())
514 myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
516 if (!myWorkspace->GetGlContext()->caps->buffersNoSwap)
520 d3dCreateRenderTarget();