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 theSizeX,
55 const GLsizei theSizeY)
57 if (theGlContext->arbFBO == NULL)
59 return Standard_False;
62 // clean up previous state
63 Release (theGlContext.operator->());
67 // setup viewport sizes as is
70 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
71 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
73 // Create the textures (will be used as color buffer and depth-stencil buffer)
74 if (!myColorTexture->Init (theGlContext, myTextFormat,
75 GL_RGBA, GL_UNSIGNED_BYTE,
76 aSizeX, aSizeY, Graphic3d_TOT_2D))
78 Release (theGlContext.operator->());
79 return Standard_False;
82 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
83 // instead of just trying to create such texture
84 if (!myDepthStencilTexture->Init (theGlContext, GL_DEPTH24_STENCIL8,
85 GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
86 aSizeX, aSizeY, Graphic3d_TOT_2D))
88 TCollection_ExtendedString aMsg = TCollection_ExtendedString()
89 + "Warning! Depth textures are not supported by hardware!";
90 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
91 GL_DEBUG_TYPE_PORTABILITY_ARB,
93 GL_DEBUG_SEVERITY_HIGH_ARB,
96 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
97 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
98 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, aSizeX, aSizeY);
99 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
102 // Build FBO and setup it as texture
103 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
104 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
105 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
106 GL_TEXTURE_2D, myColorTexture->TextureId(), 0);
107 if (myDepthStencilTexture->IsValid())
109 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
110 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
111 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
113 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
114 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
115 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
116 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
119 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
121 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
122 GL_RENDERBUFFER, myGlDepthRBufferId);
124 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
126 Release (theGlContext.operator->());
127 return Standard_False;
130 UnbindBuffer (theGlContext);
131 return Standard_True;
134 // =======================================================================
137 // =======================================================================
138 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
139 const GLsizei theViewportSizeX,
140 const GLsizei theViewportSizeY)
142 if (myVPSizeX == theViewportSizeX
143 && myVPSizeY == theViewportSizeY)
149 return Init (theGlContext, theViewportSizeX, theViewportSizeY);
152 // =======================================================================
153 // function : InitWithRB
155 // =======================================================================
156 Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
157 const GLsizei theSizeX,
158 const GLsizei theSizeY,
159 const GLuint theColorRBufferFromWindow)
161 if (theGlCtx->arbFBO == NULL)
163 return Standard_False;
166 // clean up previous state
167 Release (theGlCtx.operator->());
169 myIsOwnBuffer = true;
171 // setup viewport sizes as is
172 myVPSizeX = theSizeX;
173 myVPSizeY = theSizeY;
174 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
175 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
177 // Create the render-buffers
178 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
180 myGlColorRBufferId = theColorRBufferFromWindow;
184 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
185 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
186 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA8, aSizeX, aSizeY);
189 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
190 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
191 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, aSizeX, aSizeY);
193 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
196 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
197 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
198 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
199 GL_RENDERBUFFER, myGlColorRBufferId);
200 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
201 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
202 GL_RENDERBUFFER, myGlDepthRBufferId);
204 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
205 GL_RENDERBUFFER, myGlDepthRBufferId);
206 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
207 GL_RENDERBUFFER, myGlDepthRBufferId);
209 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
211 UnbindBuffer (theGlCtx);
212 Release (theGlCtx.operator->());
213 return Standard_False;
216 UnbindBuffer (theGlCtx);
217 return Standard_True;
220 // =======================================================================
221 // function : InitWrapper
223 // =======================================================================
224 Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
226 if (theGlCtx->arbFBO == NULL)
228 return Standard_False;
231 // clean up previous state
232 Release (theGlCtx.operator->());
234 GLint anFbo = GLint(NO_FRAMEBUFFER);
235 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
236 if (anFbo == GLint(NO_FRAMEBUFFER))
238 return Standard_False;
241 GLint aColorType = 0;
243 GLint aDepthType = 0;
245 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
246 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
248 myGlFBufferId = GLuint(anFbo);
249 myIsOwnBuffer = false;
250 if (aColorType == GL_RENDERBUFFER)
252 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
253 myGlColorRBufferId = aColorId;
255 else if (aColorType != GL_NONE)
257 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
258 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
259 GL_DEBUG_TYPE_ERROR_ARB,
261 GL_DEBUG_SEVERITY_HIGH_ARB,
265 if (aDepthType == GL_RENDERBUFFER)
267 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
268 myGlDepthRBufferId = aDepthId;
270 else if (aDepthType != GL_NONE)
272 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
273 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
274 GL_DEBUG_TYPE_ERROR_ARB,
276 GL_DEBUG_SEVERITY_HIGH_ARB,
280 // retrieve dimensions
281 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
282 if (aRBuffer != NO_RENDERBUFFER)
284 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
285 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
286 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
287 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
290 return aRBuffer != NO_RENDERBUFFER;
293 // =======================================================================
294 // function : Release
296 // =======================================================================
297 void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
299 if (isValidFrameBuffer())
301 // application can not handle this case by exception - this is bug in code
302 Standard_ASSERT_RETURN (theGlCtx != NULL,
303 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
304 if (theGlCtx->IsValid()
307 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
308 if (myGlColorRBufferId != NO_RENDERBUFFER)
310 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
312 if (myGlDepthRBufferId != NO_RENDERBUFFER)
314 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
317 myGlFBufferId = NO_FRAMEBUFFER;
318 myGlColorRBufferId = NO_RENDERBUFFER;
319 myGlDepthRBufferId = NO_RENDERBUFFER;
320 myIsOwnBuffer = false;
323 myColorTexture->Release (theGlCtx);
324 myDepthStencilTexture->Release (theGlCtx);
330 // =======================================================================
331 // function : SetupViewport
333 // =======================================================================
334 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
336 glViewport (0, 0, myVPSizeX, myVPSizeY);
339 // =======================================================================
340 // function : ChangeViewport
342 // =======================================================================
343 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
344 const GLsizei theVPSizeY)
346 myVPSizeX = theVPSizeX;
347 myVPSizeY = theVPSizeY;
350 // =======================================================================
351 // function : BindBuffer
353 // =======================================================================
354 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
356 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
359 // =======================================================================
360 // function : BindDrawBuffer
362 // =======================================================================
363 void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
365 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
368 // =======================================================================
369 // function : BindReadBuffer
371 // =======================================================================
372 void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
374 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
377 // =======================================================================
378 // function : UnbindBuffer
380 // =======================================================================
381 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
383 if (!theGlCtx->DefaultFrameBuffer().IsNull()
384 && theGlCtx->DefaultFrameBuffer().operator->() != this)
386 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
390 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);