0024023: Revamp the OCCT Handle -- automatic
[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,
fd4a6963 54 const GLsizei theViewportSizeX,
18f4e8e2 55 const GLsizei theViewportSizeY)
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
7fd59977 65 // setup viewport sizes as is
66 myVPSizeX = theViewportSizeX;
67 myVPSizeY = theViewportSizeY;
68
18f4e8e2 69 // Create the textures (will be used as color buffer and depth-stencil buffer)
fe3a29bc 70 if (!myColorTexture->Init (theGlContext, myTextFormat,
71 GL_RGBA, GL_UNSIGNED_BYTE,
72 myVPSizeX, myVPSizeY, Graphic3d_TOT_2D))
7fd59977 73 {
fd4a6963 74 Release (theGlContext.operator->());
7fd59977 75 return Standard_False;
76 }
77
fe3a29bc 78 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
79 // instead of just trying to create such texture
80 if (!myDepthStencilTexture->Init (theGlContext, GL_DEPTH24_STENCIL8,
81 GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
82 myVPSizeX, myVPSizeY, Graphic3d_TOT_2D))
83 {
84 TCollection_ExtendedString aMsg = TCollection_ExtendedString()
85 + "Warning! Depth textures are not supported by hardware!";
86 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
87 GL_DEBUG_TYPE_PORTABILITY_ARB,
88 0,
89 GL_DEBUG_SEVERITY_HIGH_ARB,
90 aMsg);
91
92 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
93 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
94 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, myVPSizeX, myVPSizeY);
95 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
96 }
97
7fd59977 98 // Build FBO and setup it as texture
01ca42b2 99 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
100 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
18f4e8e2 101 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
102 GL_TEXTURE_2D, myColorTexture->TextureId(), 0);
fe3a29bc 103 if (myDepthStencilTexture->IsValid())
104 {
105 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
106 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
107 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
108 #else
109 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
110 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
111 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
112 GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
113 #endif
114 }
115 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
116 {
117 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
118 GL_RENDERBUFFER, myGlDepthRBufferId);
119 }
01ca42b2 120 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
7fd59977 121 {
fd4a6963 122 Release (theGlContext.operator->());
7fd59977 123 return Standard_False;
124 }
125
18f4e8e2 126 UnbindBuffer (theGlContext);
7fd59977 127 return Standard_True;
128}
129
38a0206f 130// =======================================================================
131// function : Init
132// purpose :
133// =======================================================================
134Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
135 const GLsizei theViewportSizeX,
136 const GLsizei theViewportSizeY)
137{
138 if (myVPSizeX == theViewportSizeX
139 && myVPSizeY == theViewportSizeY)
189f85a3 140
38a0206f 141 {
142 return IsValid();
143 }
144
145 return Init (theGlContext, theViewportSizeX, theViewportSizeY);
146}
147
a2e4f780 148// =======================================================================
149// function : InitWithRB
150// purpose :
151// =======================================================================
152Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
153 const GLsizei theViewportSizeX,
154 const GLsizei theViewportSizeY,
155 const GLuint theColorRBufferFromWindow)
156{
157 if (theGlCtx->arbFBO == NULL)
158 {
159 return Standard_False;
160 }
161
162 // clean up previous state
163 Release (theGlCtx.operator->());
164
165 // setup viewport sizes as is
166 myVPSizeX = theViewportSizeX;
167 myVPSizeY = theViewportSizeY;
168
169 // Create the render-buffers
170 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
171 {
172 myGlColorRBufferId = theColorRBufferFromWindow;
173 }
174 else
175 {
176 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
177 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
178 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA8, myVPSizeX, myVPSizeY);
179 }
180
181 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
182 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
183 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, myVPSizeX, myVPSizeY);
184
185 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
186
187 // create FBO
188 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
189 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
190 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
191 GL_RENDERBUFFER, myGlColorRBufferId);
192#ifdef GL_DEPTH_STENCIL_ATTACHMENT
193 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
194 GL_RENDERBUFFER, myGlDepthRBufferId);
195#else
196 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
197 GL_RENDERBUFFER, myGlDepthRBufferId);
198 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
199 GL_RENDERBUFFER, myGlDepthRBufferId);
200#endif
201 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
202 {
203 UnbindBuffer (theGlCtx);
204 Release (theGlCtx.operator->());
205 return Standard_False;
206 }
207
208 UnbindBuffer (theGlCtx);
209 return Standard_True;
210}
211
212// =======================================================================
213// function : InitWrapper
214// purpose :
215// =======================================================================
216Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
217{
218 if (theGlCtx->arbFBO == NULL)
219 {
220 return Standard_False;
221 }
222
223 // clean up previous state
224 Release (theGlCtx.operator->());
225
226 GLint anFbo = GLint(NO_FRAMEBUFFER);
227 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
228 if (anFbo == GLint(NO_FRAMEBUFFER))
229 {
230 return Standard_False;
231 }
232
233 GLint aColorType = 0;
234 GLint aColorId = 0;
235 GLint aDepthType = 0;
236 GLint aDepthId = 0;
237 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
238 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
239
240 myGlFBufferId = GLuint(anFbo);
241 myIsOwnBuffer = false;
242 if (aColorType == GL_RENDERBUFFER)
243 {
244 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
245 myGlColorRBufferId = aColorId;
246 }
247 else if (aColorType != GL_NONE)
248 {
249 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
250 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
251 GL_DEBUG_TYPE_ERROR_ARB,
252 0,
253 GL_DEBUG_SEVERITY_HIGH_ARB,
254 aMsg);
255 }
256
257 if (aDepthType == GL_RENDERBUFFER)
258 {
259 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
260 myGlDepthRBufferId = aDepthId;
261 }
262 else if (aDepthType != GL_NONE)
263 {
264 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
265 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
266 GL_DEBUG_TYPE_ERROR_ARB,
267 0,
268 GL_DEBUG_SEVERITY_HIGH_ARB,
269 aMsg);
270 }
271
272 // retrieve dimensions
273 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
274 if (aRBuffer != NO_RENDERBUFFER)
275 {
276 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
277 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
278 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
279 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
280 }
281
282 return aRBuffer != NO_RENDERBUFFER;
283}
284
fd4a6963 285// =======================================================================
286// function : Release
287// purpose :
288// =======================================================================
10b9c7df 289void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
7fd59977 290{
18f4e8e2 291 if (isValidFrameBuffer())
7fd59977 292 {
fd4a6963 293 // application can not handle this case by exception - this is bug in code
294 Standard_ASSERT_RETURN (theGlCtx != NULL,
295 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
a2e4f780 296 if (theGlCtx->IsValid()
297 && myIsOwnBuffer)
2166f0fa 298 {
01ca42b2 299 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
a2e4f780 300 if (myGlColorRBufferId != NO_RENDERBUFFER)
301 {
302 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
303 }
304 if (myGlDepthRBufferId != NO_RENDERBUFFER)
305 {
306 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
307 }
2166f0fa 308 }
a2e4f780 309 myGlFBufferId = NO_FRAMEBUFFER;
310 myGlColorRBufferId = NO_RENDERBUFFER;
311 myGlDepthRBufferId = NO_RENDERBUFFER;
312 myIsOwnBuffer = false;
7fd59977 313 }
7fd59977 314
18f4e8e2 315 myColorTexture->Release (theGlCtx);
316 myDepthStencilTexture->Release (theGlCtx);
7fd59977 317}
318
fd4a6963 319// =======================================================================
320// function : SetupViewport
321// purpose :
322// =======================================================================
323void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
324{
325 glViewport (0, 0, myVPSizeX, myVPSizeY);
326}
327
328// =======================================================================
329// function : ChangeViewport
330// purpose :
331// =======================================================================
332void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
333 const GLsizei theVPSizeY)
334{
335 myVPSizeX = theVPSizeX;
336 myVPSizeY = theVPSizeY;
337}
338
339// =======================================================================
340// function : BindBuffer
341// purpose :
342// =======================================================================
343void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
344{
01ca42b2 345 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
fd4a6963 346}
347
b86bb3df 348// =======================================================================
349// function : BindDrawBuffer
350// purpose :
351// =======================================================================
352void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
353{
354 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
355}
356
357// =======================================================================
358// function : BindReadBuffer
359// purpose :
360// =======================================================================
361void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
362{
363 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
364}
365
fd4a6963 366// =======================================================================
367// function : UnbindBuffer
368// purpose :
369// =======================================================================
370void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
371{
a2e4f780 372 if (!theGlCtx->DefaultFrameBuffer().IsNull()
373 && theGlCtx->DefaultFrameBuffer().operator->() != this)
374 {
375 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
376 }
377 else
378 {
379 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
380 }
fd4a6963 381}