0023418: Crash on the object displaying when running DRAW on remote station. OpenGL...
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
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
19
20 #include <OpenGl_FrameBuffer.hxx>
21
22 #ifdef DEB
23   #include <iostream>
24 #endif
25
26 static inline bool isOddNumber (const GLsizei theNumber)
27 {
28   return theNumber & 0x01;
29 }
30
31 static 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
37 static inline bool isPowerOfTwo (const GLsizei theNumber)
38 {
39         return !(theNumber & (theNumber - 1));
40 }
41
42 static 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
55 OpenGl_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),
63   myGlDepthRBId (NO_RENDERBUFFER)
64 {
65   //
66 }
67
68 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
69                                            GLsizei theViewportSizeX,
70                                            GLsizei theViewportSizeY,
71                                            GLboolean toForcePowerOfTwo)
72 {
73   if (theGlContext->extFBO == NULL)
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
82   Release (theGlContext);
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)
103   if (!InitTrashTexture (theGlContext))
104   {
105     if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
106     {
107       return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
108     }
109     Release (theGlContext);
110     return Standard_False;
111   }
112
113   // Create RenderBuffer (will be used as depth buffer)
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);
117
118   // Build FBO and setup it as texture
119   theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
120   theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
121   glEnable (GL_TEXTURE_2D);
122   glBindTexture (GL_TEXTURE_2D, myGlTextureId);
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)
126   {
127     if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
128     {
129       return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
130     }
131     Release (theGlContext);
132     return Standard_False;
133   }
134
135   UnbindBuffer (theGlContext);
136   UnbindTexture();
137   theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
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
146 void OpenGl_FrameBuffer::Release (const Handle(OpenGl_Context)& theGlContext)
147 {
148   if (IsValidDepthBuffer())
149   {
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     }
159   }
160   if (IsValidTexture())
161   {
162     glDeleteTextures (1, &myGlTextureId);
163     myGlTextureId = NO_TEXTURE;
164   }
165   mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
166   if (IsValidFrameBuffer())
167   {
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     }
177   }
178 }
179
180 Standard_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
194 Standard_Boolean OpenGl_FrameBuffer::InitTrashTexture (const Handle(OpenGl_Context)& theGlContext)
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   {
218     Release (theGlContext);
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 }