0026862: Configuration - avoid usage of 3rd-party headers within OpenGl_View and...
[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 // =======================================================================
24 // function : d3dFormatError
25 // purpose  :
26 // =======================================================================
27 TCollection_AsciiString D3DHost_View::d3dFormatError (const long theErrCode)
28 {
29   switch (theErrCode)
30   {
31     case D3D_OK:                     return "OK";
32     case D3DERR_DEVICELOST:          return "Device lost";
33     case D3DERR_DEVICEREMOVED:       return "Device removed";
34     case D3DERR_DRIVERINTERNALERROR: return "Driver internal error";
35     case D3DERR_OUTOFVIDEOMEMORY:    return "Out of video memory";
36     case D3DERR_INVALIDCALL:         return "Invalid call";
37     default:                         return TCollection_AsciiString ("Error #") + int(theErrCode) + ")";
38   }
39 }
40
41 // =======================================================================
42 // function : D3DHost_View
43 // purpose  :
44 // =======================================================================
45 D3DHost_View::D3DHost_View (const Handle(Graphic3d_StructureManager)& theMgr,
46                             const Handle(D3DHost_GraphicDriver)& theDriver,
47                             const Handle(OpenGl_Caps)& theCaps,
48                             Standard_Boolean& theDeviceLostFlag,
49                             OpenGl_StateCounter* theCounter)
50 : OpenGl_View (theMgr, theDriver, theCaps, theDeviceLostFlag, theCounter),
51   myD3dLib      (NULL),
52   myD3dDevice   (NULL),
53   myD3dParams   (new D3DPRESENT_PARAMETERS()),
54   myRefreshRate (D3DPRESENT_RATE_DEFAULT),
55   myIsD3dEx     (false)
56 {
57   memset(myD3dParams.operator->(), 0, sizeof(D3DPRESENT_PARAMETERS));
58
59   myD3dParams->Windowed         = TRUE;
60   myD3dParams->SwapEffect       = D3DSWAPEFFECT_DISCARD;
61   myD3dParams->BackBufferFormat = D3DFMT_X8R8G8B8;
62   myD3dParams->BackBufferCount  = 1;
63   myD3dParams->BackBufferHeight = 2;
64   myD3dParams->BackBufferWidth  = 2;
65   myD3dParams->EnableAutoDepthStencil     = FALSE;
66   myD3dParams->AutoDepthStencilFormat     = D3DFMT_D16_LOCKABLE;
67   myD3dParams->FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
68   myD3dParams->PresentationInterval       = D3DPRESENT_INTERVAL_DEFAULT;
69 }
70
71 // =======================================================================
72 // function : ~D3DHost_View
73 // purpose  :
74 // =======================================================================
75 D3DHost_View::~D3DHost_View()
76 {
77   if (!myD3dWglFbo.IsNull())
78   {
79     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
80     myD3dWglFbo.Nullify();
81   }
82   if (myD3dDevice != NULL)
83   {
84     myD3dDevice->Release();
85     myD3dDevice = NULL;
86   }
87   if (myD3dLib != NULL)
88   {
89     myD3dLib->Release();
90     myD3dLib = NULL;
91   }
92 }
93
94 // =======================================================================
95 // function : SetWindow
96 // purpose  :
97 // =======================================================================
98 void D3DHost_View::SetWindow (const Handle(Aspect_Window)& theWindow,
99                               const Aspect_RenderingContext theContext)
100 {
101   if (!myD3dWglFbo.IsNull())
102   {
103     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
104     myD3dWglFbo.Nullify();
105   }
106   if (myD3dDevice != NULL)
107   {
108     myD3dDevice->Release();
109     myD3dDevice = NULL;
110   }
111
112   OpenGl_View::SetWindow (theWindow, theContext);
113
114   if (!myWindow.IsNull())
115   {
116     d3dInit();
117     d3dCreateRenderTarget();
118   }
119 }
120
121 // =======================================================================
122 // function : d3dInitLib
123 // purpose  :
124 // =======================================================================
125 bool D3DHost_View::d3dInitLib()
126 {
127   if (myD3dLib == NULL)
128   {
129     IDirect3D9Ex* aD3dLibEx = NULL;
130     // we link against d3d (using Direct3DCreate9 symbol), thus it should be already loaded
131     HMODULE aLib = GetModuleHandleW (L"d3d9");
132     if (aLib != NULL)
133     {
134       // retrieve D3D9Ex function dynamically (available only since Vista+)
135       typedef HRESULT (WINAPI* Direct3DCreate9Ex_t)(UINT , IDirect3D9Ex** );
136       Direct3DCreate9Ex_t Direct3DCreate9ExProc = (Direct3DCreate9Ex_t )GetProcAddress (aLib, "Direct3DCreate9Ex");
137       if (Direct3DCreate9ExProc != NULL)
138       {
139         Direct3DCreate9ExProc(D3D_SDK_VERSION, &aD3dLibEx);
140       }
141     }
142     myD3dLib  = aD3dLibEx;
143     myIsD3dEx = aD3dLibEx != NULL;
144     if (myD3dLib == NULL)
145     {
146       myD3dLib = Direct3DCreate9 (D3D_SDK_VERSION);
147     }
148   }
149   return myD3dLib != NULL;
150 }
151
152 // =======================================================================
153 // function : d3dInit
154 // purpose  :
155 // =======================================================================
156 bool D3DHost_View::d3dInit()
157 {
158   if (!d3dInitLib())
159   {
160     myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
161                                               GL_DEBUG_TYPE_ERROR_ARB,
162                                               0,
163                                               GL_DEBUG_SEVERITY_HIGH_ARB,
164                                               "Direct3DCreate9 failed!");
165     return false;
166   }
167
168   UINT anAdapterId = D3DADAPTER_DEFAULT;
169
170   // setup the present parameters
171   D3DDISPLAYMODE aCurrMode;
172   memset(&aCurrMode, 0, sizeof(aCurrMode));
173   if (myD3dLib->GetAdapterDisplayMode (anAdapterId, &aCurrMode) == D3D_OK)
174   {
175     myD3dParams->BackBufferFormat = aCurrMode.Format;
176     myRefreshRate = aCurrMode.RefreshRate;
177   }
178   myD3dParams->Windowed         = TRUE;
179   myD3dParams->BackBufferWidth  = myWindow->Width();
180   myD3dParams->BackBufferHeight = myWindow->Height();
181   myD3dParams->hDeviceWindow    = (HWND )myWindow->PlatformWindow()->NativeHandle();
182
183   // create the Video Device
184   HRESULT isOK = myD3dLib->CreateDevice (anAdapterId, D3DDEVTYPE_HAL,
185                                          (HWND )myWindow->PlatformWindow()->NativeHandle(),
186                                          D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
187                                          myD3dParams.get(), &myD3dDevice);
188   if (isOK < 0)
189   {
190     return false;
191   }
192
193   return myD3dDevice != NULL;
194 }
195
196 // =======================================================================
197 // function : d3dReset
198 // purpose  :
199 // =======================================================================
200 bool D3DHost_View::d3dReset()
201 {
202   if (myD3dDevice == NULL)
203   {
204     return false;
205   }
206
207   myD3dParams->Windowed         = TRUE;
208   myD3dParams->BackBufferWidth  = myWindow->Width();
209   myD3dParams->BackBufferHeight = myWindow->Height();
210   myD3dParams->hDeviceWindow    = (HWND )myWindow->PlatformWindow()->NativeHandle();
211   myD3dParams->FullScreen_RefreshRateInHz = !myD3dParams->Windowed ? myRefreshRate : 0;
212
213   HRESULT isOK = myD3dDevice->Reset(myD3dParams.get());
214   return isOK == D3D_OK;
215 }
216
217 // =======================================================================
218 // function : d3dCreateRenderTarget
219 // purpose  :
220 // =======================================================================
221 bool D3DHost_View::d3dCreateRenderTarget()
222 {
223   if (myD3dWglFbo.IsNull())
224   {
225     myD3dWglFbo = new D3DHost_FrameBuffer();
226   }
227   if (!myD3dWglFbo->Init (myWorkspace->GetGlContext(),
228                           myD3dDevice,
229                           myIsD3dEx,
230                           myWindow->Width(),
231                           myWindow->Height()))
232   {
233     return false;
234   }
235
236   myD3dDevice->SetRenderTarget (0, myD3dWglFbo->D3dColorSurface());
237   return true;
238 }
239
240 // =======================================================================
241 // function : d3dBeginRender
242 // purpose  :
243 // =======================================================================
244 void D3DHost_View::d3dBeginRender()
245 {
246   if (myD3dDevice == NULL)
247   {
248     return;
249   }
250
251   // clear the back buffer
252   myD3dDevice->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
253   myD3dDevice->BeginScene();
254 }
255
256 // =======================================================================
257 // function : d3dEndRender
258 // purpose  :
259 // =======================================================================
260 void D3DHost_View::d3dEndRender()
261 {
262   if (myD3dDevice != NULL)
263   {
264     myD3dDevice->EndScene();
265   }
266 }
267
268 // =======================================================================
269 // function : d3dSwap
270 // purpose  :
271 // =======================================================================
272 bool D3DHost_View::d3dSwap()
273 {
274   if (myD3dDevice == NULL)
275   {
276     return false;
277   }
278
279   const HRESULT isOK = myD3dDevice->Present (NULL, NULL, NULL, NULL);
280   if (isOK != D3D_OK)
281   {
282     TCollection_ExtendedString aMsg = TCollection_ExtendedString()
283       + "Direct3D9, Present device failed, " + d3dFormatError (isOK);
284     myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
285                                               GL_DEBUG_TYPE_ERROR_ARB,
286                                               0,
287                                               GL_DEBUG_SEVERITY_HIGH_ARB,
288                                               aMsg);
289   }
290   return isOK == D3D_OK;
291 }
292
293 // =======================================================================
294 // function : Redraw
295 // purpose  :
296 // =======================================================================
297 void D3DHost_View::Redraw()
298 {
299   if (!myWorkspace->Activate()
300     || myD3dDevice == NULL)
301   {
302     return;
303   }
304   else if (myFBO != NULL)
305   {
306     OpenGl_View::Redraw();
307     return;
308   }
309
310   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
311   myToFlipOutput = Standard_True;
312   myD3dWglFbo->LockSurface   (aCtx);
313   myFBO = myD3dWglFbo.get();
314   OpenGl_View::Redraw();
315   myFBO = NULL;
316   myD3dWglFbo->UnlockSurface (aCtx);
317   myToFlipOutput = Standard_False;
318   if (aCtx->caps->buffersNoSwap)
319   {
320     return;
321   }
322
323   // blit result to the D3D back buffer and swap
324   d3dBeginRender();
325
326   IDirect3DSurface9* aBackbuffer = NULL;
327   myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
328   myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
329   aBackbuffer->Release();
330
331   d3dEndRender();
332   d3dSwap();
333 }
334
335 // =======================================================================
336 // function : RedrawImmediate
337 // purpose  :
338 // =======================================================================
339 void D3DHost_View::RedrawImmediate()
340 {
341   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
342   if (!myTransientDrawToFront
343    || !myBackBufferRestored
344    || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
345   {
346     Redraw();
347     return;
348   }
349   else if (!myWorkspace->Activate()
350          || myD3dDevice == NULL)
351   {
352     return;
353   }
354   else if (myFBO != NULL)
355   {
356     OpenGl_View::Redraw();
357     return;
358   }
359
360   myToFlipOutput = Standard_True;
361   myD3dWglFbo->LockSurface   (aCtx);
362   myFBO = myD3dWglFbo.get();
363   OpenGl_View::RedrawImmediate();
364   myFBO = NULL;
365   myD3dWglFbo->UnlockSurface (aCtx);
366   myToFlipOutput = Standard_False;
367   if (aCtx->caps->buffersNoSwap)
368   {
369     return;
370   }
371
372   // blit result to the D3D back buffer and swap
373   d3dBeginRender();
374
375   IDirect3DSurface9* aBackbuffer = NULL;
376   myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
377   myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
378   aBackbuffer->Release();
379
380   d3dEndRender();
381   d3dSwap();
382 }
383
384 // =======================================================================
385 // function : Resize
386 // purpose  :
387 // =======================================================================
388 void D3DHost_View::Resized()
389 {
390   const Standard_Integer aWidthOld  = myWindow->Width();
391   const Standard_Integer aHeightOld = myWindow->Height();
392   OpenGl_View::Resized();
393   if (aWidthOld  == myWindow->Width()
394    && aHeightOld == myWindow->Height())
395   {
396     return;
397   }
398
399   if (!myD3dWglFbo.IsNull())
400   {
401     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
402   }
403   if (!myWorkspace->GetGlContext()->caps->buffersNoSwap)
404   {
405     d3dReset();
406   }
407   d3dCreateRenderTarget();
408 }