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