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