0030609: Coding - eliminate warnings issued by gcc 8.1.0
[occt.git] / src / D3DHost / D3DHost_View.cxx
1 // Created on: 2015-06-10
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2015 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <d3d9.h>
17
18 #include <D3DHost_View.hxx>
19
20 #include <D3DHost_GraphicDriver.hxx>
21 #include <TCollection_ExtendedString.hxx>
22
23 #include <Standard_WarningDisableFunctionCast.hxx>
24
25 IMPLEMENT_STANDARD_RTTIEXT(D3DHost_View,OpenGl_View)
26
27 // =======================================================================
28 // function : d3dFormatError
29 // purpose  :
30 // =======================================================================
31 TCollection_AsciiString D3DHost_View::d3dFormatError (const long theErrCode)
32 {
33   switch (theErrCode)
34   {
35     case D3D_OK:                     return "OK";
36     case D3DERR_DEVICELOST:          return "Device lost";
37     case D3DERR_DEVICEREMOVED:       return "Device removed";
38     case D3DERR_DRIVERINTERNALERROR: return "Driver internal error";
39     case D3DERR_OUTOFVIDEOMEMORY:    return "Out of video memory";
40     case D3DERR_INVALIDCALL:         return "Invalid call";
41     default:                         return TCollection_AsciiString ("Error #") + int(theErrCode) + ")";
42   }
43 }
44
45 // =======================================================================
46 // function : D3DHost_View
47 // purpose  :
48 // =======================================================================
49 D3DHost_View::D3DHost_View (const Handle(Graphic3d_StructureManager)& theMgr,
50                             const Handle(D3DHost_GraphicDriver)& theDriver,
51                             const Handle(OpenGl_Caps)& theCaps,
52                             OpenGl_StateCounter* theCounter)
53 : OpenGl_View (theMgr, theDriver, theCaps, theCounter),
54   myD3dLib      (NULL),
55   myD3dDevice   (NULL),
56   myD3dParams   (new D3DPRESENT_PARAMETERS()),
57   myRefreshRate (D3DPRESENT_RATE_DEFAULT),
58   myIsD3dEx     (false)
59 {
60   memset(myD3dParams.operator->(), 0, sizeof(D3DPRESENT_PARAMETERS));
61
62   myD3dParams->Windowed         = TRUE;
63   myD3dParams->SwapEffect       = D3DSWAPEFFECT_DISCARD;
64   myD3dParams->BackBufferFormat = D3DFMT_X8R8G8B8;
65   myD3dParams->BackBufferCount  = 1;
66   myD3dParams->BackBufferHeight = 2;
67   myD3dParams->BackBufferWidth  = 2;
68   myD3dParams->EnableAutoDepthStencil     = FALSE;
69   myD3dParams->AutoDepthStencilFormat     = D3DFMT_D16_LOCKABLE;
70   myD3dParams->FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
71   myD3dParams->PresentationInterval       = D3DPRESENT_INTERVAL_DEFAULT;
72 }
73
74 // =======================================================================
75 // function : ~D3DHost_View
76 // purpose  :
77 // =======================================================================
78 D3DHost_View::~D3DHost_View()
79 {
80   if (!myD3dWglFbo.IsNull())
81   {
82     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
83     myD3dWglFbo.Nullify();
84   }
85   if (myD3dDevice != NULL)
86   {
87     myD3dDevice->Release();
88     myD3dDevice = NULL;
89   }
90   if (myD3dLib != NULL)
91   {
92     myD3dLib->Release();
93     myD3dLib = NULL;
94   }
95 }
96
97 // =======================================================================
98 // function : D3dColorSurface
99 // purpose  :
100 // =======================================================================
101 IDirect3DSurface9* D3DHost_View::D3dColorSurface() const
102 {
103   return myD3dWglFbo->D3dColorSurface();
104 }
105
106 // =======================================================================
107 // function : SetWindow
108 // purpose  :
109 // =======================================================================
110 void D3DHost_View::SetWindow (const Handle(Aspect_Window)& theWindow,
111                               const Aspect_RenderingContext theContext)
112 {
113   if (!myD3dWglFbo.IsNull())
114   {
115     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
116     myD3dWglFbo.Nullify();
117   }
118   if (myD3dDevice != NULL)
119   {
120     myD3dDevice->Release();
121     myD3dDevice = NULL;
122   }
123
124   OpenGl_View::SetWindow (theWindow, theContext);
125
126   if (!myWindow.IsNull())
127   {
128     d3dInit();
129     d3dCreateRenderTarget();
130   }
131 }
132
133 // =======================================================================
134 // function : d3dInitLib
135 // purpose  :
136 // =======================================================================
137 bool D3DHost_View::d3dInitLib()
138 {
139   if (myD3dLib == NULL)
140   {
141     IDirect3D9Ex* aD3dLibEx = NULL;
142     // we link against d3d (using Direct3DCreate9 symbol), thus it should be already loaded
143     HMODULE aLib = GetModuleHandleW (L"d3d9");
144     if (aLib != NULL)
145     {
146       // retrieve D3D9Ex function dynamically (available only since Vista+)
147       typedef HRESULT (WINAPI* Direct3DCreate9Ex_t)(UINT , IDirect3D9Ex** );
148       Direct3DCreate9Ex_t Direct3DCreate9ExProc = (Direct3DCreate9Ex_t )GetProcAddress (aLib, "Direct3DCreate9Ex");
149       if (Direct3DCreate9ExProc != NULL)
150       {
151         Direct3DCreate9ExProc(D3D_SDK_VERSION, &aD3dLibEx);
152       }
153     }
154     myD3dLib  = aD3dLibEx;
155     myIsD3dEx = aD3dLibEx != NULL;
156     if (myD3dLib == NULL)
157     {
158       myD3dLib = Direct3DCreate9 (D3D_SDK_VERSION);
159     }
160   }
161   return myD3dLib != NULL;
162 }
163
164 // =======================================================================
165 // function : d3dInit
166 // purpose  :
167 // =======================================================================
168 bool D3DHost_View::d3dInit()
169 {
170   if (!d3dInitLib())
171   {
172     myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Direct3DCreate9 failed!");
173     return false;
174   }
175
176   UINT anAdapterId = D3DADAPTER_DEFAULT;
177
178   // setup the present parameters
179   D3DDISPLAYMODE aCurrMode;
180   memset(&aCurrMode, 0, sizeof(aCurrMode));
181   if (myD3dLib->GetAdapterDisplayMode (anAdapterId, &aCurrMode) == D3D_OK)
182   {
183     myD3dParams->BackBufferFormat = aCurrMode.Format;
184     myRefreshRate = aCurrMode.RefreshRate;
185   }
186   myD3dParams->Windowed         = TRUE;
187   myD3dParams->BackBufferWidth  = myWindow->Width();
188   myD3dParams->BackBufferHeight = myWindow->Height();
189   myD3dParams->hDeviceWindow    = (HWND )myWindow->PlatformWindow()->NativeHandle();
190
191   // create the Video Device
192   HRESULT isOK = myD3dLib->CreateDevice (anAdapterId, D3DDEVTYPE_HAL,
193                                          (HWND )myWindow->PlatformWindow()->NativeHandle(),
194                                          D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
195                                          myD3dParams.get(), &myD3dDevice);
196   if (isOK < 0)
197   {
198     return false;
199   }
200
201   return myD3dDevice != NULL;
202 }
203
204 // =======================================================================
205 // function : d3dReset
206 // purpose  :
207 // =======================================================================
208 bool D3DHost_View::d3dReset()
209 {
210   if (myD3dDevice == NULL)
211   {
212     return false;
213   }
214
215   myD3dParams->Windowed         = TRUE;
216   myD3dParams->BackBufferWidth  = myWindow->Width();
217   myD3dParams->BackBufferHeight = myWindow->Height();
218   myD3dParams->hDeviceWindow    = (HWND )myWindow->PlatformWindow()->NativeHandle();
219   myD3dParams->FullScreen_RefreshRateInHz = !myD3dParams->Windowed ? myRefreshRate : 0;
220
221   HRESULT isOK = myD3dDevice->Reset(myD3dParams.get());
222   return isOK == D3D_OK;
223 }
224
225 // =======================================================================
226 // function : d3dCreateRenderTarget
227 // purpose  :
228 // =======================================================================
229 bool D3DHost_View::d3dCreateRenderTarget()
230 {
231   bool toD3dFallback = false;
232   if (myD3dWglFbo.IsNull())
233   {
234     myD3dWglFbo = new D3DHost_FrameBuffer();
235   }
236   else
237   {
238     toD3dFallback = myD3dWglFbo->D3dFallback();
239   }
240
241   if (!toD3dFallback)
242   {
243     toD3dFallback = !myD3dWglFbo->InitD3dInterop (myWorkspace->GetGlContext(),
244                                                   myD3dDevice,
245                                                   myIsD3dEx,
246                                                   myWindow->Width(),
247                                                   myWindow->Height(),
248                                                   0); // do not request depth-stencil attachment since buffer will be flipped using addition FBO (myToFlipOutput)
249   }
250   if (toD3dFallback)
251   {
252     if (!myD3dWglFbo->InitD3dFallback (myWorkspace->GetGlContext(),
253                                        myD3dDevice,
254                                        myIsD3dEx,
255                                        myWindow->Width(),
256                                        myWindow->Height(),
257                                        GL_DEPTH24_STENCIL8))
258     {
259       return false;
260     }
261   }
262
263   myD3dDevice->SetRenderTarget (0, myD3dWglFbo->D3dColorSurface());
264   return true;
265 }
266
267 // =======================================================================
268 // function : d3dBeginRender
269 // purpose  :
270 // =======================================================================
271 void D3DHost_View::d3dBeginRender()
272 {
273   if (myD3dDevice == NULL)
274   {
275     return;
276   }
277
278   // clear the back buffer
279   myD3dDevice->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
280   myD3dDevice->BeginScene();
281 }
282
283 // =======================================================================
284 // function : d3dEndRender
285 // purpose  :
286 // =======================================================================
287 void D3DHost_View::d3dEndRender()
288 {
289   if (myD3dDevice != NULL)
290   {
291     myD3dDevice->EndScene();
292   }
293 }
294
295 // =======================================================================
296 // function : d3dSwap
297 // purpose  :
298 // =======================================================================
299 bool D3DHost_View::d3dSwap()
300 {
301   if (myD3dDevice == NULL)
302   {
303     return false;
304   }
305
306   const HRESULT isOK = myD3dDevice->Present (NULL, NULL, NULL, NULL);
307   if (isOK != D3D_OK)
308   {
309     myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
310                                               TCollection_AsciiString("Direct3D9, Present device failed, ") + d3dFormatError (isOK));
311   }
312   return isOK == D3D_OK;
313 }
314
315 // =======================================================================
316 // function : Redraw
317 // purpose  :
318 // =======================================================================
319 void D3DHost_View::Redraw()
320 {
321   if (!myWorkspace->Activate()
322     || myD3dDevice == NULL)
323   {
324     return;
325   }
326   else if (!myFBO.IsNull())
327   {
328     OpenGl_View::Redraw();
329     return;
330   }
331
332   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
333   if (myWindow->PlatformWindow()->IsVirtual()
334   &&  aCtx->arbFBO == NULL)
335   {
336     // do a dirty hack in extreme fallback mode with OpenGL driver not supporting FBO,
337     // the back buffer of hidden window is used for rendering as offscreen buffer
338     myTransientDrawToFront = false;
339     int aWinSizeX = 0, aWinSizeY = 0;
340     myWindow->PlatformWindow()->Size (aWinSizeX, aWinSizeY);
341     WINDOWPLACEMENT aPlace;
342     GetWindowPlacement ((HWND )myWindow->PlatformWindow()->NativeHandle(), &aPlace);
343     if (aPlace.rcNormalPosition.right  - aPlace.rcNormalPosition.left != aWinSizeX
344      || aPlace.rcNormalPosition.bottom - aPlace.rcNormalPosition.top  != aWinSizeY)
345     {
346       aPlace.rcNormalPosition.right  = aPlace.rcNormalPosition.left + aWinSizeX;
347       aPlace.rcNormalPosition.bottom = aPlace.rcNormalPosition.top  + aWinSizeY;
348       aPlace.showCmd = SW_HIDE;
349       SetWindowPlacement ((HWND )myWindow->PlatformWindow()->NativeHandle(), &aPlace);
350     }
351   }
352
353   myD3dWglFbo->LockSurface   (aCtx);
354   if (myD3dWglFbo->IsValid())
355   {
356     myToFlipOutput = Standard_True;
357     myFBO = myD3dWglFbo;
358   }
359   OpenGl_View::Redraw();
360   myFBO.Nullify();
361   myD3dWglFbo->UnlockSurface (aCtx);
362   myToFlipOutput = Standard_False;
363   if (aCtx->caps->buffersNoSwap)
364   {
365     return;
366   }
367
368   // blit result to the D3D back buffer and swap
369   d3dBeginRender();
370
371   IDirect3DSurface9* aBackbuffer = NULL;
372   myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
373   myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
374   aBackbuffer->Release();
375
376   d3dEndRender();
377   d3dSwap();
378 }
379
380 // =======================================================================
381 // function : RedrawImmediate
382 // purpose  :
383 // =======================================================================
384 void D3DHost_View::RedrawImmediate()
385 {
386   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
387   if (!myTransientDrawToFront
388    || !myBackBufferRestored
389    || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
390   {
391     Redraw();
392     return;
393   }
394   else if (!myWorkspace->Activate()
395          || myD3dDevice == NULL)
396   {
397     return;
398   }
399   else if (!myFBO.IsNull())
400   {
401     OpenGl_View::Redraw();
402     return;
403   }
404
405   myD3dWglFbo->LockSurface   (aCtx);
406   if (myD3dWglFbo->IsValid())
407   {
408     myToFlipOutput = Standard_True;
409     myFBO = myD3dWglFbo;
410   }
411   OpenGl_View::RedrawImmediate();
412   myFBO.Nullify();
413   myD3dWglFbo->UnlockSurface (aCtx);
414   myToFlipOutput = Standard_False;
415   if (aCtx->caps->buffersNoSwap)
416   {
417     return;
418   }
419
420   // blit result to the D3D back buffer and swap
421   d3dBeginRender();
422
423   IDirect3DSurface9* aBackbuffer = NULL;
424   myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
425   myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
426   aBackbuffer->Release();
427
428   d3dEndRender();
429   d3dSwap();
430 }
431
432 // =======================================================================
433 // function : Resize
434 // purpose  :
435 // =======================================================================
436 void D3DHost_View::Resized()
437 {
438   const Standard_Integer aWidthOld  = myWindow->Width();
439   const Standard_Integer aHeightOld = myWindow->Height();
440   OpenGl_View::Resized();
441   if (aWidthOld  == myWindow->Width()
442    && aHeightOld == myWindow->Height())
443   {
444     return;
445   }
446
447   if (!myD3dWglFbo.IsNull())
448   {
449     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
450   }
451   if (!myWorkspace->GetGlContext()->caps->buffersNoSwap)
452   {
453     d3dReset();
454   }
455   d3dCreateRenderTarget();
456 }