0027696: Return max distance in xdistcs Draw command
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2011-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <OpenGl_FrameBuffer.hxx>
16 #include <OpenGl_ArbFBO.hxx>
17
18 #include <Standard_Assert.hxx>
19 #include <TCollection_ExtendedString.hxx>
20
21 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
22
23 namespace
24 {
25
26   //! Determine data type from texture sized format.
27   static bool getDepthDataFormat (GLint   theTextFormat,
28                                   GLenum& thePixelFormat,
29                                   GLenum& theDataType)
30   {
31     switch (theTextFormat)
32     {
33       case GL_DEPTH24_STENCIL8:
34       {
35         thePixelFormat = GL_DEPTH_STENCIL;
36         theDataType    = GL_UNSIGNED_INT_24_8;
37         return true;
38       }
39       case GL_DEPTH32F_STENCIL8:
40       {
41         thePixelFormat = GL_DEPTH_STENCIL;
42         theDataType    = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
43         return true;
44       }
45       case GL_DEPTH_COMPONENT16:
46       {
47         thePixelFormat = GL_DEPTH_COMPONENT;
48         theDataType    = GL_UNSIGNED_SHORT;
49         return true;
50       }
51       case GL_DEPTH_COMPONENT24:
52       {
53         thePixelFormat = GL_DEPTH_COMPONENT;
54         theDataType    = GL_UNSIGNED_INT;
55         return true;
56       }
57       case GL_DEPTH_COMPONENT32F:
58       {
59         thePixelFormat = GL_DEPTH_COMPONENT;
60         theDataType    = GL_FLOAT;
61         return true;
62       }
63     }
64     return false;
65   }
66
67 }
68
69 // =======================================================================
70 // function : OpenGl_FrameBuffer
71 // purpose  :
72 // =======================================================================
73 OpenGl_FrameBuffer::OpenGl_FrameBuffer()
74 : myVPSizeX (0),
75   myVPSizeY (0),
76   myNbSamples (0),
77   myColorFormat (GL_RGBA8),
78   myDepthFormat (GL_DEPTH24_STENCIL8),
79   myGlFBufferId (NO_FRAMEBUFFER),
80   myGlColorRBufferId (NO_RENDERBUFFER),
81   myGlDepthRBufferId (NO_RENDERBUFFER),
82   myIsOwnBuffer  (false),
83   myColorTexture (new OpenGl_Texture()),
84   myDepthStencilTexture (new OpenGl_Texture())
85 {
86   //
87 }
88
89 // =======================================================================
90 // function : ~OpenGl_FrameBuffer
91 // purpose  :
92 // =======================================================================
93 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
94 {
95   Release (NULL);
96 }
97
98 // =======================================================================
99 // function : Init
100 // purpose  :
101 // =======================================================================
102 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
103                                            const GLsizei   theSizeX,
104                                            const GLsizei   theSizeY,
105                                            const GLint     theColorFormat,
106                                            const GLint     theDepthFormat,
107                                            const GLsizei   theNbSamples)
108 {
109   myColorFormat = theColorFormat;
110   myDepthFormat = theDepthFormat;
111   myNbSamples   = theNbSamples;
112   if (theGlContext->arbFBO == NULL)
113   {
114     return Standard_False;
115   }
116
117   // clean up previous state
118   Release (theGlContext.operator->());
119   if (myColorFormat == 0
120    && myDepthFormat == 0)
121   {
122     return Standard_False;
123   }
124
125   myIsOwnBuffer = true;
126
127   // setup viewport sizes as is
128   myVPSizeX = theSizeX;
129   myVPSizeY = theSizeY;
130   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
131   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
132
133   // Create the textures (will be used as color buffer and depth-stencil buffer)
134   if (theNbSamples != 0)
135   {
136     if (myColorFormat != 0
137     && !myColorTexture       ->Init2DMultisample (theGlContext, theNbSamples, myColorFormat, aSizeX, aSizeY))
138     {
139       Release (theGlContext.operator->());
140       return Standard_False;
141     }
142     if (myDepthFormat != 0
143     && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
144     {
145       Release (theGlContext.operator->());
146       return Standard_False;
147     }
148   }
149   else
150   {
151     if (myColorFormat != 0
152     && !myColorTexture->Init (theGlContext, myColorFormat,
153                               GL_RGBA, GL_UNSIGNED_BYTE,
154                               aSizeX, aSizeY, Graphic3d_TOT_2D))
155     {
156       Release (theGlContext.operator->());
157       return Standard_False;
158     }
159
160     // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
161     // instead of just trying to create such texture
162     GLenum aPixelFormat = 0;
163     GLenum aDataType    = 0;
164     if (myDepthFormat != 0
165     &&  getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
166     && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
167                                       aPixelFormat, aDataType,
168                                       aSizeX, aSizeY, Graphic3d_TOT_2D))
169     {
170       TCollection_ExtendedString aMsg = TCollection_ExtendedString()
171         + "Warning! Depth textures are not supported by hardware!";
172       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
173                                  GL_DEBUG_TYPE_PORTABILITY,
174                                  0,
175                                  GL_DEBUG_SEVERITY_HIGH,
176                                  aMsg);
177
178       theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
179       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
180       theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, aSizeX, aSizeY);
181       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
182     }
183   }
184
185   // Build FBO and setup it as texture
186   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
187   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
188   if (myColorTexture->IsValid())
189   {
190     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
191                                                   myColorTexture->GetTarget(), myColorTexture->TextureId(), 0);
192   }
193   if (myDepthStencilTexture->IsValid())
194   {
195   #ifdef GL_DEPTH_STENCIL_ATTACHMENT
196     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
197                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
198   #else
199     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
200                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
201     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
202                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
203   #endif
204   }
205   else if (myGlDepthRBufferId != NO_RENDERBUFFER)
206   {
207     theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
208                                                      GL_RENDERBUFFER, myGlDepthRBufferId);
209   }
210   if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
211   {
212     Release (theGlContext.operator->());
213     return Standard_False;
214   }
215
216   UnbindBuffer (theGlContext);
217   return Standard_True;
218 }
219
220 // =======================================================================
221 // function : Init
222 // purpose  :
223 // =======================================================================
224 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
225                                                const GLsizei                 theViewportSizeX,
226                                                const GLsizei                 theViewportSizeY,
227                                                const GLint                   theColorFormat,
228                                                const GLint                   theDepthFormat,
229                                                const GLsizei                 theNbSamples)
230 {
231   if (myVPSizeX     == theViewportSizeX
232    && myVPSizeY     == theViewportSizeY
233    && myColorFormat == theColorFormat
234    && myDepthFormat == theDepthFormat
235    && myNbSamples   == theNbSamples)
236   {
237     return IsValid();
238   }
239
240   return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormat, theDepthFormat, theNbSamples);
241 }
242
243 // =======================================================================
244 // function : InitWithRB
245 // purpose  :
246 // =======================================================================
247 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
248                                                  const GLsizei                 theSizeX,
249                                                  const GLsizei                 theSizeY,
250                                                  const GLint                   theColorFormat,
251                                                  const GLint                   theDepthFormat,
252                                                  const GLuint                  theColorRBufferFromWindow)
253 {
254   myColorFormat = theColorFormat;
255   myDepthFormat = theDepthFormat;
256   myNbSamples   = 0;
257   if (theGlCtx->arbFBO == NULL)
258   {
259     return Standard_False;
260   }
261
262   // clean up previous state
263   Release (theGlCtx.operator->());
264
265   myIsOwnBuffer = true;
266
267   // setup viewport sizes as is
268   myVPSizeX = theSizeX;
269   myVPSizeY = theSizeY;
270   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
271   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
272
273   // Create the render-buffers
274   if (theColorRBufferFromWindow != NO_RENDERBUFFER)
275   {
276     myGlColorRBufferId = theColorRBufferFromWindow;
277   }
278   else if (myColorFormat != 0)
279   {
280     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
281     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
282     theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myColorFormat, aSizeX, aSizeY);
283   }
284
285   if (myDepthFormat != 0)
286   {
287     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
288     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
289     theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
290     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
291   }
292
293   // create FBO
294   theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
295   theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
296   theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
297                                                GL_RENDERBUFFER, myGlColorRBufferId);
298   if (myGlDepthRBufferId != NO_RENDERBUFFER)
299   {
300   #ifdef GL_DEPTH_STENCIL_ATTACHMENT
301     theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
302                                                  GL_RENDERBUFFER, myGlDepthRBufferId);
303   #else
304     theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
305                                                  GL_RENDERBUFFER, myGlDepthRBufferId);
306     theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
307                                                  GL_RENDERBUFFER, myGlDepthRBufferId);
308   #endif
309   }
310   if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
311   {
312     UnbindBuffer (theGlCtx);
313     Release (theGlCtx.operator->());
314     return Standard_False;
315   }
316
317   UnbindBuffer (theGlCtx);
318   return Standard_True;
319 }
320
321 // =======================================================================
322 // function : InitWrapper
323 // purpose  :
324 // =======================================================================
325 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
326 {
327   myNbSamples = 0;
328   if (theGlCtx->arbFBO == NULL)
329   {
330     return Standard_False;
331   }
332
333   // clean up previous state
334   Release (theGlCtx.operator->());
335
336   GLint anFbo = GLint(NO_FRAMEBUFFER);
337   ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
338   if (anFbo == GLint(NO_FRAMEBUFFER))
339   {
340     return Standard_False;
341   }
342
343   GLint aColorType = 0;
344   GLint aColorId   = 0;
345   GLint aDepthType = 0;
346   GLint aDepthId   = 0;
347   theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
348   theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
349
350   myGlFBufferId = GLuint(anFbo);
351   myIsOwnBuffer = false;
352   if (aColorType == GL_RENDERBUFFER)
353   {
354     theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
355     myGlColorRBufferId = aColorId;
356   }
357   else if (aColorType != GL_NONE)
358   {
359     TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
360     theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
361                            GL_DEBUG_TYPE_ERROR,
362                            0,
363                            GL_DEBUG_SEVERITY_HIGH,
364                            aMsg);
365   }
366
367   if (aDepthType == GL_RENDERBUFFER)
368   {
369     theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
370     myGlDepthRBufferId = aDepthId;
371   }
372   else if (aDepthType != GL_NONE)
373   {
374     TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
375     theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
376                            GL_DEBUG_TYPE_ERROR,
377                            0,
378                            GL_DEBUG_SEVERITY_HIGH,
379                            aMsg);
380   }
381
382   // retrieve dimensions
383   GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
384   if (aRBuffer != NO_RENDERBUFFER)
385   {
386     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
387     theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &myVPSizeX);
388     theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
389     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
390   }
391
392   return aRBuffer != NO_RENDERBUFFER;
393 }
394
395 // =======================================================================
396 // function : Release
397 // purpose  :
398 // =======================================================================
399 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
400 {
401   if (isValidFrameBuffer())
402   {
403     // application can not handle this case by exception - this is bug in code
404     Standard_ASSERT_RETURN (theGlCtx != NULL,
405       "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
406     if (theGlCtx->IsValid()
407      && myIsOwnBuffer)
408     {
409       theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
410       if (myGlColorRBufferId != NO_RENDERBUFFER)
411       {
412         theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
413       }
414       if (myGlDepthRBufferId != NO_RENDERBUFFER)
415       {
416         theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
417       }
418     }
419     myGlFBufferId      = NO_FRAMEBUFFER;
420     myGlColorRBufferId = NO_RENDERBUFFER;
421     myGlDepthRBufferId = NO_RENDERBUFFER;
422     myIsOwnBuffer      = false;
423   }
424
425   myColorTexture->Release (theGlCtx);
426   myDepthStencilTexture->Release (theGlCtx);
427
428   myVPSizeX = 0;
429   myVPSizeY = 0;
430 }
431
432 // =======================================================================
433 // function : SetupViewport
434 // purpose  :
435 // =======================================================================
436 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
437 {
438   const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
439   theGlCtx->ResizeViewport (aViewport);
440 }
441
442 // =======================================================================
443 // function : ChangeViewport
444 // purpose  :
445 // =======================================================================
446 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
447                                          const GLsizei theVPSizeY)
448 {
449   myVPSizeX = theVPSizeX;
450   myVPSizeY = theVPSizeY;
451 }
452
453 // =======================================================================
454 // function : BindBuffer
455 // purpose  :
456 // =======================================================================
457 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
458 {
459   theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
460 }
461
462 // =======================================================================
463 // function : BindDrawBuffer
464 // purpose  :
465 // =======================================================================
466 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
467 {
468   theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
469 }
470
471 // =======================================================================
472 // function : BindReadBuffer
473 // purpose  :
474 // =======================================================================
475 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
476 {
477   theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
478 }
479
480 // =======================================================================
481 // function : UnbindBuffer
482 // purpose  :
483 // =======================================================================
484 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
485 {
486   if (!theGlCtx->DefaultFrameBuffer().IsNull()
487    &&  theGlCtx->DefaultFrameBuffer().operator->() != this)
488   {
489     theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
490   }
491   else
492   {
493     theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
494   }
495 }