0030748: Visualization - Marker displayed in immediate layer ruins QT Quick view...
[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
6cde53c4 18#include <NCollection_AlignedAllocator.hxx>
fd4a6963 19#include <Standard_Assert.hxx>
a2e4f780 20#include <TCollection_ExtendedString.hxx>
fd4a6963 21
92efcf78 22IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
23
3c4b62a4 24namespace
25{
da2a6aee 26 //! Checks whether two format arrays are equal or not.
27 static bool operator== (const OpenGl_ColorFormats& theFmt1,
28 const OpenGl_ColorFormats& theFmt2)
29 {
30 if (theFmt1.Length() != theFmt2.Length())
31 return false;
32 OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
33 OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
34 for (; anIt1.More(); anIt1.Next(), anIt2.Next())
35 {
36 if (anIt1.Value() != anIt2.Value())
37 return false;
38 }
39 return true;
40 }
41}
3c4b62a4 42
da2a6aee 43// =======================================================================
44// function : getDepthDataFormat
45// purpose :
46// =======================================================================
47bool OpenGl_FrameBuffer::getDepthDataFormat (GLint theTextFormat,
48 GLenum& thePixelFormat,
49 GLenum& theDataType)
50{
51 switch (theTextFormat)
3c4b62a4 52 {
da2a6aee 53 case GL_DEPTH24_STENCIL8:
3c4b62a4 54 {
da2a6aee 55 thePixelFormat = GL_DEPTH_STENCIL;
56 theDataType = GL_UNSIGNED_INT_24_8;
57 return true;
58 }
59 case GL_DEPTH32F_STENCIL8:
60 {
61 thePixelFormat = GL_DEPTH_STENCIL;
62 theDataType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
63 return true;
64 }
65 case GL_DEPTH_COMPONENT16:
66 {
67 thePixelFormat = GL_DEPTH_COMPONENT;
68 theDataType = GL_UNSIGNED_SHORT;
69 return true;
70 }
71 case GL_DEPTH_COMPONENT24:
72 {
73 thePixelFormat = GL_DEPTH_COMPONENT;
74 theDataType = GL_UNSIGNED_INT;
75 return true;
76 }
77 case GL_DEPTH_COMPONENT32F:
78 {
79 thePixelFormat = GL_DEPTH_COMPONENT;
80 theDataType = GL_FLOAT;
81 return true;
3c4b62a4 82 }
3c4b62a4 83 }
da2a6aee 84 return false;
85}
3c4b62a4 86
da2a6aee 87// =======================================================================
88// function : getColorDataFormat
89// purpose :
90// =======================================================================
91bool OpenGl_FrameBuffer::getColorDataFormat (const Handle(OpenGl_Context)& theGlContext,
92 GLint theTextFormat,
93 GLenum& thePixelFormat,
94 GLenum& theDataType)
95{
96 switch (theTextFormat)
a1073ae2 97 {
da2a6aee 98 case GL_RGBA32F:
a1073ae2 99 {
da2a6aee 100 thePixelFormat = GL_RGBA;
101 theDataType = GL_FLOAT;
102 return true;
103 }
104 case GL_R32F:
105 {
106 thePixelFormat = GL_RED;
107 theDataType = GL_FLOAT;
108 return true;
109 }
110 case GL_RGBA16F:
111 {
112 thePixelFormat = GL_RGBA;
113 theDataType = GL_HALF_FLOAT;
114 if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
a1073ae2 115 {
da2a6aee 116 #if defined(GL_ES_VERSION_2_0)
117 theDataType = GL_HALF_FLOAT_OES;
118 #else
119 theDataType = GL_FLOAT;
120 #endif
a1073ae2 121 }
da2a6aee 122 return true;
123 }
124 case GL_R16F:
125 {
126 thePixelFormat = GL_RED;
127 theDataType = GL_HALF_FLOAT;
128 if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
a1073ae2 129 {
da2a6aee 130 #if defined(GL_ES_VERSION_2_0)
131 theDataType = GL_HALF_FLOAT_OES;
132 #else
133 theDataType = GL_FLOAT;
134 #endif
a1073ae2 135 }
da2a6aee 136 return true;
a1073ae2 137 }
da2a6aee 138 case GL_RGBA8:
139 case GL_RGBA:
a1073ae2 140 {
da2a6aee 141 thePixelFormat = GL_RGBA;
142 theDataType = GL_UNSIGNED_BYTE;
143 return true;
144 }
145 case GL_RGB8:
146 case GL_RGB:
147 {
148 thePixelFormat = GL_RGB;
149 theDataType = GL_UNSIGNED_BYTE;
150 return true;
a1073ae2 151 }
a1073ae2 152 }
da2a6aee 153 return false;
3c4b62a4 154}
7fd59977 155
fd4a6963 156// =======================================================================
157// function : OpenGl_FrameBuffer
158// purpose :
159// =======================================================================
3c4b62a4 160OpenGl_FrameBuffer::OpenGl_FrameBuffer()
a0b49de4 161: myInitVPSizeX (0),
162 myInitVPSizeY (0),
163 myVPSizeX (0),
7fd59977 164 myVPSizeY (0),
3c4b62a4 165 myNbSamples (0),
3c4b62a4 166 myDepthFormat (GL_DEPTH24_STENCIL8),
7fd59977 167 myGlFBufferId (NO_FRAMEBUFFER),
a2e4f780 168 myGlColorRBufferId (NO_RENDERBUFFER),
169 myGlDepthRBufferId (NO_RENDERBUFFER),
170 myIsOwnBuffer (false),
12d6e155 171 myIsOwnDepth (false),
18f4e8e2 172 myDepthStencilTexture (new OpenGl_Texture())
7fd59977 173{
a1073ae2 174 myColorFormats.Append (GL_RGBA8);
175 myColorTextures.Append (new OpenGl_Texture());
7fd59977 176}
177
fd4a6963 178// =======================================================================
179// function : ~OpenGl_FrameBuffer
180// purpose :
181// =======================================================================
182OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
183{
184 Release (NULL);
185}
186
187// =======================================================================
188// function : Init
189// purpose :
190// =======================================================================
2166f0fa 191Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
a1073ae2 192 const GLsizei theSizeX,
193 const GLsizei theSizeY,
194 const GLint theColorFormat,
195 const GLint theDepthFormat,
196 const GLsizei theNbSamples)
7fd59977 197{
a1073ae2 198 OpenGl_ColorFormats aColorFormats;
199
200 aColorFormats.Append (theColorFormat);
201
202 return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples);
203}
204
205// =======================================================================
206// function : Init
207// purpose :
208// =======================================================================
209Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
210 const GLsizei theSizeX,
211 const GLsizei theSizeY,
212 const OpenGl_ColorFormats& theColorFormats,
213 const Handle(OpenGl_Texture)& theDepthStencilTexture,
214 const GLsizei theNbSamples)
215{
216 myColorFormats = theColorFormats;
217
218 OpenGl_TextureArray aTextures (myColorTextures);
219 if (!myColorTextures.IsEmpty())
220 {
221 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
222 {
223 aTextureIt.Value()->Release (theGlContext.operator->());
224 }
225 myColorTextures.Clear();
226 }
227 for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
228 {
229 myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
230 }
231
232 myDepthFormat = theDepthStencilTexture->GetFormat();
233 myNbSamples = theNbSamples;
234 if (theGlContext->arbFBO == NULL)
235 {
236 return Standard_False;
237 }
238
239 // clean up previous state
240 Release (theGlContext.operator->());
241 if (myColorFormats.IsEmpty()
242 && myDepthFormat == 0)
243 {
244 return Standard_False;
245 }
246
247 myDepthStencilTexture = theDepthStencilTexture;
248 myIsOwnDepth = false;
249 myIsOwnBuffer = true;
250
251 // setup viewport sizes as is
252 myVPSizeX = theSizeX;
253 myVPSizeY = theSizeY;
254 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
255 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
256
257 // Create the textures (will be used as color buffer and depth-stencil buffer)
258 if (theNbSamples != 0)
259 {
260 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
261 {
262 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
263 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
264 if (aColorFormat != 0
265 && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
266 aColorFormat, aSizeX, aSizeY))
267 {
268 Release (theGlContext.operator->());
269 return Standard_False;
270 }
271 }
272 }
273 else
274 {
275 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
276 {
277 GLenum aPixelFormat = 0;
278 GLenum aDataType = 0;
279 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
280 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
281 if (aColorFormat != 0
177781da 282 && getColorDataFormat (theGlContext, aColorFormat, aPixelFormat, aDataType)
a1073ae2 283 && !aColorTexture->Init (theGlContext, aColorFormat,
284 aPixelFormat, aDataType,
285 aSizeX, aSizeY, Graphic3d_TOT_2D))
286 {
287 Release (theGlContext.operator->());
288 return Standard_False;
289 }
290 }
291 }
292
293 // Build FBO and setup it as texture
294 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
295 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
296
297 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
298 {
299 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
300 if (aColorTexture->IsValid())
301 {
302 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
303 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
304 }
305 }
306 if (myDepthStencilTexture->IsValid())
307 {
308 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
309 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
310 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
311 #else
312 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
313 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
314 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
315 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
316 #endif
317 }
318 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
319 {
320 Release (theGlContext.operator->());
321 return Standard_False;
322 }
323
324 UnbindBuffer (theGlContext);
325 return Standard_True;
326}
327
328// =======================================================================
329// function : Init
330// purpose :
331// =======================================================================
332Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
333 const GLsizei theSizeX,
334 const GLsizei theSizeY,
335 const OpenGl_ColorFormats& theColorFormats,
336 const GLint theDepthFormat,
337 const GLsizei theNbSamples)
338{
339 myColorFormats = theColorFormats;
340
341 OpenGl_TextureArray aTextures (myColorTextures);
342 if (!myColorTextures.IsEmpty())
343 {
344 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
345 {
346 aTextureIt.Value()->Release (theGlContext.operator->());
347 }
348 myColorTextures.Clear();
349 }
350 for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
351 {
352 myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
353 }
354
3c4b62a4 355 myDepthFormat = theDepthFormat;
356 myNbSamples = theNbSamples;
a0b49de4 357 myInitVPSizeX = theSizeX;
358 myInitVPSizeY = theSizeY;
01ca42b2 359 if (theGlContext->arbFBO == NULL)
7fd59977 360 {
7fd59977 361 return Standard_False;
362 }
363
364 // clean up previous state
fd4a6963 365 Release (theGlContext.operator->());
a1073ae2 366 if (myColorFormats.IsEmpty()
3c4b62a4 367 && myDepthFormat == 0)
368 {
369 return Standard_False;
370 }
7fd59977 371
a447178e 372 myIsOwnBuffer = true;
a1073ae2 373 myIsOwnDepth = true;
a447178e 374
7fd59977 375 // setup viewport sizes as is
62e1beed 376 myVPSizeX = theSizeX;
377 myVPSizeY = theSizeY;
378 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
379 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
e473b95f 380 bool hasStencilRB = false;
7fd59977 381
18f4e8e2 382 // Create the textures (will be used as color buffer and depth-stencil buffer)
3c4b62a4 383 if (theNbSamples != 0)
7fd59977 384 {
a1073ae2 385 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
3c4b62a4 386 {
a1073ae2 387 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
388 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
389 if (aColorFormat != 0
390 && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
391 {
392 Release (theGlContext.operator->());
393 return Standard_False;
394 }
3c4b62a4 395 }
396 if (myDepthFormat != 0
397 && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
398 {
399 Release (theGlContext.operator->());
400 return Standard_False;
401 }
7fd59977 402 }
3c4b62a4 403 else
fe3a29bc 404 {
a1073ae2 405 GLenum aPixelFormat = 0;
406 GLenum aDataType = 0;
407
408 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
3c4b62a4 409 {
a1073ae2 410 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
411 const GLint aColorFormat = myColorFormats (aColorBufferIdx);
412 if (aColorFormat != 0
177781da 413 && getColorDataFormat (theGlContext, aColorFormat, aPixelFormat, aDataType)
a1073ae2 414 && !aColorTexture->Init (theGlContext, aColorFormat,
415 aPixelFormat, aDataType,
416 aSizeX, aSizeY, Graphic3d_TOT_2D))
417 {
418 Release (theGlContext.operator->());
419 return Standard_False;
420 }
3c4b62a4 421 }
fe3a29bc 422
3c4b62a4 423 // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
424 // instead of just trying to create such texture
3c4b62a4 425 if (myDepthFormat != 0
426 && getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
427 && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
428 aPixelFormat, aDataType,
429 aSizeX, aSizeY, Graphic3d_TOT_2D))
430 {
431 TCollection_ExtendedString aMsg = TCollection_ExtendedString()
432 + "Warning! Depth textures are not supported by hardware!";
3b523c4c 433 theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
434 GL_DEBUG_TYPE_PORTABILITY,
3c4b62a4 435 0,
3b523c4c 436 GL_DEBUG_SEVERITY_HIGH,
3c4b62a4 437 aMsg);
438
e473b95f 439 hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL
440 && theGlContext->extPDS;
441 GLint aDepthStencilFormat = hasStencilRB
442 ? GL_DEPTH24_STENCIL8
443 : GL_DEPTH_COMPONENT16;
444
3c4b62a4 445 theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
446 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
e473b95f 447 theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
3c4b62a4 448 theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
449 }
fe3a29bc 450 }
451
7fd59977 452 // Build FBO and setup it as texture
01ca42b2 453 theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
454 theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
a1073ae2 455 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
3c4b62a4 456 {
a1073ae2 457 const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
458 if (aColorTexture->IsValid())
459 {
460 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
461 aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
462 }
3c4b62a4 463 }
fe3a29bc 464 if (myDepthStencilTexture->IsValid())
465 {
466 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
467 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
3c4b62a4 468 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
fe3a29bc 469 #else
470 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
3c4b62a4 471 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
fe3a29bc 472 theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
3c4b62a4 473 myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
fe3a29bc 474 #endif
475 }
476 else if (myGlDepthRBufferId != NO_RENDERBUFFER)
477 {
e473b95f 478 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
479 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
480 GL_RENDERBUFFER, myGlDepthRBufferId);
481 #else
fe3a29bc 482 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
483 GL_RENDERBUFFER, myGlDepthRBufferId);
e473b95f 484 if (hasStencilRB)
485 {
486 theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
487 GL_RENDERBUFFER, myGlDepthRBufferId);
488 }
489 #endif
fe3a29bc 490 }
01ca42b2 491 if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
7fd59977 492 {
fd4a6963 493 Release (theGlContext.operator->());
7fd59977 494 return Standard_False;
495 }
496
18f4e8e2 497 UnbindBuffer (theGlContext);
7fd59977 498 return Standard_True;
499}
500
fd4a6963 501// =======================================================================
a1073ae2 502// function : InitLazy
38a0206f 503// purpose :
504// =======================================================================
505Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
506 const GLsizei theViewportSizeX,
3c4b62a4 507 const GLsizei theViewportSizeY,
508 const GLint theColorFormat,
509 const GLint theDepthFormat,
510 const GLsizei theNbSamples)
38a0206f 511{
a1073ae2 512 OpenGl_ColorFormats aColorFormats;
513
514 aColorFormats.Append (theColorFormat);
515
516 return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples);
517}
518
519// =======================================================================
520// function : InitLazy
521// purpose :
522// =======================================================================
523Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
524 const GLsizei theViewportSizeX,
525 const GLsizei theViewportSizeY,
526 const OpenGl_ColorFormats& theColorFormats,
527 const GLint theDepthFormat,
528 const GLsizei theNbSamples)
529{
530 if (myVPSizeX == theViewportSizeX
531 && myVPSizeY == theViewportSizeY
532 && myColorFormats == theColorFormats
533 && myDepthFormat == theDepthFormat
534 && myNbSamples == theNbSamples)
38a0206f 535 {
536 return IsValid();
537 }
538
a1073ae2 539 return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples);
38a0206f 540}
541
542// =======================================================================
a2e4f780 543// function : InitWithRB
544// purpose :
545// =======================================================================
546Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
62e1beed 547 const GLsizei theSizeX,
548 const GLsizei theSizeY,
3c4b62a4 549 const GLint theColorFormat,
550 const GLint theDepthFormat,
a2e4f780 551 const GLuint theColorRBufferFromWindow)
552{
a1073ae2 553 myColorFormats.Clear();
554 myColorFormats.Append (theColorFormat);
555 if (!myColorTextures.IsEmpty())
556 {
557 Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
558 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
559 {
560 aTextureIt.Value()->Release (theGlCtx.operator->());
561 }
562 myColorTextures.Clear();
563 myColorTextures.Append (aTexutre);
564 }
565
3c4b62a4 566 myDepthFormat = theDepthFormat;
567 myNbSamples = 0;
a0b49de4 568 myInitVPSizeX = theSizeX;
569 myInitVPSizeY = theSizeY;
a2e4f780 570 if (theGlCtx->arbFBO == NULL)
571 {
572 return Standard_False;
573 }
574
575 // clean up previous state
576 Release (theGlCtx.operator->());
577
a447178e 578 myIsOwnBuffer = true;
a1073ae2 579 myIsOwnDepth = true;
a447178e 580
a2e4f780 581 // setup viewport sizes as is
62e1beed 582 myVPSizeX = theSizeX;
583 myVPSizeY = theSizeY;
584 const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
585 const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
a2e4f780 586
587 // Create the render-buffers
588 if (theColorRBufferFromWindow != NO_RENDERBUFFER)
589 {
590 myGlColorRBufferId = theColorRBufferFromWindow;
591 }
a1073ae2 592 else if (theColorFormat != 0)
a2e4f780 593 {
594 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
595 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
a1073ae2 596 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
a2e4f780 597 }
598
e473b95f 599 bool hasStencilRB = false;
3c4b62a4 600 if (myDepthFormat != 0)
601 {
e473b95f 602 GLenum aPixelFormat = 0;
603 GLenum aDataType = 0;
604 getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType);
605 hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL;
606
3c4b62a4 607 theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
608 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
609 theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
610 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
611 }
a2e4f780 612
613 // create FBO
614 theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
615 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
616 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
617 GL_RENDERBUFFER, myGlColorRBufferId);
3c4b62a4 618 if (myGlDepthRBufferId != NO_RENDERBUFFER)
619 {
620 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
e473b95f 621 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
3c4b62a4 622 GL_RENDERBUFFER, myGlDepthRBufferId);
623 #else
624 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
625 GL_RENDERBUFFER, myGlDepthRBufferId);
e473b95f 626 if (hasStencilRB)
627 {
628 theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
629 GL_RENDERBUFFER, myGlDepthRBufferId);
630 }
3c4b62a4 631 #endif
632 }
a2e4f780 633 if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
634 {
635 UnbindBuffer (theGlCtx);
636 Release (theGlCtx.operator->());
637 return Standard_False;
638 }
639
640 UnbindBuffer (theGlCtx);
641 return Standard_True;
642}
643
644// =======================================================================
645// function : InitWrapper
646// purpose :
647// =======================================================================
648Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
649{
3c4b62a4 650 myNbSamples = 0;
a2e4f780 651 if (theGlCtx->arbFBO == NULL)
652 {
653 return Standard_False;
654 }
655
656 // clean up previous state
657 Release (theGlCtx.operator->());
658
659 GLint anFbo = GLint(NO_FRAMEBUFFER);
660 ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
661 if (anFbo == GLint(NO_FRAMEBUFFER))
662 {
663 return Standard_False;
664 }
665
666 GLint aColorType = 0;
667 GLint aColorId = 0;
668 GLint aDepthType = 0;
669 GLint aDepthId = 0;
670 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
671 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
672
673 myGlFBufferId = GLuint(anFbo);
674 myIsOwnBuffer = false;
a1073ae2 675 myIsOwnDepth = false;
a2e4f780 676 if (aColorType == GL_RENDERBUFFER)
677 {
678 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
679 myGlColorRBufferId = aColorId;
680 }
681 else if (aColorType != GL_NONE)
682 {
683 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
3b523c4c 684 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
685 GL_DEBUG_TYPE_ERROR,
a2e4f780 686 0,
3b523c4c 687 GL_DEBUG_SEVERITY_HIGH,
a2e4f780 688 aMsg);
689 }
690
691 if (aDepthType == GL_RENDERBUFFER)
692 {
693 theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
694 myGlDepthRBufferId = aDepthId;
695 }
696 else if (aDepthType != GL_NONE)
697 {
698 TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
3b523c4c 699 theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
700 GL_DEBUG_TYPE_ERROR,
a2e4f780 701 0,
3b523c4c 702 GL_DEBUG_SEVERITY_HIGH,
a2e4f780 703 aMsg);
704 }
705
706 // retrieve dimensions
707 GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
708 if (aRBuffer != NO_RENDERBUFFER)
709 {
710 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
711 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
712 theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
713 theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
714 }
715
716 return aRBuffer != NO_RENDERBUFFER;
717}
718
719// =======================================================================
fd4a6963 720// function : Release
721// purpose :
722// =======================================================================
10b9c7df 723void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
7fd59977 724{
18f4e8e2 725 if (isValidFrameBuffer())
7fd59977 726 {
fd4a6963 727 // application can not handle this case by exception - this is bug in code
728 Standard_ASSERT_RETURN (theGlCtx != NULL,
729 "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
a2e4f780 730 if (theGlCtx->IsValid()
731 && myIsOwnBuffer)
2166f0fa 732 {
01ca42b2 733 theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
a2e4f780 734 if (myGlColorRBufferId != NO_RENDERBUFFER)
735 {
736 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
737 }
738 if (myGlDepthRBufferId != NO_RENDERBUFFER)
739 {
740 theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
741 }
2166f0fa 742 }
a2e4f780 743 myGlFBufferId = NO_FRAMEBUFFER;
744 myGlColorRBufferId = NO_RENDERBUFFER;
745 myGlDepthRBufferId = NO_RENDERBUFFER;
746 myIsOwnBuffer = false;
7fd59977 747 }
7fd59977 748
a1073ae2 749 for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
750 {
751 myColorTextures (aColorBufferIdx)->Release (theGlCtx);
752 }
753
754 if (myIsOwnDepth)
755 {
756 myDepthStencilTexture->Release (theGlCtx);
757 myIsOwnDepth = false;
758 }
bf02aa7d 759
760 myVPSizeX = 0;
761 myVPSizeY = 0;
7fd59977 762}
763
fd4a6963 764// =======================================================================
fd4a6963 765// function : SetupViewport
766// purpose :
767// =======================================================================
3bffef55 768void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
fd4a6963 769{
3bffef55 770 const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
771 theGlCtx->ResizeViewport (aViewport);
fd4a6963 772}
773
774// =======================================================================
775// function : ChangeViewport
776// purpose :
777// =======================================================================
778void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX,
779 const GLsizei theVPSizeY)
780{
781 myVPSizeX = theVPSizeX;
782 myVPSizeY = theVPSizeY;
783}
784
785// =======================================================================
786// function : BindBuffer
787// purpose :
788// =======================================================================
789void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
790{
01ca42b2 791 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
fd4a6963 792}
793
794// =======================================================================
b86bb3df 795// function : BindDrawBuffer
796// purpose :
797// =======================================================================
798void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
799{
800 theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
801}
802
803// =======================================================================
804// function : BindReadBuffer
805// purpose :
806// =======================================================================
807void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
808{
809 theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
810}
811
812// =======================================================================
fd4a6963 813// function : UnbindBuffer
814// purpose :
815// =======================================================================
816void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
817{
a2e4f780 818 if (!theGlCtx->DefaultFrameBuffer().IsNull()
819 && theGlCtx->DefaultFrameBuffer().operator->() != this)
820 {
821 theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
822 }
823 else
824 {
825 theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
826 }
fd4a6963 827}
6cde53c4 828
829// =======================================================================
830// function : getAligned
831// purpose :
832// =======================================================================
833inline Standard_Size getAligned (const Standard_Size theNumber,
834 const Standard_Size theAlignment)
835{
836 return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment;
837}
838
839template<typename T>
840inline void convertRowFromRgba (T* theRgbRow,
841 const Image_ColorRGBA* theRgbaRow,
842 const Standard_Size theWidth)
843{
844 for (Standard_Size aCol = 0; aCol < theWidth; ++aCol)
845 {
846 const Image_ColorRGBA& anRgba = theRgbaRow[aCol];
847 T& anRgb = theRgbRow[aCol];
848 anRgb.r() = anRgba.r();
849 anRgb.g() = anRgba.g();
850 anRgb.b() = anRgba.b();
851 }
852}
853
854// =======================================================================
855// function : BufferDump
856// purpose :
857// =======================================================================
858Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& theGlCtx,
859 const Handle(OpenGl_FrameBuffer)& theFbo,
860 Image_PixMap& theImage,
861 Graphic3d_BufferType theBufferType)
862{
863 if (theGlCtx.IsNull()
864 || theImage.IsEmpty())
865 {
866 return Standard_False;
867 }
868
869 GLenum aFormat = 0;
870 GLenum aType = 0;
871 bool toSwapRgbaBgra = false;
872 bool toConvRgba2Rgb = false;
873 switch (theImage.Format())
874 {
875 #if !defined(GL_ES_VERSION_2_0)
876 case Image_Format_Gray:
877 aFormat = GL_DEPTH_COMPONENT;
878 aType = GL_UNSIGNED_BYTE;
879 break;
880 case Image_Format_GrayF:
881 aFormat = GL_DEPTH_COMPONENT;
882 aType = GL_FLOAT;
883 break;
884 case Image_Format_RGB:
885 aFormat = GL_RGB;
886 aType = GL_UNSIGNED_BYTE;
887 break;
888 case Image_Format_BGR:
889 aFormat = GL_BGR;
890 aType = GL_UNSIGNED_BYTE;
891 break;
892 case Image_Format_BGRA:
893 case Image_Format_BGR32:
894 aFormat = GL_BGRA;
895 aType = GL_UNSIGNED_BYTE;
896 break;
897 case Image_Format_BGRF:
898 aFormat = GL_BGR;
899 aType = GL_FLOAT;
900 break;
901 case Image_Format_BGRAF:
902 aFormat = GL_BGRA;
903 aType = GL_FLOAT;
904 break;
905 #else
906 case Image_Format_Gray:
907 case Image_Format_GrayF:
908 case Image_Format_BGRF:
909 case Image_Format_BGRAF:
910 return Standard_False;
911 case Image_Format_BGRA:
912 case Image_Format_BGR32:
913 aFormat = GL_RGBA;
914 aType = GL_UNSIGNED_BYTE;
915 toSwapRgbaBgra = true;
916 break;
917 case Image_Format_BGR:
918 case Image_Format_RGB:
919 aFormat = GL_RGBA;
920 aType = GL_UNSIGNED_BYTE;
921 toConvRgba2Rgb = true;
922 break;
923 #endif
924 case Image_Format_RGBA:
925 case Image_Format_RGB32:
926 aFormat = GL_RGBA;
927 aType = GL_UNSIGNED_BYTE;
928 break;
929 case Image_Format_RGBF:
930 aFormat = GL_RGB;
931 aType = GL_FLOAT;
932 break;
933 case Image_Format_RGBAF:
934 aFormat = GL_RGBA;
935 aType = GL_FLOAT;
936 break;
937 case Image_Format_Alpha:
938 case Image_Format_AlphaF:
939 return Standard_False; // GL_ALPHA is no more supported in core context
940 case Image_Format_UNKNOWN:
941 return Standard_False;
942 }
943
944 if (aFormat == 0)
945 {
946 return Standard_False;
947 }
948
949#if !defined(GL_ES_VERSION_2_0)
950 GLint aReadBufferPrev = GL_BACK;
951 if (theBufferType == Graphic3d_BT_Depth
952 && aFormat != GL_DEPTH_COMPONENT)
953 {
954 return Standard_False;
955 }
956#else
957 (void )theBufferType;
958#endif
959
960 // bind FBO if used
961 if (!theFbo.IsNull() && theFbo->IsValid())
962 {
963 theFbo->BindBuffer (theGlCtx);
964 }
965 else
966 {
967 #if !defined(GL_ES_VERSION_2_0)
968 glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
969 GLint aDrawBufferPrev = GL_BACK;
970 glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
971 glReadBuffer (aDrawBufferPrev);
972 #endif
973 }
974
975 // setup alignment
976 const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
977 glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
978 bool isBatchCopy = !theImage.IsTopDown();
979
980 const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
981 GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
982 Standard_Size aSizeRowBytesEstim = getAligned (theImage.SizePixelBytes() * aPixelsWidth, anAligment);
983 if (anExtraBytes < anAligment)
984 {
985 aPixelsWidth = 0;
986 }
987 else if (aSizeRowBytesEstim != theImage.SizeRowBytes())
988 {
989 aPixelsWidth = 0;
990 isBatchCopy = false;
991 }
992#if !defined(GL_ES_VERSION_2_0)
993 glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
994#else
995 if (aPixelsWidth != 0)
996 {
997 isBatchCopy = false;
998 }
999#endif
1000 if (toConvRgba2Rgb)
1001 {
1002 Handle(NCollection_BaseAllocator) anAlloc = new NCollection_AlignedAllocator (16);
1003 const Standard_Size aRowSize = theImage.SizeX() * 4;
1004 NCollection_Buffer aRowBuffer (anAlloc);
1005 if (!aRowBuffer.Allocate (aRowSize))
1006 {
1007 return Standard_False;
1008 }
1009
1010 for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1011 {
1012 // Image_PixMap rows indexation always starts from the upper corner
1013 // while order in memory depends on the flag and processed by ChangeRow() method
1014 glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
1015 const Image_ColorRGBA* aRowDataRgba = (const Image_ColorRGBA* )aRowBuffer.Data();
1016 if (theImage.Format() == Image_Format_BGR)
1017 {
1018 convertRowFromRgba ((Image_ColorBGR* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1019 }
1020 else
1021 {
1022 convertRowFromRgba ((Image_ColorRGB* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
1023 }
1024 }
1025 }
1026 else if (!isBatchCopy)
1027 {
1028 // copy row by row
1029 for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
1030 {
1031 // Image_PixMap rows indexation always starts from the upper corner
1032 // while order in memory depends on the flag and processed by ChangeRow() method
1033 glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
1034 }
1035 }
1036 else
1037 {
1038 glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
1039 }
1040 const bool hasErrors = theGlCtx->ResetErrors (true);
1041
1042 glPixelStorei (GL_PACK_ALIGNMENT, 1);
1043#if !defined(GL_ES_VERSION_2_0)
1044 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
1045#endif
1046
1047 if (!theFbo.IsNull() && theFbo->IsValid())
1048 {
1049 theFbo->UnbindBuffer (theGlCtx);
1050 }
1051 else
1052 {
1053 #if !defined(GL_ES_VERSION_2_0)
1054 glReadBuffer (aReadBufferPrev);
1055 #endif
1056 }
1057
1058 if (toSwapRgbaBgra)
1059 {
1060 Image_PixMap::SwapRgbaBgra (theImage);
1061 }
1062
1063 return !hasErrors;
1064}
15669413 1065
1066// =======================================================================
1067// function : EstimatedDataSize
1068// purpose :
1069// =======================================================================
1070Standard_Size OpenGl_FrameBuffer::EstimatedDataSize() const
1071{
1072 if (!IsValid())
1073 {
1074 return 0;
1075 }
1076
1077 Standard_Size aSize = 0;
1078 for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
1079 {
1080 aSize += aTextureIt.Value()->EstimatedDataSize();
1081 }
1082 if (!myDepthStencilTexture.IsNull())
1083 {
1084 aSize += myDepthStencilTexture->EstimatedDataSize();
1085 }
1086 if (myGlColorRBufferId != NO_RENDERBUFFER
1087 && !myColorFormats.IsEmpty())
1088 {
1089 aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myColorFormats.First()) * myInitVPSizeX * myInitVPSizeY;
1090 }
1091 if (myGlDepthRBufferId != NO_RENDERBUFFER)
1092 {
1093 aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myDepthFormat) * myInitVPSizeX * myInitVPSizeY;
1094 }
1095 return aSize;
1096}