0028744: Visualization, OpenGl_FrameBuffer missing GL_RGB8 format
[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   //! Determine data type from texture sized format.
68   static bool getColorDataFormat (GLint   theTextFormat,
69                                   GLenum& thePixelFormat,
70                                   GLenum& theDataType)
71   {
72     switch (theTextFormat)
73     {
74       case GL_RGBA32F:
75       {
76         thePixelFormat = GL_RGBA;
77         theDataType    = GL_FLOAT;
78         return true;
79       }
80       case GL_R32F:
81       {
82         thePixelFormat = GL_RED;
83         theDataType    = GL_FLOAT;
84         return true;
85       }
86       case GL_RGBA16F:
87       {
88         thePixelFormat = GL_RGBA;
89         theDataType    = GL_HALF_FLOAT;
90         return true;
91       }
92       case GL_R16F:
93       {
94         thePixelFormat = GL_RED;
95         theDataType    = GL_HALF_FLOAT;
96         return true;
97       }
98       case GL_RGBA8:
99       case GL_RGBA:
100       {
101         thePixelFormat = GL_RGBA;
102         theDataType    = GL_UNSIGNED_BYTE;
103         return true;
104       }
105       case GL_RGB8:
106       case GL_RGB:
107       {
108         thePixelFormat = GL_RGB;
109         theDataType = GL_UNSIGNED_BYTE;
110         return true;
111       }
112     }
113     return false;
114   }
115
116   //! Checks whether two format arrays are equal or not.
117   static bool operator== (const OpenGl_ColorFormats& theFmt1,
118                           const OpenGl_ColorFormats& theFmt2)
119   {
120     if (theFmt1.Length() != theFmt2.Length())
121       return false;
122     OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
123     OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
124     for (; anIt1.More(); anIt1.Next(), anIt2.Next())
125     {
126       if (anIt1.Value() != anIt2.Value())
127         return false;
128     }
129     return true;
130   }
131 }
132
133 // =======================================================================
134 // function : OpenGl_FrameBuffer
135 // purpose  :
136 // =======================================================================
137 OpenGl_FrameBuffer::OpenGl_FrameBuffer()
138 : myInitVPSizeX (0),
139   myInitVPSizeY (0),
140   myVPSizeX (0),
141   myVPSizeY (0),
142   myNbSamples (0),
143   myDepthFormat (GL_DEPTH24_STENCIL8),
144   myGlFBufferId (NO_FRAMEBUFFER),
145   myGlColorRBufferId (NO_RENDERBUFFER),
146   myGlDepthRBufferId (NO_RENDERBUFFER),
147   myIsOwnBuffer  (false),
148   myDepthStencilTexture (new OpenGl_Texture())
149 {
150   myColorFormats.Append (GL_RGBA8);
151   myColorTextures.Append (new OpenGl_Texture());
152 }
153
154 // =======================================================================
155 // function : ~OpenGl_FrameBuffer
156 // purpose  :
157 // =======================================================================
158 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
159 {
160   Release (NULL);
161 }
162
163 // =======================================================================
164 // function : Init
165 // purpose  :
166 // =======================================================================
167 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
168                                            const GLsizei                 theSizeX,
169                                            const GLsizei                 theSizeY,
170                                            const GLint                   theColorFormat,
171                                            const GLint                   theDepthFormat,
172                                            const GLsizei                 theNbSamples)
173 {
174   OpenGl_ColorFormats aColorFormats;
175
176   aColorFormats.Append (theColorFormat);
177
178   return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples);
179 }
180
181 // =======================================================================
182 // function : Init
183 // purpose  :
184 // =======================================================================
185 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
186                                            const GLsizei                 theSizeX,
187                                            const GLsizei                 theSizeY,
188                                            const OpenGl_ColorFormats&    theColorFormats,
189                                            const Handle(OpenGl_Texture)& theDepthStencilTexture,
190                                            const GLsizei                 theNbSamples)
191 {
192   myColorFormats = theColorFormats;
193
194   OpenGl_TextureArray aTextures (myColorTextures);
195   if (!myColorTextures.IsEmpty())
196   {
197     for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
198     {
199       aTextureIt.Value()->Release (theGlContext.operator->());
200     }
201     myColorTextures.Clear();
202   }
203   for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
204   {
205     myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
206   }
207
208   myDepthFormat = theDepthStencilTexture->GetFormat();
209   myNbSamples   = theNbSamples;
210   if (theGlContext->arbFBO == NULL)
211   {
212     return Standard_False;
213   }
214
215   // clean up previous state
216   Release (theGlContext.operator->());
217   if (myColorFormats.IsEmpty()
218    && myDepthFormat == 0)
219   {
220     return Standard_False;
221   }
222
223   myDepthStencilTexture = theDepthStencilTexture;
224   myIsOwnDepth  = false;
225   myIsOwnBuffer = true;
226
227   // setup viewport sizes as is
228   myVPSizeX = theSizeX;
229   myVPSizeY = theSizeY;
230   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
231   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
232
233   // Create the textures (will be used as color buffer and depth-stencil buffer)
234   if (theNbSamples != 0)
235   {
236     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
237     {
238       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
239       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
240       if (aColorFormat != 0
241       && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
242                                             aColorFormat, aSizeX, aSizeY))
243       {
244         Release (theGlContext.operator->());
245         return Standard_False;
246       }
247     }
248   }
249   else
250   {
251     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
252     {
253       GLenum aPixelFormat = 0;
254       GLenum aDataType    = 0;
255       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
256       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
257       if (aColorFormat != 0
258       &&  getColorDataFormat (aColorFormat, aPixelFormat, aDataType)
259       && !aColorTexture->Init (theGlContext, aColorFormat,
260                                aPixelFormat, aDataType,
261                                aSizeX, aSizeY, Graphic3d_TOT_2D))
262       {
263         Release (theGlContext.operator->());
264         return Standard_False;
265       }
266     }
267   }
268
269   // Build FBO and setup it as texture
270   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
271   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
272
273   for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
274   {
275     const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
276     if (aColorTexture->IsValid())
277     {
278       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
279                                                     aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
280     }
281   }
282   if (myDepthStencilTexture->IsValid())
283   {
284   #ifdef GL_DEPTH_STENCIL_ATTACHMENT
285     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
286                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
287   #else
288     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
289                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
290     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
291                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
292   #endif
293   }
294   if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
295   {
296     Release (theGlContext.operator->());
297     return Standard_False;
298   }
299
300   UnbindBuffer (theGlContext);
301   return Standard_True;
302 }
303
304 // =======================================================================
305 // function : Init
306 // purpose  :
307 // =======================================================================
308 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
309                                            const GLsizei                 theSizeX,
310                                            const GLsizei                 theSizeY,
311                                            const OpenGl_ColorFormats&    theColorFormats,
312                                            const GLint                   theDepthFormat,
313                                            const GLsizei                 theNbSamples)
314 {
315   myColorFormats = theColorFormats;
316
317   OpenGl_TextureArray aTextures (myColorTextures);
318   if (!myColorTextures.IsEmpty())
319   {
320     for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
321     {
322       aTextureIt.Value()->Release (theGlContext.operator->());
323     }
324     myColorTextures.Clear();
325   }
326   for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
327   {
328     myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
329   }
330
331   myDepthFormat = theDepthFormat;
332   myNbSamples   = theNbSamples;
333   myInitVPSizeX = theSizeX;
334   myInitVPSizeY = theSizeY;
335   if (theGlContext->arbFBO == NULL)
336   {
337     return Standard_False;
338   }
339
340   // clean up previous state
341   Release (theGlContext.operator->());
342   if (myColorFormats.IsEmpty()
343    && myDepthFormat == 0)
344   {
345     return Standard_False;
346   }
347
348   myIsOwnBuffer = true;
349   myIsOwnDepth  = true;
350
351   // setup viewport sizes as is
352   myVPSizeX = theSizeX;
353   myVPSizeY = theSizeY;
354   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
355   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
356   bool hasStencilRB = false;
357
358   // Create the textures (will be used as color buffer and depth-stencil buffer)
359   if (theNbSamples != 0)
360   {
361     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
362     {
363       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
364       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
365       if (aColorFormat != 0
366       && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
367       {
368         Release (theGlContext.operator->());
369         return Standard_False;
370       }
371     }
372     if (myDepthFormat != 0
373     && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
374     {
375       Release (theGlContext.operator->());
376       return Standard_False;
377     }
378   }
379   else
380   {
381     GLenum aPixelFormat = 0;
382     GLenum aDataType    = 0;
383
384     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
385     {
386       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
387       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
388       if (aColorFormat != 0
389       &&  getColorDataFormat (aColorFormat, aPixelFormat, aDataType)
390       && !aColorTexture->Init (theGlContext, aColorFormat,
391                                aPixelFormat, aDataType,
392                                aSizeX, aSizeY, Graphic3d_TOT_2D))
393       {
394         Release (theGlContext.operator->());
395         return Standard_False;
396       }
397     }
398
399     // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
400     // instead of just trying to create such texture
401     if (myDepthFormat != 0
402     &&  getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
403     && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
404                                       aPixelFormat, aDataType,
405                                       aSizeX, aSizeY, Graphic3d_TOT_2D))
406     {
407       TCollection_ExtendedString aMsg = TCollection_ExtendedString()
408         + "Warning! Depth textures are not supported by hardware!";
409       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
410                                  GL_DEBUG_TYPE_PORTABILITY,
411                                  0,
412                                  GL_DEBUG_SEVERITY_HIGH,
413                                  aMsg);
414
415       hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL
416                   && theGlContext->extPDS;
417       GLint aDepthStencilFormat = hasStencilRB
418                                 ? GL_DEPTH24_STENCIL8
419                                 : GL_DEPTH_COMPONENT16;
420
421       theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
422       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
423       theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
424       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
425     }
426   }
427
428   // Build FBO and setup it as texture
429   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
430   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
431   for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
432   {
433     const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
434     if (aColorTexture->IsValid())
435     {
436       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
437                                                     aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
438     }
439   }
440   if (myDepthStencilTexture->IsValid())
441   {
442   #ifdef GL_DEPTH_STENCIL_ATTACHMENT
443     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
444                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
445   #else
446     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
447                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
448     theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
449                                                   myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
450   #endif
451   }
452   else if (myGlDepthRBufferId != NO_RENDERBUFFER)
453   {
454   #ifdef GL_DEPTH_STENCIL_ATTACHMENT
455     theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
456                                                      GL_RENDERBUFFER, myGlDepthRBufferId);
457   #else
458     theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
459                                                      GL_RENDERBUFFER, myGlDepthRBufferId);
460     if (hasStencilRB)
461     {
462       theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
463                                                        GL_RENDERBUFFER, myGlDepthRBufferId);
464     }
465   #endif
466   }
467   if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
468   {
469     Release (theGlContext.operator->());
470     return Standard_False;
471   }
472
473   UnbindBuffer (theGlContext);
474   return Standard_True;
475 }
476
477 // =======================================================================
478 // function : InitLazy
479 // purpose  :
480 // =======================================================================
481 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
482                                                const GLsizei                 theViewportSizeX,
483                                                const GLsizei                 theViewportSizeY,
484                                                const GLint                   theColorFormat,
485                                                const GLint                   theDepthFormat,
486                                                const GLsizei                 theNbSamples)
487 {
488   OpenGl_ColorFormats aColorFormats;
489
490   aColorFormats.Append (theColorFormat);
491
492   return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples);
493 }
494
495 // =======================================================================
496 // function : InitLazy
497 // purpose  :
498 // =======================================================================
499 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
500                                                const GLsizei                 theViewportSizeX,
501                                                const GLsizei                 theViewportSizeY,
502                                                const OpenGl_ColorFormats&    theColorFormats,
503                                                const GLint                   theDepthFormat,
504                                                const GLsizei                 theNbSamples)
505 {
506   if (myVPSizeX      == theViewportSizeX
507    && myVPSizeY      == theViewportSizeY
508    && myColorFormats == theColorFormats
509    && myDepthFormat  == theDepthFormat
510    && myNbSamples    == theNbSamples)
511   {
512     return IsValid();
513   }
514
515   return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples);
516 }
517
518 // =======================================================================
519 // function : InitWithRB
520 // purpose  :
521 // =======================================================================
522 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
523                                                  const GLsizei                 theSizeX,
524                                                  const GLsizei                 theSizeY,
525                                                  const GLint                   theColorFormat,
526                                                  const GLint                   theDepthFormat,
527                                                  const GLuint                  theColorRBufferFromWindow)
528 {
529   myColorFormats.Clear();
530   myColorFormats.Append (theColorFormat);
531   if (!myColorTextures.IsEmpty())
532   {
533     Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
534     for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
535     {
536       aTextureIt.Value()->Release (theGlCtx.operator->());
537     }
538     myColorTextures.Clear();
539     myColorTextures.Append (aTexutre);
540   }
541
542   myDepthFormat = theDepthFormat;
543   myNbSamples   = 0;
544   myInitVPSizeX = theSizeX;
545   myInitVPSizeY = theSizeY;
546   if (theGlCtx->arbFBO == NULL)
547   {
548     return Standard_False;
549   }
550
551   // clean up previous state
552   Release (theGlCtx.operator->());
553
554   myIsOwnBuffer = true;
555   myIsOwnDepth  = true;
556
557   // setup viewport sizes as is
558   myVPSizeX = theSizeX;
559   myVPSizeY = theSizeY;
560   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
561   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
562
563   // Create the render-buffers
564   if (theColorRBufferFromWindow != NO_RENDERBUFFER)
565   {
566     myGlColorRBufferId = theColorRBufferFromWindow;
567   }
568   else if (theColorFormat != 0)
569   {
570     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
571     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
572     theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
573   }
574
575   bool hasStencilRB = false;
576   if (myDepthFormat != 0)
577   {
578     GLenum aPixelFormat = 0;
579     GLenum aDataType    = 0;
580     getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType);
581     hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL;
582
583     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
584     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
585     theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
586     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
587   }
588
589   // create FBO
590   theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
591   theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
592   theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
593                                                GL_RENDERBUFFER, myGlColorRBufferId);
594   if (myGlDepthRBufferId != NO_RENDERBUFFER)
595   {
596   #ifdef GL_DEPTH_STENCIL_ATTACHMENT
597     theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
598                                                  GL_RENDERBUFFER, myGlDepthRBufferId);
599   #else
600     theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
601                                                  GL_RENDERBUFFER, myGlDepthRBufferId);
602     if (hasStencilRB)
603     {
604       theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
605                                                    GL_RENDERBUFFER, myGlDepthRBufferId);
606     }
607   #endif
608   }
609   if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
610   {
611     UnbindBuffer (theGlCtx);
612     Release (theGlCtx.operator->());
613     return Standard_False;
614   }
615
616   UnbindBuffer (theGlCtx);
617   return Standard_True;
618 }
619
620 // =======================================================================
621 // function : InitWrapper
622 // purpose  :
623 // =======================================================================
624 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
625 {
626   myNbSamples = 0;
627   if (theGlCtx->arbFBO == NULL)
628   {
629     return Standard_False;
630   }
631
632   // clean up previous state
633   Release (theGlCtx.operator->());
634
635   GLint anFbo = GLint(NO_FRAMEBUFFER);
636   ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
637   if (anFbo == GLint(NO_FRAMEBUFFER))
638   {
639     return Standard_False;
640   }
641
642   GLint aColorType = 0;
643   GLint aColorId   = 0;
644   GLint aDepthType = 0;
645   GLint aDepthId   = 0;
646   theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
647   theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
648
649   myGlFBufferId = GLuint(anFbo);
650   myIsOwnBuffer = false;
651   myIsOwnDepth  = false;
652   if (aColorType == GL_RENDERBUFFER)
653   {
654     theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
655     myGlColorRBufferId = aColorId;
656   }
657   else if (aColorType != GL_NONE)
658   {
659     TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
660     theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
661                            GL_DEBUG_TYPE_ERROR,
662                            0,
663                            GL_DEBUG_SEVERITY_HIGH,
664                            aMsg);
665   }
666
667   if (aDepthType == GL_RENDERBUFFER)
668   {
669     theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
670     myGlDepthRBufferId = aDepthId;
671   }
672   else if (aDepthType != GL_NONE)
673   {
674     TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
675     theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
676                            GL_DEBUG_TYPE_ERROR,
677                            0,
678                            GL_DEBUG_SEVERITY_HIGH,
679                            aMsg);
680   }
681
682   // retrieve dimensions
683   GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
684   if (aRBuffer != NO_RENDERBUFFER)
685   {
686     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
687     theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &myVPSizeX);
688     theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
689     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
690   }
691
692   return aRBuffer != NO_RENDERBUFFER;
693 }
694
695 // =======================================================================
696 // function : Release
697 // purpose  :
698 // =======================================================================
699 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
700 {
701   if (isValidFrameBuffer())
702   {
703     // application can not handle this case by exception - this is bug in code
704     Standard_ASSERT_RETURN (theGlCtx != NULL,
705       "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
706     if (theGlCtx->IsValid()
707      && myIsOwnBuffer)
708     {
709       theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
710       if (myGlColorRBufferId != NO_RENDERBUFFER)
711       {
712         theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
713       }
714       if (myGlDepthRBufferId != NO_RENDERBUFFER)
715       {
716         theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
717       }
718     }
719     myGlFBufferId      = NO_FRAMEBUFFER;
720     myGlColorRBufferId = NO_RENDERBUFFER;
721     myGlDepthRBufferId = NO_RENDERBUFFER;
722     myIsOwnBuffer      = false;
723   }
724
725   for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
726   {
727     myColorTextures (aColorBufferIdx)->Release (theGlCtx);
728   }
729
730   if (myIsOwnDepth)
731   {
732     myDepthStencilTexture->Release (theGlCtx);
733     myIsOwnDepth = false;
734   }
735
736   myVPSizeX = 0;
737   myVPSizeY = 0;
738 }
739
740 // =======================================================================
741 // function : SetupViewport
742 // purpose  :
743 // =======================================================================
744 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
745 {
746   const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
747   theGlCtx->ResizeViewport (aViewport);
748 }
749
750 // =======================================================================
751 // function : ChangeViewport
752 // purpose  :
753 // =======================================================================
754 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
755                                          const GLsizei theVPSizeY)
756 {
757   myVPSizeX = theVPSizeX;
758   myVPSizeY = theVPSizeY;
759 }
760
761 // =======================================================================
762 // function : BindBuffer
763 // purpose  :
764 // =======================================================================
765 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
766 {
767   theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
768 }
769
770 // =======================================================================
771 // function : BindDrawBuffer
772 // purpose  :
773 // =======================================================================
774 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
775 {
776   theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
777 }
778
779 // =======================================================================
780 // function : BindReadBuffer
781 // purpose  :
782 // =======================================================================
783 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
784 {
785   theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
786 }
787
788 // =======================================================================
789 // function : UnbindBuffer
790 // purpose  :
791 // =======================================================================
792 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
793 {
794   if (!theGlCtx->DefaultFrameBuffer().IsNull()
795    &&  theGlCtx->DefaultFrameBuffer().operator->() != this)
796   {
797     theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
798   }
799   else
800   {
801     theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
802   }
803 }