0032153: Visualization, Graphic3d_ArrayOfPrimitives - share common allocator
[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   //! Checks whether two format arrays are equal or not.
26   static bool operator== (const OpenGl_ColorFormats& theFmt1,
27                           const OpenGl_ColorFormats& theFmt2)
28   {
29     if (theFmt1.Length() != theFmt2.Length())
30       return false;
31     OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
32     OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
33     for (; anIt1.More(); anIt1.Next(), anIt2.Next())
34     {
35       if (anIt1.Value() != anIt2.Value())
36         return false;
37     }
38     return true;
39   }
40
41   //! Return TRUE if GL_DEPTH_STENCIL_ATTACHMENT can be used.
42   static bool hasDepthStencilAttach (const Handle(OpenGl_Context)& theCtx)
43   {
44   #ifdef __EMSCRIPTEN__
45     // supported since WebGL 2.0,
46     // while WebGL 1.0 + GL_WEBGL_depth_texture needs GL_DEPTH_STENCIL_ATTACHMENT
47     // and NOT separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls which is different to OpenGL ES 2.0 + extension
48     return theCtx->IsGlGreaterEqual (3, 0) || theCtx->extPDS;
49   #elif defined(GL_ES_VERSION_2_0)
50     // supported since OpenGL ES 3.0,
51     // while OpenGL ES 2.0 + GL_EXT_packed_depth_stencil needs separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls
52     return theCtx->IsGlGreaterEqual (3, 0);
53   #else
54     // available on desktop since OpenGL 3.0
55     // or OpenGL 2.0 + GL_ARB_framebuffer_object (GL_EXT_framebuffer_object is unsupported by OCCT)
56     (void )theCtx;
57     return true;
58   #endif
59   }
60 }
61
62 // =======================================================================
63 // function : OpenGl_FrameBuffer
64 // purpose  :
65 // =======================================================================
66 OpenGl_FrameBuffer::OpenGl_FrameBuffer()
67 : myInitVPSizeX (0),
68   myInitVPSizeY (0),
69   myVPSizeX (0),
70   myVPSizeY (0),
71   myNbSamples (0),
72   myDepthFormat (GL_DEPTH24_STENCIL8),
73   myGlFBufferId (NO_FRAMEBUFFER),
74   myGlColorRBufferId (NO_RENDERBUFFER),
75   myGlDepthRBufferId (NO_RENDERBUFFER),
76   myIsOwnBuffer (false),
77   myIsOwnColor  (false),
78   myIsOwnDepth  (false),
79   myDepthStencilTexture (new OpenGl_Texture())
80 {
81   myColorFormats.Append (GL_RGBA8);
82   myColorTextures.Append (new OpenGl_Texture());
83 }
84
85 // =======================================================================
86 // function : ~OpenGl_FrameBuffer
87 // purpose  :
88 // =======================================================================
89 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
90 {
91   Release (NULL);
92 }
93
94 // =======================================================================
95 // function : InitWrapper
96 // purpose  :
97 // =======================================================================
98 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlContext,
99                                                   const NCollection_Sequence<Handle(OpenGl_Texture)>& theColorTextures,
100                                                   const Handle(OpenGl_Texture)& theDepthTexture)
101 {
102   Release (theGlContext.get());
103   if (theGlContext->arbFBO == NULL)
104   {
105     return false;
106   }
107
108   myColorFormats.Clear();
109   myColorTextures.Clear();
110   for (NCollection_Sequence<Handle(OpenGl_Texture)>::Iterator aColorIter (theColorTextures); aColorIter.More(); aColorIter.Next())
111   {
112     myColorTextures.Append (aColorIter.Value());
113   }
114   myDepthFormat = 0;
115   myDepthStencilTexture = theDepthTexture;
116   myNbSamples = theColorTextures.First()->NbSamples();
117
118   myIsOwnColor  = false;
119   myIsOwnDepth  = false;
120   myIsOwnBuffer = true;
121
122   myVPSizeX = theColorTextures.First()->SizeX();
123   myVPSizeY = theColorTextures.First()->SizeY();
124
125   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
126   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
127   for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
128   {
129     const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
130     if (aColorTexture->IsValid())
131     {
132       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
133                                                     aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
134     }
135   }
136   if (!myDepthStencilTexture.IsNull()
137     && myDepthStencilTexture->IsValid())
138   {
139     if (hasDepthStencilAttach (theGlContext))
140     {
141       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
142                                                     myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
143     }
144     else
145     {
146       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
147                                                     myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
148       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
149                                                     myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
150     }
151   }
152   if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
153   {
154     Release (theGlContext.get());
155     return false;
156   }
157
158   UnbindBuffer (theGlContext);
159   return true;
160 }
161
162 // =======================================================================
163 // function : Init
164 // purpose  :
165 // =======================================================================
166 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
167                                            const GLsizei                 theSizeX,
168                                            const GLsizei                 theSizeY,
169                                            const GLint                   theColorFormat,
170                                            const GLint                   theDepthFormat,
171                                            const GLsizei                 theNbSamples)
172 {
173   OpenGl_ColorFormats aColorFormats;
174   if (theColorFormat != 0)
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   myIsOwnColor  = true;
225   myIsOwnDepth  = false;
226   myIsOwnBuffer = true;
227
228   // setup viewport sizes as is
229   myVPSizeX = theSizeX;
230   myVPSizeY = theSizeY;
231   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
232   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
233
234   // Create the textures (will be used as color buffer and depth-stencil buffer)
235   if (theNbSamples != 0)
236   {
237     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
238     {
239       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
240       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
241       if (aColorFormat == 0
242       || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
243                                             aColorFormat, aSizeX, aSizeY))
244       {
245         Release (theGlContext.get());
246         return Standard_False;
247       }
248     }
249   }
250   else
251   {
252     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
253     {
254       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
255       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
256       const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat);
257       if (!aFormat.IsValid()
258        || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
259       {
260         Release (theGlContext.get());
261         return Standard_False;
262       }
263     }
264   }
265
266   // Build FBO and setup it as texture
267   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
268   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
269
270   for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
271   {
272     const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
273     if (aColorTexture->IsValid())
274     {
275       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
276                                                     aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
277     }
278   }
279   if (myDepthStencilTexture->IsValid())
280   {
281     if (hasDepthStencilAttach (theGlContext))
282     {
283       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
284                                                     myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
285     }
286     else
287     {
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     }
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   myIsOwnColor  = true;
349   myIsOwnBuffer = true;
350   myIsOwnDepth  = true;
351
352   // setup viewport sizes as is
353   myVPSizeX = theSizeX;
354   myVPSizeY = theSizeY;
355   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
356   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
357   bool hasStencilRB = false;
358
359   // Create the textures (will be used as color buffer and depth-stencil buffer)
360   if (theNbSamples != 0)
361   {
362     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
363     {
364       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
365       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
366       if (aColorFormat == 0
367       || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
368       {
369         Release (theGlContext.operator->());
370         return Standard_False;
371       }
372     }
373     if (myDepthFormat != 0
374     && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
375     {
376       Release (theGlContext.operator->());
377       return Standard_False;
378     }
379   }
380   else
381   {
382     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
383     {
384       const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
385       const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
386       const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat);
387       if (!aFormat.IsValid()
388        || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
389       {
390         Release (theGlContext.operator->());
391         return Standard_False;
392       }
393     }
394
395     // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
396     // instead of just trying to create such texture
397     const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, myDepthFormat);
398     if (aDepthFormat.IsValid()
399     && !myDepthStencilTexture->Init (theGlContext, aDepthFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
400     {
401       theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
402                                  "Warning! Depth textures are not supported by hardware!");
403
404       hasStencilRB = aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL
405                   && theGlContext->extPDS;
406       GLint aDepthStencilFormat = hasStencilRB
407                                 ? GL_DEPTH24_STENCIL8
408                                 : GL_DEPTH_COMPONENT16;
409
410       theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
411       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
412       theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
413       theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
414     }
415   }
416
417   // Build FBO and setup it as texture
418   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
419   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
420   for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
421   {
422     const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
423     if (aColorTexture->IsValid())
424     {
425       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
426                                                     aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
427     }
428   }
429
430   if (myDepthStencilTexture->IsValid())
431   {
432     if (hasDepthStencilAttach (theGlContext))
433     {
434       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
435                                                     myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
436     }
437     else
438     {
439       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
440                                                     myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
441       theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
442                                                     myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
443     }
444   }
445   else if (myGlDepthRBufferId != NO_RENDERBUFFER)
446   {
447     if (hasDepthStencilAttach (theGlContext) && hasStencilRB)
448     {
449       theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
450                                                        GL_RENDERBUFFER, myGlDepthRBufferId);
451     }
452     else
453     {
454       theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
455                                                        GL_RENDERBUFFER, myGlDepthRBufferId);
456       if (hasStencilRB)
457       {
458         theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
459                                                          GL_RENDERBUFFER, myGlDepthRBufferId);
460       }
461     }
462   }
463   if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
464   {
465     Release (theGlContext.operator->());
466     return Standard_False;
467   }
468
469   UnbindBuffer (theGlContext);
470   return Standard_True;
471 }
472
473 // =======================================================================
474 // function : InitLazy
475 // purpose  :
476 // =======================================================================
477 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
478                                                const GLsizei                 theViewportSizeX,
479                                                const GLsizei                 theViewportSizeY,
480                                                const GLint                   theColorFormat,
481                                                const GLint                   theDepthFormat,
482                                                const GLsizei                 theNbSamples)
483 {
484   OpenGl_ColorFormats aColorFormats;
485
486   aColorFormats.Append (theColorFormat);
487
488   return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples);
489 }
490
491 // =======================================================================
492 // function : InitLazy
493 // purpose  :
494 // =======================================================================
495 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
496                                                const GLsizei                 theViewportSizeX,
497                                                const GLsizei                 theViewportSizeY,
498                                                const OpenGl_ColorFormats&    theColorFormats,
499                                                const GLint                   theDepthFormat,
500                                                const GLsizei                 theNbSamples)
501 {
502   if (myVPSizeX      == theViewportSizeX
503    && myVPSizeY      == theViewportSizeY
504    && myColorFormats == theColorFormats
505    && myDepthFormat  == theDepthFormat
506    && myNbSamples    == theNbSamples)
507   {
508     return IsValid();
509   }
510
511   return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples);
512 }
513
514 // =======================================================================
515 // function : InitWithRB
516 // purpose  :
517 // =======================================================================
518 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
519                                                  const GLsizei                 theSizeX,
520                                                  const GLsizei                 theSizeY,
521                                                  const GLint                   theColorFormat,
522                                                  const GLint                   theDepthFormat,
523                                                  const GLuint                  theColorRBufferFromWindow)
524 {
525   myColorFormats.Clear();
526   myColorFormats.Append (theColorFormat);
527   if (!myColorTextures.IsEmpty())
528   {
529     Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
530     for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
531     {
532       aTextureIt.Value()->Release (theGlCtx.operator->());
533     }
534     myColorTextures.Clear();
535     myColorTextures.Append (aTexutre);
536   }
537
538   myDepthFormat = theDepthFormat;
539   myNbSamples   = 0;
540   myInitVPSizeX = theSizeX;
541   myInitVPSizeY = theSizeY;
542   if (theGlCtx->arbFBO == NULL)
543   {
544     return Standard_False;
545   }
546
547   // clean up previous state
548   Release (theGlCtx.operator->());
549
550   myIsOwnColor  = true;
551   myIsOwnBuffer = true;
552   myIsOwnDepth  = true;
553
554   // setup viewport sizes as is
555   myVPSizeX = theSizeX;
556   myVPSizeY = theSizeY;
557   const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
558   const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
559
560   // Create the render-buffers
561   if (theColorRBufferFromWindow != NO_RENDERBUFFER)
562   {
563     myGlColorRBufferId = theColorRBufferFromWindow;
564   }
565   else if (theColorFormat != 0)
566   {
567     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
568     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
569     theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
570   }
571
572   bool hasStencilRB = false;
573   if (myDepthFormat != 0)
574   {
575     const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theGlCtx, myDepthFormat);
576     hasStencilRB = aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL;
577
578     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
579     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
580     theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
581     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
582   }
583
584   // create FBO
585   theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
586   theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
587   theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
588                                                GL_RENDERBUFFER, myGlColorRBufferId);
589   if (myGlDepthRBufferId != NO_RENDERBUFFER)
590   {
591     if (hasDepthStencilAttach (theGlCtx) && hasStencilRB)
592     {
593       theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
594                                                    GL_RENDERBUFFER, myGlDepthRBufferId);
595     }
596     else
597     {
598       theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
599                                                    GL_RENDERBUFFER, myGlDepthRBufferId);
600       if (hasStencilRB)
601       {
602         theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
603                                                      GL_RENDERBUFFER, myGlDepthRBufferId);
604       }
605     }
606   }
607   if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
608   {
609     UnbindBuffer (theGlCtx);
610     Release (theGlCtx.operator->());
611     return Standard_False;
612   }
613
614   UnbindBuffer (theGlCtx);
615   return Standard_True;
616 }
617
618 // =======================================================================
619 // function : InitWrapper
620 // purpose  :
621 // =======================================================================
622 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
623 {
624   myNbSamples = 0;
625   if (theGlCtx->arbFBO == NULL)
626   {
627     return Standard_False;
628   }
629
630   // clean up previous state
631   Release (theGlCtx.operator->());
632
633   GLint anFbo = GLint(NO_FRAMEBUFFER);
634   ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
635   if (anFbo == GLint(NO_FRAMEBUFFER))
636   {
637     return Standard_False;
638   }
639
640   GLint aColorType = 0;
641   GLint aColorId   = 0;
642   GLint aDepthType = 0;
643   GLint aDepthId   = 0;
644   theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
645   theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
646
647   myGlFBufferId = GLuint(anFbo);
648   myIsOwnColor  = false;
649   myIsOwnBuffer = false;
650   myIsOwnDepth  = false;
651   if (aColorType == GL_RENDERBUFFER)
652   {
653     theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
654     myGlColorRBufferId = aColorId;
655   }
656   else if (aColorType != GL_NONE)
657   {
658     TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
659     theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
660                            GL_DEBUG_TYPE_ERROR,
661                            0,
662                            GL_DEBUG_SEVERITY_HIGH,
663                            aMsg);
664   }
665
666   if (aDepthType == GL_RENDERBUFFER)
667   {
668     theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
669     myGlDepthRBufferId = aDepthId;
670   }
671   else if (aDepthType != GL_NONE)
672   {
673     TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
674     theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
675                            GL_DEBUG_TYPE_ERROR,
676                            0,
677                            GL_DEBUG_SEVERITY_HIGH,
678                            aMsg);
679   }
680
681   // retrieve dimensions
682   GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
683   if (aRBuffer != NO_RENDERBUFFER)
684   {
685     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
686     theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &myVPSizeX);
687     theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
688     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
689   }
690
691   return aRBuffer != NO_RENDERBUFFER;
692 }
693
694 // =======================================================================
695 // function : Release
696 // purpose  :
697 // =======================================================================
698 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
699 {
700   if (isValidFrameBuffer())
701   {
702     // application can not handle this case by exception - this is bug in code
703     Standard_ASSERT_RETURN (theGlCtx != NULL,
704       "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
705     if (theGlCtx->IsValid()
706      && myIsOwnBuffer)
707     {
708       theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
709       if (myGlColorRBufferId != NO_RENDERBUFFER)
710       {
711         theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
712       }
713       if (myGlDepthRBufferId != NO_RENDERBUFFER)
714       {
715         theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
716       }
717     }
718     myGlFBufferId      = NO_FRAMEBUFFER;
719     myGlColorRBufferId = NO_RENDERBUFFER;
720     myGlDepthRBufferId = NO_RENDERBUFFER;
721     myIsOwnBuffer      = false;
722   }
723
724   if (myIsOwnColor)
725   {
726     for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
727     {
728       myColorTextures (aColorBufferIdx)->Release (theGlCtx);
729     }
730     myIsOwnColor = false;
731   }
732
733   if (myIsOwnDepth)
734   {
735     myDepthStencilTexture->Release (theGlCtx);
736     myIsOwnDepth = false;
737   }
738
739   myVPSizeX = 0;
740   myVPSizeY = 0;
741 }
742
743 // =======================================================================
744 // function : SetupViewport
745 // purpose  :
746 // =======================================================================
747 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
748 {
749   const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
750   theGlCtx->ResizeViewport (aViewport);
751 }
752
753 // =======================================================================
754 // function : ChangeViewport
755 // purpose  :
756 // =======================================================================
757 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
758                                          const GLsizei theVPSizeY)
759 {
760   myVPSizeX = theVPSizeX;
761   myVPSizeY = theVPSizeY;
762 }
763
764 // =======================================================================
765 // function : BindBuffer
766 // purpose  :
767 // =======================================================================
768 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
769 {
770   theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
771   theGlCtx->SetFrameBufferSRGB (true);
772 }
773
774 // =======================================================================
775 // function : BindDrawBuffer
776 // purpose  :
777 // =======================================================================
778 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
779 {
780   theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
781   theGlCtx->SetFrameBufferSRGB (true);
782 }
783
784 // =======================================================================
785 // function : BindReadBuffer
786 // purpose  :
787 // =======================================================================
788 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
789 {
790   theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
791 }
792
793 // =======================================================================
794 // function : UnbindBuffer
795 // purpose  :
796 // =======================================================================
797 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
798 {
799   if (!theGlCtx->DefaultFrameBuffer().IsNull()
800    &&  theGlCtx->DefaultFrameBuffer().operator->() != this)
801   {
802     theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
803   }
804   else
805   {
806     theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
807     theGlCtx->SetFrameBufferSRGB (false);
808   }
809 }
810
811 // =======================================================================
812 // function : getAligned
813 // purpose  :
814 // =======================================================================
815 inline Standard_Size getAligned (const Standard_Size theNumber,
816                                  const Standard_Size theAlignment)
817 {
818   return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment;
819 }
820
821 template<typename T>
822 inline void convertRowFromRgba (T* theRgbRow,
823                                 const Image_ColorRGBA* theRgbaRow,
824                                 const Standard_Size theWidth)
825 {
826   for (Standard_Size aCol = 0; aCol < theWidth; ++aCol)
827   {
828     const Image_ColorRGBA& anRgba = theRgbaRow[aCol];
829     T& anRgb = theRgbRow[aCol];
830     anRgb.r() = anRgba.r();
831     anRgb.g() = anRgba.g();
832     anRgb.b() = anRgba.b();
833   }
834 }
835
836 // =======================================================================
837 // function : BufferDump
838 // purpose  :
839 // =======================================================================
840 Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& theGlCtx,
841                                                  const Handle(OpenGl_FrameBuffer)& theFbo,
842                                                  Image_PixMap& theImage,
843                                                  Graphic3d_BufferType theBufferType)
844 {
845   if (theGlCtx.IsNull()
846    || theImage.IsEmpty())
847   {
848     return Standard_False;
849   }
850
851   GLenum aFormat = 0;
852   GLenum aType   = 0;
853   bool toSwapRgbaBgra = false;
854   bool toConvRgba2Rgb = false;
855   switch (theImage.Format())
856   {
857   #if !defined(GL_ES_VERSION_2_0)
858     case Image_Format_Gray:
859       aFormat = theBufferType == Graphic3d_BT_Depth ? GL_DEPTH_COMPONENT : GL_RED;
860       aType   = GL_UNSIGNED_BYTE;
861       break;
862     case Image_Format_GrayF:
863       aFormat = theBufferType == Graphic3d_BT_Depth ? GL_DEPTH_COMPONENT : GL_RED;
864       aType   = GL_FLOAT;
865       break;
866     case Image_Format_RGF:
867       aFormat = GL_RG;
868       aType   = GL_FLOAT;
869       break;
870     case Image_Format_RGB:
871       aFormat = GL_RGB;
872       aType   = GL_UNSIGNED_BYTE;
873       break;
874     case Image_Format_BGR:
875       aFormat = GL_BGR;
876       aType   = GL_UNSIGNED_BYTE;
877       break;
878     case Image_Format_BGRA:
879     case Image_Format_BGR32:
880       aFormat = GL_BGRA;
881       aType   = GL_UNSIGNED_BYTE;
882       break;
883     case Image_Format_BGRF:
884       aFormat = GL_BGR;
885       aType   = GL_FLOAT;
886       break;
887     case Image_Format_BGRAF:
888       aFormat = GL_BGRA;
889       aType   = GL_FLOAT;
890       break;
891   #else
892     case Image_Format_Gray:
893     case Image_Format_GrayF:
894     case Image_Format_BGRF:
895     case Image_Format_BGRAF:
896     case Image_Format_RGF:
897       return Standard_False;
898     case Image_Format_BGRA:
899     case Image_Format_BGR32:
900       aFormat = GL_RGBA;
901       aType   = GL_UNSIGNED_BYTE;
902       toSwapRgbaBgra = true;
903       break;
904     case Image_Format_BGR:
905     case Image_Format_RGB:
906       aFormat = GL_RGBA;
907       aType   = GL_UNSIGNED_BYTE;
908       toConvRgba2Rgb = true;
909       break;
910   #endif
911     case Image_Format_RGBA:
912     case Image_Format_RGB32:
913       aFormat = GL_RGBA;
914       aType   = GL_UNSIGNED_BYTE;
915       break;
916     case Image_Format_RGBF:
917       aFormat = GL_RGB;
918       aType   = GL_FLOAT;
919       break;
920     case Image_Format_RGBAF:
921       aFormat = GL_RGBA;
922       aType   = GL_FLOAT;
923       break;
924     case Image_Format_RGBAF_half:
925       aFormat = GL_RGBA;
926       aType   = GL_HALF_FLOAT;
927       break;
928     case Image_Format_Alpha:
929     case Image_Format_AlphaF:
930       return Standard_False; // GL_ALPHA is no more supported in core context
931     case Image_Format_RGF_half:
932     case Image_Format_UNKNOWN:
933       return Standard_False;
934   }
935
936   if (aFormat == 0)
937   {
938     return Standard_False;
939   }
940
941 #if !defined(GL_ES_VERSION_2_0)
942   GLint aReadBufferPrev = GL_BACK;
943   if (theBufferType == Graphic3d_BT_Depth
944    && aFormat != GL_DEPTH_COMPONENT)
945   {
946     return Standard_False;
947   }
948 #else
949   (void )theBufferType;
950 #endif
951
952   // bind FBO if used
953   if (!theFbo.IsNull() && theFbo->IsValid())
954   {
955     theFbo->BindBuffer (theGlCtx);
956   }
957   else
958   {
959   #if !defined(GL_ES_VERSION_2_0)
960     theGlCtx->core11fwd->glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
961     GLint aDrawBufferPrev = GL_BACK;
962     theGlCtx->core11fwd->glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
963     glReadBuffer (aDrawBufferPrev);
964   #endif
965   }
966
967   // setup alignment
968   const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
969   theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
970   bool isBatchCopy = !theImage.IsTopDown();
971
972   const GLint   anExtraBytes       = GLint(theImage.RowExtraBytes());
973   GLint         aPixelsWidth       = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
974   Standard_Size aSizeRowBytesEstim = getAligned (theImage.SizePixelBytes() * aPixelsWidth, anAligment);
975   if (anExtraBytes < anAligment)
976   {
977     aPixelsWidth = 0;
978   }
979   else if (aSizeRowBytesEstim != theImage.SizeRowBytes())
980   {
981     aPixelsWidth = 0;
982     isBatchCopy  = false;
983   }
984   if (theGlCtx->hasPackRowLength)
985   {
986     theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
987   }
988   else if (aPixelsWidth != 0)
989   {
990     isBatchCopy = false;
991   }
992
993   if (toConvRgba2Rgb)
994   {
995     const Standard_Size aRowSize = theImage.SizeX() * 4;
996     NCollection_Buffer aRowBuffer (Image_PixMap::DefaultAllocator());
997     if (!aRowBuffer.Allocate (aRowSize))
998     {
999       return Standard_False;
1000     }
1001
1002     for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1003     {
1004       // Image_PixMap rows indexation always starts from the upper corner
1005       // while order in memory depends on the flag and processed by ChangeRow() method
1006       theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
1007       const Image_ColorRGBA* aRowDataRgba = (const Image_ColorRGBA* )aRowBuffer.Data();
1008       if (theImage.Format() == Image_Format_BGR)
1009       {
1010         convertRowFromRgba ((Image_ColorBGR* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1011       }
1012       else
1013       {
1014         convertRowFromRgba ((Image_ColorRGB* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1015       }
1016     }
1017   }
1018   else if (!isBatchCopy)
1019   {
1020     // copy row by row
1021     for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1022     {
1023       // Image_PixMap rows indexation always starts from the upper corner
1024       // while order in memory depends on the flag and processed by ChangeRow() method
1025       theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
1026     }
1027   }
1028   else
1029   {
1030     theGlCtx->core11fwd->glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
1031   }
1032   const bool hasErrors = theGlCtx->ResetErrors (true);
1033
1034   theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
1035   if (theGlCtx->hasPackRowLength)
1036   {
1037     theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
1038   }
1039
1040   if (!theFbo.IsNull() && theFbo->IsValid())
1041   {
1042     theFbo->UnbindBuffer (theGlCtx);
1043   }
1044   else
1045   {
1046   #if !defined(GL_ES_VERSION_2_0)
1047     glReadBuffer (aReadBufferPrev);
1048   #endif
1049   }
1050
1051   if (toSwapRgbaBgra)
1052   {
1053     Image_PixMap::SwapRgbaBgra (theImage);
1054   }
1055
1056   return !hasErrors;
1057 }
1058
1059 // =======================================================================
1060 // function : EstimatedDataSize
1061 // purpose  :
1062 // =======================================================================
1063 Standard_Size OpenGl_FrameBuffer::EstimatedDataSize() const
1064 {
1065   if (!IsValid())
1066   {
1067     return 0;
1068   }
1069
1070   Standard_Size aSize = 0;
1071   for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
1072   {
1073     aSize += aTextureIt.Value()->EstimatedDataSize();
1074   }
1075   if (!myDepthStencilTexture.IsNull())
1076   {
1077     aSize += myDepthStencilTexture->EstimatedDataSize();
1078   }
1079   if (myGlColorRBufferId != NO_RENDERBUFFER
1080   && !myColorFormats.IsEmpty())
1081   {
1082     aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myColorFormats.First()) * myInitVPSizeX * myInitVPSizeY;
1083   }
1084   if (myGlDepthRBufferId != NO_RENDERBUFFER)
1085   {
1086     aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myDepthFormat) * myInitVPSizeX * myInitVPSizeY;
1087   }
1088   return aSize;
1089 }