0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / D3DHost / D3DHost_View.cxx
CommitLineData
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
f4a7308f 23#include <Standard_WarningDisableFunctionCast.hxx>
24
92efcf78 25IMPLEMENT_STANDARD_RTTIEXT(D3DHost_View,OpenGl_View)
26
dc9f1dbf 27namespace
28{
29 enum D3DHost_VendorId
30 {
31 D3DHost_VendorId_AMD = 0x1002,
32 D3DHost_VendorId_NVIDIA = 0x10DE,
33 D3DHost_VendorId_Intel = 0x8086,
34 };
35}
36
62e1beed 37// =======================================================================
38// function : d3dFormatError
39// purpose :
40// =======================================================================
d2eddacc 41TCollection_AsciiString D3DHost_View::d3dFormatError (const long theErrCode)
62e1beed 42{
43 switch (theErrCode)
44 {
45 case D3D_OK: return "OK";
46 case D3DERR_DEVICELOST: return "Device lost";
47 case D3DERR_DEVICEREMOVED: return "Device removed";
48 case D3DERR_DRIVERINTERNALERROR: return "Driver internal error";
49 case D3DERR_OUTOFVIDEOMEMORY: return "Out of video memory";
50 case D3DERR_INVALIDCALL: return "Invalid call";
51 default: return TCollection_AsciiString ("Error #") + int(theErrCode) + ")";
52 }
53}
54
55// =======================================================================
c357e426 56// function : D3DHost_View
62e1beed 57// purpose :
58// =======================================================================
c357e426 59D3DHost_View::D3DHost_View (const Handle(Graphic3d_StructureManager)& theMgr,
60 const Handle(D3DHost_GraphicDriver)& theDriver,
61 const Handle(OpenGl_Caps)& theCaps,
c357e426 62 OpenGl_StateCounter* theCounter)
851dacdb 63: OpenGl_View (theMgr, theDriver, theCaps, theCounter),
62e1beed 64 myD3dLib (NULL),
65 myD3dDevice (NULL),
d2eddacc 66 myD3dParams (new D3DPRESENT_PARAMETERS()),
62e1beed 67 myRefreshRate (D3DPRESENT_RATE_DEFAULT),
68 myIsD3dEx (false)
69{
d2eddacc 70 memset(myD3dParams.operator->(), 0, sizeof(D3DPRESENT_PARAMETERS));
71
72 myD3dParams->Windowed = TRUE;
73 myD3dParams->SwapEffect = D3DSWAPEFFECT_DISCARD;
74 myD3dParams->BackBufferFormat = D3DFMT_X8R8G8B8;
75 myD3dParams->BackBufferCount = 1;
76 myD3dParams->BackBufferHeight = 2;
77 myD3dParams->BackBufferWidth = 2;
78 myD3dParams->EnableAutoDepthStencil = FALSE;
79 myD3dParams->AutoDepthStencilFormat = D3DFMT_D16_LOCKABLE;
80 myD3dParams->FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
81 myD3dParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
62e1beed 82}
83
84// =======================================================================
c357e426 85// function : ~D3DHost_View
62e1beed 86// purpose :
87// =======================================================================
c357e426 88D3DHost_View::~D3DHost_View()
62e1beed 89{
90 if (!myD3dWglFbo.IsNull())
91 {
c357e426 92 myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
62e1beed 93 myD3dWglFbo.Nullify();
94 }
95 if (myD3dDevice != NULL)
96 {
97 myD3dDevice->Release();
98 myD3dDevice = NULL;
99 }
100 if (myD3dLib != NULL)
101 {
102 myD3dLib->Release();
103 myD3dLib = NULL;
104 }
105}
106
6cde53c4 107// =======================================================================
108// function : D3dColorSurface
109// purpose :
110// =======================================================================
111IDirect3DSurface9* D3DHost_View::D3dColorSurface() const
112{
113 return myD3dWglFbo->D3dColorSurface();
114}
115
c357e426 116// =======================================================================
117// function : SetWindow
118// purpose :
119// =======================================================================
120void D3DHost_View::SetWindow (const Handle(Aspect_Window)& theWindow,
7aa74f30 121 const Aspect_RenderingContext theContext)
c357e426 122{
123 if (!myD3dWglFbo.IsNull())
124 {
125 myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
126 myD3dWglFbo.Nullify();
127 }
128 if (myD3dDevice != NULL)
129 {
130 myD3dDevice->Release();
131 myD3dDevice = NULL;
132 }
133
7aa74f30 134 OpenGl_View::SetWindow (theWindow, theContext);
c357e426 135
136 if (!myWindow.IsNull())
137 {
138 d3dInit();
139 d3dCreateRenderTarget();
140 }
141}
142
dc9f1dbf 143// =======================================================================
144// function : DiagnosticInformation
145// purpose :
146// =======================================================================
147void D3DHost_View::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
148 Graphic3d_DiagnosticInfo theFlags) const
149{
150 base_type::DiagnosticInformation (theDict, theFlags);
151 if (myD3dDevice == NULL)
152 {
153 return;
154 }
155
156 D3DCAPS9 aDevCaps;
157 memset (&aDevCaps, 0, sizeof(aDevCaps));
158 if (myD3dDevice->GetDeviceCaps (&aDevCaps) < 0)
159 {
160 return;
161 }
162
163 const UINT anAdapter = aDevCaps.AdapterOrdinal;
164 D3DADAPTER_IDENTIFIER9 aDevId;
165 memset (&aDevId, 0, sizeof(aDevId));
166 if (myD3dLib->GetAdapterIdentifier (anAdapter, 0, &aDevId) < 0)
167 {
168 return;
169 }
170
171 TCollection_AsciiString aVendorId ((int )aDevId.VendorId);
172 switch (aDevId.VendorId)
173 {
174 case D3DHost_VendorId_AMD: aVendorId = "AMD"; break;
175 case D3DHost_VendorId_NVIDIA: aVendorId = "NVIDIA"; break;
176 case D3DHost_VendorId_Intel: aVendorId = "Intel"; break;
177 }
178 theDict.Add ("D3Dvendor", aVendorId);
179 theDict.Add ("D3Ddescription", aDevId.Description);
180 theDict.Add ("D3DdeviceName", aDevId.DeviceName);
181 theDict.Add ("D3Ddriver", aDevId.Driver);
182 theDict.Add ("D3DdeviceId", TCollection_AsciiString((int )aDevId.DeviceId));
183 theDict.Add ("D3Dinterop", myD3dWglFbo.IsNull() || myD3dWglFbo->D3dFallback()
184 ? "Software Fallback"
185 : "WGL_NV_DX_interop");
186}
187
62e1beed 188// =======================================================================
189// function : d3dInitLib
190// purpose :
191// =======================================================================
c357e426 192bool D3DHost_View::d3dInitLib()
62e1beed 193{
194 if (myD3dLib == NULL)
195 {
196 IDirect3D9Ex* aD3dLibEx = NULL;
197 // we link against d3d (using Direct3DCreate9 symbol), thus it should be already loaded
198 HMODULE aLib = GetModuleHandleW (L"d3d9");
199 if (aLib != NULL)
200 {
201 // retrieve D3D9Ex function dynamically (available only since Vista+)
202 typedef HRESULT (WINAPI* Direct3DCreate9Ex_t)(UINT , IDirect3D9Ex** );
203 Direct3DCreate9Ex_t Direct3DCreate9ExProc = (Direct3DCreate9Ex_t )GetProcAddress (aLib, "Direct3DCreate9Ex");
204 if (Direct3DCreate9ExProc != NULL)
205 {
206 Direct3DCreate9ExProc(D3D_SDK_VERSION, &aD3dLibEx);
207 }
208 }
209 myD3dLib = aD3dLibEx;
210 myIsD3dEx = aD3dLibEx != NULL;
211 if (myD3dLib == NULL)
212 {
213 myD3dLib = Direct3DCreate9 (D3D_SDK_VERSION);
214 }
215 }
216 return myD3dLib != NULL;
217}
218
219// =======================================================================
220// function : d3dInit
221// purpose :
222// =======================================================================
c357e426 223bool D3DHost_View::d3dInit()
62e1beed 224{
225 if (!d3dInitLib())
226 {
6cde53c4 227 myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Direct3DCreate9 failed!");
62e1beed 228 return false;
229 }
230
231 UINT anAdapterId = D3DADAPTER_DEFAULT;
232
233 // setup the present parameters
d2eddacc 234 D3DDISPLAYMODE aCurrMode;
235 memset(&aCurrMode, 0, sizeof(aCurrMode));
236 if (myD3dLib->GetAdapterDisplayMode (anAdapterId, &aCurrMode) == D3D_OK)
62e1beed 237 {
d2eddacc 238 myD3dParams->BackBufferFormat = aCurrMode.Format;
239 myRefreshRate = aCurrMode.RefreshRate;
62e1beed 240 }
d2eddacc 241 myD3dParams->Windowed = TRUE;
242 myD3dParams->BackBufferWidth = myWindow->Width();
243 myD3dParams->BackBufferHeight = myWindow->Height();
244 myD3dParams->hDeviceWindow = (HWND )myWindow->PlatformWindow()->NativeHandle();
62e1beed 245
246 // create the Video Device
247 HRESULT isOK = myD3dLib->CreateDevice (anAdapterId, D3DDEVTYPE_HAL,
c357e426 248 (HWND )myWindow->PlatformWindow()->NativeHandle(),
62e1beed 249 D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
d2eddacc 250 myD3dParams.get(), &myD3dDevice);
62e1beed 251 if (isOK < 0)
252 {
253 return false;
254 }
255
256 return myD3dDevice != NULL;
257}
258
259// =======================================================================
260// function : d3dReset
261// purpose :
262// =======================================================================
c357e426 263bool D3DHost_View::d3dReset()
62e1beed 264{
265 if (myD3dDevice == NULL)
266 {
267 return false;
268 }
269
d2eddacc 270 myD3dParams->Windowed = TRUE;
271 myD3dParams->BackBufferWidth = myWindow->Width();
272 myD3dParams->BackBufferHeight = myWindow->Height();
273 myD3dParams->hDeviceWindow = (HWND )myWindow->PlatformWindow()->NativeHandle();
274 myD3dParams->FullScreen_RefreshRateInHz = !myD3dParams->Windowed ? myRefreshRate : 0;
62e1beed 275
d2eddacc 276 HRESULT isOK = myD3dDevice->Reset(myD3dParams.get());
62e1beed 277 return isOK == D3D_OK;
278}
279
280// =======================================================================
281// function : d3dCreateRenderTarget
282// purpose :
283// =======================================================================
c357e426 284bool D3DHost_View::d3dCreateRenderTarget()
62e1beed 285{
6cde53c4 286 bool toD3dFallback = false;
62e1beed 287 if (myD3dWglFbo.IsNull())
288 {
289 myD3dWglFbo = new D3DHost_FrameBuffer();
290 }
6cde53c4 291 else
62e1beed 292 {
6cde53c4 293 toD3dFallback = myD3dWglFbo->D3dFallback();
294 }
295
296 if (!toD3dFallback)
297 {
298 toD3dFallback = !myD3dWglFbo->InitD3dInterop (myWorkspace->GetGlContext(),
299 myD3dDevice,
300 myIsD3dEx,
301 myWindow->Width(),
da2a6aee 302 myWindow->Height(),
303 0); // do not request depth-stencil attachment since buffer will be flipped using addition FBO (myToFlipOutput)
6cde53c4 304 }
305 if (toD3dFallback)
306 {
307 if (!myD3dWglFbo->InitD3dFallback (myWorkspace->GetGlContext(),
308 myD3dDevice,
309 myIsD3dEx,
310 myWindow->Width(),
da2a6aee 311 myWindow->Height(),
312 GL_DEPTH24_STENCIL8))
6cde53c4 313 {
314 return false;
315 }
62e1beed 316 }
317
318 myD3dDevice->SetRenderTarget (0, myD3dWglFbo->D3dColorSurface());
319 return true;
320}
321
322// =======================================================================
323// function : d3dBeginRender
324// purpose :
325// =======================================================================
c357e426 326void D3DHost_View::d3dBeginRender()
62e1beed 327{
328 if (myD3dDevice == NULL)
329 {
330 return;
331 }
332
333 // clear the back buffer
334 myD3dDevice->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
335 myD3dDevice->BeginScene();
336}
337
338// =======================================================================
339// function : d3dEndRender
340// purpose :
341// =======================================================================
c357e426 342void D3DHost_View::d3dEndRender()
62e1beed 343{
344 if (myD3dDevice != NULL)
345 {
346 myD3dDevice->EndScene();
347 }
348}
349
350// =======================================================================
351// function : d3dSwap
352// purpose :
353// =======================================================================
c357e426 354bool D3DHost_View::d3dSwap()
62e1beed 355{
356 if (myD3dDevice == NULL)
357 {
358 return false;
359 }
360
361 const HRESULT isOK = myD3dDevice->Present (NULL, NULL, NULL, NULL);
362 if (isOK != D3D_OK)
363 {
6cde53c4 364 myWorkspace->GetGlContext()->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
365 TCollection_AsciiString("Direct3D9, Present device failed, ") + d3dFormatError (isOK));
62e1beed 366 }
367 return isOK == D3D_OK;
368}
369
370// =======================================================================
371// function : Redraw
372// purpose :
373// =======================================================================
c357e426 374void D3DHost_View::Redraw()
62e1beed 375{
c357e426 376 if (!myWorkspace->Activate()
62e1beed 377 || myD3dDevice == NULL)
378 {
379 return;
380 }
b128c892 381 else if (!myFBO.IsNull())
d2eddacc 382 {
383 OpenGl_View::Redraw();
384 return;
385 }
62e1beed 386
c357e426 387 Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
6cde53c4 388 if (myWindow->PlatformWindow()->IsVirtual()
389 && aCtx->arbFBO == NULL)
390 {
391 // do a dirty hack in extreme fallback mode with OpenGL driver not supporting FBO,
392 // the back buffer of hidden window is used for rendering as offscreen buffer
393 myTransientDrawToFront = false;
394 int aWinSizeX = 0, aWinSizeY = 0;
395 myWindow->PlatformWindow()->Size (aWinSizeX, aWinSizeY);
396 WINDOWPLACEMENT aPlace;
397 GetWindowPlacement ((HWND )myWindow->PlatformWindow()->NativeHandle(), &aPlace);
398 if (aPlace.rcNormalPosition.right - aPlace.rcNormalPosition.left != aWinSizeX
399 || aPlace.rcNormalPosition.bottom - aPlace.rcNormalPosition.top != aWinSizeY)
400 {
401 aPlace.rcNormalPosition.right = aPlace.rcNormalPosition.left + aWinSizeX;
402 aPlace.rcNormalPosition.bottom = aPlace.rcNormalPosition.top + aWinSizeY;
403 aPlace.showCmd = SW_HIDE;
404 SetWindowPlacement ((HWND )myWindow->PlatformWindow()->NativeHandle(), &aPlace);
405 }
406 }
407
c357e426 408 myD3dWglFbo->LockSurface (aCtx);
6cde53c4 409 if (myD3dWglFbo->IsValid())
410 {
411 myToFlipOutput = Standard_True;
412 myFBO = myD3dWglFbo;
413 }
c357e426 414 OpenGl_View::Redraw();
b128c892 415 myFBO.Nullify();
c357e426 416 myD3dWglFbo->UnlockSurface (aCtx);
62e1beed 417 myToFlipOutput = Standard_False;
c357e426 418 if (aCtx->caps->buffersNoSwap)
62e1beed 419 {
420 return;
421 }
422
423 // blit result to the D3D back buffer and swap
424 d3dBeginRender();
425
426 IDirect3DSurface9* aBackbuffer = NULL;
427 myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
428 myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
429 aBackbuffer->Release();
430
431 d3dEndRender();
432 d3dSwap();
433}
434
435// =======================================================================
436// function : RedrawImmediate
437// purpose :
438// =======================================================================
c357e426 439void D3DHost_View::RedrawImmediate()
62e1beed 440{
c357e426 441 Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
62e1beed 442 if (!myTransientDrawToFront
443 || !myBackBufferRestored
c357e426 444 || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
62e1beed 445 {
c357e426 446 Redraw();
62e1beed 447 return;
448 }
c357e426 449 else if (!myWorkspace->Activate()
62e1beed 450 || myD3dDevice == NULL)
451 {
452 return;
453 }
b128c892 454 else if (!myFBO.IsNull())
d2eddacc 455 {
456 OpenGl_View::Redraw();
457 return;
458 }
62e1beed 459
c357e426 460 myD3dWglFbo->LockSurface (aCtx);
6cde53c4 461 if (myD3dWglFbo->IsValid())
462 {
463 myToFlipOutput = Standard_True;
464 myFBO = myD3dWglFbo;
465 }
c357e426 466 OpenGl_View::RedrawImmediate();
b128c892 467 myFBO.Nullify();
c357e426 468 myD3dWglFbo->UnlockSurface (aCtx);
62e1beed 469 myToFlipOutput = Standard_False;
c357e426 470 if (aCtx->caps->buffersNoSwap)
62e1beed 471 {
472 return;
473 }
474
475 // blit result to the D3D back buffer and swap
476 d3dBeginRender();
477
478 IDirect3DSurface9* aBackbuffer = NULL;
479 myD3dDevice->GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, &aBackbuffer);
480 myD3dDevice->StretchRect (myD3dWglFbo->D3dColorSurface(), NULL, aBackbuffer, NULL, D3DTEXF_LINEAR);
481 aBackbuffer->Release();
482
483 d3dEndRender();
484 d3dSwap();
485}
486
487// =======================================================================
488// function : Resize
489// purpose :
490// =======================================================================
c357e426 491void D3DHost_View::Resized()
62e1beed 492{
c357e426 493 const Standard_Integer aWidthOld = myWindow->Width();
494 const Standard_Integer aHeightOld = myWindow->Height();
495 OpenGl_View::Resized();
496 if (aWidthOld == myWindow->Width()
497 && aHeightOld == myWindow->Height())
62e1beed 498 {
499 return;
500 }
501
502 if (!myD3dWglFbo.IsNull())
503 {
c357e426 504 myD3dWglFbo->Release (myWorkspace->GetGlContext().operator->());
62e1beed 505 }
c357e426 506 if (!myWorkspace->GetGlContext()->caps->buffersNoSwap)
62e1beed 507 {
c357e426 508 d3dReset();
62e1beed 509 }
510 d3dCreateRenderTarget();
511}