0024228: TKOpenGL - destroy GL context at view close
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
CommitLineData
b311480e 1// Created by: Kirill GAVRILOV
2// Copyright (c) 2011-2012 OPEN CASCADE SAS
3//
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.
8//
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.
11//
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.
18
7fd59977 19#include <OpenGl_FrameBuffer.hxx>
20
fd4a6963 21#include <Standard_Assert.hxx>
22
23IMPLEMENT_STANDARD_HANDLE (OpenGl_FrameBuffer, OpenGl_Resource)
24IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_Resource)
7fd59977 25
7fd59977 26static inline bool isOddNumber (const GLsizei theNumber)
27{
28 return theNumber & 0x01;
29}
30
31static inline GLsizei getEvenNumber (const GLsizei theNumber)
32{
33 return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
34}
35
36//! Notice - 0 is not power of two here
37static inline bool isPowerOfTwo (const GLsizei theNumber)
38{
39 return !(theNumber & (theNumber - 1));
40}
41
fd4a6963 42// =======================================================================
43// function : OpenGl_FrameBuffer
44// purpose :
45// =======================================================================
7fd59977 46OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
47: mySizeX (0),
48 mySizeY (0),
49 myVPSizeX (0),
50 myVPSizeY (0),
51 myTextFormat (theTextureFormat),
52 myGlTextureId (NO_TEXTURE),
53 myGlFBufferId (NO_FRAMEBUFFER),
b859a34d 54 myGlDepthRBId (NO_RENDERBUFFER),
55 myGlStencilRBId (NO_RENDERBUFFER)
7fd59977 56{
57 //
58}
59
fd4a6963 60// =======================================================================
61// function : ~OpenGl_FrameBuffer
62// purpose :
63// =======================================================================
64OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
65{
66 Release (NULL);
67}
68
69// =======================================================================
70// function : Init
71// purpose :
72// =======================================================================
2166f0fa 73Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
fd4a6963 74 const GLsizei theViewportSizeX,
75 const GLsizei theViewportSizeY,
76 const GLboolean toForcePowerOfTwo)
7fd59977 77{
2166f0fa 78 if (theGlContext->extFBO == NULL)
7fd59977 79 {
7fd59977 80 return Standard_False;
81 }
82
83 // clean up previous state
fd4a6963 84 Release (theGlContext.operator->());
7fd59977 85
86 // upscale width/height if numbers are odd
87 if (toForcePowerOfTwo)
88 {
a174a3c5 89 mySizeX = OpenGl_Context::GetPowerOfTwo (theViewportSizeX, theGlContext->MaxTextureSize());
90 mySizeY = OpenGl_Context::GetPowerOfTwo (theViewportSizeY, theGlContext->MaxTextureSize());
7fd59977 91 }
92 else
93 {
94 mySizeX = getEvenNumber (theViewportSizeX);
95 mySizeY = getEvenNumber (theViewportSizeY);
96 }
97
98 // setup viewport sizes as is
99 myVPSizeX = theViewportSizeX;
100 myVPSizeY = theViewportSizeY;
101
102 // Create the texture (will be used as color buffer)
fd4a6963 103 if (!initTrashTexture (theGlContext))
7fd59977 104 {
105 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
106 {
2166f0fa 107 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
7fd59977 108 }
fd4a6963 109 Release (theGlContext.operator->());
7fd59977 110 return Standard_False;
111 }
112
b859a34d 113 if (!theGlContext->extPDS)
114 {
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);
119
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);
124 }
125 else
126 {
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;
132 }
7fd59977 133
134 // Build FBO and setup it as texture
2166f0fa
SK
135 theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
136 theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
7fd59977 137 glEnable (GL_TEXTURE_2D);
138 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
2166f0fa 139 theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
9be3a894 140 theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlDepthRBId);
b859a34d 141 theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlStencilRBId);
2166f0fa 142 if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
7fd59977 143 {
144 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
145 {
2166f0fa 146 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
7fd59977 147 }
fd4a6963 148 Release (theGlContext.operator->());
7fd59977 149 return Standard_False;
150 }
151
fd4a6963 152 UnbindBuffer (theGlContext);
153 UnbindTexture (theGlContext);
2166f0fa 154 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
7fd59977 155 return Standard_True;
156}
157
fd4a6963 158// =======================================================================
159// function : Release
160// purpose :
161// =======================================================================
162void OpenGl_FrameBuffer::Release (const OpenGl_Context* theGlCtx)
7fd59977 163{
fd4a6963 164 if (isValidDepthBuffer()
165 || isValidStencilBuffer()
166 || isValidTexture()
167 || isValidFrameBuffer())
7fd59977 168 {
fd4a6963 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...",);
7fd59977 172 }
fd4a6963 173 if (isValidStencilBuffer())
b859a34d 174 {
fd4a6963 175 if (theGlCtx->IsValid()
176 && myGlStencilRBId != myGlDepthRBId)
b859a34d 177 {
fd4a6963 178 theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlStencilRBId);
b859a34d 179 }
fd4a6963 180 myGlStencilRBId = NO_RENDERBUFFER;
181 }
182 if (isValidDepthBuffer())
183 {
184 if (theGlCtx->IsValid())
b859a34d 185 {
fd4a6963 186 theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
b859a34d 187 }
fd4a6963 188 myGlDepthRBId = NO_RENDERBUFFER;
b859a34d 189 }
fd4a6963 190 if (isValidTexture())
7fd59977 191 {
fd4a6963 192 if (theGlCtx->IsValid())
193 {
194 glDeleteTextures (1, &myGlTextureId);
195 }
7fd59977 196 myGlTextureId = NO_TEXTURE;
197 }
198 mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
fd4a6963 199 if (isValidFrameBuffer())
7fd59977 200 {
fd4a6963 201 if (theGlCtx->IsValid())
2166f0fa 202 {
fd4a6963 203 theGlCtx->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId);
2166f0fa 204 }
fd4a6963 205 myGlFBufferId = NO_FRAMEBUFFER;
7fd59977 206 }
207}
208
fd4a6963 209// =======================================================================
210// function : isProxySuccess
211// purpose :
212// =======================================================================
213Standard_Boolean OpenGl_FrameBuffer::isProxySuccess() const
7fd59977 214{
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
219 mySizeX, mySizeY, 0,
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;
225}
226
fd4a6963 227// =======================================================================
228// function : initTrashTexture
229// purpose :
230// =======================================================================
231Standard_Boolean OpenGl_FrameBuffer::initTrashTexture (const Handle(OpenGl_Context)& theGlContext)
7fd59977 232{
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)
237 {
238 return Standard_False;
239 }
240
241 // generate new id
242 glEnable (GL_TEXTURE_2D);
fd4a6963 243 if (!isValidTexture())
7fd59977 244 {
245 glGenTextures (1, &myGlTextureId); // Create The Texture
246 }
247 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
248
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);
252
fd4a6963 253 if (!isProxySuccess())
7fd59977 254 {
fd4a6963 255 Release (theGlContext.operator->());
7fd59977 256 return Standard_False;
257 }
258
259 glTexImage2D (GL_TEXTURE_2D,
260 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
261 myTextFormat, // internalformat
262 mySizeX, mySizeY, 0,
263 GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
264 return Standard_True;
265}
fd4a6963 266
267// =======================================================================
268// function : SetupViewport
269// purpose :
270// =======================================================================
271void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
272{
273 glViewport (0, 0, myVPSizeX, myVPSizeY);
274}
275
276// =======================================================================
277// function : ChangeViewport
278// purpose :
279// =======================================================================
280void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
281 const GLsizei theVPSizeY)
282{
283 myVPSizeX = theVPSizeX;
284 myVPSizeY = theVPSizeY;
285}
286
287// =======================================================================
288// function : BindBuffer
289// purpose :
290// =======================================================================
291void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
292{
293 theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
294}
295
296// =======================================================================
297// function : UnbindBuffer
298// purpose :
299// =======================================================================
300void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
301{
302 theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, NO_FRAMEBUFFER);
303}
304
305// =======================================================================
306// function : BindTexture
307// purpose :
308// =======================================================================
309void OpenGl_FrameBuffer::BindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
310{
311 glEnable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
312 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
313}
314
315// =======================================================================
316// function : UnbindTexture
317// purpose :
318// =======================================================================
319void OpenGl_FrameBuffer::UnbindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
320{
321 glBindTexture (GL_TEXTURE_2D, NO_TEXTURE);
322 glDisable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
323}