Commit | Line | Data |
---|---|---|
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 | // |
973c2be1 | 6 | // This library is free software; you can redistribute it and / or modify it |
7 | // under the terms of the GNU Lesser General Public version 2.1 as published | |
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> |
16 | ||
fd4a6963 | 17 | #include <Standard_Assert.hxx> |
18 | ||
19 | IMPLEMENT_STANDARD_HANDLE (OpenGl_FrameBuffer, OpenGl_Resource) | |
20 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_Resource) | |
7fd59977 | 21 | |
7fd59977 | 22 | static inline bool isOddNumber (const GLsizei theNumber) |
23 | { | |
24 | return theNumber & 0x01; | |
25 | } | |
26 | ||
27 | static inline GLsizei getEvenNumber (const GLsizei theNumber) | |
28 | { | |
29 | return isOddNumber (theNumber) ? (theNumber + 1) : theNumber; | |
30 | } | |
31 | ||
32 | //! Notice - 0 is not power of two here | |
33 | static inline bool isPowerOfTwo (const GLsizei theNumber) | |
34 | { | |
35 | return !(theNumber & (theNumber - 1)); | |
36 | } | |
37 | ||
fd4a6963 | 38 | // ======================================================================= |
39 | // function : OpenGl_FrameBuffer | |
40 | // purpose : | |
41 | // ======================================================================= | |
7fd59977 | 42 | OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat) |
43 | : mySizeX (0), | |
44 | mySizeY (0), | |
45 | myVPSizeX (0), | |
46 | myVPSizeY (0), | |
47 | myTextFormat (theTextureFormat), | |
48 | myGlTextureId (NO_TEXTURE), | |
49 | myGlFBufferId (NO_FRAMEBUFFER), | |
b859a34d | 50 | myGlDepthRBId (NO_RENDERBUFFER), |
51 | myGlStencilRBId (NO_RENDERBUFFER) | |
7fd59977 | 52 | { |
53 | // | |
54 | } | |
55 | ||
fd4a6963 | 56 | // ======================================================================= |
57 | // function : ~OpenGl_FrameBuffer | |
58 | // purpose : | |
59 | // ======================================================================= | |
60 | OpenGl_FrameBuffer::~OpenGl_FrameBuffer() | |
61 | { | |
62 | Release (NULL); | |
63 | } | |
64 | ||
65 | // ======================================================================= | |
66 | // function : Init | |
67 | // purpose : | |
68 | // ======================================================================= | |
2166f0fa | 69 | Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext, |
fd4a6963 | 70 | const GLsizei theViewportSizeX, |
71 | const GLsizei theViewportSizeY, | |
72 | const GLboolean toForcePowerOfTwo) | |
7fd59977 | 73 | { |
2166f0fa | 74 | if (theGlContext->extFBO == NULL) |
7fd59977 | 75 | { |
7fd59977 | 76 | return Standard_False; |
77 | } | |
78 | ||
79 | // clean up previous state | |
fd4a6963 | 80 | Release (theGlContext.operator->()); |
7fd59977 | 81 | |
82 | // upscale width/height if numbers are odd | |
83 | if (toForcePowerOfTwo) | |
84 | { | |
a174a3c5 | 85 | mySizeX = OpenGl_Context::GetPowerOfTwo (theViewportSizeX, theGlContext->MaxTextureSize()); |
86 | mySizeY = OpenGl_Context::GetPowerOfTwo (theViewportSizeY, theGlContext->MaxTextureSize()); | |
7fd59977 | 87 | } |
88 | else | |
89 | { | |
90 | mySizeX = getEvenNumber (theViewportSizeX); | |
91 | mySizeY = getEvenNumber (theViewportSizeY); | |
92 | } | |
93 | ||
94 | // setup viewport sizes as is | |
95 | myVPSizeX = theViewportSizeX; | |
96 | myVPSizeY = theViewportSizeY; | |
97 | ||
98 | // Create the texture (will be used as color buffer) | |
fd4a6963 | 99 | if (!initTrashTexture (theGlContext)) |
7fd59977 | 100 | { |
101 | if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY)) | |
102 | { | |
2166f0fa | 103 | return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE); |
7fd59977 | 104 | } |
fd4a6963 | 105 | Release (theGlContext.operator->()); |
7fd59977 | 106 | return Standard_False; |
107 | } | |
108 | ||
b859a34d | 109 | if (!theGlContext->extPDS) |
110 | { | |
111 | // Create RenderBuffer to be used as depth buffer | |
112 | theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId); | |
113 | theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId); | |
114 | theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY); | |
115 | ||
116 | // Create RenderBuffer to be used as stencil buffer | |
117 | theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlStencilRBId); | |
118 | theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlStencilRBId); | |
119 | theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, mySizeX, mySizeY); | |
120 | } | |
121 | else | |
122 | { | |
123 | // Create combined depth stencil buffer | |
124 | theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId); | |
125 | theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId); | |
126 | theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mySizeX, mySizeY); | |
127 | myGlStencilRBId = myGlDepthRBId; | |
128 | } | |
7fd59977 | 129 | |
130 | // Build FBO and setup it as texture | |
2166f0fa SK |
131 | theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId); |
132 | theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId); | |
7fd59977 | 133 | glEnable (GL_TEXTURE_2D); |
134 | glBindTexture (GL_TEXTURE_2D, myGlTextureId); | |
2166f0fa | 135 | theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0); |
9be3a894 | 136 | theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlDepthRBId); |
b859a34d | 137 | theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlStencilRBId); |
2166f0fa | 138 | if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) |
7fd59977 | 139 | { |
140 | if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY)) | |
141 | { | |
2166f0fa | 142 | return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE); |
7fd59977 | 143 | } |
fd4a6963 | 144 | Release (theGlContext.operator->()); |
7fd59977 | 145 | return Standard_False; |
146 | } | |
147 | ||
fd4a6963 | 148 | UnbindBuffer (theGlContext); |
149 | UnbindTexture (theGlContext); | |
2166f0fa | 150 | theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER); |
7fd59977 | 151 | return Standard_True; |
152 | } | |
153 | ||
fd4a6963 | 154 | // ======================================================================= |
155 | // function : Release | |
156 | // purpose : | |
157 | // ======================================================================= | |
158 | void OpenGl_FrameBuffer::Release (const OpenGl_Context* theGlCtx) | |
7fd59977 | 159 | { |
fd4a6963 | 160 | if (isValidDepthBuffer() |
161 | || isValidStencilBuffer() | |
162 | || isValidTexture() | |
163 | || isValidFrameBuffer()) | |
7fd59977 | 164 | { |
fd4a6963 | 165 | // application can not handle this case by exception - this is bug in code |
166 | Standard_ASSERT_RETURN (theGlCtx != NULL, | |
167 | "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",); | |
7fd59977 | 168 | } |
fd4a6963 | 169 | if (isValidStencilBuffer()) |
b859a34d | 170 | { |
fd4a6963 | 171 | if (theGlCtx->IsValid() |
172 | && myGlStencilRBId != myGlDepthRBId) | |
b859a34d | 173 | { |
fd4a6963 | 174 | theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlStencilRBId); |
b859a34d | 175 | } |
fd4a6963 | 176 | myGlStencilRBId = NO_RENDERBUFFER; |
177 | } | |
178 | if (isValidDepthBuffer()) | |
179 | { | |
180 | if (theGlCtx->IsValid()) | |
b859a34d | 181 | { |
fd4a6963 | 182 | theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId); |
b859a34d | 183 | } |
fd4a6963 | 184 | myGlDepthRBId = NO_RENDERBUFFER; |
b859a34d | 185 | } |
fd4a6963 | 186 | if (isValidTexture()) |
7fd59977 | 187 | { |
fd4a6963 | 188 | if (theGlCtx->IsValid()) |
189 | { | |
190 | glDeleteTextures (1, &myGlTextureId); | |
191 | } | |
7fd59977 | 192 | myGlTextureId = NO_TEXTURE; |
193 | } | |
194 | mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0; | |
fd4a6963 | 195 | if (isValidFrameBuffer()) |
7fd59977 | 196 | { |
fd4a6963 | 197 | if (theGlCtx->IsValid()) |
2166f0fa | 198 | { |
fd4a6963 | 199 | theGlCtx->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId); |
2166f0fa | 200 | } |
fd4a6963 | 201 | myGlFBufferId = NO_FRAMEBUFFER; |
7fd59977 | 202 | } |
203 | } | |
204 | ||
fd4a6963 | 205 | // ======================================================================= |
206 | // function : isProxySuccess | |
207 | // purpose : | |
208 | // ======================================================================= | |
209 | Standard_Boolean OpenGl_FrameBuffer::isProxySuccess() const | |
7fd59977 | 210 | { |
211 | // use proxy to check texture could be created or not | |
212 | glTexImage2D (GL_PROXY_TEXTURE_2D, | |
213 | 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image | |
214 | myTextFormat, // internalformat | |
215 | mySizeX, mySizeY, 0, | |
216 | GL_RGBA, GL_UNSIGNED_BYTE, NULL); | |
217 | GLint aTestParamX (0), aTestParamY (0); | |
218 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX); | |
219 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY); | |
220 | return aTestParamX != 0 && aTestParamY != 0; | |
221 | } | |
222 | ||
fd4a6963 | 223 | // ======================================================================= |
224 | // function : initTrashTexture | |
225 | // purpose : | |
226 | // ======================================================================= | |
227 | Standard_Boolean OpenGl_FrameBuffer::initTrashTexture (const Handle(OpenGl_Context)& theGlContext) | |
7fd59977 | 228 | { |
229 | // Check texture size is fit dimension maximum | |
230 | GLint aMaxTexDim = 2048; | |
231 | glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim); | |
232 | if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim) | |
233 | { | |
234 | return Standard_False; | |
235 | } | |
236 | ||
237 | // generate new id | |
238 | glEnable (GL_TEXTURE_2D); | |
fd4a6963 | 239 | if (!isValidTexture()) |
7fd59977 | 240 | { |
241 | glGenTextures (1, &myGlTextureId); // Create The Texture | |
242 | } | |
243 | glBindTexture (GL_TEXTURE_2D, myGlTextureId); | |
244 | ||
245 | // texture interpolation parameters - could be overridden later | |
246 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
247 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
248 | ||
fd4a6963 | 249 | if (!isProxySuccess()) |
7fd59977 | 250 | { |
fd4a6963 | 251 | Release (theGlContext.operator->()); |
7fd59977 | 252 | return Standard_False; |
253 | } | |
254 | ||
255 | glTexImage2D (GL_TEXTURE_2D, | |
256 | 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image | |
257 | myTextFormat, // internalformat | |
258 | mySizeX, mySizeY, 0, | |
259 | GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1 | |
260 | return Standard_True; | |
261 | } | |
fd4a6963 | 262 | |
263 | // ======================================================================= | |
264 | // function : SetupViewport | |
265 | // purpose : | |
266 | // ======================================================================= | |
267 | void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/) | |
268 | { | |
269 | glViewport (0, 0, myVPSizeX, myVPSizeY); | |
270 | } | |
271 | ||
272 | // ======================================================================= | |
273 | // function : ChangeViewport | |
274 | // purpose : | |
275 | // ======================================================================= | |
276 | void OpenGl_FrameBuffer::ChangeViewport (const GLsizei theVPSizeX, | |
277 | const GLsizei theVPSizeY) | |
278 | { | |
279 | myVPSizeX = theVPSizeX; | |
280 | myVPSizeY = theVPSizeY; | |
281 | } | |
282 | ||
283 | // ======================================================================= | |
284 | // function : BindBuffer | |
285 | // purpose : | |
286 | // ======================================================================= | |
287 | void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx) | |
288 | { | |
289 | theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId); | |
290 | } | |
291 | ||
292 | // ======================================================================= | |
293 | // function : UnbindBuffer | |
294 | // purpose : | |
295 | // ======================================================================= | |
296 | void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx) | |
297 | { | |
298 | theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, NO_FRAMEBUFFER); | |
299 | } | |
300 | ||
301 | // ======================================================================= | |
302 | // function : BindTexture | |
303 | // purpose : | |
304 | // ======================================================================= | |
305 | void OpenGl_FrameBuffer::BindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/) | |
306 | { | |
307 | glEnable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering | |
308 | glBindTexture (GL_TEXTURE_2D, myGlTextureId); | |
309 | } | |
310 | ||
311 | // ======================================================================= | |
312 | // function : UnbindTexture | |
313 | // purpose : | |
314 | // ======================================================================= | |
315 | void OpenGl_FrameBuffer::UnbindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/) | |
316 | { | |
317 | glBindTexture (GL_TEXTURE_2D, NO_TEXTURE); | |
318 | glDisable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering | |
319 | } |