62e1beed |
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 | |
d2eddacc |
16 | #include <d3d9.h> |
17 | |
c357e426 |
18 | #include <D3DHost_View.hxx> |
62e1beed |
19 | |
c357e426 |
20 | #include <D3DHost_GraphicDriver.hxx> |
62e1beed |
21 | #include <TCollection_ExtendedString.hxx> |
22 | |
92efcf78 |
23 | IMPLEMENT_STANDARD_RTTIEXT(D3DHost_View,OpenGl_View) |
24 | |
62e1beed |
25 | // ======================================================================= |
26 | // function : d3dFormatError |
27 | // purpose : |
28 | // ======================================================================= |
d2eddacc |
29 | TCollection_AsciiString D3DHost_View::d3dFormatError (const long theErrCode) |
62e1beed |
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 | // ======================================================================= |
c357e426 |
44 | // function : D3DHost_View |
62e1beed |
45 | // purpose : |
46 | // ======================================================================= |
c357e426 |
47 | D3DHost_View::D3DHost_View (const Handle(Graphic3d_StructureManager)& theMgr, |
48 | const Handle(D3DHost_GraphicDriver)& theDriver, |
49 | const Handle(OpenGl_Caps)& theCaps, |
c357e426 |
50 | OpenGl_StateCounter* theCounter) |
851dacdb |
51 | : OpenGl_View (theMgr, theDriver, theCaps, theCounter), |
62e1beed |
52 | myD3dLib (NULL), |
53 | myD3dDevice (NULL), |
d2eddacc |
54 | myD3dParams (new D3DPRESENT_PARAMETERS()), |
62e1beed |
55 | myRefreshRate (D3DPRESENT_RATE_DEFAULT), |
56 | myIsD3dEx (false) |
57 | { |
d2eddacc |
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; |
62e1beed |
70 | } |
71 | |
72 | // ======================================================================= |
c357e426 |
73 | // function : ~D3DHost_View |
62e1beed |
74 | // purpose : |
75 | // ======================================================================= |
c357e426 |
76 | D3DHost_View::~D3DHost_View() |
62e1beed |
77 | { |
78 | if (!myD3dWglFbo.IsNull()) |
79 | { |
c357e426 |
80 | myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->()); |
62e1beed |
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 | |
c357e426 |
95 | // ======================================================================= |
96 | // function : SetWindow |
97 | // purpose : |
98 | // ======================================================================= |
99 | void D3DHost_View::SetWindow (const Handle(Aspect_Window)& theWindow, |
7aa74f30 |
100 | const Aspect_RenderingContext theContext) |
c357e426 |
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 | |
7aa74f30 |
113 | OpenGl_View::SetWindow (theWindow, theContext); |
c357e426 |
114 | |
115 | if (!myWindow.IsNull()) |
116 | { |
117 | d3dInit(); |
118 | d3dCreateRenderTarget(); |
119 | } |
120 | } |
121 | |
62e1beed |
122 | // ======================================================================= |
123 | // function : d3dInitLib |
124 | // purpose : |
125 | // ======================================================================= |
c357e426 |
126 | bool D3DHost_View::d3dInitLib() |
62e1beed |
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 | // ======================================================================= |
c357e426 |
157 | bool D3DHost_View::d3dInit() |
62e1beed |
158 | { |
159 | if (!d3dInitLib()) |
160 | { |
c357e426 |
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!"); |
62e1beed |
166 | return false; |
167 | } |
168 | |
169 | UINT anAdapterId = D3DADAPTER_DEFAULT; |
170 | |
171 | // setup the present parameters |
d2eddacc |
172 | D3DDISPLAYMODE aCurrMode; |
173 | memset(&aCurrMode, 0, sizeof(aCurrMode)); |
174 | if (myD3dLib->GetAdapterDisplayMode (anAdapterId, &aCurrMode) == D3D_OK) |
62e1beed |
175 | { |
d2eddacc |
176 | myD3dParams->BackBufferFormat = aCurrMode.Format; |
177 | myRefreshRate = aCurrMode.RefreshRate; |
62e1beed |
178 | } |
d2eddacc |
179 | myD3dParams->Windowed = TRUE; |
180 | myD3dParams->BackBufferWidth = myWindow->Width(); |
181 | myD3dParams->BackBufferHeight = myWindow->Height(); |
182 | myD3dParams->hDeviceWindow = (HWND )myWindow->PlatformWindow()->NativeHandle(); |
62e1beed |
183 | |
184 | // create the Video Device |
185 | HRESULT isOK = myD3dLib->CreateDevice (anAdapterId, D3DDEVTYPE_HAL, |
c357e426 |
186 | (HWND )myWindow->PlatformWindow()->NativeHandle(), |
62e1beed |
187 | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, |
d2eddacc |
188 | myD3dParams.get(), &myD3dDevice); |
62e1beed |
189 | if (isOK < 0) |
190 | { |
191 | return false; |
192 | } |
193 | |
194 | return myD3dDevice != NULL; |
195 | } |
196 | |
197 | // ======================================================================= |
198 | // function : d3dReset |
199 | // purpose : |
200 | // ======================================================================= |
c357e426 |
201 | bool D3DHost_View::d3dReset() |
62e1beed |
202 | { |
203 | if (myD3dDevice == NULL) |
204 | { |
205 | return false; |
206 | } |
207 | |
d2eddacc |
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; |
62e1beed |
213 | |
d2eddacc |
214 | HRESULT isOK = myD3dDevice->Reset(myD3dParams.get()); |
62e1beed |
215 | return isOK == D3D_OK; |
216 | } |
217 | |
218 | // ======================================================================= |
219 | // function : d3dCreateRenderTarget |
220 | // purpose : |
221 | // ======================================================================= |
c357e426 |
222 | bool D3DHost_View::d3dCreateRenderTarget() |
62e1beed |
223 | { |
224 | if (myD3dWglFbo.IsNull()) |
225 | { |
226 | myD3dWglFbo = new D3DHost_FrameBuffer(); |
227 | } |
c357e426 |
228 | if (!myD3dWglFbo->Init (myWorkspace->GetGlContext(), |
229 | myD3dDevice, |
230 | myIsD3dEx, |
231 | myWindow->Width(), |
232 | myWindow->Height())) |
62e1beed |
233 | { |
234 | return false; |
235 | } |
236 | |
237 | myD3dDevice->SetRenderTarget (0, myD3dWglFbo->D3dColorSurface()); |
238 | return true; |
239 | } |
240 | |
241 | // ======================================================================= |
242 | // function : d3dBeginRender |
243 | // purpose : |
244 | // ======================================================================= |
c357e426 |
245 | void D3DHost_View::d3dBeginRender() |
62e1beed |
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 | // ======================================================================= |
c357e426 |
261 | void D3DHost_View::d3dEndRender() |
62e1beed |
262 | { |
263 | if (myD3dDevice != NULL) |
264 | { |
265 | myD3dDevice->EndScene(); |
266 | } |
267 | } |
268 | |
269 | // ======================================================================= |
270 | // function : d3dSwap |
271 | // purpose : |
272 | // ======================================================================= |
c357e426 |
273 | bool D3DHost_View::d3dSwap() |
62e1beed |
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); |
c357e426 |
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); |
62e1beed |
290 | } |
291 | return isOK == D3D_OK; |
292 | } |
293 | |
294 | // ======================================================================= |
295 | // function : Redraw |
296 | // purpose : |
297 | // ======================================================================= |
c357e426 |
298 | void D3DHost_View::Redraw() |
62e1beed |
299 | { |
c357e426 |
300 | if (!myWorkspace->Activate() |
62e1beed |
301 | || myD3dDevice == NULL) |
302 | { |
303 | return; |
304 | } |
b128c892 |
305 | else if (!myFBO.IsNull()) |
d2eddacc |
306 | { |
307 | OpenGl_View::Redraw(); |
308 | return; |
309 | } |
62e1beed |
310 | |
c357e426 |
311 | Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext(); |
62e1beed |
312 | myToFlipOutput = Standard_True; |
c357e426 |
313 | myD3dWglFbo->LockSurface (aCtx); |
b128c892 |
314 | myFBO = myD3dWglFbo; |
c357e426 |
315 | OpenGl_View::Redraw(); |
b128c892 |
316 | myFBO.Nullify(); |
c357e426 |
317 | myD3dWglFbo->UnlockSurface (aCtx); |
62e1beed |
318 | myToFlipOutput = Standard_False; |
c357e426 |
319 | if (aCtx->caps->buffersNoSwap) |
62e1beed |
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 | // ======================================================================= |
c357e426 |
340 | void D3DHost_View::RedrawImmediate() |
62e1beed |
341 | { |
c357e426 |
342 | Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext(); |
62e1beed |
343 | if (!myTransientDrawToFront |
344 | || !myBackBufferRestored |
c357e426 |
345 | || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid())) |
62e1beed |
346 | { |
c357e426 |
347 | Redraw(); |
62e1beed |
348 | return; |
349 | } |
c357e426 |
350 | else if (!myWorkspace->Activate() |
62e1beed |
351 | || myD3dDevice == NULL) |
352 | { |
353 | return; |
354 | } |
b128c892 |
355 | else if (!myFBO.IsNull()) |
d2eddacc |
356 | { |
357 | OpenGl_View::Redraw(); |
358 | return; |
359 | } |
62e1beed |
360 | |
361 | myToFlipOutput = Standard_True; |
c357e426 |
362 | myD3dWglFbo->LockSurface (aCtx); |
b128c892 |
363 | myFBO = myD3dWglFbo; |
c357e426 |
364 | OpenGl_View::RedrawImmediate(); |
b128c892 |
365 | myFBO.Nullify(); |
c357e426 |
366 | myD3dWglFbo->UnlockSurface (aCtx); |
62e1beed |
367 | myToFlipOutput = Standard_False; |
c357e426 |
368 | if (aCtx->caps->buffersNoSwap) |
62e1beed |
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 | // ======================================================================= |
c357e426 |
389 | void D3DHost_View::Resized() |
62e1beed |
390 | { |
c357e426 |
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()) |
62e1beed |
396 | { |
397 | return; |
398 | } |
399 | |
400 | if (!myD3dWglFbo.IsNull()) |
401 | { |
c357e426 |
402 | myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->()); |
62e1beed |
403 | } |
c357e426 |
404 | if (!myWorkspace->GetGlContext()->caps->buffersNoSwap) |
62e1beed |
405 | { |
c357e426 |
406 | d3dReset(); |
62e1beed |
407 | } |
408 | d3dCreateRenderTarget(); |
409 | } |