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