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