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