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 |
22 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource) |
23 | |
3c4b62a4 |
24 | namespace |
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 |
67 | OpenGl_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 | // ======================================================================= |
89 | OpenGl_FrameBuffer::~OpenGl_FrameBuffer() |
90 | { |
91 | Release (NULL); |
92 | } |
93 | |
94 | // ======================================================================= |
95 | // function : Init |
96 | // purpose : |
97 | // ======================================================================= |
2166f0fa |
98 | Standard_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 | // ======================================================================= |
116 | Standard_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 | // ======================================================================= |
238 | Standard_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 | // ======================================================================= |
406 | Standard_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 | // ======================================================================= |
424 | Standard_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 | // ======================================================================= |
447 | Standard_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 | // ======================================================================= |
550 | Standard_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 |
625 | void 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 |
670 | void 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 | // ======================================================================= |
680 | void 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 | // ======================================================================= |
691 | void 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 | // ======================================================================= |
701 | void 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 | // ======================================================================= |
711 | void 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 | // ======================================================================= |
720 | void 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 | // ======================================================================= |
738 | inline Standard_Size getAligned (const Standard_Size theNumber, |
739 | const Standard_Size theAlignment) |
740 | { |
741 | return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment; |
742 | } |
743 | |
744 | template<typename T> |
745 | inline 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 | // ======================================================================= |
763 | Standard_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: |
782 | aFormat = GL_DEPTH_COMPONENT; |
783 | aType = GL_UNSIGNED_BYTE; |
784 | break; |
785 | case Image_Format_GrayF: |
786 | aFormat = GL_DEPTH_COMPONENT; |
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 | // ======================================================================= |
980 | Standard_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 | } |