1 // Created on: 2015-06-10
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2015 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
18 #include <D3DHost_FrameBuffer.hxx>
20 #include <OpenGl_GlCore20.hxx>
21 #include <OpenGl_ArbFBO.hxx>
22 #include <Standard_ProgramError.hxx>
23 #include <TCollection_ExtendedString.hxx>
25 IMPLEMENT_STANDARD_RTTIEXT(D3DHost_FrameBuffer,OpenGl_FrameBuffer)
27 // =======================================================================
28 // function : D3DHost_FrameBuffer
30 // =======================================================================
31 D3DHost_FrameBuffer::D3DHost_FrameBuffer()
33 myD3dSurfShare (NULL),
37 myD3dFallback (Standard_False),
38 myIsSRGBReady (Standard_False)
43 // =======================================================================
44 // function : ~D3DHost_FrameBuffer
46 // =======================================================================
47 D3DHost_FrameBuffer::~D3DHost_FrameBuffer()
52 // =======================================================================
55 // =======================================================================
56 void D3DHost_FrameBuffer::Release (OpenGl_Context* theCtx)
58 #if !defined(GL_ES_VERSION_2_0)
59 if (myGlD3dDevice != NULL)
61 const OpenGl_GlFunctions* aFuncs = (theCtx != NULL && theCtx->IsValid())
64 if (myGlD3dSurf != NULL)
68 aFuncs->wglDXUnregisterObjectNV (myGlD3dDevice, myGlD3dSurf);
75 aFuncs->wglDXCloseDeviceNV (myGlD3dDevice);
81 if (myD3dSurf != NULL)
85 myD3dSurfShare = NULL;
88 OpenGl_FrameBuffer::Release (theCtx);
91 // =======================================================================
94 // =======================================================================
95 Standard_Boolean D3DHost_FrameBuffer::Init (const Handle(OpenGl_Context)& theCtx,
96 IDirect3DDevice9* theD3DDevice,
97 const Standard_Boolean theIsD3dEx,
98 const Standard_Integer theSizeX,
99 const Standard_Integer theSizeY)
101 if (InitD3dInterop (theCtx, theD3DDevice, theIsD3dEx, theSizeX, theSizeY, GL_DEPTH24_STENCIL8))
103 return Standard_True;
105 return InitD3dFallback (theCtx, theD3DDevice, theIsD3dEx, theSizeX, theSizeY, GL_DEPTH24_STENCIL8);
108 // =======================================================================
109 // function : InitD3dFallback
111 // =======================================================================
112 Standard_Boolean D3DHost_FrameBuffer::InitD3dFallback (const Handle(OpenGl_Context)& theCtx,
113 IDirect3DDevice9* theD3DDevice,
114 const Standard_Boolean theIsD3dEx,
115 const Standard_Integer theSizeX,
116 const Standard_Integer theSizeY,
117 const GLint theDepthFormat)
119 const Standard_Boolean isGlInit = OpenGl_FrameBuffer::Init (theCtx, theSizeX, theSizeY, GL_RGBA8, theDepthFormat, 0);
120 myD3dFallback = Standard_True;
122 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
123 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
124 if (theD3DDevice->CreateRenderTarget (aSizeX, aSizeY,
125 D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, theIsD3dEx ? TRUE : FALSE,
126 &myD3dSurf, theIsD3dEx ? &myD3dSurfShare : NULL) != D3D_OK)
128 Release (theCtx.operator->());
129 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
130 TCollection_AsciiString ("D3DHost_FrameBuffer, could not create D3DFMT_X8R8G8B8 render target ") + aSizeX + "x" + aSizeY);
131 return Standard_False;
136 // =======================================================================
137 // function : InitD3dInterop
139 // =======================================================================
140 Standard_Boolean D3DHost_FrameBuffer::InitD3dInterop (const Handle(OpenGl_Context)& theCtx,
141 IDirect3DDevice9* theD3DDevice,
142 const Standard_Boolean theIsD3dEx,
143 const Standard_Integer theSizeX,
144 const Standard_Integer theSizeY,
145 const GLint theDepthFormat)
147 Release (theCtx.operator->());
148 #if !defined(GL_ES_VERSION_2_0)
149 myDepthFormat = theDepthFormat;
150 myVPSizeX = theSizeX;
151 myVPSizeY = theSizeY;
152 myInitVPSizeX = theSizeX;
153 myInitVPSizeY = theSizeY;
154 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
155 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
157 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
158 if (aFuncs->wglDXOpenDeviceNV == NULL)
160 Release (theCtx.operator->());
161 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
162 "D3DHost_FrameBuffer, WGL_NV_DX_interop is unavailable!");
163 return Standard_False;
166 // Render target surface should be lockable on
167 // Windows XP and non-lockable on Windows Vista or higher
168 if (theD3DDevice->CreateRenderTarget (aSizeX, aSizeY,
169 D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, theIsD3dEx ? TRUE : FALSE,
170 &myD3dSurf, theIsD3dEx ? &myD3dSurfShare : NULL) != D3D_OK)
172 Release (theCtx.operator->());
173 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
174 TCollection_AsciiString ("D3DHost_FrameBuffer, could not create D3DFMT_X8R8G8B8 render target ") + aSizeX + "x" + aSizeY);
175 return Standard_False;
178 myGlD3dDevice = aFuncs->wglDXOpenDeviceNV (theD3DDevice);
179 if (myGlD3dDevice == NULL)
181 Release (theCtx.operator->());
182 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
183 "D3DHost_FrameBuffer, could not create the GL <-> DirectX Interop using wglDXOpenDeviceNV()");
184 return Standard_False;
187 if (!registerD3dBuffer (theCtx))
189 Release (theCtx.operator->());
190 return Standard_False;
193 myIsOwnBuffer = true;
195 theCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
197 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, myDepthFormat);
198 if (aDepthFormat.IsValid()
199 && !myDepthStencilTexture->Init (theCtx, aDepthFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
201 Release (theCtx.get());
202 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
203 TCollection_AsciiString("D3DHost_FrameBuffer, could not initialize GL_DEPTH24_STENCIL8 texture ") + aSizeX + "x" + aSizeY);
204 return Standard_False;
207 myD3dFallback = Standard_False;
208 return Standard_True;
214 (void )theDepthFormat;
215 return Standard_False;
219 // =======================================================================
220 // function : registerD3dBuffer
222 // =======================================================================
223 Standard_Boolean D3DHost_FrameBuffer::registerD3dBuffer (const Handle(OpenGl_Context)& theCtx)
225 #if defined(GL_ES_VERSION_2_0)
227 return Standard_False;
229 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
230 if (myGlD3dSurf != NULL)
232 if (!aFuncs->wglDXUnregisterObjectNV (myGlD3dDevice, myGlD3dSurf))
234 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
235 "D3DHost_FrameBuffer, can not unregister color buffer");
236 return Standard_False;
241 if (!aFuncs->wglDXSetResourceShareHandleNV (myD3dSurf, myD3dSurfShare))
243 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
244 "D3DHost_FrameBuffer, wglDXSetResourceShareHandleNV() has failed");
245 return Standard_False;
248 myColorTextures (0)->Release (theCtx.operator->());
249 myColorTextures (0)->Create (theCtx);
251 myGlD3dSurf = aFuncs->wglDXRegisterObjectNV (myGlD3dDevice,
253 myColorTextures (0)->TextureId(),
255 WGL_ACCESS_WRITE_DISCARD_NV);
256 theCtx->ResetErrors (true);
257 if (myGlD3dSurf == NULL)
259 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
260 "D3DHost_FrameBuffer, can not register color buffer");
261 return Standard_False;
264 return Standard_True;
268 // =======================================================================
269 // function : BindBuffer
271 // =======================================================================
272 void D3DHost_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theCtx)
274 Standard_ProgramError_Raise_if (myLockCount < 1, "D3DHost_FrameBuffer::BindBuffer(), resource should be locked beforehand!");
275 if (theCtx->arbFBO == NULL)
280 OpenGl_FrameBuffer::BindBuffer (theCtx);
281 theCtx->SetFrameBufferSRGB (true, myIsSRGBReady);
287 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
288 myColorTextures (0)->GetTarget(), myColorTextures (0)->TextureId(), 0);
290 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, myDepthFormat);
291 if (myDepthStencilTexture->IsValid())
293 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
294 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
295 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
297 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
298 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
299 if (aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL)
301 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
302 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
306 if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
308 if (myDepthStencilTexture->IsValid())
310 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
311 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
312 myDepthStencilTexture->GetTarget(), 0, 0);
314 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
315 myDepthStencilTexture->GetTarget(), 0, 0);
316 if (aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL)
318 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
319 myDepthStencilTexture->GetTarget(), 0, 0);
323 if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
325 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
326 "D3DHost_FrameBuffer, OpenGL FBO is incomplete!");
327 Release (theCtx.operator->());
332 myDepthStencilTexture->Release (theCtx.get());
333 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
334 "D3DHost_FrameBuffer, OpenGL FBO is created without Depth+Stencil attachements!");
339 // =======================================================================
340 // function : LockSurface
342 // =======================================================================
343 void D3DHost_FrameBuffer::LockSurface (const Handle(OpenGl_Context)& theCtx)
345 if (++myLockCount > 1)
349 if (myGlD3dSurf == NULL)
354 #if !defined(GL_ES_VERSION_2_0)
355 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
356 if (!aFuncs->wglDXLockObjectsNV (myGlD3dDevice, 1, &myGlD3dSurf))
358 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
359 "D3DHost_FrameBuffer::LockSurface(), lock failed!");
366 // =======================================================================
367 // function : UnlockSurface
369 // =======================================================================
370 void D3DHost_FrameBuffer::UnlockSurface (const Handle(OpenGl_Context)& theCtx)
372 if (--myLockCount != 0)
379 if (myD3dSurf == NULL)
384 D3DLOCKED_RECT aLockedRect;
385 if (myD3dSurf->LockRect (&aLockedRect, NULL, 0) != 0)
387 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
388 "D3DHost_FrameBuffer::UnlockSurface(), lock failed!");
393 if (anImg.InitWrapper (Image_Format_BGRA, (Standard_Byte* )aLockedRect.pBits, myInitVPSizeX, myInitVPSizeY, aLockedRect.Pitch))
395 anImg.SetTopDown (!IsValid()); // flip in software if OpenGL FBO is unavailable
397 if (!BufferDump (theCtx, this, anImg, Graphic3d_BT_RGBA))
399 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
400 "D3DHost_FrameBuffer::UnlockSurface(), buffer dump failed!");
406 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
407 "D3DHost_FrameBuffer::UnlockSurface(), buffer dump failed!");
409 myD3dSurf->UnlockRect();
412 if (myGlD3dSurf == NULL)
417 #if !defined(GL_ES_VERSION_2_0)
418 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
419 aFuncs->wglDXUnlockObjectsNV (myGlD3dDevice, 1, &myGlD3dSurf);