0029137: Visualization - D3DHost_FrameBuffer does not release Depth texture and FBO...
[occt.git] / src / D3DHost / D3DHost_FrameBuffer.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 <d3d9.h>
17
18 #include <D3DHost_FrameBuffer.hxx>
19
20 #include <OpenGl_GlCore20.hxx>
21 #include <OpenGl_ArbFBO.hxx>
22 #include <Standard_ProgramError.hxx>
23 #include <TCollection_ExtendedString.hxx>
24
25 IMPLEMENT_STANDARD_RTTIEXT(D3DHost_FrameBuffer,OpenGl_FrameBuffer)
26
27 // =======================================================================
28 // function : D3DHost_FrameBuffer
29 // purpose  :
30 // =======================================================================
31 D3DHost_FrameBuffer::D3DHost_FrameBuffer()
32 : myD3dSurf      (NULL),
33   myD3dSurfShare (NULL),
34   myGlD3dDevice  (NULL),
35   myGlD3dSurf    (NULL),
36   myLockCount    (0)
37 {
38   //
39 }
40
41 // =======================================================================
42 // function : ~D3DHost_FrameBuffer
43 // purpose  :
44 // =======================================================================
45 D3DHost_FrameBuffer::~D3DHost_FrameBuffer()
46 {
47   Release (NULL);
48 }
49
50 // =======================================================================
51 // function : Release
52 // purpose  :
53 // =======================================================================
54 void D3DHost_FrameBuffer::Release (OpenGl_Context* theCtx)
55 {
56 #if !defined(GL_ES_VERSION_2_0)
57   if (myGlD3dDevice != NULL)
58   {
59     const OpenGl_GlFunctions* aFuncs = (theCtx != NULL && theCtx->IsValid())
60                                      ? theCtx->Functions()
61                                      : NULL;
62     if (myGlD3dSurf != NULL)
63     {
64       if (aFuncs != NULL)
65       {
66         aFuncs->wglDXUnregisterObjectNV (myGlD3dDevice, myGlD3dSurf);
67       }
68       myGlD3dSurf = NULL;
69     }
70
71     if (aFuncs != NULL)
72     {
73       aFuncs->wglDXCloseDeviceNV (myGlD3dDevice);
74     }
75     myGlD3dDevice = NULL;
76   }
77 #endif
78
79   if (myD3dSurf != NULL)
80   {
81     myD3dSurf->Release();
82     myD3dSurf      = NULL;
83     myD3dSurfShare = NULL;
84   }
85
86   OpenGl_FrameBuffer::Release (theCtx);
87 }
88
89 // =======================================================================
90 // function : Init
91 // purpose  :
92 // =======================================================================
93 Standard_Boolean D3DHost_FrameBuffer::Init (const Handle(OpenGl_Context)& theCtx,
94                                             IDirect3DDevice9*             theD3DDevice,
95                                             const Standard_Boolean        theIsD3dEx,
96                                             const Standard_Integer        theSizeX,
97                                             const Standard_Integer        theSizeY)
98 {
99   Release (theCtx.operator->());
100 #if !defined(GL_ES_VERSION_2_0)
101   myVPSizeX = theSizeX;
102   myVPSizeY = theSizeY;
103   myInitVPSizeX = theSizeX;
104   myInitVPSizeY = theSizeY;
105   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
106   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
107
108   const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
109   if (aFuncs->wglDXOpenDeviceNV == NULL)
110   {
111     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
112                          GL_DEBUG_TYPE_ERROR_ARB,
113                          0,
114                          GL_DEBUG_SEVERITY_HIGH_ARB,
115                          "D3DHost_FrameBuffer, WGL_NV_DX_interop is unavailable!");
116     return Standard_False;
117   }
118
119   // Render target surface should be lockable on
120   // Windows XP and non-lockable on Windows Vista or higher
121   if (theD3DDevice->CreateRenderTarget (aSizeX, aSizeY,
122                                         D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, theIsD3dEx ? TRUE : FALSE,
123                                         &myD3dSurf, theIsD3dEx ? &myD3dSurfShare : NULL) != D3D_OK)
124   {
125     Release (theCtx.operator->());
126     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
127                          TCollection_AsciiString ("D3DHost_FrameBuffer, could not D3DFMT_X8R8G8B8 render target ") + aSizeX + "x" + aSizeY);
128     return Standard_False;
129   }
130
131   myGlD3dDevice = aFuncs->wglDXOpenDeviceNV (theD3DDevice);
132   if (myGlD3dDevice == NULL)
133   {
134     Release (theCtx.operator->());
135     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
136                          "D3DHost_FrameBuffer, could not create the GL <-> DirectX Interop using wglDXOpenDeviceNV()");
137     return Standard_False;
138   }
139
140   if (!registerD3dBuffer (theCtx))
141   {
142     Release (theCtx.operator->());
143     return Standard_False;
144   }
145
146   myIsOwnBuffer = true;
147   myIsOwnDepth  = true;
148   theCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
149   if (!myDepthStencilTexture->Init (theCtx, GL_DEPTH24_STENCIL8,
150                                     GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
151                                     aSizeX, aSizeY, Graphic3d_TOT_2D))
152   {
153     Release (theCtx.operator->());
154     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
155                          TCollection_AsciiString("D3DHost_FrameBuffer, could not initialize GL_DEPTH24_STENCIL8 texture ") + aSizeX + "x" + aSizeY);
156     return Standard_False;
157   }
158
159   return Standard_True;
160 #else
161   (void )theD3DDevice;
162   (void )theIsD3dEx;
163   (void )theSizeX;
164   (void )theSizeY;
165   return Standard_False;
166 #endif
167 }
168
169 // =======================================================================
170 // function : registerD3dBuffer
171 // purpose  :
172 // =======================================================================
173 Standard_Boolean D3DHost_FrameBuffer::registerD3dBuffer (const Handle(OpenGl_Context)& theCtx)
174 {
175 #if defined(GL_ES_VERSION_2_0)
176   (void )theCtx;
177   return Standard_False;
178 #else
179   const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
180   if (myGlD3dSurf != NULL)
181   {
182     if (!aFuncs->wglDXUnregisterObjectNV (myGlD3dDevice, myGlD3dSurf))
183     {
184       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
185                            "D3DHost_FrameBuffer, can not unregister color buffer");
186       return Standard_False;
187     }
188     myGlD3dSurf = NULL;
189   }
190
191   if (!aFuncs->wglDXSetResourceShareHandleNV (myD3dSurf, myD3dSurfShare))
192   {
193     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
194                          "D3DHost_FrameBuffer, wglDXSetResourceShareHandleNV() has failed");
195     return Standard_False;
196   }
197
198   myColorTextures (0)->Release (theCtx.operator->());
199   myColorTextures (0)->Create  (theCtx);
200
201   myGlD3dSurf = aFuncs->wglDXRegisterObjectNV (myGlD3dDevice,
202                                                myD3dSurf,
203                                                myColorTextures (0)->TextureId(),
204                                                GL_TEXTURE_2D,
205                                                WGL_ACCESS_WRITE_DISCARD_NV);
206
207   if (myGlD3dSurf == NULL)
208   {
209     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
210                          "D3DHost_FrameBuffer, can not register color buffer");
211     return Standard_False;
212   }
213
214   return Standard_True;
215 #endif
216 }
217
218 // =======================================================================
219 // function : BindBuffer
220 // purpose  :
221 // =======================================================================
222 void D3DHost_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theCtx)
223 {
224   Standard_ProgramError_Raise_if (myLockCount < 1, "D3DHost_FrameBuffer::BindBuffer(), resource should be locked beforehand!");
225
226   OpenGl_FrameBuffer::BindBuffer (theCtx);
227   theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
228                                           myColorTextures (0)->GetTarget(), myColorTextures (0)->TextureId(), 0);
229 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
230   theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
231                                           myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
232 #else
233   theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
234                                           myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
235   theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
236                                           myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
237 #endif
238   if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
239   {
240     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
241                          "D3DHost_FrameBuffer, OpenGL FBO is incomplete!");
242     Release (theCtx.operator->());
243   }
244 }
245
246 // =======================================================================
247 // function : LockSurface
248 // purpose  :
249 // =======================================================================
250 void D3DHost_FrameBuffer::LockSurface (const Handle(OpenGl_Context)& theCtx)
251 {
252   if (++myLockCount > 1)
253   {
254     return;
255   }
256   if (myGlD3dSurf == NULL)
257   {
258     return;
259   }
260
261 #if !defined(GL_ES_VERSION_2_0)
262   const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
263   if (!aFuncs->wglDXLockObjectsNV (myGlD3dDevice, 1, &myGlD3dSurf))
264   {
265     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
266                          "D3DHost_FrameBuffer::LockSurface(), lock failed!");
267   }
268 #else
269   (void )theCtx;
270 #endif
271 }
272
273 // =======================================================================
274 // function : UnlockSurface
275 // purpose  :
276 // =======================================================================
277 void D3DHost_FrameBuffer::UnlockSurface (const Handle(OpenGl_Context)& theCtx)
278 {
279   if (--myLockCount != 0)
280   {
281     return;
282   }
283   if (myGlD3dSurf == NULL)
284   {
285     return;
286   }
287
288 #if !defined(GL_ES_VERSION_2_0)
289   const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
290   aFuncs->wglDXUnlockObjectsNV (myGlD3dDevice, 1, &myGlD3dSurf);
291 #endif
292 }