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