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>
16 #include <OpenGl_ArbFBO.hxx>
18 #include <Standard_Assert.hxx>
19 #include <TCollection_ExtendedString.hxx>
21 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
25 //! Checks whether two format arrays are equal or not.
26 static bool operator== (const OpenGl_ColorFormats& theFmt1,
27 const OpenGl_ColorFormats& theFmt2)
29 if (theFmt1.Length() != theFmt2.Length())
31 OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
32 OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
33 for (; anIt1.More(); anIt1.Next(), anIt2.Next())
35 if (anIt1.Value() != anIt2.Value())
41 //! Return TRUE if GL_DEPTH_STENCIL_ATTACHMENT can be used.
42 static bool hasDepthStencilAttach (const Handle(OpenGl_Context)& theCtx)
45 // supported since WebGL 2.0,
46 // while WebGL 1.0 + GL_WEBGL_depth_texture needs GL_DEPTH_STENCIL_ATTACHMENT
47 // and NOT separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls which is different to OpenGL ES 2.0 + extension
48 return theCtx->IsGlGreaterEqual (3, 0) || theCtx->extPDS;
49 #elif defined(GL_ES_VERSION_2_0)
50 // supported since OpenGL ES 3.0,
51 // while OpenGL ES 2.0 + GL_EXT_packed_depth_stencil needs separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls
52 return theCtx->IsGlGreaterEqual (3, 0);
54 // available on desktop since OpenGL 3.0
55 // or OpenGL 2.0 + GL_ARB_framebuffer_object (GL_EXT_framebuffer_object is unsupported by OCCT)
62 // =======================================================================
63 // function : OpenGl_FrameBuffer
65 // =======================================================================
66 OpenGl_FrameBuffer::OpenGl_FrameBuffer()
72 myDepthFormat (GL_DEPTH24_STENCIL8),
73 myGlFBufferId (NO_FRAMEBUFFER),
74 myGlColorRBufferId (NO_RENDERBUFFER),
75 myGlDepthRBufferId (NO_RENDERBUFFER),
76 myIsOwnBuffer (false),
79 myDepthStencilTexture (new OpenGl_Texture())
81 myColorFormats.Append (GL_RGBA8);
82 myColorTextures.Append (new OpenGl_Texture());
85 // =======================================================================
86 // function : ~OpenGl_FrameBuffer
88 // =======================================================================
89 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
94 // =======================================================================
95 // function : InitWrapper
97 // =======================================================================
98 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlContext,
99 const NCollection_Sequence<Handle(OpenGl_Texture)>& theColorTextures,
100 const Handle(OpenGl_Texture)& theDepthTexture)
102 Release (theGlContext.get());
103 if (theGlContext->arbFBO == NULL)
108 myColorFormats.Clear();
109 myColorTextures.Clear();
110 for (NCollection_Sequence<Handle(OpenGl_Texture)>::Iterator aColorIter (theColorTextures); aColorIter.More(); aColorIter.Next())
112 myColorTextures.Append (aColorIter.Value());
115 myDepthStencilTexture = theDepthTexture;
116 myNbSamples = theColorTextures.First()->NbSamples();
118 myIsOwnColor = false;
119 myIsOwnDepth = false;
120 myIsOwnBuffer = true;
122 myVPSizeX = theColorTextures.First()->SizeX();
123 myVPSizeY = theColorTextures.First()->SizeY();
125 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
126 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
127 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
129 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
130 if (aColorTexture->IsValid())
132 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
133 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
136 if (!myDepthStencilTexture.IsNull()
137 && myDepthStencilTexture->IsValid())
139 if (hasDepthStencilAttach (theGlContext))
141 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
142 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
146 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
147 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
148 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
149 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
152 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
154 Release (theGlContext.get());
158 UnbindBuffer (theGlContext);
162 // =======================================================================
165 // =======================================================================
166 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
167 const GLsizei theSizeX,
168 const GLsizei theSizeY,
169 const GLint theColorFormat,
170 const GLint theDepthFormat,
171 const GLsizei theNbSamples)
173 OpenGl_ColorFormats aColorFormats;
174 if (theColorFormat != 0)
176 aColorFormats.Append (theColorFormat);
178 return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples);
181 // =======================================================================
184 // =======================================================================
185 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
186 const GLsizei theSizeX,
187 const GLsizei theSizeY,
188 const OpenGl_ColorFormats& theColorFormats,
189 const Handle(OpenGl_Texture)& theDepthStencilTexture,
190 const GLsizei theNbSamples)
192 myColorFormats = theColorFormats;
194 OpenGl_TextureArray aTextures (myColorTextures);
195 if (!myColorTextures.IsEmpty())
197 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
199 aTextureIt.Value()->Release (theGlContext.operator->());
201 myColorTextures.Clear();
203 for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
205 myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
208 myDepthFormat = theDepthStencilTexture->GetFormat();
209 myNbSamples = theNbSamples;
210 if (theGlContext->arbFBO == NULL)
212 return Standard_False;
215 // clean up previous state
216 Release (theGlContext.operator->());
217 if (myColorFormats.IsEmpty()
218 && myDepthFormat == 0)
220 return Standard_False;
223 myDepthStencilTexture = theDepthStencilTexture;
225 myIsOwnDepth = false;
226 myIsOwnBuffer = true;
228 // setup viewport sizes as is
229 myVPSizeX = theSizeX;
230 myVPSizeY = theSizeY;
231 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
232 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
234 // Create the textures (will be used as color buffer and depth-stencil buffer)
235 if (theNbSamples != 0)
237 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
239 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
240 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
241 if (aColorFormat == 0
242 || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
243 aColorFormat, aSizeX, aSizeY))
245 Release (theGlContext.get());
246 return Standard_False;
252 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
254 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
255 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
256 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat);
257 if (!aFormat.IsValid()
258 || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
260 Release (theGlContext.get());
261 return Standard_False;
266 // Build FBO and setup it as texture
267 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
268 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
270 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
272 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
273 if (aColorTexture->IsValid())
275 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
276 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
279 if (myDepthStencilTexture->IsValid())
281 if (hasDepthStencilAttach (theGlContext))
283 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
284 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
288 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
289 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
290 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
291 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
294 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
296 Release (theGlContext.operator->());
297 return Standard_False;
300 UnbindBuffer (theGlContext);
301 return Standard_True;
304 // =======================================================================
307 // =======================================================================
308 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
309 const GLsizei theSizeX,
310 const GLsizei theSizeY,
311 const OpenGl_ColorFormats& theColorFormats,
312 const GLint theDepthFormat,
313 const GLsizei theNbSamples)
315 myColorFormats = theColorFormats;
317 OpenGl_TextureArray aTextures (myColorTextures);
318 if (!myColorTextures.IsEmpty())
320 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
322 aTextureIt.Value()->Release (theGlContext.operator->());
324 myColorTextures.Clear();
326 for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
328 myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
331 myDepthFormat = theDepthFormat;
332 myNbSamples = theNbSamples;
333 myInitVPSizeX = theSizeX;
334 myInitVPSizeY = theSizeY;
335 if (theGlContext->arbFBO == NULL)
337 return Standard_False;
340 // clean up previous state
341 Release (theGlContext.operator->());
342 if (myColorFormats.IsEmpty()
343 && myDepthFormat == 0)
345 return Standard_False;
349 myIsOwnBuffer = true;
352 // setup viewport sizes as is
353 myVPSizeX = theSizeX;
354 myVPSizeY = theSizeY;
355 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
356 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
357 bool hasStencilRB = false;
359 // Create the textures (will be used as color buffer and depth-stencil buffer)
360 if (theNbSamples != 0)
362 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
364 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
365 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
366 if (aColorFormat == 0
367 || !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
369 Release (theGlContext.operator->());
370 return Standard_False;
373 if (myDepthFormat != 0
374 && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
376 Release (theGlContext.operator->());
377 return Standard_False;
382 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
384 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
385 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
386 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, aColorFormat);
387 if (!aFormat.IsValid()
388 || !aColorTexture->Init (theGlContext, aFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
390 Release (theGlContext.operator->());
391 return Standard_False;
395 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
396 // instead of just trying to create such texture
397 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theGlContext, myDepthFormat);
398 if (aDepthFormat.IsValid()
399 && !myDepthStencilTexture->Init (theGlContext, aDepthFormat, Graphic3d_Vec2i (aSizeX, aSizeY), Graphic3d_TOT_2D))
401 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
402 "Warning! Depth textures are not supported by hardware!");
404 hasStencilRB = aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL
405 && theGlContext->extPDS;
406 GLint aDepthStencilFormat = hasStencilRB
407 ? GL_DEPTH24_STENCIL8
408 : GL_DEPTH_COMPONENT16;
410 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
411 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
412 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
413 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
417 // Build FBO and setup it as texture
418 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
419 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
420 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
422 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
423 if (aColorTexture->IsValid())
425 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
426 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
430 if (myDepthStencilTexture->IsValid())
432 if (hasDepthStencilAttach (theGlContext))
434 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
435 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
439 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
440 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
441 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
442 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
445 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
447 if (hasDepthStencilAttach (theGlContext) && hasStencilRB)
449 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
450 GL_RENDERBUFFER, myGlDepthRBufferId);
454 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
455 GL_RENDERBUFFER, myGlDepthRBufferId);
458 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
459 GL_RENDERBUFFER, myGlDepthRBufferId);
463 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
465 Release (theGlContext.operator->());
466 return Standard_False;
469 UnbindBuffer (theGlContext);
470 return Standard_True;
473 // =======================================================================
474 // function : InitLazy
476 // =======================================================================
477 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
478 const GLsizei theViewportSizeX,
479 const GLsizei theViewportSizeY,
480 const GLint theColorFormat,
481 const GLint theDepthFormat,
482 const GLsizei theNbSamples)
484 OpenGl_ColorFormats aColorFormats;
486 aColorFormats.Append (theColorFormat);
488 return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples);
491 // =======================================================================
492 // function : InitLazy
494 // =======================================================================
495 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
496 const GLsizei theViewportSizeX,
497 const GLsizei theViewportSizeY,
498 const OpenGl_ColorFormats& theColorFormats,
499 const GLint theDepthFormat,
500 const GLsizei theNbSamples)
502 if (myVPSizeX == theViewportSizeX
503 && myVPSizeY == theViewportSizeY
504 && myColorFormats == theColorFormats
505 && myDepthFormat == theDepthFormat
506 && myNbSamples == theNbSamples)
511 return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples);
514 // =======================================================================
515 // function : InitWithRB
517 // =======================================================================
518 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
519 const GLsizei theSizeX,
520 const GLsizei theSizeY,
521 const GLint theColorFormat,
522 const GLint theDepthFormat,
523 const GLuint theColorRBufferFromWindow)
525 myColorFormats.Clear();
526 myColorFormats.Append (theColorFormat);
527 if (!myColorTextures.IsEmpty())
529 Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
530 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
532 aTextureIt.Value()->Release (theGlCtx.operator->());
534 myColorTextures.Clear();
535 myColorTextures.Append (aTexutre);
538 myDepthFormat = theDepthFormat;
540 myInitVPSizeX = theSizeX;
541 myInitVPSizeY = theSizeY;
542 if (theGlCtx->arbFBO == NULL)
544 return Standard_False;
547 // clean up previous state
548 Release (theGlCtx.operator->());
551 myIsOwnBuffer = true;
554 // setup viewport sizes as is
555 myVPSizeX = theSizeX;
556 myVPSizeY = theSizeY;
557 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
558 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
560 // Create the render-buffers
561 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
563 myGlColorRBufferId = theColorRBufferFromWindow;
565 else if (theColorFormat != 0)
567 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
568 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
569 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
572 bool hasStencilRB = false;
573 if (myDepthFormat != 0)
575 const OpenGl_TextureFormat aDepthFormat = OpenGl_TextureFormat::FindSizedFormat (theGlCtx, myDepthFormat);
576 hasStencilRB = aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL;
578 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
579 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
580 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
581 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
585 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
586 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
587 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
588 GL_RENDERBUFFER, myGlColorRBufferId);
589 if (myGlDepthRBufferId != NO_RENDERBUFFER)
591 if (hasDepthStencilAttach (theGlCtx) && hasStencilRB)
593 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
594 GL_RENDERBUFFER, myGlDepthRBufferId);
598 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
599 GL_RENDERBUFFER, myGlDepthRBufferId);
602 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
603 GL_RENDERBUFFER, myGlDepthRBufferId);
607 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
609 UnbindBuffer (theGlCtx);
610 Release (theGlCtx.operator->());
611 return Standard_False;
614 UnbindBuffer (theGlCtx);
615 return Standard_True;
618 // =======================================================================
619 // function : InitWrapper
621 // =======================================================================
622 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
625 if (theGlCtx->arbFBO == NULL)
627 return Standard_False;
630 // clean up previous state
631 Release (theGlCtx.operator->());
633 GLint anFbo = GLint(NO_FRAMEBUFFER);
634 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
635 if (anFbo == GLint(NO_FRAMEBUFFER))
637 return Standard_False;
640 GLint aColorType = 0;
642 GLint aDepthType = 0;
644 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
645 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
647 myGlFBufferId = GLuint(anFbo);
648 myIsOwnColor = false;
649 myIsOwnBuffer = false;
650 myIsOwnDepth = false;
651 if (aColorType == GL_RENDERBUFFER)
653 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
654 myGlColorRBufferId = aColorId;
656 else if (aColorType != GL_NONE)
658 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
659 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
662 GL_DEBUG_SEVERITY_HIGH,
666 if (aDepthType == GL_RENDERBUFFER)
668 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
669 myGlDepthRBufferId = aDepthId;
671 else if (aDepthType != GL_NONE)
673 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
674 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
677 GL_DEBUG_SEVERITY_HIGH,
681 // retrieve dimensions
682 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
683 if (aRBuffer != NO_RENDERBUFFER)
685 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
686 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
687 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
688 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
691 return aRBuffer != NO_RENDERBUFFER;
694 // =======================================================================
695 // function : Release
697 // =======================================================================
698 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
700 if (isValidFrameBuffer())
702 // application can not handle this case by exception - this is bug in code
703 Standard_ASSERT_RETURN (theGlCtx != NULL,
704 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
705 if (theGlCtx->IsValid()
708 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
709 if (myGlColorRBufferId != NO_RENDERBUFFER)
711 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
713 if (myGlDepthRBufferId != NO_RENDERBUFFER)
715 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
718 myGlFBufferId = NO_FRAMEBUFFER;
719 myGlColorRBufferId = NO_RENDERBUFFER;
720 myGlDepthRBufferId = NO_RENDERBUFFER;
721 myIsOwnBuffer = false;
726 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
728 myColorTextures (aColorBufferIdx)->Release (theGlCtx);
730 myIsOwnColor = false;
735 myDepthStencilTexture->Release (theGlCtx);
736 myIsOwnDepth = false;
743 // =======================================================================
744 // function : SetupViewport
746 // =======================================================================
747 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
749 const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
750 theGlCtx->ResizeViewport (aViewport);
753 // =======================================================================
754 // function : ChangeViewport
756 // =======================================================================
757 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
758 const GLsizei theVPSizeY)
760 myVPSizeX = theVPSizeX;
761 myVPSizeY = theVPSizeY;
764 // =======================================================================
765 // function : BindBuffer
767 // =======================================================================
768 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
770 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
771 theGlCtx->SetFrameBufferSRGB (true);
774 // =======================================================================
775 // function : BindDrawBuffer
777 // =======================================================================
778 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
780 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
781 theGlCtx->SetFrameBufferSRGB (true);
784 // =======================================================================
785 // function : BindReadBuffer
787 // =======================================================================
788 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
790 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
793 // =======================================================================
794 // function : UnbindBuffer
796 // =======================================================================
797 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
799 if (!theGlCtx->DefaultFrameBuffer().IsNull()
800 && theGlCtx->DefaultFrameBuffer().operator->() != this)
802 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
806 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
807 theGlCtx->SetFrameBufferSRGB (false);
811 // =======================================================================
812 // function : getAligned
814 // =======================================================================
815 inline Standard_Size getAligned (const Standard_Size theNumber,
816 const Standard_Size theAlignment)
818 return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment;
822 inline void convertRowFromRgba (T* theRgbRow,
823 const Image_ColorRGBA* theRgbaRow,
824 const Standard_Size theWidth)
826 for (Standard_Size aCol = 0; aCol < theWidth; ++aCol)
828 const Image_ColorRGBA& anRgba = theRgbaRow[aCol];
829 T& anRgb = theRgbRow[aCol];
830 anRgb.r() = anRgba.r();
831 anRgb.g() = anRgba.g();
832 anRgb.b() = anRgba.b();
836 // =======================================================================
837 // function : BufferDump
839 // =======================================================================
840 Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& theGlCtx,
841 const Handle(OpenGl_FrameBuffer)& theFbo,
842 Image_PixMap& theImage,
843 Graphic3d_BufferType theBufferType)
845 if (theGlCtx.IsNull()
846 || theImage.IsEmpty())
848 return Standard_False;
853 bool toSwapRgbaBgra = false;
854 bool toConvRgba2Rgb = false;
855 switch (theImage.Format())
857 #if !defined(GL_ES_VERSION_2_0)
858 case Image_Format_Gray:
859 aFormat = theBufferType == Graphic3d_BT_Depth ? GL_DEPTH_COMPONENT : GL_RED;
860 aType = GL_UNSIGNED_BYTE;
862 case Image_Format_GrayF:
863 aFormat = theBufferType == Graphic3d_BT_Depth ? GL_DEPTH_COMPONENT : GL_RED;
866 case Image_Format_RGF:
870 case Image_Format_RGB:
872 aType = GL_UNSIGNED_BYTE;
874 case Image_Format_BGR:
876 aType = GL_UNSIGNED_BYTE;
878 case Image_Format_BGRA:
879 case Image_Format_BGR32:
881 aType = GL_UNSIGNED_BYTE;
883 case Image_Format_BGRF:
887 case Image_Format_BGRAF:
892 case Image_Format_Gray:
893 case Image_Format_GrayF:
894 case Image_Format_BGRF:
895 case Image_Format_BGRAF:
896 case Image_Format_RGF:
897 return Standard_False;
898 case Image_Format_BGRA:
899 case Image_Format_BGR32:
901 aType = GL_UNSIGNED_BYTE;
902 toSwapRgbaBgra = true;
904 case Image_Format_BGR:
905 case Image_Format_RGB:
907 aType = GL_UNSIGNED_BYTE;
908 toConvRgba2Rgb = true;
911 case Image_Format_RGBA:
912 case Image_Format_RGB32:
914 aType = GL_UNSIGNED_BYTE;
916 case Image_Format_RGBF:
920 case Image_Format_RGBAF:
924 case Image_Format_RGBAF_half:
926 aType = GL_HALF_FLOAT;
928 case Image_Format_Alpha:
929 case Image_Format_AlphaF:
930 return Standard_False; // GL_ALPHA is no more supported in core context
931 case Image_Format_RGF_half:
932 case Image_Format_UNKNOWN:
933 return Standard_False;
938 return Standard_False;
941 #if !defined(GL_ES_VERSION_2_0)
942 GLint aReadBufferPrev = GL_BACK;
943 if (theBufferType == Graphic3d_BT_Depth
944 && aFormat != GL_DEPTH_COMPONENT)
946 return Standard_False;
949 (void )theBufferType;
953 if (!theFbo.IsNull() && theFbo->IsValid())
955 theFbo->BindBuffer (theGlCtx);
959 #if !defined(GL_ES_VERSION_2_0)
960 theGlCtx->core11fwd->glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
961 GLint aDrawBufferPrev = GL_BACK;
962 theGlCtx->core11fwd->glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
963 glReadBuffer (aDrawBufferPrev);
968 const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
969 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
970 bool isBatchCopy = !theImage.IsTopDown();
972 const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
973 GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
974 Standard_Size aSizeRowBytesEstim = getAligned (theImage.SizePixelBytes() * aPixelsWidth, anAligment);
975 if (anExtraBytes < anAligment)
979 else if (aSizeRowBytesEstim != theImage.SizeRowBytes())
984 if (theGlCtx->hasPackRowLength)
986 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
988 else if (aPixelsWidth != 0)
995 const Standard_Size aRowSize = theImage.SizeX() * 4;
996 NCollection_Buffer aRowBuffer (Image_PixMap::DefaultAllocator());
997 if (!aRowBuffer.Allocate (aRowSize))
999 return Standard_False;
1002 for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1004 // Image_PixMap rows indexation always starts from the upper corner
1005 // while order in memory depends on the flag and processed by ChangeRow() method
1006 theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
1007 const Image_ColorRGBA* aRowDataRgba = (const Image_ColorRGBA* )aRowBuffer.Data();
1008 if (theImage.Format() == Image_Format_BGR)
1010 convertRowFromRgba ((Image_ColorBGR* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1014 convertRowFromRgba ((Image_ColorRGB* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1018 else if (!isBatchCopy)
1021 for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1023 // Image_PixMap rows indexation always starts from the upper corner
1024 // while order in memory depends on the flag and processed by ChangeRow() method
1025 theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
1030 theGlCtx->core11fwd->glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
1032 const bool hasErrors = theGlCtx->ResetErrors (true);
1034 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
1035 if (theGlCtx->hasPackRowLength)
1037 theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
1040 if (!theFbo.IsNull() && theFbo->IsValid())
1042 theFbo->UnbindBuffer (theGlCtx);
1046 #if !defined(GL_ES_VERSION_2_0)
1047 glReadBuffer (aReadBufferPrev);
1053 Image_PixMap::SwapRgbaBgra (theImage);
1059 // =======================================================================
1060 // function : EstimatedDataSize
1062 // =======================================================================
1063 Standard_Size OpenGl_FrameBuffer::EstimatedDataSize() const
1070 Standard_Size aSize = 0;
1071 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
1073 aSize += aTextureIt.Value()->EstimatedDataSize();
1075 if (!myDepthStencilTexture.IsNull())
1077 aSize += myDepthStencilTexture->EstimatedDataSize();
1079 if (myGlColorRBufferId != NO_RENDERBUFFER
1080 && !myColorFormats.IsEmpty())
1082 aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myColorFormats.First()) * myInitVPSizeX * myInitVPSizeY;
1084 if (myGlDepthRBufferId != NO_RENDERBUFFER)
1086 aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myDepthFormat) * myInitVPSizeX * myInitVPSizeY;