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