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