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 <Standard_Assert.hxx>
19 IMPLEMENT_STANDARD_HANDLE (OpenGl_FrameBuffer, OpenGl_Resource)
20 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_Resource)
22 static inline bool isOddNumber (const GLsizei theNumber)
24 return theNumber & 0x01;
27 static inline GLsizei getEvenNumber (const GLsizei theNumber)
29 return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
32 //! Notice - 0 is not power of two here
33 static inline bool isPowerOfTwo (const GLsizei theNumber)
35 return !(theNumber & (theNumber - 1));
38 // =======================================================================
39 // function : OpenGl_FrameBuffer
41 // =======================================================================
42 OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
47 myTextFormat (theTextureFormat),
48 myGlTextureId (NO_TEXTURE),
49 myGlFBufferId (NO_FRAMEBUFFER),
50 myGlDepthRBId (NO_RENDERBUFFER),
51 myGlStencilRBId (NO_RENDERBUFFER)
56 // =======================================================================
57 // function : ~OpenGl_FrameBuffer
59 // =======================================================================
60 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
65 // =======================================================================
68 // =======================================================================
69 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
70 const GLsizei theViewportSizeX,
71 const GLsizei theViewportSizeY,
72 const GLboolean toForcePowerOfTwo)
74 if (theGlContext->extFBO == NULL)
76 return Standard_False;
79 // clean up previous state
80 Release (theGlContext.operator->());
82 // upscale width/height if numbers are odd
83 if (toForcePowerOfTwo)
85 mySizeX = OpenGl_Context::GetPowerOfTwo (theViewportSizeX, theGlContext->MaxTextureSize());
86 mySizeY = OpenGl_Context::GetPowerOfTwo (theViewportSizeY, theGlContext->MaxTextureSize());
90 mySizeX = getEvenNumber (theViewportSizeX);
91 mySizeY = getEvenNumber (theViewportSizeY);
94 // setup viewport sizes as is
95 myVPSizeX = theViewportSizeX;
96 myVPSizeY = theViewportSizeY;
98 // Create the texture (will be used as color buffer)
99 if (!initTrashTexture (theGlContext))
101 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
103 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
105 Release (theGlContext.operator->());
106 return Standard_False;
109 if (!theGlContext->extPDS)
111 // Create RenderBuffer to be used as depth buffer
112 theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
113 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
114 theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY);
116 // Create RenderBuffer to be used as stencil buffer
117 theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlStencilRBId);
118 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlStencilRBId);
119 theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, mySizeX, mySizeY);
123 // Create combined depth stencil buffer
124 theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
125 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
126 theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mySizeX, mySizeY);
127 myGlStencilRBId = myGlDepthRBId;
130 // Build FBO and setup it as texture
131 theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
132 theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
133 glEnable (GL_TEXTURE_2D);
134 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
135 theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
136 theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlDepthRBId);
137 theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlStencilRBId);
138 if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
140 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
142 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
144 Release (theGlContext.operator->());
145 return Standard_False;
148 UnbindBuffer (theGlContext);
149 UnbindTexture (theGlContext);
150 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
151 return Standard_True;
154 // =======================================================================
155 // function : Release
157 // =======================================================================
158 void OpenGl_FrameBuffer::Release (const OpenGl_Context* theGlCtx)
160 if (isValidDepthBuffer()
161 || isValidStencilBuffer()
163 || isValidFrameBuffer())
165 // application can not handle this case by exception - this is bug in code
166 Standard_ASSERT_RETURN (theGlCtx != NULL,
167 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
169 if (isValidStencilBuffer())
171 if (theGlCtx->IsValid()
172 && myGlStencilRBId != myGlDepthRBId)
174 theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlStencilRBId);
176 myGlStencilRBId = NO_RENDERBUFFER;
178 if (isValidDepthBuffer())
180 if (theGlCtx->IsValid())
182 theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
184 myGlDepthRBId = NO_RENDERBUFFER;
186 if (isValidTexture())
188 if (theGlCtx->IsValid())
190 glDeleteTextures (1, &myGlTextureId);
192 myGlTextureId = NO_TEXTURE;
194 mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
195 if (isValidFrameBuffer())
197 if (theGlCtx->IsValid())
199 theGlCtx->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId);
201 myGlFBufferId = NO_FRAMEBUFFER;
205 // =======================================================================
206 // function : isProxySuccess
208 // =======================================================================
209 Standard_Boolean OpenGl_FrameBuffer::isProxySuccess() const
211 // use proxy to check texture could be created or not
212 glTexImage2D (GL_PROXY_TEXTURE_2D,
213 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
214 myTextFormat, // internalformat
216 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
217 GLint aTestParamX (0), aTestParamY (0);
218 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX);
219 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY);
220 return aTestParamX != 0 && aTestParamY != 0;
223 // =======================================================================
224 // function : initTrashTexture
226 // =======================================================================
227 Standard_Boolean OpenGl_FrameBuffer::initTrashTexture (const Handle(OpenGl_Context)& theGlContext)
229 // Check texture size is fit dimension maximum
230 GLint aMaxTexDim = 2048;
231 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
232 if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim)
234 return Standard_False;
238 glEnable (GL_TEXTURE_2D);
239 if (!isValidTexture())
241 glGenTextures (1, &myGlTextureId); // Create The Texture
243 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
245 // texture interpolation parameters - could be overridden later
246 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
247 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
249 if (!isProxySuccess())
251 Release (theGlContext.operator->());
252 return Standard_False;
255 glTexImage2D (GL_TEXTURE_2D,
256 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
257 myTextFormat, // internalformat
259 GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
260 return Standard_True;
263 // =======================================================================
264 // function : SetupViewport
266 // =======================================================================
267 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
269 glViewport (0, 0, myVPSizeX, myVPSizeY);
272 // =======================================================================
273 // function : ChangeViewport
275 // =======================================================================
276 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
277 const GLsizei theVPSizeY)
279 myVPSizeX = theVPSizeX;
280 myVPSizeY = theVPSizeY;
283 // =======================================================================
284 // function : BindBuffer
286 // =======================================================================
287 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
289 theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
292 // =======================================================================
293 // function : UnbindBuffer
295 // =======================================================================
296 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
298 theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, NO_FRAMEBUFFER);
301 // =======================================================================
302 // function : BindTexture
304 // =======================================================================
305 void OpenGl_FrameBuffer::BindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
307 glEnable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
308 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
311 // =======================================================================
312 // function : UnbindTexture
314 // =======================================================================
315 void OpenGl_FrameBuffer::UnbindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
317 glBindTexture (GL_TEXTURE_2D, NO_TEXTURE);
318 glDisable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering