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