b311480e |
1 | // Created by: Kirill GAVRILOV |
973c2be1 |
2 | // Copyright (c) 2011-2014 OPEN CASCADE SAS |
b311480e |
3 | // |
973c2be1 |
4 | // This file is part of Open CASCADE Technology software library. |
b311480e |
5 | // |
d5f74e42 |
6 | // This library is free software; you can redistribute it and/or modify it under |
7 | // the terms of the GNU Lesser General Public License version 2.1 as published |
973c2be1 |
8 | // by the Free Software Foundation, with special exception defined in the file |
9 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
10 | // distribution for complete text of the license and disclaimer of any warranty. |
b311480e |
11 | // |
973c2be1 |
12 | // Alternatively, this file may be used under the terms of Open CASCADE |
13 | // commercial license or contractual agreement. |
b311480e |
14 | |
7fd59977 |
15 | #include <OpenGl_FrameBuffer.hxx> |
01ca42b2 |
16 | #include <OpenGl_ArbFBO.hxx> |
7fd59977 |
17 | |
fd4a6963 |
18 | #include <Standard_Assert.hxx> |
a2e4f780 |
19 | #include <TCollection_ExtendedString.hxx> |
fd4a6963 |
20 | |
7fd59977 |
21 | |
fd4a6963 |
22 | // ======================================================================= |
23 | // function : OpenGl_FrameBuffer |
24 | // purpose : |
25 | // ======================================================================= |
7fd59977 |
26 | OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat) |
18f4e8e2 |
27 | : myVPSizeX (0), |
7fd59977 |
28 | myVPSizeY (0), |
29 | myTextFormat (theTextureFormat), |
7fd59977 |
30 | myGlFBufferId (NO_FRAMEBUFFER), |
a2e4f780 |
31 | myGlColorRBufferId (NO_RENDERBUFFER), |
32 | myGlDepthRBufferId (NO_RENDERBUFFER), |
33 | myIsOwnBuffer (false), |
18f4e8e2 |
34 | myColorTexture (new OpenGl_Texture()), |
35 | myDepthStencilTexture (new OpenGl_Texture()) |
7fd59977 |
36 | { |
37 | // |
38 | } |
39 | |
fd4a6963 |
40 | // ======================================================================= |
41 | // function : ~OpenGl_FrameBuffer |
42 | // purpose : |
43 | // ======================================================================= |
44 | OpenGl_FrameBuffer::~OpenGl_FrameBuffer() |
45 | { |
46 | Release (NULL); |
47 | } |
48 | |
49 | // ======================================================================= |
50 | // function : Init |
51 | // purpose : |
52 | // ======================================================================= |
2166f0fa |
53 | Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext, |
62e1beed |
54 | const GLsizei theSizeX, |
55 | const GLsizei theSizeY) |
7fd59977 |
56 | { |
01ca42b2 |
57 | if (theGlContext->arbFBO == NULL) |
7fd59977 |
58 | { |
7fd59977 |
59 | return Standard_False; |
60 | } |
61 | |
62 | // clean up previous state |
fd4a6963 |
63 | Release (theGlContext.operator->()); |
7fd59977 |
64 | |
a447178e |
65 | myIsOwnBuffer = true; |
66 | |
7fd59977 |
67 | // setup viewport sizes as is |
62e1beed |
68 | myVPSizeX = theSizeX; |
69 | myVPSizeY = theSizeY; |
70 | const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2; |
71 | const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2; |
7fd59977 |
72 | |
18f4e8e2 |
73 | // Create the textures (will be used as color buffer and depth-stencil buffer) |
fe3a29bc |
74 | if (!myColorTexture->Init (theGlContext, myTextFormat, |
75 | GL_RGBA, GL_UNSIGNED_BYTE, |
62e1beed |
76 | aSizeX, aSizeY, Graphic3d_TOT_2D)) |
7fd59977 |
77 | { |
fd4a6963 |
78 | Release (theGlContext.operator->()); |
7fd59977 |
79 | return Standard_False; |
80 | } |
81 | |
fe3a29bc |
82 | // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats |
83 | // instead of just trying to create such texture |
84 | if (!myDepthStencilTexture->Init (theGlContext, GL_DEPTH24_STENCIL8, |
85 | GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, |
62e1beed |
86 | aSizeX, aSizeY, Graphic3d_TOT_2D)) |
fe3a29bc |
87 | { |
88 | TCollection_ExtendedString aMsg = TCollection_ExtendedString() |
89 | + "Warning! Depth textures are not supported by hardware!"; |
90 | theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, |
91 | GL_DEBUG_TYPE_PORTABILITY_ARB, |
92 | 0, |
93 | GL_DEBUG_SEVERITY_HIGH_ARB, |
94 | aMsg); |
95 | |
96 | theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId); |
97 | theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId); |
62e1beed |
98 | theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, aSizeX, aSizeY); |
fe3a29bc |
99 | theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER); |
100 | } |
101 | |
7fd59977 |
102 | // Build FBO and setup it as texture |
01ca42b2 |
103 | theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId); |
104 | theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); |
18f4e8e2 |
105 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
106 | GL_TEXTURE_2D, myColorTexture->TextureId(), 0); |
fe3a29bc |
107 | if (myDepthStencilTexture->IsValid()) |
108 | { |
109 | #ifdef GL_DEPTH_STENCIL_ATTACHMENT |
110 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
111 | GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0); |
112 | #else |
113 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
114 | GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0); |
115 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, |
116 | GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0); |
117 | #endif |
118 | } |
119 | else if (myGlDepthRBufferId != NO_RENDERBUFFER) |
120 | { |
121 | theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
122 | GL_RENDERBUFFER, myGlDepthRBufferId); |
123 | } |
01ca42b2 |
124 | if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
7fd59977 |
125 | { |
fd4a6963 |
126 | Release (theGlContext.operator->()); |
7fd59977 |
127 | return Standard_False; |
128 | } |
129 | |
18f4e8e2 |
130 | UnbindBuffer (theGlContext); |
7fd59977 |
131 | return Standard_True; |
132 | } |
133 | |
38a0206f |
134 | // ======================================================================= |
135 | // function : Init |
136 | // purpose : |
137 | // ======================================================================= |
138 | Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext, |
139 | const GLsizei theViewportSizeX, |
140 | const GLsizei theViewportSizeY) |
141 | { |
142 | if (myVPSizeX == theViewportSizeX |
143 | && myVPSizeY == theViewportSizeY) |
189f85a3 |
144 | |
38a0206f |
145 | { |
146 | return IsValid(); |
147 | } |
148 | |
149 | return Init (theGlContext, theViewportSizeX, theViewportSizeY); |
150 | } |
151 | |
a2e4f780 |
152 | // ======================================================================= |
153 | // function : InitWithRB |
154 | // purpose : |
155 | // ======================================================================= |
156 | Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx, |
62e1beed |
157 | const GLsizei theSizeX, |
158 | const GLsizei theSizeY, |
a2e4f780 |
159 | const GLuint theColorRBufferFromWindow) |
160 | { |
161 | if (theGlCtx->arbFBO == NULL) |
162 | { |
163 | return Standard_False; |
164 | } |
165 | |
166 | // clean up previous state |
167 | Release (theGlCtx.operator->()); |
168 | |
a447178e |
169 | myIsOwnBuffer = true; |
170 | |
a2e4f780 |
171 | // setup viewport sizes as is |
62e1beed |
172 | myVPSizeX = theSizeX; |
173 | myVPSizeY = theSizeY; |
174 | const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2; |
175 | const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2; |
a2e4f780 |
176 | |
177 | // Create the render-buffers |
178 | if (theColorRBufferFromWindow != NO_RENDERBUFFER) |
179 | { |
180 | myGlColorRBufferId = theColorRBufferFromWindow; |
181 | } |
182 | else |
183 | { |
184 | theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId); |
185 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId); |
62e1beed |
186 | theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA8, aSizeX, aSizeY); |
a2e4f780 |
187 | } |
188 | |
189 | theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId); |
190 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId); |
62e1beed |
191 | theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, aSizeX, aSizeY); |
a2e4f780 |
192 | |
193 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER); |
194 | |
195 | // create FBO |
196 | theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId); |
197 | theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); |
198 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
199 | GL_RENDERBUFFER, myGlColorRBufferId); |
200 | #ifdef GL_DEPTH_STENCIL_ATTACHMENT |
201 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
202 | GL_RENDERBUFFER, myGlDepthRBufferId); |
203 | #else |
204 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
205 | GL_RENDERBUFFER, myGlDepthRBufferId); |
206 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, |
207 | GL_RENDERBUFFER, myGlDepthRBufferId); |
208 | #endif |
209 | if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
210 | { |
211 | UnbindBuffer (theGlCtx); |
212 | Release (theGlCtx.operator->()); |
213 | return Standard_False; |
214 | } |
215 | |
216 | UnbindBuffer (theGlCtx); |
217 | return Standard_True; |
218 | } |
219 | |
220 | // ======================================================================= |
221 | // function : InitWrapper |
222 | // purpose : |
223 | // ======================================================================= |
224 | Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx) |
225 | { |
226 | if (theGlCtx->arbFBO == NULL) |
227 | { |
228 | return Standard_False; |
229 | } |
230 | |
231 | // clean up previous state |
232 | Release (theGlCtx.operator->()); |
233 | |
234 | GLint anFbo = GLint(NO_FRAMEBUFFER); |
235 | ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo); |
236 | if (anFbo == GLint(NO_FRAMEBUFFER)) |
237 | { |
238 | return Standard_False; |
239 | } |
240 | |
241 | GLint aColorType = 0; |
242 | GLint aColorId = 0; |
243 | GLint aDepthType = 0; |
244 | GLint aDepthId = 0; |
245 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType); |
246 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType); |
247 | |
248 | myGlFBufferId = GLuint(anFbo); |
249 | myIsOwnBuffer = false; |
250 | if (aColorType == GL_RENDERBUFFER) |
251 | { |
252 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId); |
253 | myGlColorRBufferId = aColorId; |
254 | } |
255 | else if (aColorType != GL_NONE) |
256 | { |
257 | TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!"; |
258 | theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, |
259 | GL_DEBUG_TYPE_ERROR_ARB, |
260 | 0, |
261 | GL_DEBUG_SEVERITY_HIGH_ARB, |
262 | aMsg); |
263 | } |
264 | |
265 | if (aDepthType == GL_RENDERBUFFER) |
266 | { |
267 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId); |
268 | myGlDepthRBufferId = aDepthId; |
269 | } |
270 | else if (aDepthType != GL_NONE) |
271 | { |
272 | TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!"; |
273 | theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, |
274 | GL_DEBUG_TYPE_ERROR_ARB, |
275 | 0, |
276 | GL_DEBUG_SEVERITY_HIGH_ARB, |
277 | aMsg); |
278 | } |
279 | |
280 | // retrieve dimensions |
281 | GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId; |
282 | if (aRBuffer != NO_RENDERBUFFER) |
283 | { |
284 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer); |
285 | theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX); |
286 | theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY); |
287 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER); |
288 | } |
289 | |
290 | return aRBuffer != NO_RENDERBUFFER; |
291 | } |
292 | |
fd4a6963 |
293 | // ======================================================================= |
294 | // function : Release |
295 | // purpose : |
296 | // ======================================================================= |
10b9c7df |
297 | void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx) |
7fd59977 |
298 | { |
18f4e8e2 |
299 | if (isValidFrameBuffer()) |
7fd59977 |
300 | { |
fd4a6963 |
301 | // application can not handle this case by exception - this is bug in code |
302 | Standard_ASSERT_RETURN (theGlCtx != NULL, |
303 | "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",); |
a2e4f780 |
304 | if (theGlCtx->IsValid() |
305 | && myIsOwnBuffer) |
2166f0fa |
306 | { |
01ca42b2 |
307 | theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId); |
a2e4f780 |
308 | if (myGlColorRBufferId != NO_RENDERBUFFER) |
309 | { |
310 | theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId); |
311 | } |
312 | if (myGlDepthRBufferId != NO_RENDERBUFFER) |
313 | { |
314 | theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId); |
315 | } |
2166f0fa |
316 | } |
a2e4f780 |
317 | myGlFBufferId = NO_FRAMEBUFFER; |
318 | myGlColorRBufferId = NO_RENDERBUFFER; |
319 | myGlDepthRBufferId = NO_RENDERBUFFER; |
320 | myIsOwnBuffer = false; |
7fd59977 |
321 | } |
7fd59977 |
322 | |
18f4e8e2 |
323 | myColorTexture->Release (theGlCtx); |
324 | myDepthStencilTexture->Release (theGlCtx); |
7fd59977 |
325 | } |
326 | |
fd4a6963 |
327 | // ======================================================================= |
328 | // function : SetupViewport |
329 | // purpose : |
330 | // ======================================================================= |
331 | void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/) |
332 | { |
333 | glViewport (0, 0, myVPSizeX, myVPSizeY); |
334 | } |
335 | |
336 | // ======================================================================= |
337 | // function : ChangeViewport |
338 | // purpose : |
339 | // ======================================================================= |
340 | void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX, |
341 | const GLsizei theVPSizeY) |
342 | { |
343 | myVPSizeX = theVPSizeX; |
344 | myVPSizeY = theVPSizeY; |
345 | } |
346 | |
347 | // ======================================================================= |
348 | // function : BindBuffer |
349 | // purpose : |
350 | // ======================================================================= |
351 | void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx) |
352 | { |
01ca42b2 |
353 | theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); |
fd4a6963 |
354 | } |
355 | |
b86bb3df |
356 | // ======================================================================= |
357 | // function : BindDrawBuffer |
358 | // purpose : |
359 | // ======================================================================= |
360 | void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx) |
361 | { |
362 | theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId); |
363 | } |
364 | |
365 | // ======================================================================= |
366 | // function : BindReadBuffer |
367 | // purpose : |
368 | // ======================================================================= |
369 | void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx) |
370 | { |
371 | theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId); |
372 | } |
373 | |
fd4a6963 |
374 | // ======================================================================= |
375 | // function : UnbindBuffer |
376 | // purpose : |
377 | // ======================================================================= |
378 | void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx) |
379 | { |
a2e4f780 |
380 | if (!theGlCtx->DefaultFrameBuffer().IsNull() |
381 | && theGlCtx->DefaultFrameBuffer().operator->() != this) |
382 | { |
383 | theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx); |
384 | } |
385 | else |
386 | { |
387 | theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER); |
388 | } |
fd4a6963 |
389 | } |