0026734: Visualization, D3DHost_View - drop outdated UserDraw interfaces
[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 {
98   if (!myD3dWglFbo.IsNull())
99   {
100     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
101     myD3dWglFbo.Nullify();
102   }
103   if (myD3dDevice != NULL)
104   {
105     myD3dDevice->Release();
106     myD3dDevice = NULL;
107   }
108
109   OpenGl_View::SetWindow (theWindow, theContext);
110
111   if (!myWindow.IsNull())
112   {
113     d3dInit();
114     d3dCreateRenderTarget();
115   }
116 }
117
118 // =======================================================================
119 // function : d3dInitLib
120 // purpose  :
121 // =======================================================================
122 bool D3DHost_View::d3dInitLib()
123 {
124   if (myD3dLib == NULL)
125   {
126     IDirect3D9Ex* aD3dLibEx = NULL;
127     // we link against d3d (using Direct3DCreate9 symbol), thus it should be already loaded
128     HMODULE aLib = GetModuleHandleW (L"d3d9");
129     if (aLib != NULL)
130     {
131       // retrieve D3D9Ex function dynamically (available only since Vista+)
132       typedef HRESULT (WINAPI* Direct3DCreate9Ex_t)(UINT , IDirect3D9Ex** );
133       Direct3DCreate9Ex_t Direct3DCreate9ExProc = (Direct3DCreate9Ex_t )GetProcAddress (aLib, "Direct3DCreate9Ex");
134       if (Direct3DCreate9ExProc != NULL)
135       {
136         Direct3DCreate9ExProc(D3D_SDK_VERSION, &aD3dLibEx);
137       }
138     }
139     myD3dLib  = aD3dLibEx;
140     myIsD3dEx = aD3dLibEx != NULL;
141     if (myD3dLib == NULL)
142     {
143       myD3dLib = Direct3DCreate9 (D3D_SDK_VERSION);
144     }
145   }
146   return myD3dLib != NULL;
147 }
148
149 // =======================================================================
150 // function : d3dInit
151 // purpose  :
152 // =======================================================================
153 bool D3DHost_View::d3dInit()
154 {
155   if (!d3dInitLib())
156   {
157     myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
158                                               GL_DEBUG_TYPE_ERROR_ARB,
159                                               0,
160                                               GL_DEBUG_SEVERITY_HIGH_ARB,
161                                               "Direct3DCreate9 failed!");
162     return false;
163   }
164
165   UINT anAdapterId = D3DADAPTER_DEFAULT;
166
167   // setup the present parameters
168   if (myD3dLib->GetAdapterDisplayMode (anAdapterId, &myCurrMode) == D3D_OK)
169   {
170     myD3dParams.BackBufferFormat = myCurrMode.Format;
171     myRefreshRate = myCurrMode.RefreshRate;
172   }
173   myD3dParams.Windowed         = TRUE;
174   myD3dParams.BackBufferWidth  = myWindow->Width();
175   myD3dParams.BackBufferHeight = myWindow->Height();
176   myD3dParams.hDeviceWindow    = (HWND )myWindow->PlatformWindow()->NativeHandle();
177
178   // create the Video Device
179   HRESULT isOK = myD3dLib->CreateDevice (anAdapterId, D3DDEVTYPE_HAL,
180                                          (HWND )myWindow->PlatformWindow()->NativeHandle(),
181                                          D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
182                                          &myD3dParams, &myD3dDevice);
183   if (isOK < 0)
184   {
185     return false;
186   }
187
188   return myD3dDevice != NULL;
189 }
190
191 // =======================================================================
192 // function : d3dReset
193 // purpose  :
194 // =======================================================================
195 bool D3DHost_View::d3dReset()
196 {
197   if (myD3dDevice == NULL)
198   {
199     return false;
200   }
201
202   myD3dParams.Windowed         = TRUE;
203   myD3dParams.BackBufferWidth  = myWindow->Width();
204   myD3dParams.BackBufferHeight = myWindow->Height();
205   myD3dParams.hDeviceWindow    = (HWND )myWindow->PlatformWindow()->NativeHandle();
206   myD3dParams.FullScreen_RefreshRateInHz = !myD3dParams.Windowed ? myRefreshRate : 0;
207
208   HRESULT isOK = myD3dDevice->Reset(&myD3dParams);
209   return isOK == D3D_OK;
210 }
211
212 // =======================================================================
213 // function : d3dCreateRenderTarget
214 // purpose  :
215 // =======================================================================
216 bool D3DHost_View::d3dCreateRenderTarget()
217 {
218   if (myD3dWglFbo.IsNull())
219   {
220     myD3dWglFbo = new D3DHost_FrameBuffer();
221   }
222   if (!myD3dWglFbo->Init (myWorkspace->GetGlContext(),
223                           myD3dDevice,
224                           myIsD3dEx,
225                           myWindow->Width(),
226                           myWindow->Height()))
227   {
228     return false;
229   }
230
231   myD3dDevice->SetRenderTarget (0, myD3dWglFbo->D3dColorSurface());
232   return true;
233 }
234
235 // =======================================================================
236 // function : d3dBeginRender
237 // purpose  :
238 // =======================================================================
239 void D3DHost_View::d3dBeginRender()
240 {
241   if (myD3dDevice == NULL)
242   {
243     return;
244   }
245
246   // clear the back buffer
247   myD3dDevice->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
248   myD3dDevice->BeginScene();
249 }
250
251 // =======================================================================
252 // function : d3dEndRender
253 // purpose  :
254 // =======================================================================
255 void D3DHost_View::d3dEndRender()
256 {
257   if (myD3dDevice != NULL)
258   {
259     myD3dDevice->EndScene();
260   }
261 }
262
263 // =======================================================================
264 // function : d3dSwap
265 // purpose  :
266 // =======================================================================
267 bool D3DHost_View::d3dSwap()
268 {
269   if (myD3dDevice == NULL)
270   {
271     return false;
272   }
273
274   const HRESULT isOK = myD3dDevice->Present (NULL, NULL, NULL, NULL);
275   if (isOK != D3D_OK)
276   {
277     TCollection_ExtendedString aMsg = TCollection_ExtendedString()
278       + "Direct3D9, Present device failed, " + d3dFormatError (isOK);
279     myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
280                                               GL_DEBUG_TYPE_ERROR_ARB,
281                                               0,
282                                               GL_DEBUG_SEVERITY_HIGH_ARB,
283                                               aMsg);
284   }
285   return isOK == D3D_OK;
286 }
287
288 // =======================================================================
289 // function : Redraw
290 // purpose  :
291 // =======================================================================
292 void D3DHost_View::Redraw()
293 {
294   if (!myWorkspace->Activate()
295     || myD3dDevice == NULL)
296   {
297     return;
298   }
299
300   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
301   myToFlipOutput = Standard_True;
302   myD3dWglFbo->LockSurface   (aCtx);
303   OpenGl_View::Redraw();
304   myD3dWglFbo->UnlockSurface (aCtx);
305   myToFlipOutput = Standard_False;
306   if (aCtx->caps->buffersNoSwap)
307   {
308     return;
309   }
310
311   // blit result to the D3D back buffer and swap
312   d3dBeginRender();
313
314   IDirect3DSurface9* aBackbuffer = NULL;
315   myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
316   myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
317   aBackbuffer->Release();
318
319   d3dEndRender();
320   d3dSwap();
321 }
322
323 // =======================================================================
324 // function : RedrawImmediate
325 // purpose  :
326 // =======================================================================
327 void D3DHost_View::RedrawImmediate()
328 {
329   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
330   if (!myTransientDrawToFront
331    || !myBackBufferRestored
332    || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
333   {
334     Redraw();
335     return;
336   }
337   else if (!myWorkspace->Activate()
338          || myD3dDevice == NULL)
339   {
340     return;
341   }
342
343   myToFlipOutput = Standard_True;
344   myD3dWglFbo->LockSurface   (aCtx);
345   OpenGl_View::RedrawImmediate();
346   myD3dWglFbo->UnlockSurface (aCtx);
347   myToFlipOutput = Standard_False;
348   if (aCtx->caps->buffersNoSwap)
349   {
350     return;
351   }
352
353   // blit result to the D3D back buffer and swap
354   d3dBeginRender();
355
356   IDirect3DSurface9* aBackbuffer = NULL;
357   myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
358   myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
359   aBackbuffer->Release();
360
361   d3dEndRender();
362   d3dSwap();
363 }
364
365 // =======================================================================
366 // function : Resize
367 // purpose  :
368 // =======================================================================
369 void D3DHost_View::Resized()
370 {
371   const Standard_Integer aWidthOld  = myWindow->Width();
372   const Standard_Integer aHeightOld = myWindow->Height();
373   OpenGl_View::Resized();
374   if (aWidthOld  == myWindow->Width()
375    && aHeightOld == myWindow->Height())
376   {
377     return;
378   }
379
380   if (!myD3dWglFbo.IsNull())
381   {
382     myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
383   }
384   if (!myWorkspace->GetGlContext()->caps->buffersNoSwap)
385   {
386     d3dReset();
387   }
388   d3dCreateRenderTarget();
389 }