0027341: Incorrect exact HLR results
[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
92efcf78 21IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
22
3c4b62a4 23namespace
24{
25
26 //! Determine data type from texture sized format.
27 static bool getDepthDataFormat (GLint theTextFormat,
28 GLenum& thePixelFormat,
29 GLenum& theDataType)
30 {
31 switch (theTextFormat)
32 {
33 case GL_DEPTH24_STENCIL8:
34 {
35 thePixelFormat = GL_DEPTH_STENCIL;
36 theDataType = GL_UNSIGNED_INT_24_8;
37 return true;
38 }
39 case GL_DEPTH32F_STENCIL8:
40 {
41 thePixelFormat = GL_DEPTH_STENCIL;
42 theDataType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
43 return true;
44 }
45 case GL_DEPTH_COMPONENT16:
46 {
2e26cf76 47 thePixelFormat = GL_DEPTH_COMPONENT;
3c4b62a4 48 theDataType = GL_UNSIGNED_SHORT;
49 return true;
50 }
51 case GL_DEPTH_COMPONENT24:
52 {
2e26cf76 53 thePixelFormat = GL_DEPTH_COMPONENT;
3c4b62a4 54 theDataType = GL_UNSIGNED_INT;
55 return true;
56 }
57 case GL_DEPTH_COMPONENT32F:
58 {
2e26cf76 59 thePixelFormat = GL_DEPTH_COMPONENT;
3c4b62a4 60 theDataType = GL_FLOAT;
61 return true;
62 }
63 }
64 return false;
65 }
66
67}
7fd59977 68
fd4a6963 69// =======================================================================
70// function : OpenGl_FrameBuffer
71// purpose :
72// =======================================================================
3c4b62a4 73OpenGl_FrameBuffer::OpenGl_FrameBuffer()
18f4e8e2 74: myVPSizeX (0),
7fd59977 75 myVPSizeY (0),
3c4b62a4 76 myNbSamples (0),
77 myColorFormat (GL_RGBA8),
78 myDepthFormat (GL_DEPTH24_STENCIL8),
7fd59977 79 myGlFBufferId (NO_FRAMEBUFFER),
a2e4f780 80 myGlColorRBufferId (NO_RENDERBUFFER),
81 myGlDepthRBufferId (NO_RENDERBUFFER),
82 myIsOwnBuffer (false),
18f4e8e2 83 myColorTexture (new OpenGl_Texture()),
84 myDepthStencilTexture (new OpenGl_Texture())
7fd59977 85{
86 //
87}
88
fd4a6963 89// =======================================================================
90// function : ~OpenGl_FrameBuffer
91// purpose :
92// =======================================================================
93OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
94{
95 Release (NULL);
96}
97
98// =======================================================================
99// function : Init
100// purpose :
101// =======================================================================
2166f0fa 102Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
62e1beed 103 const GLsizei theSizeX,
3c4b62a4 104 const GLsizei theSizeY,
105 const GLint theColorFormat,
106 const GLint theDepthFormat,
107 const GLsizei theNbSamples)
7fd59977 108{
3c4b62a4 109 myColorFormat = theColorFormat;
110 myDepthFormat = theDepthFormat;
111 myNbSamples = theNbSamples;
01ca42b2 112 if (theGlContext->arbFBO == NULL)
7fd59977 113 {
7fd59977 114 return Standard_False;
115 }
116
117 // clean up previous state
fd4a6963 118 Release (theGlContext.operator->());
3c4b62a4 119 if (myColorFormat == 0
120 && myDepthFormat == 0)
121 {
122 return Standard_False;
123 }
7fd59977 124
a447178e 125 myIsOwnBuffer = true;
126
7fd59977 127 // setup viewport sizes as is
62e1beed 128 myVPSizeX = theSizeX;
129 myVPSizeY = theSizeY;
130 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
131 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
7fd59977 132
18f4e8e2 133 // Create the textures (will be used as color buffer and depth-stencil buffer)
3c4b62a4 134 if (theNbSamples != 0)
7fd59977 135 {
3c4b62a4 136 if (myColorFormat != 0
137 && !myColorTexture ->Init2DMultisample (theGlContext, theNbSamples, myColorFormat, aSizeX, aSizeY))
138 {
139 Release (theGlContext.operator->());
140 return Standard_False;
141 }
142 if (myDepthFormat != 0
143 && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
144 {
145 Release (theGlContext.operator->());
146 return Standard_False;
147 }
7fd59977 148 }
3c4b62a4 149 else
fe3a29bc 150 {
3c4b62a4 151 if (myColorFormat != 0
152 && !myColorTexture->Init (theGlContext, myColorFormat,
153 GL_RGBA, GL_UNSIGNED_BYTE,
154 aSizeX, aSizeY, Graphic3d_TOT_2D))
155 {
156 Release (theGlContext.operator->());
157 return Standard_False;
158 }
fe3a29bc 159
3c4b62a4 160 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
161 // instead of just trying to create such texture
162 GLenum aPixelFormat = 0;
163 GLenum aDataType = 0;
164 if (myDepthFormat != 0
165 && getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
166 && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
167 aPixelFormat, aDataType,
168 aSizeX, aSizeY, Graphic3d_TOT_2D))
169 {
170 TCollection_ExtendedString aMsg = TCollection_ExtendedString()
171 + "Warning! Depth textures are not supported by hardware!";
3b523c4c 172 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
173 GL_DEBUG_TYPE_PORTABILITY,
3c4b62a4 174 0,
3b523c4c 175 GL_DEBUG_SEVERITY_HIGH,
3c4b62a4 176 aMsg);
177
178 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
179 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
180 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, aSizeX, aSizeY);
181 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
182 }
fe3a29bc 183 }
184
7fd59977 185 // Build FBO and setup it as texture
01ca42b2 186 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
187 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
3c4b62a4 188 if (myColorTexture->IsValid())
189 {
190 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
191 myColorTexture->GetTarget(), myColorTexture->TextureId(), 0);
192 }
fe3a29bc 193 if (myDepthStencilTexture->IsValid())
194 {
195 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
196 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
3c4b62a4 197 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
fe3a29bc 198 #else
199 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
3c4b62a4 200 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
fe3a29bc 201 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
3c4b62a4 202 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
fe3a29bc 203 #endif
204 }
205 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
206 {
207 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
208 GL_RENDERBUFFER, myGlDepthRBufferId);
209 }
01ca42b2 210 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
7fd59977 211 {
fd4a6963 212 Release (theGlContext.operator->());
7fd59977 213 return Standard_False;
214 }
215
18f4e8e2 216 UnbindBuffer (theGlContext);
7fd59977 217 return Standard_True;
218}
219
38a0206f 220// =======================================================================
221// function : Init
222// purpose :
223// =======================================================================
224Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
225 const GLsizei theViewportSizeX,
3c4b62a4 226 const GLsizei theViewportSizeY,
227 const GLint theColorFormat,
228 const GLint theDepthFormat,
229 const GLsizei theNbSamples)
38a0206f 230{
3c4b62a4 231 if (myVPSizeX == theViewportSizeX
232 && myVPSizeY == theViewportSizeY
233 && myColorFormat == theColorFormat
234 && myDepthFormat == theDepthFormat
235 && myNbSamples == theNbSamples)
38a0206f 236 {
237 return IsValid();
238 }
239
3c4b62a4 240 return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormat, theDepthFormat, theNbSamples);
38a0206f 241}
242
a2e4f780 243// =======================================================================
244// function : InitWithRB
245// purpose :
246// =======================================================================
247Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
62e1beed 248 const GLsizei theSizeX,
249 const GLsizei theSizeY,
3c4b62a4 250 const GLint theColorFormat,
251 const GLint theDepthFormat,
a2e4f780 252 const GLuint theColorRBufferFromWindow)
253{
3c4b62a4 254 myColorFormat = theColorFormat;
255 myDepthFormat = theDepthFormat;
256 myNbSamples = 0;
a2e4f780 257 if (theGlCtx->arbFBO == NULL)
258 {
259 return Standard_False;
260 }
261
262 // clean up previous state
263 Release (theGlCtx.operator->());
264
a447178e 265 myIsOwnBuffer = true;
266
a2e4f780 267 // setup viewport sizes as is
62e1beed 268 myVPSizeX = theSizeX;
269 myVPSizeY = theSizeY;
270 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
271 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
a2e4f780 272
273 // Create the render-buffers
274 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
275 {
276 myGlColorRBufferId = theColorRBufferFromWindow;
277 }
3c4b62a4 278 else if (myColorFormat != 0)
a2e4f780 279 {
280 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
281 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
3c4b62a4 282 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myColorFormat, aSizeX, aSizeY);
a2e4f780 283 }
284
3c4b62a4 285 if (myDepthFormat != 0)
286 {
287 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
288 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
289 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
290 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
291 }
a2e4f780 292
293 // create FBO
294 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
295 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
296 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
297 GL_RENDERBUFFER, myGlColorRBufferId);
3c4b62a4 298 if (myGlDepthRBufferId != NO_RENDERBUFFER)
299 {
300 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
301 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
302 GL_RENDERBUFFER, myGlDepthRBufferId);
303 #else
304 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
305 GL_RENDERBUFFER, myGlDepthRBufferId);
306 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
307 GL_RENDERBUFFER, myGlDepthRBufferId);
308 #endif
309 }
a2e4f780 310 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
311 {
312 UnbindBuffer (theGlCtx);
313 Release (theGlCtx.operator->());
314 return Standard_False;
315 }
316
317 UnbindBuffer (theGlCtx);
318 return Standard_True;
319}
320
321// =======================================================================
322// function : InitWrapper
323// purpose :
324// =======================================================================
325Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
326{
3c4b62a4 327 myNbSamples = 0;
a2e4f780 328 if (theGlCtx->arbFBO == NULL)
329 {
330 return Standard_False;
331 }
332
333 // clean up previous state
334 Release (theGlCtx.operator->());
335
336 GLint anFbo = GLint(NO_FRAMEBUFFER);
337 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
338 if (anFbo == GLint(NO_FRAMEBUFFER))
339 {
340 return Standard_False;
341 }
342
343 GLint aColorType = 0;
344 GLint aColorId = 0;
345 GLint aDepthType = 0;
346 GLint aDepthId = 0;
347 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
348 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
349
350 myGlFBufferId = GLuint(anFbo);
351 myIsOwnBuffer = false;
352 if (aColorType == GL_RENDERBUFFER)
353 {
354 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
355 myGlColorRBufferId = aColorId;
356 }
357 else if (aColorType != GL_NONE)
358 {
359 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
3b523c4c 360 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
361 GL_DEBUG_TYPE_ERROR,
a2e4f780 362 0,
3b523c4c 363 GL_DEBUG_SEVERITY_HIGH,
a2e4f780 364 aMsg);
365 }
366
367 if (aDepthType == GL_RENDERBUFFER)
368 {
369 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
370 myGlDepthRBufferId = aDepthId;
371 }
372 else if (aDepthType != GL_NONE)
373 {
374 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
3b523c4c 375 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
376 GL_DEBUG_TYPE_ERROR,
a2e4f780 377 0,
3b523c4c 378 GL_DEBUG_SEVERITY_HIGH,
a2e4f780 379 aMsg);
380 }
381
382 // retrieve dimensions
383 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
384 if (aRBuffer != NO_RENDERBUFFER)
385 {
386 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
387 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
388 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
389 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
390 }
391
392 return aRBuffer != NO_RENDERBUFFER;
393}
394
fd4a6963 395// =======================================================================
396// function : Release
397// purpose :
398// =======================================================================
10b9c7df 399void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
7fd59977 400{
18f4e8e2 401 if (isValidFrameBuffer())
7fd59977 402 {
fd4a6963 403 // application can not handle this case by exception - this is bug in code
404 Standard_ASSERT_RETURN (theGlCtx != NULL,
405 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
a2e4f780 406 if (theGlCtx->IsValid()
407 && myIsOwnBuffer)
2166f0fa 408 {
01ca42b2 409 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
a2e4f780 410 if (myGlColorRBufferId != NO_RENDERBUFFER)
411 {
412 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
413 }
414 if (myGlDepthRBufferId != NO_RENDERBUFFER)
415 {
416 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
417 }
2166f0fa 418 }
a2e4f780 419 myGlFBufferId = NO_FRAMEBUFFER;
420 myGlColorRBufferId = NO_RENDERBUFFER;
421 myGlDepthRBufferId = NO_RENDERBUFFER;
422 myIsOwnBuffer = false;
7fd59977 423 }
7fd59977 424
18f4e8e2 425 myColorTexture->Release (theGlCtx);
426 myDepthStencilTexture->Release (theGlCtx);
bf02aa7d 427
428 myVPSizeX = 0;
429 myVPSizeY = 0;
7fd59977 430}
431
fd4a6963 432// =======================================================================
433// function : SetupViewport
434// purpose :
435// =======================================================================
436void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
437{
438 glViewport (0, 0, myVPSizeX, myVPSizeY);
439}
440
441// =======================================================================
442// function : ChangeViewport
443// purpose :
444// =======================================================================
445void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
446 const GLsizei theVPSizeY)
447{
448 myVPSizeX = theVPSizeX;
449 myVPSizeY = theVPSizeY;
450}
451
452// =======================================================================
453// function : BindBuffer
454// purpose :
455// =======================================================================
456void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
457{
01ca42b2 458 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
fd4a6963 459}
460
b86bb3df 461// =======================================================================
462// function : BindDrawBuffer
463// purpose :
464// =======================================================================
465void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
466{
467 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
468}
469
470// =======================================================================
471// function : BindReadBuffer
472// purpose :
473// =======================================================================
474void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
475{
476 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
477}
478
fd4a6963 479// =======================================================================
480// function : UnbindBuffer
481// purpose :
482// =======================================================================
483void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
484{
a2e4f780 485 if (!theGlCtx->DefaultFrameBuffer().IsNull()
486 && theGlCtx->DefaultFrameBuffer().operator->() != this)
487 {
488 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
489 }
490 else
491 {
492 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
493 }
fd4a6963 494}