1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2011-2012 OPEN CASCADE SAS
4 // The content of this file is subject to the Open CASCADE Technology Public
5 // License Version 6.5 (the "License"). You may not use the content of this file
6 // except in compliance with the License. Please obtain a copy of the License
7 // at http://www.opencascade.org and read it completely before using this file.
9 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 // The Original Code and all software distributed under the License is
13 // distributed on an "AS IS" basis, without warranty of any kind, and the
14 // Initial Developer hereby disclaims all such warranties, including without
15 // limitation, any warranties of merchantability, fitness for a particular
16 // purpose or non-infringement. Please see the License for the specific terms
17 // and conditions governing the rights and limitations under the License.
19 #include <OpenGl_FrameBuffer.hxx>
21 #include <Standard_Assert.hxx>
23 IMPLEMENT_STANDARD_HANDLE (OpenGl_FrameBuffer, OpenGl_Resource)
24 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_Resource)
26 static inline bool isOddNumber (const GLsizei theNumber)
28 return theNumber & 0x01;
31 static inline GLsizei getEvenNumber (const GLsizei theNumber)
33 return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
36 //! Notice - 0 is not power of two here
37 static inline bool isPowerOfTwo (const GLsizei theNumber)
39 return !(theNumber & (theNumber - 1));
42 // =======================================================================
43 // function : OpenGl_FrameBuffer
45 // =======================================================================
46 OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
51 myTextFormat (theTextureFormat),
52 myGlTextureId (NO_TEXTURE),
53 myGlFBufferId (NO_FRAMEBUFFER),
54 myGlDepthRBId (NO_RENDERBUFFER),
55 myGlStencilRBId (NO_RENDERBUFFER)
60 // =======================================================================
61 // function : ~OpenGl_FrameBuffer
63 // =======================================================================
64 OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
69 // =======================================================================
72 // =======================================================================
73 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
74 const GLsizei theViewportSizeX,
75 const GLsizei theViewportSizeY,
76 const GLboolean toForcePowerOfTwo)
78 if (theGlContext->extFBO == NULL)
80 return Standard_False;
83 // clean up previous state
84 Release (theGlContext.operator->());
86 // upscale width/height if numbers are odd
87 if (toForcePowerOfTwo)
89 mySizeX = OpenGl_Context::GetPowerOfTwo (theViewportSizeX, theGlContext->MaxTextureSize());
90 mySizeY = OpenGl_Context::GetPowerOfTwo (theViewportSizeY, theGlContext->MaxTextureSize());
94 mySizeX = getEvenNumber (theViewportSizeX);
95 mySizeY = getEvenNumber (theViewportSizeY);
98 // setup viewport sizes as is
99 myVPSizeX = theViewportSizeX;
100 myVPSizeY = theViewportSizeY;
102 // Create the texture (will be used as color buffer)
103 if (!initTrashTexture (theGlContext))
105 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
107 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
109 Release (theGlContext.operator->());
110 return Standard_False;
113 if (!theGlContext->extPDS)
115 // Create RenderBuffer to be used as depth buffer
116 theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
117 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
118 theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY);
120 // Create RenderBuffer to be used as stencil buffer
121 theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlStencilRBId);
122 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlStencilRBId);
123 theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, mySizeX, mySizeY);
127 // Create combined depth stencil buffer
128 theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
129 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
130 theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mySizeX, mySizeY);
131 myGlStencilRBId = myGlDepthRBId;
134 // Build FBO and setup it as texture
135 theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
136 theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
137 glEnable (GL_TEXTURE_2D);
138 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
139 theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
140 theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlDepthRBId);
141 theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlStencilRBId);
142 if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
144 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
146 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
148 Release (theGlContext.operator->());
149 return Standard_False;
152 UnbindBuffer (theGlContext);
153 UnbindTexture (theGlContext);
154 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
155 return Standard_True;
158 // =======================================================================
159 // function : Release
161 // =======================================================================
162 void OpenGl_FrameBuffer::Release (const OpenGl_Context* theGlCtx)
164 if (isValidDepthBuffer()
165 || isValidStencilBuffer()
167 || isValidFrameBuffer())
169 // application can not handle this case by exception - this is bug in code
170 Standard_ASSERT_RETURN (theGlCtx != NULL,
171 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
173 if (isValidStencilBuffer())
175 if (theGlCtx->IsValid()
176 && myGlStencilRBId != myGlDepthRBId)
178 theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlStencilRBId);
180 myGlStencilRBId = NO_RENDERBUFFER;
182 if (isValidDepthBuffer())
184 if (theGlCtx->IsValid())
186 theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
188 myGlDepthRBId = NO_RENDERBUFFER;
190 if (isValidTexture())
192 if (theGlCtx->IsValid())
194 glDeleteTextures (1, &myGlTextureId);
196 myGlTextureId = NO_TEXTURE;
198 mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
199 if (isValidFrameBuffer())
201 if (theGlCtx->IsValid())
203 theGlCtx->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId);
205 myGlFBufferId = NO_FRAMEBUFFER;
209 // =======================================================================
210 // function : isProxySuccess
212 // =======================================================================
213 Standard_Boolean OpenGl_FrameBuffer::isProxySuccess() const
215 // use proxy to check texture could be created or not
216 glTexImage2D (GL_PROXY_TEXTURE_2D,
217 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
218 myTextFormat, // internalformat
220 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
221 GLint aTestParamX (0), aTestParamY (0);
222 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX);
223 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY);
224 return aTestParamX != 0 && aTestParamY != 0;
227 // =======================================================================
228 // function : initTrashTexture
230 // =======================================================================
231 Standard_Boolean OpenGl_FrameBuffer::initTrashTexture (const Handle(OpenGl_Context)& theGlContext)
233 // Check texture size is fit dimension maximum
234 GLint aMaxTexDim = 2048;
235 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
236 if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim)
238 return Standard_False;
242 glEnable (GL_TEXTURE_2D);
243 if (!isValidTexture())
245 glGenTextures (1, &myGlTextureId); // Create The Texture
247 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
249 // texture interpolation parameters - could be overridden later
250 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
251 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
253 if (!isProxySuccess())
255 Release (theGlContext.operator->());
256 return Standard_False;
259 glTexImage2D (GL_TEXTURE_2D,
260 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
261 myTextFormat, // internalformat
263 GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
264 return Standard_True;
267 // =======================================================================
268 // function : SetupViewport
270 // =======================================================================
271 void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
273 glViewport (0, 0, myVPSizeX, myVPSizeY);
276 // =======================================================================
277 // function : ChangeViewport
279 // =======================================================================
280 void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
281 const GLsizei theVPSizeY)
283 myVPSizeX = theVPSizeX;
284 myVPSizeY = theVPSizeY;
287 // =======================================================================
288 // function : BindBuffer
290 // =======================================================================
291 void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
293 theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
296 // =======================================================================
297 // function : UnbindBuffer
299 // =======================================================================
300 void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
302 theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, NO_FRAMEBUFFER);
305 // =======================================================================
306 // function : BindTexture
308 // =======================================================================
309 void OpenGl_FrameBuffer::BindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
311 glEnable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
312 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
315 // =======================================================================
316 // function : UnbindTexture
318 // =======================================================================
319 void OpenGl_FrameBuffer::UnbindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
321 glBindTexture (GL_TEXTURE_2D, NO_TEXTURE);
322 glDisable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering