0026492: OpenGl_FrameBuffer does not releases itself correctly
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
CommitLineData
b311480e 1// Created by: Kirill GAVRILOV
973c2be1 2// Copyright (c) 2011-2014 OPEN CASCADE SAS
b311480e 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
b311480e 5//
d5f74e42 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
973c2be1 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.
b311480e 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
b311480e 14
7fd59977 15#include <OpenGl_FrameBuffer.hxx>
01ca42b2 16#include <OpenGl_ArbFBO.hxx>
7fd59977 17
fd4a6963 18#include <Standard_Assert.hxx>
a2e4f780 19#include <TCollection_ExtendedString.hxx>
fd4a6963 20
7fd59977 21
fd4a6963 22// =======================================================================
23// function : OpenGl_FrameBuffer
24// purpose :
25// =======================================================================
7fd59977 26OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
18f4e8e2 27: myVPSizeX (0),
7fd59977 28 myVPSizeY (0),
29 myTextFormat (theTextureFormat),
7fd59977 30 myGlFBufferId (NO_FRAMEBUFFER),
a2e4f780 31 myGlColorRBufferId (NO_RENDERBUFFER),
32 myGlDepthRBufferId (NO_RENDERBUFFER),
33 myIsOwnBuffer (false),
18f4e8e2 34 myColorTexture (new OpenGl_Texture()),
35 myDepthStencilTexture (new OpenGl_Texture())
7fd59977 36{
37 //
38}
39
fd4a6963 40// =======================================================================
41// function : ~OpenGl_FrameBuffer
42// purpose :
43// =======================================================================
44OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
45{
46 Release (NULL);
47}
48
49// =======================================================================
50// function : Init
51// purpose :
52// =======================================================================
2166f0fa 53Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
62e1beed 54 const GLsizei theSizeX,
55 const GLsizei theSizeY)
7fd59977 56{
01ca42b2 57 if (theGlContext->arbFBO == NULL)
7fd59977 58 {
7fd59977 59 return Standard_False;
60 }
61
62 // clean up previous state
fd4a6963 63 Release (theGlContext.operator->());
7fd59977 64
a447178e 65 myIsOwnBuffer = true;
66
7fd59977 67 // setup viewport sizes as is
62e1beed 68 myVPSizeX = theSizeX;
69 myVPSizeY = theSizeY;
70 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
71 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
7fd59977 72
18f4e8e2 73 // Create the textures (will be used as color buffer and depth-stencil buffer)
fe3a29bc 74 if (!myColorTexture->Init (theGlContext, myTextFormat,
75 GL_RGBA, GL_UNSIGNED_BYTE,
62e1beed 76 aSizeX, aSizeY, Graphic3d_TOT_2D))
7fd59977 77 {
fd4a6963 78 Release (theGlContext.operator->());
7fd59977 79 return Standard_False;
80 }
81
fe3a29bc 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,
62e1beed 86 aSizeX, aSizeY, Graphic3d_TOT_2D))
fe3a29bc 87 {
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,
92 0,
93 GL_DEBUG_SEVERITY_HIGH_ARB,
94 aMsg);
95
96 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
97 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
62e1beed 98 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, aSizeX, aSizeY);
fe3a29bc 99 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
100 }
101
7fd59977 102 // Build FBO and setup it as texture
01ca42b2 103 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
104 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
18f4e8e2 105 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
106 GL_TEXTURE_2D, myColorTexture->TextureId(), 0);
fe3a29bc 107 if (myDepthStencilTexture->IsValid())
108 {
109 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
110 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
111 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
112 #else
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);
117 #endif
118 }
119 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
120 {
121 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
122 GL_RENDERBUFFER, myGlDepthRBufferId);
123 }
01ca42b2 124 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
7fd59977 125 {
fd4a6963 126 Release (theGlContext.operator->());
7fd59977 127 return Standard_False;
128 }
129
18f4e8e2 130 UnbindBuffer (theGlContext);
7fd59977 131 return Standard_True;
132}
133
38a0206f 134// =======================================================================
135// function : Init
136// purpose :
137// =======================================================================
138Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
139 const GLsizei theViewportSizeX,
140 const GLsizei theViewportSizeY)
141{
142 if (myVPSizeX == theViewportSizeX
143 && myVPSizeY == theViewportSizeY)
189f85a3 144
38a0206f 145 {
146 return IsValid();
147 }
148
149 return Init (theGlContext, theViewportSizeX, theViewportSizeY);
150}
151
a2e4f780 152// =======================================================================
153// function : InitWithRB
154// purpose :
155// =======================================================================
156Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
62e1beed 157 const GLsizei theSizeX,
158 const GLsizei theSizeY,
a2e4f780 159 const GLuint theColorRBufferFromWindow)
160{
161 if (theGlCtx->arbFBO == NULL)
162 {
163 return Standard_False;
164 }
165
166 // clean up previous state
167 Release (theGlCtx.operator->());
168
a447178e 169 myIsOwnBuffer = true;
170
a2e4f780 171 // setup viewport sizes as is
62e1beed 172 myVPSizeX = theSizeX;
173 myVPSizeY = theSizeY;
174 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
175 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
a2e4f780 176
177 // Create the render-buffers
178 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
179 {
180 myGlColorRBufferId = theColorRBufferFromWindow;
181 }
182 else
183 {
184 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
185 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
62e1beed 186 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA8, aSizeX, aSizeY);
a2e4f780 187 }
188
189 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
190 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
62e1beed 191 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, aSizeX, aSizeY);
a2e4f780 192
193 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
194
195 // create FBO
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);
203#else
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);
208#endif
209 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
210 {
211 UnbindBuffer (theGlCtx);
212 Release (theGlCtx.operator->());
213 return Standard_False;
214 }
215
216 UnbindBuffer (theGlCtx);
217 return Standard_True;
218}
219
220// =======================================================================
221// function : InitWrapper
222// purpose :
223// =======================================================================
224Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
225{
226 if (theGlCtx->arbFBO == NULL)
227 {
228 return Standard_False;
229 }
230
231 // clean up previous state
232 Release (theGlCtx.operator->());
233
234 GLint anFbo = GLint(NO_FRAMEBUFFER);
235 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
236 if (anFbo == GLint(NO_FRAMEBUFFER))
237 {
238 return Standard_False;
239 }
240
241 GLint aColorType = 0;
242 GLint aColorId = 0;
243 GLint aDepthType = 0;
244 GLint aDepthId = 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);
247
248 myGlFBufferId = GLuint(anFbo);
249 myIsOwnBuffer = false;
250 if (aColorType == GL_RENDERBUFFER)
251 {
252 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
253 myGlColorRBufferId = aColorId;
254 }
255 else if (aColorType != GL_NONE)
256 {
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,
260 0,
261 GL_DEBUG_SEVERITY_HIGH_ARB,
262 aMsg);
263 }
264
265 if (aDepthType == GL_RENDERBUFFER)
266 {
267 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
268 myGlDepthRBufferId = aDepthId;
269 }
270 else if (aDepthType != GL_NONE)
271 {
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,
275 0,
276 GL_DEBUG_SEVERITY_HIGH_ARB,
277 aMsg);
278 }
279
280 // retrieve dimensions
281 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
282 if (aRBuffer != NO_RENDERBUFFER)
283 {
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);
288 }
289
290 return aRBuffer != NO_RENDERBUFFER;
291}
292
fd4a6963 293// =======================================================================
294// function : Release
295// purpose :
296// =======================================================================
10b9c7df 297void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
7fd59977 298{
18f4e8e2 299 if (isValidFrameBuffer())
7fd59977 300 {
fd4a6963 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...",);
a2e4f780 304 if (theGlCtx->IsValid()
305 && myIsOwnBuffer)
2166f0fa 306 {
01ca42b2 307 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
a2e4f780 308 if (myGlColorRBufferId != NO_RENDERBUFFER)
309 {
310 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
311 }
312 if (myGlDepthRBufferId != NO_RENDERBUFFER)
313 {
314 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
315 }
2166f0fa 316 }
a2e4f780 317 myGlFBufferId = NO_FRAMEBUFFER;
318 myGlColorRBufferId = NO_RENDERBUFFER;
319 myGlDepthRBufferId = NO_RENDERBUFFER;
320 myIsOwnBuffer = false;
7fd59977 321 }
7fd59977 322
18f4e8e2 323 myColorTexture->Release (theGlCtx);
324 myDepthStencilTexture->Release (theGlCtx);
7fd59977 325}
326
fd4a6963 327// =======================================================================
328// function : SetupViewport
329// purpose :
330// =======================================================================
331void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
332{
333 glViewport (0, 0, myVPSizeX, myVPSizeY);
334}
335
336// =======================================================================
337// function : ChangeViewport
338// purpose :
339// =======================================================================
340void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
341 const GLsizei theVPSizeY)
342{
343 myVPSizeX = theVPSizeX;
344 myVPSizeY = theVPSizeY;
345}
346
347// =======================================================================
348// function : BindBuffer
349// purpose :
350// =======================================================================
351void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
352{
01ca42b2 353 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
fd4a6963 354}
355
b86bb3df 356// =======================================================================
357// function : BindDrawBuffer
358// purpose :
359// =======================================================================
360void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
361{
362 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
363}
364
365// =======================================================================
366// function : BindReadBuffer
367// purpose :
368// =======================================================================
369void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
370{
371 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
372}
373
fd4a6963 374// =======================================================================
375// function : UnbindBuffer
376// purpose :
377// =======================================================================
378void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
379{
a2e4f780 380 if (!theGlCtx->DefaultFrameBuffer().IsNull()
381 && theGlCtx->DefaultFrameBuffer().operator->() != this)
382 {
383 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
384 }
385 else
386 {
387 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
388 }
fd4a6963 389}