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>
22 // =======================================================================
23 // function : OpenGl_FrameBuffer
25 // =======================================================================
26 OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
29 myTextFormat (theTextureFormat),
30 myGlFBufferId (NO_FRAMEBUFFER),
31 myGlColorRBufferId (NO_RENDERBUFFER),
32 myGlDepthRBufferId (NO_RENDERBUFFER),
33 myIsOwnBuffer (false),
34 myColorTexture (new OpenGl_Texture()),
35 myDepthStencilTexture (new OpenGl_Texture())
40 // =======================================================================
41 // function : ~OpenGl_FrameBuffer
43 // =======================================================================
44 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
49 // =======================================================================
52 // =======================================================================
53 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
54 const GLsizei theViewportSizeX,
55 const GLsizei theViewportSizeY)
57 if (theGlContext->arbFBO == NULL)
59 return Standard_False;
62 // clean up previous state
63 Release (theGlContext.operator->());
65 // setup viewport sizes as is
66 myVPSizeX = theViewportSizeX;
67 myVPSizeY = theViewportSizeY;
69 // Create the textures (will be used as color buffer and depth-stencil buffer)
70 if (!myColorTexture->Init (theGlContext, myTextFormat,
71 GL_RGBA, GL_UNSIGNED_BYTE,
72 myVPSizeX, myVPSizeY, Graphic3d_TOT_2D))
74 Release (theGlContext.operator->());
75 return Standard_False;
78 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
79 // instead of just trying to create such texture
80 if (!myDepthStencilTexture->Init (theGlContext, GL_DEPTH24_STENCIL8,
81 GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
82 myVPSizeX, myVPSizeY, Graphic3d_TOT_2D))
84 TCollection_ExtendedString aMsg = TCollection_ExtendedString()
85 + "Warning! Depth textures are not supported by hardware!";
86 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
87 GL_DEBUG_TYPE_PORTABILITY_ARB,
89 GL_DEBUG_SEVERITY_HIGH_ARB,
92 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
93 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
94 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, myVPSizeX, myVPSizeY);
95 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
98 // Build FBO and setup it as texture
99 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
100 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
101 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
102 GL_TEXTURE_2D, myColorTexture->TextureId(), 0);
103 if (myDepthStencilTexture->IsValid())
105 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
106 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
107 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
109 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
110 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
111 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
112 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
115 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
117 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
118 GL_RENDERBUFFER, myGlDepthRBufferId);
120 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
122 Release (theGlContext.operator->());
123 return Standard_False;
126 UnbindBuffer (theGlContext);
127 return Standard_True;
130 // =======================================================================
133 // =======================================================================
134 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
135 const GLsizei theViewportSizeX,
136 const GLsizei theViewportSizeY)
138 if (myVPSizeX == theViewportSizeX
139 && myVPSizeY == theViewportSizeY)
145 return Init (theGlContext, theViewportSizeX, theViewportSizeY);
148 // =======================================================================
149 // function : InitWithRB
151 // =======================================================================
152 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
153 const GLsizei theViewportSizeX,
154 const GLsizei theViewportSizeY,
155 const GLuint theColorRBufferFromWindow)
157 if (theGlCtx->arbFBO == NULL)
159 return Standard_False;
162 // clean up previous state
163 Release (theGlCtx.operator->());
165 // setup viewport sizes as is
166 myVPSizeX = theViewportSizeX;
167 myVPSizeY = theViewportSizeY;
169 // Create the render-buffers
170 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
172 myGlColorRBufferId = theColorRBufferFromWindow;
176 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
177 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
178 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA8, myVPSizeX, myVPSizeY);
181 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
182 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
183 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, myVPSizeX, myVPSizeY);
185 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
188 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
189 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
190 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
191 GL_RENDERBUFFER, myGlColorRBufferId);
192 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
193 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
194 GL_RENDERBUFFER, myGlDepthRBufferId);
196 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
197 GL_RENDERBUFFER, myGlDepthRBufferId);
198 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
199 GL_RENDERBUFFER, myGlDepthRBufferId);
201 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
203 UnbindBuffer (theGlCtx);
204 Release (theGlCtx.operator->());
205 return Standard_False;
208 UnbindBuffer (theGlCtx);
209 return Standard_True;
212 // =======================================================================
213 // function : InitWrapper
215 // =======================================================================
216 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
218 if (theGlCtx->arbFBO == NULL)
220 return Standard_False;
223 // clean up previous state
224 Release (theGlCtx.operator->());
226 GLint anFbo = GLint(NO_FRAMEBUFFER);
227 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
228 if (anFbo == GLint(NO_FRAMEBUFFER))
230 return Standard_False;
233 GLint aColorType = 0;
235 GLint aDepthType = 0;
237 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
238 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
240 myGlFBufferId = GLuint(anFbo);
241 myIsOwnBuffer = false;
242 if (aColorType == GL_RENDERBUFFER)
244 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
245 myGlColorRBufferId = aColorId;
247 else if (aColorType != GL_NONE)
249 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
250 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
251 GL_DEBUG_TYPE_ERROR_ARB,
253 GL_DEBUG_SEVERITY_HIGH_ARB,
257 if (aDepthType == GL_RENDERBUFFER)
259 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
260 myGlDepthRBufferId = aDepthId;
262 else if (aDepthType != GL_NONE)
264 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
265 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
266 GL_DEBUG_TYPE_ERROR_ARB,
268 GL_DEBUG_SEVERITY_HIGH_ARB,
272 // retrieve dimensions
273 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
274 if (aRBuffer != NO_RENDERBUFFER)
276 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
277 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
278 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
279 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
282 return aRBuffer != NO_RENDERBUFFER;
285 // =======================================================================
286 // function : Release
288 // =======================================================================
289 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
291 if (isValidFrameBuffer())
293 // application can not handle this case by exception - this is bug in code
294 Standard_ASSERT_RETURN (theGlCtx != NULL,
295 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
296 if (theGlCtx->IsValid()
299 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
300 if (myGlColorRBufferId != NO_RENDERBUFFER)
302 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
304 if (myGlDepthRBufferId != NO_RENDERBUFFER)
306 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
309 myGlFBufferId = NO_FRAMEBUFFER;
310 myGlColorRBufferId = NO_RENDERBUFFER;
311 myGlDepthRBufferId = NO_RENDERBUFFER;
312 myIsOwnBuffer = false;
315 myColorTexture->Release (theGlCtx);
316 myDepthStencilTexture->Release (theGlCtx);
319 // =======================================================================
320 // function : SetupViewport
322 // =======================================================================
323 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
325 glViewport (0, 0, myVPSizeX, myVPSizeY);
328 // =======================================================================
329 // function : ChangeViewport
331 // =======================================================================
332 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
333 const GLsizei theVPSizeY)
335 myVPSizeX = theVPSizeX;
336 myVPSizeY = theVPSizeY;
339 // =======================================================================
340 // function : BindBuffer
342 // =======================================================================
343 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
345 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
348 // =======================================================================
349 // function : BindDrawBuffer
351 // =======================================================================
352 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
354 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
357 // =======================================================================
358 // function : BindReadBuffer
360 // =======================================================================
361 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
363 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
366 // =======================================================================
367 // function : UnbindBuffer
369 // =======================================================================
370 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
372 if (!theGlCtx->DefaultFrameBuffer().IsNull()
373 && theGlCtx->DefaultFrameBuffer().operator->() != this)
375 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
379 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);