1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2011-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <OpenGl_FrameBuffer.hxx>
17 #include <OpenGl_ArbFBO.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_Texture.hxx>
21 #include <Standard_Assert.hxx>
22 #include <TCollection_ExtendedString.hxx>
24 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
28 //! Checks whether two format arrays are equal or not.
29 static bool operator== (const OpenGl_ColorFormats& theFmt1,
30 const OpenGl_ColorFormats& theFmt2)
32 if (theFmt1.Length() != theFmt2.Length())
34 OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
35 OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
36 for (; anIt1.More(); anIt1.Next(), anIt2.Next())
38 if (anIt1.Value() != anIt2.Value())
44 //! Return TRUE if GL_DEPTH_STENCIL_ATTACHMENT can be used.
45 static bool hasDepthStencilAttach (const Handle(OpenGl_Context)& theCtx)
48 // supported since WebGL 2.0,
49 // while WebGL 1.0 + GL_WEBGL_depth_texture needs GL_DEPTH_STENCIL_ATTACHMENT
50 // and NOT separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls which is different to OpenGL ES 2.0 + extension
51 return theCtx->IsGlGreaterEqual (3, 0) || theCtx->extPDS;
52 #elif defined(GL_ES_VERSION_2_0)
53 // supported since OpenGL ES 3.0,
54 // while OpenGL ES 2.0 + GL_EXT_packed_depth_stencil needs separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls
55 return theCtx->IsGlGreaterEqual (3, 0);
57 // available on desktop since OpenGL 3.0
58 // or OpenGL 2.0 + GL_ARB_framebuffer_object (GL_EXT_framebuffer_object is unsupported by OCCT)
65 // =======================================================================
66 // function : OpenGl_FrameBuffer
68 // =======================================================================
69 OpenGl_FrameBuffer::OpenGl_FrameBuffer()
75 myDepthFormat (GL_DEPTH24_STENCIL8),
76 myGlFBufferId (NO_FRAMEBUFFER),
77 myGlColorRBufferId (NO_RENDERBUFFER),
78 myGlDepthRBufferId (NO_RENDERBUFFER),
79 myIsOwnBuffer (false),
82 myDepthStencilTexture (new OpenGl_Texture())
84 myColorFormats.Append (GL_RGBA8);
85 myColorTextures.Append (new OpenGl_Texture());
88 // =======================================================================
89 // function : ~OpenGl_FrameBuffer
91 // =======================================================================
92 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
97 // =======================================================================
98 // function : GetSizeX
100 // =======================================================================
101 Standard_Integer OpenGl_FrameBuffer::GetSizeX() const
103 return !myColorTextures.IsEmpty() ? myColorTextures.First()->SizeX() : 0;
106 // =======================================================================
107 // function : GetSizeY
109 // =======================================================================
110 Standard_Integer OpenGl_FrameBuffer::GetSizeY() const
112 return !myColorTextures.IsEmpty() ? myColorTextures.First()->SizeY() : 0;
115 // =======================================================================
116 // function : InitWrapper
118 // =======================================================================
119 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlContext,
120 const NCollection_Sequence<Handle(OpenGl_Texture)>& theColorTextures,
121 const Handle(OpenGl_Texture)& theDepthTexture)
123 Release (theGlContext.get());
124 if (theGlContext->arbFBO == NULL)
129 myColorFormats.Clear();
130 myColorTextures.Clear();
131 for (NCollection_Sequence<Handle(OpenGl_Texture)>::Iterator aColorIter (theColorTextures); aColorIter.More(); aColorIter.Next())
133 myColorTextures.Append (aColorIter.Value());
136 myDepthStencilTexture = theDepthTexture;
137 myNbSamples = theColorTextures.First()->NbSamples();
139 myIsOwnColor = false;
140 myIsOwnDepth = false;
141 myIsOwnBuffer = true;
143 myVPSizeX = theColorTextures.First()->SizeX();
144 myVPSizeY = theColorTextures.First()->SizeY();
146 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
147 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
148 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
150 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
151 if (aColorTexture->IsValid())
153 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
154 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
157 if (!myDepthStencilTexture.IsNull()
158 && myDepthStencilTexture->IsValid())
160 if (hasDepthStencilAttach (theGlContext))
162 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
163 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
167 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
168 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
169 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
170 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
173 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
175 Release (theGlContext.get());
179 UnbindBuffer (theGlContext);
183 // =======================================================================
186 // =======================================================================
187 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
188 const Graphic3d_Vec2i& theSize,
189 const Standard_Integer theColorFormat,
190 const Standard_Integer theDepthFormat,
191 const Standard_Integer theNbSamples)
193 OpenGl_ColorFormats aColorFormats;
194 if (theColorFormat != 0)
196 aColorFormats.Append (theColorFormat);
198 return Init (theGlContext, theSize, aColorFormats, theDepthFormat, theNbSamples);
201 // =======================================================================
204 // =======================================================================
205 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
206 const Graphic3d_Vec2i& theSize,
207 const OpenGl_ColorFormats& theColorFormats,
208 const Handle(OpenGl_Texture)& theDepthStencilTexture,
209 const Standard_Integer theNbSamples)
211 myColorFormats = theColorFormats;
213 OpenGl_TextureArray aTextures (myColorTextures);
214 if (!myColorTextures.IsEmpty())
216 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
218 aTextureIt.Value()->Release (theGlContext.operator->());
220 myColorTextures.Clear();
222 for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
224 myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
227 myDepthFormat = theDepthStencilTexture->GetFormat();
228 myNbSamples = theNbSamples;
229 if (theGlContext->arbFBO == NULL)
231 return Standard_False;
234 // clean up previous state
235 Release (theGlContext.operator->());
236 if (myColorFormats.IsEmpty()
237 && myDepthFormat == 0)
239 return Standard_False;
242 myDepthStencilTexture = theDepthStencilTexture;
244 myIsOwnDepth = false;
245 myIsOwnBuffer = true;
247 // setup viewport sizes as is
248 myVPSizeX = theSize.x();
249 myVPSizeY = theSize.y();
250 const Standard_Integer aSizeX = theSize.x() > 0 ? theSize.x() : 2;
251 const Standard_Integer aSizeY = theSize.y() > 0 ? theSize.y() : 2;
253 // Create the textures (will be used as color buffer and depth-stencil buffer)
254 if (theNbSamples != 0)
256 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
258 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
259 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
260 if (aColorFormat == 0
261 || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
262 aColorFormat, aSizeX, aSizeY))
264 Release (theGlContext.get());
265 return Standard_False;
271 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
273 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
274 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
275 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat);
276 if (!aFormat.IsValid()
277 || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
279 Release (theGlContext.get());
280 return Standard_False;
285 // Build FBO and setup it as texture
286 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
287 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
289 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
291 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
292 if (aColorTexture->IsValid())
294 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
295 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
298 if (myDepthStencilTexture->IsValid())
300 if (hasDepthStencilAttach (theGlContext))
302 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
303 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
307 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
308 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
309 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
310 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
313 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
315 Release (theGlContext.operator->());
316 return Standard_False;
319 UnbindBuffer (theGlContext);
320 return Standard_True;
323 // =======================================================================
326 // =======================================================================
327 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
328 const Graphic3d_Vec2i& theSize,
329 const OpenGl_ColorFormats& theColorFormats,
330 const Standard_Integer theDepthFormat,
331 const Standard_Integer theNbSamples)
333 myColorFormats = theColorFormats;
335 OpenGl_TextureArray aTextures (myColorTextures);
336 if (!myColorTextures.IsEmpty())
338 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
340 aTextureIt.Value()->Release (theGlContext.operator->());
342 myColorTextures.Clear();
344 for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
346 myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
349 myDepthFormat = theDepthFormat;
350 myNbSamples = theNbSamples;
351 myInitVPSizeX = theSize.x();
352 myInitVPSizeY = theSize.y();
353 if (theGlContext->arbFBO == NULL)
355 return Standard_False;
358 // clean up previous state
359 Release (theGlContext.operator->());
360 if (myColorFormats.IsEmpty()
361 && myDepthFormat == 0)
363 return Standard_False;
367 myIsOwnBuffer = true;
370 // setup viewport sizes as is
371 myVPSizeX = theSize.x();
372 myVPSizeY = theSize.y();
373 const Standard_Integer aSizeX = theSize.x() > 0 ? theSize.x() : 2;
374 const Standard_Integer aSizeY = theSize.y() > 0 ? theSize.y() : 2;
375 bool hasStencilRB = false;
377 // Create the textures (will be used as color buffer and depth-stencil buffer)
378 if (theNbSamples != 0)
380 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
382 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
383 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
384 if (aColorFormat == 0
385 || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
387 Release (theGlContext.operator->());
388 return Standard_False;
391 if (myDepthFormat != 0
392 && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
394 Release (theGlContext.operator->());
395 return Standard_False;
400 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
402 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
403 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
404 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat);
405 if (!aFormat.IsValid()
406 || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
408 Release (theGlContext.operator->());
409 return Standard_False;
413 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
414 // instead of just trying to create such texture
415 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, myDepthFormat);
416 if (aDepthFormat.IsValid()
417 && !myDepthStencilTexture->Init (theGlContext, aDepthFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
419 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
420 "Warning! Depth textures are not supported by hardware!");
422 hasStencilRB = aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL
423 && theGlContext->extPDS;
424 GLint aDepthStencilFormat = hasStencilRB
425 ? GL_DEPTH24_STENCIL8
426 : GL_DEPTH_COMPONENT16;
428 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
429 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
430 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
431 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
435 // Build FBO and setup it as texture
436 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
437 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
438 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
440 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
441 if (aColorTexture->IsValid())
443 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
444 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
448 if (myDepthStencilTexture->IsValid())
450 if (hasDepthStencilAttach (theGlContext))
452 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
453 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
457 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
458 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
459 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
460 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
463 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
465 if (hasDepthStencilAttach (theGlContext) && hasStencilRB)
467 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
468 GL_RENDERBUFFER, myGlDepthRBufferId);
472 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
473 GL_RENDERBUFFER, myGlDepthRBufferId);
476 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
477 GL_RENDERBUFFER, myGlDepthRBufferId);
481 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
483 Release (theGlContext.operator->());
484 return Standard_False;
487 UnbindBuffer (theGlContext);
488 return Standard_True;
491 // =======================================================================
492 // function : InitLazy
494 // =======================================================================
495 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
496 const Graphic3d_Vec2i& theViewportSize,
497 const Standard_Integer theColorFormat,
498 const Standard_Integer theDepthFormat,
499 const Standard_Integer theNbSamples)
501 OpenGl_ColorFormats aColorFormats;
502 aColorFormats.Append (theColorFormat);
503 return InitLazy (theGlContext, theViewportSize, aColorFormats, theDepthFormat, theNbSamples);
506 // =======================================================================
507 // function : InitLazy
509 // =======================================================================
510 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
511 const Graphic3d_Vec2i& theViewportSize,
512 const OpenGl_ColorFormats& theColorFormats,
513 const Standard_Integer theDepthFormat,
514 const Standard_Integer theNbSamples)
516 if (myVPSizeX == theViewportSize.x()
517 && myVPSizeY == theViewportSize.y()
518 && myColorFormats == theColorFormats
519 && myDepthFormat == theDepthFormat
520 && myNbSamples == theNbSamples)
525 return Init (theGlContext, theViewportSize, theColorFormats, theDepthFormat, theNbSamples);
528 // =======================================================================
529 // function : InitWithRB
531 // =======================================================================
532 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
533 const Graphic3d_Vec2i& theSize,
534 const Standard_Integer theColorFormat,
535 const Standard_Integer theDepthFormat,
536 const unsigned int theColorRBufferFromWindow)
538 myColorFormats.Clear();
539 myColorFormats.Append (theColorFormat);
540 if (!myColorTextures.IsEmpty())
542 Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
543 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
545 aTextureIt.Value()->Release (theGlCtx.operator->());
547 myColorTextures.Clear();
548 myColorTextures.Append (aTexutre);
551 myDepthFormat = theDepthFormat;
553 myInitVPSizeX = theSize.x();
554 myInitVPSizeY = theSize.y();
555 if (theGlCtx->arbFBO == NULL)
557 return Standard_False;
560 // clean up previous state
561 Release (theGlCtx.operator->());
564 myIsOwnBuffer = true;
567 // setup viewport sizes as is
568 myVPSizeX = theSize.x();
569 myVPSizeY = theSize.y();
570 const Standard_Integer aSizeX = theSize.x() > 0 ? theSize.x() : 2;
571 const Standard_Integer aSizeY = theSize.y() > 0 ? theSize.y() : 2;
573 // Create the render-buffers
574 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
576 myGlColorRBufferId = theColorRBufferFromWindow;
578 else if (theColorFormat != 0)
580 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
581 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
582 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
585 bool hasStencilRB = false;
586 if (myDepthFormat != 0)
588 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theGlCtx, myDepthFormat);
589 hasStencilRB = aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL;
591 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
592 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
593 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
594 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
598 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
599 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
600 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
601 GL_RENDERBUFFER, myGlColorRBufferId);
602 if (myGlDepthRBufferId != NO_RENDERBUFFER)
604 if (hasDepthStencilAttach (theGlCtx) && hasStencilRB)
606 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
607 GL_RENDERBUFFER, myGlDepthRBufferId);
611 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
612 GL_RENDERBUFFER, myGlDepthRBufferId);
615 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
616 GL_RENDERBUFFER, myGlDepthRBufferId);
620 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
622 UnbindBuffer (theGlCtx);
623 Release (theGlCtx.operator->());
624 return Standard_False;
627 UnbindBuffer (theGlCtx);
628 return Standard_True;
631 // =======================================================================
632 // function : InitWrapper
634 // =======================================================================
635 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
638 if (theGlCtx->arbFBO == NULL)
640 return Standard_False;
643 // clean up previous state
644 Release (theGlCtx.operator->());
646 GLint anFbo = GLint(NO_FRAMEBUFFER);
647 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
648 if (anFbo == GLint(NO_FRAMEBUFFER))
650 return Standard_False;
653 GLint aColorType = 0;
655 GLint aDepthType = 0;
657 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
658 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
660 myGlFBufferId = GLuint(anFbo);
661 myIsOwnColor = false;
662 myIsOwnBuffer = false;
663 myIsOwnDepth = false;
664 if (aColorType == GL_RENDERBUFFER)
666 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
667 myGlColorRBufferId = aColorId;
669 else if (aColorType != GL_NONE)
671 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
672 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
675 GL_DEBUG_SEVERITY_HIGH,
679 if (aDepthType == GL_RENDERBUFFER)
681 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
682 myGlDepthRBufferId = aDepthId;
684 else if (aDepthType != GL_NONE)
686 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
687 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
690 GL_DEBUG_SEVERITY_HIGH,
694 // retrieve dimensions
695 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
696 if (aRBuffer != NO_RENDERBUFFER)
698 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
699 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
700 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
701 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
704 return aRBuffer != NO_RENDERBUFFER;
707 // =======================================================================
708 // function : Release
710 // =======================================================================
711 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
713 if (isValidFrameBuffer())
715 // application can not handle this case by exception - this is bug in code
716 Standard_ASSERT_RETURN (theGlCtx != NULL,
717 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
718 if (theGlCtx->IsValid()
721 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
722 if (myGlColorRBufferId != NO_RENDERBUFFER)
724 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
726 if (myGlDepthRBufferId != NO_RENDERBUFFER)
728 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
731 myGlFBufferId = NO_FRAMEBUFFER;
732 myGlColorRBufferId = NO_RENDERBUFFER;
733 myGlDepthRBufferId = NO_RENDERBUFFER;
734 myIsOwnBuffer = false;
739 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
741 myColorTextures (aColorBufferIdx)->Release (theGlCtx);
743 myIsOwnColor = false;
748 myDepthStencilTexture->Release (theGlCtx);
749 myIsOwnDepth = false;
756 // =======================================================================
757 // function : SetupViewport
759 // =======================================================================
760 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
762 const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
763 theGlCtx->ResizeViewport (aViewport);
766 // =======================================================================
767 // function : ChangeViewport
769 // =======================================================================
770 void OpenGl_FrameBuffer::ChangeViewport (const Standard_Integer theVPSizeX,
771 const Standard_Integer theVPSizeY)
773 myVPSizeX = theVPSizeX;
774 myVPSizeY = theVPSizeY;
777 // =======================================================================
778 // function : BindBuffer
780 // =======================================================================
781 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
783 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
784 theGlCtx->SetFrameBufferSRGB (true);
787 // =======================================================================
788 // function : BindDrawBuffer
790 // =======================================================================
791 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
793 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
794 theGlCtx->SetFrameBufferSRGB (true);
797 // =======================================================================
798 // function : BindReadBuffer
800 // =======================================================================
801 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
803 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
806 // =======================================================================
807 // function : UnbindBuffer
809 // =======================================================================
810 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
812 if (!theGlCtx->DefaultFrameBuffer().IsNull()
813 && theGlCtx->DefaultFrameBuffer().operator->() != this)
815 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
819 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
820 theGlCtx->SetFrameBufferSRGB (false);
824 // =======================================================================
825 // function : getAligned
827 // =======================================================================
828 inline Standard_Size getAligned (const Standard_Size theNumber,
829 const Standard_Size theAlignment)
831 return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment;
835 inline void convertRowFromRgba (T* theRgbRow,
836 const Image_ColorRGBA* theRgbaRow,
837 const Standard_Size theWidth)
839 for (Standard_Size aCol = 0; aCol < theWidth; ++aCol)
841 const Image_ColorRGBA& anRgba = theRgbaRow[aCol];
842 T& anRgb = theRgbRow[aCol];
843 anRgb.r() = anRgba.r();
844 anRgb.g() = anRgba.g();
845 anRgb.b() = anRgba.b();
849 // =======================================================================
850 // function : BufferDump
852 // =======================================================================
853 Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& theGlCtx,
854 const Handle(OpenGl_FrameBuffer)& theFbo,
855 Image_PixMap& theImage,
856 Graphic3d_BufferType theBufferType)
858 if (theGlCtx.IsNull()
859 || theImage.IsEmpty())
861 return Standard_False;
866 bool toSwapRgbaBgra = false;
867 bool toConvRgba2Rgb = false;
868 switch (theImage.Format())
870 #if !defined(GL_ES_VERSION_2_0)
871 case Image_Format_Gray:
872 aFormat = theBufferType == Graphic3d_BT_Depth ? GL_DEPTH_COMPONENT : GL_RED;
873 aType = GL_UNSIGNED_BYTE;
875 case Image_Format_GrayF:
876 aFormat = theBufferType == Graphic3d_BT_Depth ? GL_DEPTH_COMPONENT : GL_RED;
879 case Image_Format_RGF:
883 case Image_Format_RGB:
885 aType = GL_UNSIGNED_BYTE;
887 case Image_Format_BGR:
889 aType = GL_UNSIGNED_BYTE;
891 case Image_Format_BGRA:
892 case Image_Format_BGR32:
894 aType = GL_UNSIGNED_BYTE;
896 case Image_Format_BGRF:
900 case Image_Format_BGRAF:
905 case Image_Format_Gray:
906 case Image_Format_GrayF:
907 case Image_Format_BGRF:
908 case Image_Format_BGRAF:
909 case Image_Format_RGF:
910 return Standard_False;
911 case Image_Format_BGRA:
912 case Image_Format_BGR32:
914 aType = GL_UNSIGNED_BYTE;
915 toSwapRgbaBgra = true;
917 case Image_Format_BGR:
918 case Image_Format_RGB:
920 aType = GL_UNSIGNED_BYTE;
921 toConvRgba2Rgb = true;
924 case Image_Format_RGBA:
925 case Image_Format_RGB32:
927 aType = GL_UNSIGNED_BYTE;
929 case Image_Format_RGBF:
933 case Image_Format_RGBAF:
937 case Image_Format_RGBAF_half:
939 aType = GL_HALF_FLOAT;
941 case Image_Format_Alpha:
942 case Image_Format_AlphaF:
943 return Standard_False; // GL_ALPHA is no more supported in core context
944 case Image_Format_RGF_half:
945 case Image_Format_UNKNOWN:
946 return Standard_False;
951 return Standard_False;
954 #if !defined(GL_ES_VERSION_2_0)
955 GLint aReadBufferPrev = GL_BACK;
956 if (theBufferType == Graphic3d_BT_Depth
957 && aFormat != GL_DEPTH_COMPONENT)
959 return Standard_False;
962 (void )theBufferType;
966 if (!theFbo.IsNull() && theFbo->IsValid())
968 theFbo->BindBuffer (theGlCtx);
972 #if !defined(GL_ES_VERSION_2_0)
973 theGlCtx->core11fwd->glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
974 GLint aDrawBufferPrev = GL_BACK;
975 theGlCtx->core11fwd->glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
976 glReadBuffer (aDrawBufferPrev);
981 const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
982 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
983 bool isBatchCopy = !theImage.IsTopDown();
985 const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
986 GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
987 Standard_Size aSizeRowBytesEstim = getAligned (theImage.SizePixelBytes() * aPixelsWidth, anAligment);
988 if (anExtraBytes < anAligment)
992 else if (aSizeRowBytesEstim != theImage.SizeRowBytes())
997 if (theGlCtx->hasPackRowLength)
999 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
1001 else if (aPixelsWidth != 0)
1003 isBatchCopy = false;
1008 const Standard_Size aRowSize = theImage.SizeX() * 4;
1009 NCollection_Buffer aRowBuffer (Image_PixMap::DefaultAllocator());
1010 if (!aRowBuffer.Allocate (aRowSize))
1012 return Standard_False;
1015 for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1017 // Image_PixMap rows indexation always starts from the upper corner
1018 // while order in memory depends on the flag and processed by ChangeRow() method
1019 theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
1020 const Image_ColorRGBA* aRowDataRgba = (const Image_ColorRGBA* )aRowBuffer.Data();
1021 if (theImage.Format() == Image_Format_BGR)
1023 convertRowFromRgba ((Image_ColorBGR* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1027 convertRowFromRgba ((Image_ColorRGB* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1031 else if (!isBatchCopy)
1034 for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1036 // Image_PixMap rows indexation always starts from the upper corner
1037 // while order in memory depends on the flag and processed by ChangeRow() method
1038 theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
1043 theGlCtx->core11fwd->glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
1045 const bool hasErrors = theGlCtx->ResetErrors (true);
1047 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
1048 if (theGlCtx->hasPackRowLength)
1050 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
1053 if (!theFbo.IsNull() && theFbo->IsValid())
1055 theFbo->UnbindBuffer (theGlCtx);
1059 #if !defined(GL_ES_VERSION_2_0)
1060 glReadBuffer (aReadBufferPrev);
1066 Image_PixMap::SwapRgbaBgra (theImage);
1072 // =======================================================================
1073 // function : EstimatedDataSize
1075 // =======================================================================
1076 Standard_Size OpenGl_FrameBuffer::EstimatedDataSize() const
1083 Standard_Size aSize = 0;
1084 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
1086 aSize += aTextureIt.Value()->EstimatedDataSize();
1088 if (!myDepthStencilTexture.IsNull())
1090 aSize += myDepthStencilTexture->EstimatedDataSize();
1092 if (myGlColorRBufferId != NO_RENDERBUFFER
1093 && !myColorFormats.IsEmpty())
1095 aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myColorFormats.First()) * myInitVPSizeX * myInitVPSizeY;
1097 if (myGlDepthRBufferId != NO_RENDERBUFFER)
1099 aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myDepthFormat) * myInitVPSizeX * myInitVPSizeY;