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)
26 //! Determine data type from texture sized format.
27 static bool getDepthDataFormat (GLint theTextFormat,
28 GLenum& thePixelFormat,
31 switch (theTextFormat)
33 case GL_DEPTH24_STENCIL8:
35 thePixelFormat = GL_DEPTH_STENCIL;
36 theDataType = GL_UNSIGNED_INT_24_8;
39 case GL_DEPTH32F_STENCIL8:
41 thePixelFormat = GL_DEPTH_STENCIL;
42 theDataType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
45 case GL_DEPTH_COMPONENT16:
47 thePixelFormat = GL_DEPTH_COMPONENT;
48 theDataType = GL_UNSIGNED_SHORT;
51 case GL_DEPTH_COMPONENT24:
53 thePixelFormat = GL_DEPTH_COMPONENT;
54 theDataType = GL_UNSIGNED_INT;
57 case GL_DEPTH_COMPONENT32F:
59 thePixelFormat = GL_DEPTH_COMPONENT;
60 theDataType = GL_FLOAT;
69 // =======================================================================
70 // function : OpenGl_FrameBuffer
72 // =======================================================================
73 OpenGl_FrameBuffer::OpenGl_FrameBuffer()
77 myColorFormat (GL_RGBA8),
78 myDepthFormat (GL_DEPTH24_STENCIL8),
79 myGlFBufferId (NO_FRAMEBUFFER),
80 myGlColorRBufferId (NO_RENDERBUFFER),
81 myGlDepthRBufferId (NO_RENDERBUFFER),
82 myIsOwnBuffer (false),
83 myColorTexture (new OpenGl_Texture()),
84 myDepthStencilTexture (new OpenGl_Texture())
89 // =======================================================================
90 // function : ~OpenGl_FrameBuffer
92 // =======================================================================
93 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
98 // =======================================================================
101 // =======================================================================
102 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
103 const GLsizei theSizeX,
104 const GLsizei theSizeY,
105 const GLint theColorFormat,
106 const GLint theDepthFormat,
107 const GLsizei theNbSamples)
109 myColorFormat = theColorFormat;
110 myDepthFormat = theDepthFormat;
111 myNbSamples = theNbSamples;
112 if (theGlContext->arbFBO == NULL)
114 return Standard_False;
117 // clean up previous state
118 Release (theGlContext.operator->());
119 if (myColorFormat == 0
120 && myDepthFormat == 0)
122 return Standard_False;
125 myIsOwnBuffer = true;
127 // setup viewport sizes as is
128 myVPSizeX = theSizeX;
129 myVPSizeY = theSizeY;
130 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
131 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
132 bool hasStencilRB = false;
134 // Create the textures (will be used as color buffer and depth-stencil buffer)
135 if (theNbSamples != 0)
137 if (myColorFormat != 0
138 && !myColorTexture ->Init2DMultisample (theGlContext, theNbSamples, myColorFormat, aSizeX, aSizeY))
140 Release (theGlContext.operator->());
141 return Standard_False;
143 if (myDepthFormat != 0
144 && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
146 Release (theGlContext.operator->());
147 return Standard_False;
152 if (myColorFormat != 0
153 && !myColorTexture->Init (theGlContext, myColorFormat,
154 GL_RGBA, GL_UNSIGNED_BYTE,
155 aSizeX, aSizeY, Graphic3d_TOT_2D))
157 Release (theGlContext.operator->());
158 return Standard_False;
161 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
162 // instead of just trying to create such texture
163 GLenum aPixelFormat = 0;
164 GLenum aDataType = 0;
165 if (myDepthFormat != 0
166 && getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
167 && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
168 aPixelFormat, aDataType,
169 aSizeX, aSizeY, Graphic3d_TOT_2D))
171 TCollection_ExtendedString aMsg = TCollection_ExtendedString()
172 + "Warning! Depth textures are not supported by hardware!";
173 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
174 GL_DEBUG_TYPE_PORTABILITY,
176 GL_DEBUG_SEVERITY_HIGH,
179 hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL
180 && theGlContext->extPDS;
181 GLint aDepthStencilFormat = hasStencilRB
182 ? GL_DEPTH24_STENCIL8
183 : GL_DEPTH_COMPONENT16;
185 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
186 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
187 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
188 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
192 // Build FBO and setup it as texture
193 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
194 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
195 if (myColorTexture->IsValid())
197 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
198 myColorTexture->GetTarget(), myColorTexture->TextureId(), 0);
200 if (myDepthStencilTexture->IsValid())
202 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
203 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
204 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
206 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
207 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
208 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
209 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
212 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
214 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
215 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
216 GL_RENDERBUFFER, myGlDepthRBufferId);
218 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
219 GL_RENDERBUFFER, myGlDepthRBufferId);
222 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
223 GL_RENDERBUFFER, myGlDepthRBufferId);
227 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
229 Release (theGlContext.operator->());
230 return Standard_False;
233 UnbindBuffer (theGlContext);
234 return Standard_True;
237 // =======================================================================
240 // =======================================================================
241 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
242 const GLsizei theViewportSizeX,
243 const GLsizei theViewportSizeY,
244 const GLint theColorFormat,
245 const GLint theDepthFormat,
246 const GLsizei theNbSamples)
248 if (myVPSizeX == theViewportSizeX
249 && myVPSizeY == theViewportSizeY
250 && myColorFormat == theColorFormat
251 && myDepthFormat == theDepthFormat
252 && myNbSamples == theNbSamples)
257 return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormat, theDepthFormat, theNbSamples);
260 // =======================================================================
261 // function : InitWithRB
263 // =======================================================================
264 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
265 const GLsizei theSizeX,
266 const GLsizei theSizeY,
267 const GLint theColorFormat,
268 const GLint theDepthFormat,
269 const GLuint theColorRBufferFromWindow)
271 myColorFormat = theColorFormat;
272 myDepthFormat = theDepthFormat;
274 if (theGlCtx->arbFBO == NULL)
276 return Standard_False;
279 // clean up previous state
280 Release (theGlCtx.operator->());
282 myIsOwnBuffer = true;
284 // setup viewport sizes as is
285 myVPSizeX = theSizeX;
286 myVPSizeY = theSizeY;
287 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
288 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
290 // Create the render-buffers
291 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
293 myGlColorRBufferId = theColorRBufferFromWindow;
295 else if (myColorFormat != 0)
297 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
298 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
299 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myColorFormat, aSizeX, aSizeY);
302 bool hasStencilRB = false;
303 if (myDepthFormat != 0)
305 GLenum aPixelFormat = 0;
306 GLenum aDataType = 0;
307 getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType);
308 hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL;
310 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
311 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
312 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
313 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
317 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
318 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
319 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
320 GL_RENDERBUFFER, myGlColorRBufferId);
321 if (myGlDepthRBufferId != NO_RENDERBUFFER)
323 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
324 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
325 GL_RENDERBUFFER, myGlDepthRBufferId);
327 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
328 GL_RENDERBUFFER, myGlDepthRBufferId);
331 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
332 GL_RENDERBUFFER, myGlDepthRBufferId);
336 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
338 UnbindBuffer (theGlCtx);
339 Release (theGlCtx.operator->());
340 return Standard_False;
343 UnbindBuffer (theGlCtx);
344 return Standard_True;
347 // =======================================================================
348 // function : InitWrapper
350 // =======================================================================
351 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
354 if (theGlCtx->arbFBO == NULL)
356 return Standard_False;
359 // clean up previous state
360 Release (theGlCtx.operator->());
362 GLint anFbo = GLint(NO_FRAMEBUFFER);
363 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
364 if (anFbo == GLint(NO_FRAMEBUFFER))
366 return Standard_False;
369 GLint aColorType = 0;
371 GLint aDepthType = 0;
373 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
374 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
376 myGlFBufferId = GLuint(anFbo);
377 myIsOwnBuffer = false;
378 if (aColorType == GL_RENDERBUFFER)
380 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
381 myGlColorRBufferId = aColorId;
383 else if (aColorType != GL_NONE)
385 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
386 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
389 GL_DEBUG_SEVERITY_HIGH,
393 if (aDepthType == GL_RENDERBUFFER)
395 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
396 myGlDepthRBufferId = aDepthId;
398 else if (aDepthType != GL_NONE)
400 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
401 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
404 GL_DEBUG_SEVERITY_HIGH,
408 // retrieve dimensions
409 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
410 if (aRBuffer != NO_RENDERBUFFER)
412 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
413 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
414 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
415 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
418 return aRBuffer != NO_RENDERBUFFER;
421 // =======================================================================
422 // function : Release
424 // =======================================================================
425 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
427 if (isValidFrameBuffer())
429 // application can not handle this case by exception - this is bug in code
430 Standard_ASSERT_RETURN (theGlCtx != NULL,
431 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
432 if (theGlCtx->IsValid()
435 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
436 if (myGlColorRBufferId != NO_RENDERBUFFER)
438 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
440 if (myGlDepthRBufferId != NO_RENDERBUFFER)
442 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
445 myGlFBufferId = NO_FRAMEBUFFER;
446 myGlColorRBufferId = NO_RENDERBUFFER;
447 myGlDepthRBufferId = NO_RENDERBUFFER;
448 myIsOwnBuffer = false;
451 myColorTexture->Release (theGlCtx);
452 myDepthStencilTexture->Release (theGlCtx);
458 // =======================================================================
459 // function : SetupViewport
461 // =======================================================================
462 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
464 const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
465 theGlCtx->ResizeViewport (aViewport);
468 // =======================================================================
469 // function : ChangeViewport
471 // =======================================================================
472 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
473 const GLsizei theVPSizeY)
475 myVPSizeX = theVPSizeX;
476 myVPSizeY = theVPSizeY;
479 // =======================================================================
480 // function : BindBuffer
482 // =======================================================================
483 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
485 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
488 // =======================================================================
489 // function : BindDrawBuffer
491 // =======================================================================
492 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
494 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
497 // =======================================================================
498 // function : BindReadBuffer
500 // =======================================================================
501 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
503 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
506 // =======================================================================
507 // function : UnbindBuffer
509 // =======================================================================
510 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
512 if (!theGlCtx->DefaultFrameBuffer().IsNull()
513 && theGlCtx->DefaultFrameBuffer().operator->() != this)
515 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
519 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);