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 <OpenGl_Context.hxx>
23 #include <OpenGl_Texture.hxx>
24 #include <Standard_ProgramError.hxx>
26 IMPLEMENT_STANDARD_RTTIEXT(D3DHost_FrameBuffer,OpenGl_FrameBuffer)
28 // =======================================================================
29 // function : D3DHost_FrameBuffer
31 // =======================================================================
32 D3DHost_FrameBuffer::D3DHost_FrameBuffer()
34 myD3dSurfShare (NULL),
38 myD3dFallback (Standard_False),
39 myIsSRGBReady (Standard_False)
44 // =======================================================================
45 // function : ~D3DHost_FrameBuffer
47 // =======================================================================
48 D3DHost_FrameBuffer::~D3DHost_FrameBuffer()
53 // =======================================================================
56 // =======================================================================
57 void D3DHost_FrameBuffer::Release (OpenGl_Context* theCtx)
59 #if !defined(GL_ES_VERSION_2_0)
60 if (myGlD3dDevice != NULL)
62 const OpenGl_GlFunctions* aFuncs = (theCtx != NULL && theCtx->IsValid())
65 if (myGlD3dSurf != NULL)
69 aFuncs->wglDXUnregisterObjectNV (myGlD3dDevice, myGlD3dSurf);
76 aFuncs->wglDXCloseDeviceNV (myGlD3dDevice);
82 if (myD3dSurf != NULL)
86 myD3dSurfShare = NULL;
89 OpenGl_FrameBuffer::Release (theCtx);
92 // =======================================================================
95 // =======================================================================
96 Standard_Boolean D3DHost_FrameBuffer::Init (const Handle(OpenGl_Context)& theCtx,
97 IDirect3DDevice9* theD3DDevice,
98 const Standard_Boolean theIsD3dEx,
99 const Standard_Integer theSizeX,
100 const Standard_Integer theSizeY)
102 if (InitD3dInterop (theCtx, theD3DDevice, theIsD3dEx, theSizeX, theSizeY, GL_DEPTH24_STENCIL8))
104 return Standard_True;
106 return InitD3dFallback (theCtx, theD3DDevice, theIsD3dEx, theSizeX, theSizeY, GL_DEPTH24_STENCIL8);
109 // =======================================================================
110 // function : InitD3dFallback
112 // =======================================================================
113 Standard_Boolean D3DHost_FrameBuffer::InitD3dFallback (const Handle(OpenGl_Context)& theCtx,
114 IDirect3DDevice9* theD3DDevice,
115 const Standard_Boolean theIsD3dEx,
116 const Standard_Integer theSizeX,
117 const Standard_Integer theSizeY,
118 const Standard_Integer theDepthFormat)
120 const Standard_Boolean isGlInit = OpenGl_FrameBuffer::Init (theCtx, Graphic3d_Vec2i (theSizeX, theSizeY), GL_RGBA8, theDepthFormat, 0);
121 myD3dFallback = Standard_True;
123 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
124 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
125 if (theD3DDevice->CreateRenderTarget (aSizeX, aSizeY,
126 D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, theIsD3dEx ? TRUE : FALSE,
127 &myD3dSurf, theIsD3dEx ? &myD3dSurfShare : NULL) != D3D_OK)
129 Release (theCtx.operator->());
130 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
131 TCollection_AsciiString ("D3DHost_FrameBuffer, could not create D3DFMT_X8R8G8B8 render target ") + aSizeX + "x" + aSizeY);
132 return Standard_False;
137 // =======================================================================
138 // function : InitD3dInterop
140 // =======================================================================
141 Standard_Boolean D3DHost_FrameBuffer::InitD3dInterop (const Handle(OpenGl_Context)& theCtx,
142 IDirect3DDevice9* theD3DDevice,
143 const Standard_Boolean theIsD3dEx,
144 const Standard_Integer theSizeX,
145 const Standard_Integer theSizeY,
146 const Standard_Integer theDepthFormat)
148 Release (theCtx.operator->());
149 #if !defined(GL_ES_VERSION_2_0)
150 myDepthFormat = theDepthFormat;
151 myVPSizeX = theSizeX;
152 myVPSizeY = theSizeY;
153 myInitVPSizeX = theSizeX;
154 myInitVPSizeY = theSizeY;
155 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
156 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
158 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
159 if (aFuncs->wglDXOpenDeviceNV == NULL)
161 Release (theCtx.operator->());
162 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
163 "D3DHost_FrameBuffer, WGL_NV_DX_interop is unavailable!");
164 return Standard_False;
167 // Render target surface should be lockable on
168 // Windows XP and non-lockable on Windows Vista or higher
169 if (theD3DDevice->CreateRenderTarget (aSizeX, aSizeY,
170 D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, theIsD3dEx ? TRUE : FALSE,
171 &myD3dSurf, theIsD3dEx ? &myD3dSurfShare : NULL) != D3D_OK)
173 Release (theCtx.operator->());
174 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
175 TCollection_AsciiString ("D3DHost_FrameBuffer, could not create D3DFMT_X8R8G8B8 render target ") + aSizeX + "x" + aSizeY);
176 return Standard_False;
179 myGlD3dDevice = aFuncs->wglDXOpenDeviceNV (theD3DDevice);
180 if (myGlD3dDevice == NULL)
182 Release (theCtx.operator->());
183 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
184 "D3DHost_FrameBuffer, could not create the GL <-> DirectX Interop using wglDXOpenDeviceNV()");
185 return Standard_False;
188 if (!registerD3dBuffer (theCtx))
190 Release (theCtx.operator->());
191 return Standard_False;
194 myIsOwnBuffer = true;
196 theCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
198 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, myDepthFormat);
199 if (aDepthFormat.IsValid()
200 && !myDepthStencilTexture->Init (theCtx, aDepthFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
202 Release (theCtx.get());
203 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
204 TCollection_AsciiString("D3DHost_FrameBuffer, could not initialize GL_DEPTH24_STENCIL8 texture ") + aSizeX + "x" + aSizeY);
205 return Standard_False;
208 myD3dFallback = Standard_False;
209 return Standard_True;
215 (void )theDepthFormat;
216 return Standard_False;
220 // =======================================================================
221 // function : registerD3dBuffer
223 // =======================================================================
224 Standard_Boolean D3DHost_FrameBuffer::registerD3dBuffer (const Handle(OpenGl_Context)& theCtx)
226 #if defined(GL_ES_VERSION_2_0)
228 return Standard_False;
230 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
231 if (myGlD3dSurf != NULL)
233 if (!aFuncs->wglDXUnregisterObjectNV (myGlD3dDevice, myGlD3dSurf))
235 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
236 "D3DHost_FrameBuffer, can not unregister color buffer");
237 return Standard_False;
242 if (!aFuncs->wglDXSetResourceShareHandleNV (myD3dSurf, myD3dSurfShare))
244 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
245 "D3DHost_FrameBuffer, wglDXSetResourceShareHandleNV() has failed");
246 return Standard_False;
250 myColorTextures (0)->Release (theCtx.operator->());
251 myColorTextures (0)->Create (theCtx);
253 myGlD3dSurf = aFuncs->wglDXRegisterObjectNV (myGlD3dDevice,
255 myColorTextures (0)->TextureId(),
257 WGL_ACCESS_WRITE_DISCARD_NV);
258 theCtx->ResetErrors (true);
259 if (myGlD3dSurf == NULL)
261 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
262 "D3DHost_FrameBuffer, can not register color buffer");
263 return Standard_False;
266 return Standard_True;
270 // =======================================================================
271 // function : BindBuffer
273 // =======================================================================
274 void D3DHost_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theCtx)
276 Standard_ProgramError_Raise_if (myLockCount < 1, "D3DHost_FrameBuffer::BindBuffer(), resource should be locked beforehand!");
277 if (theCtx->arbFBO == NULL)
282 OpenGl_FrameBuffer::BindBuffer (theCtx);
283 theCtx->SetFrameBufferSRGB (true, myIsSRGBReady);
289 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
290 myColorTextures (0)->GetTarget(), myColorTextures (0)->TextureId(), 0);
292 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, myDepthFormat);
293 if (myDepthStencilTexture->IsValid())
295 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
296 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
297 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
299 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
300 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
301 if (aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL)
303 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
304 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
308 if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
310 if (myDepthStencilTexture->IsValid())
312 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
313 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
314 myDepthStencilTexture->GetTarget(), 0, 0);
316 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
317 myDepthStencilTexture->GetTarget(), 0, 0);
318 if (aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL)
320 theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
321 myDepthStencilTexture->GetTarget(), 0, 0);
325 if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
327 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
328 "D3DHost_FrameBuffer, OpenGL FBO is incomplete!");
329 Release (theCtx.operator->());
334 myDepthStencilTexture->Release (theCtx.get());
335 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
336 "D3DHost_FrameBuffer, OpenGL FBO is created without Depth+Stencil attachments!");
341 // =======================================================================
342 // function : LockSurface
344 // =======================================================================
345 void D3DHost_FrameBuffer::LockSurface (const Handle(OpenGl_Context)& theCtx)
347 if (++myLockCount > 1)
351 if (myGlD3dSurf == NULL)
356 #if !defined(GL_ES_VERSION_2_0)
357 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
358 if (!aFuncs->wglDXLockObjectsNV (myGlD3dDevice, 1, &myGlD3dSurf))
360 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
361 "D3DHost_FrameBuffer::LockSurface(), lock failed!");
368 // =======================================================================
369 // function : UnlockSurface
371 // =======================================================================
372 void D3DHost_FrameBuffer::UnlockSurface (const Handle(OpenGl_Context)& theCtx)
374 if (--myLockCount != 0)
381 if (myD3dSurf == NULL)
386 D3DLOCKED_RECT aLockedRect;
387 if (myD3dSurf->LockRect (&aLockedRect, NULL, 0) != 0)
389 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
390 "D3DHost_FrameBuffer::UnlockSurface(), lock failed!");
395 if (anImg.InitWrapper (Image_Format_BGRA, (Standard_Byte* )aLockedRect.pBits, myInitVPSizeX, myInitVPSizeY, aLockedRect.Pitch))
397 anImg.SetTopDown (!IsValid()); // flip in software if OpenGL FBO is unavailable
399 if (!BufferDump (theCtx, this, anImg, Graphic3d_BT_RGBA))
401 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
402 "D3DHost_FrameBuffer::UnlockSurface(), buffer dump failed!");
408 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
409 "D3DHost_FrameBuffer::UnlockSurface(), buffer dump failed!");
411 myD3dSurf->UnlockRect();
414 if (myGlD3dSurf == NULL)
419 #if !defined(GL_ES_VERSION_2_0)
420 const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
421 aFuncs->wglDXUnlockObjectsNV (myGlD3dDevice, 1, &myGlD3dSurf);