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