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, |
fd4a6963 |
54 | const GLsizei theViewportSizeX, |
18f4e8e2 |
55 | const GLsizei theViewportSizeY) |
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 | |
7fd59977 |
65 | // setup viewport sizes as is |
66 | myVPSizeX = theViewportSizeX; |
67 | myVPSizeY = theViewportSizeY; |
68 | |
18f4e8e2 |
69 | // Create the textures (will be used as color buffer and depth-stencil buffer) |
fe3a29bc |
70 | if (!myColorTexture->Init (theGlContext, myTextFormat, |
71 | GL_RGBA, GL_UNSIGNED_BYTE, |
72 | myVPSizeX, myVPSizeY, Graphic3d_TOT_2D)) |
7fd59977 |
73 | { |
fd4a6963 |
74 | Release (theGlContext.operator->()); |
7fd59977 |
75 | return Standard_False; |
76 | } |
77 | |
fe3a29bc |
78 | // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats |
79 | // instead of just trying to create such texture |
80 | if (!myDepthStencilTexture->Init (theGlContext, GL_DEPTH24_STENCIL8, |
81 | GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, |
82 | myVPSizeX, myVPSizeY, Graphic3d_TOT_2D)) |
83 | { |
84 | TCollection_ExtendedString aMsg = TCollection_ExtendedString() |
85 | + "Warning! Depth textures are not supported by hardware!"; |
86 | theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, |
87 | GL_DEBUG_TYPE_PORTABILITY_ARB, |
88 | 0, |
89 | GL_DEBUG_SEVERITY_HIGH_ARB, |
90 | aMsg); |
91 | |
92 | theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId); |
93 | theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId); |
94 | theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, myVPSizeX, myVPSizeY); |
95 | theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER); |
96 | } |
97 | |
7fd59977 |
98 | // Build FBO and setup it as texture |
01ca42b2 |
99 | theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId); |
100 | theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); |
18f4e8e2 |
101 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
102 | GL_TEXTURE_2D, myColorTexture->TextureId(), 0); |
fe3a29bc |
103 | if (myDepthStencilTexture->IsValid()) |
104 | { |
105 | #ifdef GL_DEPTH_STENCIL_ATTACHMENT |
106 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
107 | GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0); |
108 | #else |
109 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
110 | GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0); |
111 | theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, |
112 | GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0); |
113 | #endif |
114 | } |
115 | else if (myGlDepthRBufferId != NO_RENDERBUFFER) |
116 | { |
117 | theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
118 | GL_RENDERBUFFER, myGlDepthRBufferId); |
119 | } |
01ca42b2 |
120 | if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
7fd59977 |
121 | { |
fd4a6963 |
122 | Release (theGlContext.operator->()); |
7fd59977 |
123 | return Standard_False; |
124 | } |
125 | |
18f4e8e2 |
126 | UnbindBuffer (theGlContext); |
7fd59977 |
127 | return Standard_True; |
128 | } |
129 | |
38a0206f |
130 | // ======================================================================= |
131 | // function : Init |
132 | // purpose : |
133 | // ======================================================================= |
134 | Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext, |
135 | const GLsizei theViewportSizeX, |
136 | const GLsizei theViewportSizeY) |
137 | { |
138 | if (myVPSizeX == theViewportSizeX |
139 | && myVPSizeY == theViewportSizeY) |
189f85a3 |
140 | |
38a0206f |
141 | { |
142 | return IsValid(); |
143 | } |
144 | |
145 | return Init (theGlContext, theViewportSizeX, theViewportSizeY); |
146 | } |
147 | |
a2e4f780 |
148 | // ======================================================================= |
149 | // function : InitWithRB |
150 | // purpose : |
151 | // ======================================================================= |
152 | Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx, |
153 | const GLsizei theViewportSizeX, |
154 | const GLsizei theViewportSizeY, |
155 | const GLuint theColorRBufferFromWindow) |
156 | { |
157 | if (theGlCtx->arbFBO == NULL) |
158 | { |
159 | return Standard_False; |
160 | } |
161 | |
162 | // clean up previous state |
163 | Release (theGlCtx.operator->()); |
164 | |
165 | // setup viewport sizes as is |
166 | myVPSizeX = theViewportSizeX; |
167 | myVPSizeY = theViewportSizeY; |
168 | |
169 | // Create the render-buffers |
170 | if (theColorRBufferFromWindow != NO_RENDERBUFFER) |
171 | { |
172 | myGlColorRBufferId = theColorRBufferFromWindow; |
173 | } |
174 | else |
175 | { |
176 | theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId); |
177 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId); |
178 | theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_RGBA8, myVPSizeX, myVPSizeY); |
179 | } |
180 | |
181 | theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId); |
182 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId); |
183 | theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, myVPSizeX, myVPSizeY); |
184 | |
185 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER); |
186 | |
187 | // create FBO |
188 | theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId); |
189 | theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); |
190 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
191 | GL_RENDERBUFFER, myGlColorRBufferId); |
192 | #ifdef GL_DEPTH_STENCIL_ATTACHMENT |
193 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
194 | GL_RENDERBUFFER, myGlDepthRBufferId); |
195 | #else |
196 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
197 | GL_RENDERBUFFER, myGlDepthRBufferId); |
198 | theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, |
199 | GL_RENDERBUFFER, myGlDepthRBufferId); |
200 | #endif |
201 | if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
202 | { |
203 | UnbindBuffer (theGlCtx); |
204 | Release (theGlCtx.operator->()); |
205 | return Standard_False; |
206 | } |
207 | |
208 | UnbindBuffer (theGlCtx); |
209 | return Standard_True; |
210 | } |
211 | |
212 | // ======================================================================= |
213 | // function : InitWrapper |
214 | // purpose : |
215 | // ======================================================================= |
216 | Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx) |
217 | { |
218 | if (theGlCtx->arbFBO == NULL) |
219 | { |
220 | return Standard_False; |
221 | } |
222 | |
223 | // clean up previous state |
224 | Release (theGlCtx.operator->()); |
225 | |
226 | GLint anFbo = GLint(NO_FRAMEBUFFER); |
227 | ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo); |
228 | if (anFbo == GLint(NO_FRAMEBUFFER)) |
229 | { |
230 | return Standard_False; |
231 | } |
232 | |
233 | GLint aColorType = 0; |
234 | GLint aColorId = 0; |
235 | GLint aDepthType = 0; |
236 | GLint aDepthId = 0; |
237 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType); |
238 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType); |
239 | |
240 | myGlFBufferId = GLuint(anFbo); |
241 | myIsOwnBuffer = false; |
242 | if (aColorType == GL_RENDERBUFFER) |
243 | { |
244 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId); |
245 | myGlColorRBufferId = aColorId; |
246 | } |
247 | else if (aColorType != GL_NONE) |
248 | { |
249 | TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!"; |
250 | theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, |
251 | GL_DEBUG_TYPE_ERROR_ARB, |
252 | 0, |
253 | GL_DEBUG_SEVERITY_HIGH_ARB, |
254 | aMsg); |
255 | } |
256 | |
257 | if (aDepthType == GL_RENDERBUFFER) |
258 | { |
259 | theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId); |
260 | myGlDepthRBufferId = aDepthId; |
261 | } |
262 | else if (aDepthType != GL_NONE) |
263 | { |
264 | TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!"; |
265 | theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, |
266 | GL_DEBUG_TYPE_ERROR_ARB, |
267 | 0, |
268 | GL_DEBUG_SEVERITY_HIGH_ARB, |
269 | aMsg); |
270 | } |
271 | |
272 | // retrieve dimensions |
273 | GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId; |
274 | if (aRBuffer != NO_RENDERBUFFER) |
275 | { |
276 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer); |
277 | theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX); |
278 | theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY); |
279 | theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER); |
280 | } |
281 | |
282 | return aRBuffer != NO_RENDERBUFFER; |
283 | } |
284 | |
fd4a6963 |
285 | // ======================================================================= |
286 | // function : Release |
287 | // purpose : |
288 | // ======================================================================= |
10b9c7df |
289 | void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx) |
7fd59977 |
290 | { |
18f4e8e2 |
291 | if (isValidFrameBuffer()) |
7fd59977 |
292 | { |
fd4a6963 |
293 | // application can not handle this case by exception - this is bug in code |
294 | Standard_ASSERT_RETURN (theGlCtx != NULL, |
295 | "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",); |
a2e4f780 |
296 | if (theGlCtx->IsValid() |
297 | && myIsOwnBuffer) |
2166f0fa |
298 | { |
01ca42b2 |
299 | theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId); |
a2e4f780 |
300 | if (myGlColorRBufferId != NO_RENDERBUFFER) |
301 | { |
302 | theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId); |
303 | } |
304 | if (myGlDepthRBufferId != NO_RENDERBUFFER) |
305 | { |
306 | theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId); |
307 | } |
2166f0fa |
308 | } |
a2e4f780 |
309 | myGlFBufferId = NO_FRAMEBUFFER; |
310 | myGlColorRBufferId = NO_RENDERBUFFER; |
311 | myGlDepthRBufferId = NO_RENDERBUFFER; |
312 | myIsOwnBuffer = false; |
7fd59977 |
313 | } |
7fd59977 |
314 | |
18f4e8e2 |
315 | myColorTexture->Release (theGlCtx); |
316 | myDepthStencilTexture->Release (theGlCtx); |
7fd59977 |
317 | } |
318 | |
fd4a6963 |
319 | // ======================================================================= |
320 | // function : SetupViewport |
321 | // purpose : |
322 | // ======================================================================= |
323 | void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/) |
324 | { |
325 | glViewport (0, 0, myVPSizeX, myVPSizeY); |
326 | } |
327 | |
328 | // ======================================================================= |
329 | // function : ChangeViewport |
330 | // purpose : |
331 | // ======================================================================= |
332 | void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX, |
333 | const GLsizei theVPSizeY) |
334 | { |
335 | myVPSizeX = theVPSizeX; |
336 | myVPSizeY = theVPSizeY; |
337 | } |
338 | |
339 | // ======================================================================= |
340 | // function : BindBuffer |
341 | // purpose : |
342 | // ======================================================================= |
343 | void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx) |
344 | { |
01ca42b2 |
345 | theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId); |
fd4a6963 |
346 | } |
347 | |
b86bb3df |
348 | // ======================================================================= |
349 | // function : BindDrawBuffer |
350 | // purpose : |
351 | // ======================================================================= |
352 | void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx) |
353 | { |
354 | theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId); |
355 | } |
356 | |
357 | // ======================================================================= |
358 | // function : BindReadBuffer |
359 | // purpose : |
360 | // ======================================================================= |
361 | void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx) |
362 | { |
363 | theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId); |
364 | } |
365 | |
fd4a6963 |
366 | // ======================================================================= |
367 | // function : UnbindBuffer |
368 | // purpose : |
369 | // ======================================================================= |
370 | void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx) |
371 | { |
a2e4f780 |
372 | if (!theGlCtx->DefaultFrameBuffer().IsNull() |
373 | && theGlCtx->DefaultFrameBuffer().operator->() != this) |
374 | { |
375 | theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx); |
376 | } |
377 | else |
378 | { |
379 | theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER); |
380 | } |
fd4a6963 |
381 | } |