0023418: Crash on the object displaying when running DRAW on remote station. OpenGL...
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
CommitLineData
b311480e 1// Created by: Kirill GAVRILOV
2// Copyright (c) 2011-2012 OPEN CASCADE SAS
3//
4// The content of this file is subject to the Open CASCADE Technology Public
5// License Version 6.5 (the "License"). You may not use the content of this file
6// except in compliance with the License. Please obtain a copy of the License
7// at http://www.opencascade.org and read it completely before using this file.
8//
9// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11//
12// The Original Code and all software distributed under the License is
13// distributed on an "AS IS" basis, without warranty of any kind, and the
14// Initial Developer hereby disclaims all such warranties, including without
15// limitation, any warranties of merchantability, fitness for a particular
16// purpose or non-infringement. Please see the License for the specific terms
17// and conditions governing the rights and limitations under the License.
18
2166f0fa 19
7fd59977 20#include <OpenGl_FrameBuffer.hxx>
21
22#ifdef DEB
23 #include <iostream>
24#endif
25
7fd59977 26static inline bool isOddNumber (const GLsizei theNumber)
27{
28 return theNumber & 0x01;
29}
30
31static inline GLsizei getEvenNumber (const GLsizei theNumber)
32{
33 return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
34}
35
36//! Notice - 0 is not power of two here
37static inline bool isPowerOfTwo (const GLsizei theNumber)
38{
39 return !(theNumber & (theNumber - 1));
40}
41
42static inline GLsizei getPowerOfTwo (const GLsizei theNumber,
43 const GLsizei theThreshold)
44{
45 for (GLsizei p2 = 2; p2 <= theThreshold; p2 <<= 1)
46 {
47 if (theNumber <= p2)
48 {
49 return p2;
50 }
51 }
52 return theThreshold;
53}
54
7fd59977 55OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
56: mySizeX (0),
57 mySizeY (0),
58 myVPSizeX (0),
59 myVPSizeY (0),
60 myTextFormat (theTextureFormat),
61 myGlTextureId (NO_TEXTURE),
62 myGlFBufferId (NO_FRAMEBUFFER),
2166f0fa 63 myGlDepthRBId (NO_RENDERBUFFER)
7fd59977 64{
65 //
66}
67
2166f0fa
SK
68Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
69 GLsizei theViewportSizeX,
7fd59977 70 GLsizei theViewportSizeY,
71 GLboolean toForcePowerOfTwo)
72{
2166f0fa 73 if (theGlContext->extFBO == NULL)
7fd59977 74 {
75 #ifdef DEB
76 std::cerr << "OpenGl_FrameBuffer, FBO extension not supported!\n";
77 #endif
78 return Standard_False;
79 }
80
81 // clean up previous state
2166f0fa 82 Release (theGlContext);
7fd59977 83
84 // upscale width/height if numbers are odd
85 if (toForcePowerOfTwo)
86 {
87 GLint aMaxTexDim = 2048;
88 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
89 mySizeX = getPowerOfTwo (theViewportSizeX, aMaxTexDim);
90 mySizeY = getPowerOfTwo (theViewportSizeY, aMaxTexDim);
91 }
92 else
93 {
94 mySizeX = getEvenNumber (theViewportSizeX);
95 mySizeY = getEvenNumber (theViewportSizeY);
96 }
97
98 // setup viewport sizes as is
99 myVPSizeX = theViewportSizeX;
100 myVPSizeY = theViewportSizeY;
101
102 // Create the texture (will be used as color buffer)
2166f0fa 103 if (!InitTrashTexture (theGlContext))
7fd59977 104 {
105 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
106 {
2166f0fa 107 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
7fd59977 108 }
2166f0fa 109 Release (theGlContext);
7fd59977 110 return Standard_False;
111 }
112
113 // Create RenderBuffer (will be used as depth buffer)
2166f0fa
SK
114 theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
115 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
116 theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY);
7fd59977 117
118 // Build FBO and setup it as texture
2166f0fa
SK
119 theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
120 theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
7fd59977 121 glEnable (GL_TEXTURE_2D);
122 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
2166f0fa
SK
123 theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
124 theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlFBufferId);
125 if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
7fd59977 126 {
127 if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
128 {
2166f0fa 129 return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
7fd59977 130 }
2166f0fa 131 Release (theGlContext);
7fd59977 132 return Standard_False;
133 }
134
2166f0fa 135 UnbindBuffer (theGlContext);
7fd59977 136 UnbindTexture();
2166f0fa 137 theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
7fd59977 138
139 #ifdef DEB
140 std::cerr << "OpenGl_FrameBuffer, created FBO " << mySizeX << "x" << mySizeY
141 << " for viewport " << theViewportSizeX << "x" << theViewportSizeY << "\n";
142 #endif
143 return Standard_True;
144}
145
2166f0fa 146void OpenGl_FrameBuffer::Release (const Handle(OpenGl_Context)& theGlContext)
7fd59977 147{
148 if (IsValidDepthBuffer())
149 {
2166f0fa
SK
150 if (!theGlContext.IsNull() && theGlContext->extFBO != NULL)
151 {
152 theGlContext->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
153 myGlDepthRBId = NO_RENDERBUFFER;
154 }
155 else
156 {
157 std::cerr << "OpenGl_FrameBuffer::Release() called with invalid OpenGl_Context!\n";
158 }
7fd59977 159 }
160 if (IsValidTexture())
161 {
162 glDeleteTextures (1, &myGlTextureId);
163 myGlTextureId = NO_TEXTURE;
164 }
165 mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
166 if (IsValidFrameBuffer())
167 {
2166f0fa
SK
168 if (!theGlContext.IsNull() && theGlContext->extFBO != NULL)
169 {
170 theGlContext->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId);
171 myGlFBufferId = NO_FRAMEBUFFER;
172 }
173 else
174 {
175 std::cerr << "OpenGl_FrameBuffer::Release() called with invalid OpenGl_Context!\n";
176 }
7fd59977 177 }
178}
179
180Standard_Boolean OpenGl_FrameBuffer::IsProxySuccess() const
181{
182 // use proxy to check texture could be created or not
183 glTexImage2D (GL_PROXY_TEXTURE_2D,
184 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
185 myTextFormat, // internalformat
186 mySizeX, mySizeY, 0,
187 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
188 GLint aTestParamX (0), aTestParamY (0);
189 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX);
190 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY);
191 return aTestParamX != 0 && aTestParamY != 0;
192}
193
2166f0fa 194Standard_Boolean OpenGl_FrameBuffer::InitTrashTexture (const Handle(OpenGl_Context)& theGlContext)
7fd59977 195{
196 // Check texture size is fit dimension maximum
197 GLint aMaxTexDim = 2048;
198 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
199 if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim)
200 {
201 return Standard_False;
202 }
203
204 // generate new id
205 glEnable (GL_TEXTURE_2D);
206 if (!IsValidTexture())
207 {
208 glGenTextures (1, &myGlTextureId); // Create The Texture
209 }
210 glBindTexture (GL_TEXTURE_2D, myGlTextureId);
211
212 // texture interpolation parameters - could be overridden later
213 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
214 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
215
216 if (!IsProxySuccess())
217 {
2166f0fa 218 Release (theGlContext);
7fd59977 219 return Standard_False;
220 }
221
222 glTexImage2D (GL_TEXTURE_2D,
223 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
224 myTextFormat, // internalformat
225 mySizeX, mySizeY, 0,
226 GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
227 return Standard_True;
228}