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