Line data Source code
1 :
2 : /* Copyright (c) 2008-2015, Cedric Stalder <cedric.stalder@gmail.com>
3 : * Stefan Eilemann <eile@equalizergraphics.com>
4 : * Daniel Nachbaur <danielnachbaur@gmail.com>
5 : *
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
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "frameBufferObject.h"
21 :
22 : #include <eq/gl.h>
23 : #include <eq/fabric/pixelViewport.h>
24 :
25 : #ifdef _WIN32
26 : # define bzero( ptr, size ) memset( ptr, 0, size );
27 : #endif
28 :
29 : namespace eq
30 : {
31 : namespace util
32 : {
33 :
34 0 : FrameBufferObject::FrameBufferObject( const GLEWContext* glewContext,
35 : const GLenum textureTarget )
36 : : _fboID( 0 )
37 : , _depth( textureTarget, glewContext )
38 : , _glewContext( glewContext )
39 0 : , _valid( false )
40 : {
41 0 : LBASSERT( GLEW_EXT_framebuffer_object );
42 0 : _colors.push_back( new Texture( textureTarget, glewContext ));
43 0 : }
44 :
45 0 : FrameBufferObject::~FrameBufferObject()
46 : {
47 0 : this->exit();
48 0 : for( Texture* color : _colors )
49 0 : delete color;
50 0 : }
51 :
52 0 : bool FrameBufferObject::addColorTexture()
53 : {
54 0 : if( _colors.size() >= 16 )
55 : {
56 0 : LBWARN << "Too many color textures, can't add another one" << std::endl;
57 0 : return false;
58 : }
59 :
60 0 : _colors.push_back( new Texture(_colors.front()->getTarget(), _glewContext));
61 0 : _valid = false;
62 0 : return true;
63 : }
64 :
65 0 : Error FrameBufferObject::init( const int32_t width, const int32_t height,
66 : const GLuint colorFormat,
67 : const int32_t depthSize,
68 : const int32_t stencilSize,
69 : const int32_t samplesSize )
70 : {
71 0 : LB_TS_THREAD( _thread );
72 :
73 : // Check for frame dimensions
74 : GLint maxViewportDims[2];
75 0 : EQ_GL_CALL( glGetIntegerv( GL_MAX_VIEWPORT_DIMS, &maxViewportDims[0] ));
76 0 : if( width > maxViewportDims[0] || height > maxViewportDims[1] )
77 0 : return Error( ERROR_FRAMEBUFFER_INVALID_SIZE );
78 :
79 : // Check for MAX_SAMPLES
80 : GLint maxSamples;
81 0 : glGetIntegerv( GL_MAX_SAMPLES, &maxSamples );
82 0 : if( samplesSize < 0 || samplesSize > maxSamples )
83 0 : return Error( ERROR_FRAMEBUFFER_INVALID_SAMPLES );
84 :
85 0 : if( _fboID )
86 0 : return Error( ERROR_FRAMEBUFFER_INITIALIZED );
87 :
88 : // generate and bind the framebuffer
89 0 : EQ_GL_CALL( glGenFramebuffersEXT( 1, &_fboID ));
90 0 : EQ_GL_CALL( glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, _fboID ));
91 :
92 : GLint mask;
93 0 : glGetIntegerv( GL_CONTEXT_PROFILE_MASK, &mask );
94 0 : const GLenum glError = glGetError(); // might get GL_INVALID_ENUM
95 : const bool coreContext =
96 0 : glError ? false : mask & GL_CONTEXT_CORE_PROFILE_BIT;
97 :
98 : // create and bind textures
99 0 : for( unsigned i = 0; i < _colors.size(); ++i )
100 : {
101 0 : _colors[i]->init( colorFormat, width, height );
102 0 : _colors[i]->bindToFBO( GL_COLOR_ATTACHMENT0 + i, width, height,
103 0 : samplesSize );
104 0 : const Error error = _checkStatus();
105 0 : if( error )
106 : {
107 0 : LBDEBUG << "FrameBufferObject::init: " << error << " when binding "
108 0 : << _colors.size() << " color texture(s) of format 0x"
109 0 : << std::hex << colorFormat << std::dec << " size " << width
110 0 : << "x" << height << " FBO " << _fboID << std::endl;
111 0 : exit();
112 0 : return error;
113 : }
114 : }
115 0 : if( stencilSize > 0 && ( GLEW_EXT_packed_depth_stencil || coreContext ))
116 : {
117 0 : _depth.init( GL_DEPTH24_STENCIL8, width, height );
118 : _depth.bindToFBO( GL_DEPTH_STENCIL_ATTACHMENT, width, height,
119 0 : samplesSize );
120 0 : const Error error = _checkStatus();
121 0 : if( error )
122 : {
123 0 : LBDEBUG << "FrameBufferObject::init: " << error
124 0 : << " when binding GL_DEPTH24_STENCIL8 texture" << std::endl;
125 0 : exit();
126 0 : return error;
127 : }
128 : }
129 0 : else if( depthSize > 0 )
130 : {
131 0 : _depth.init( GL_DEPTH_COMPONENT, width, height );
132 0 : _depth.bindToFBO( GL_DEPTH_ATTACHMENT, width, height, samplesSize );
133 0 : const Error error = _checkStatus();
134 0 : if( error )
135 : {
136 0 : LBDEBUG << "FrameBufferObject::init: " << error
137 0 : << " when binding GL_DEPTH_COMPONENT texture" << std::endl;
138 0 : exit();
139 0 : return error;
140 : }
141 : }
142 :
143 0 : const Error error = _checkStatus();
144 0 : if( error )
145 : {
146 0 : LBDEBUG << "FrameBufferObject::init: " << error << std::endl;
147 0 : exit();
148 : }
149 0 : return error;
150 : }
151 :
152 0 : void FrameBufferObject::exit()
153 : {
154 0 : LB_TS_THREAD( _thread );
155 0 : if( _fboID )
156 : {
157 0 : glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
158 0 : glDeleteFramebuffersEXT( 1, &_fboID );
159 0 : _fboID = 0;
160 : }
161 :
162 0 : for( size_t i = 0; i < _colors.size(); ++i )
163 0 : _colors[i]->flush();
164 0 : _depth.flush();
165 :
166 0 : _valid = false;
167 0 : }
168 :
169 0 : Error FrameBufferObject::_checkStatus()
170 : {
171 0 : _valid = false;
172 :
173 0 : const GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
174 0 : switch( status )
175 : {
176 : case GL_FRAMEBUFFER_COMPLETE_EXT:
177 0 : _valid = true;
178 0 : return Error( ERROR_NONE );
179 :
180 : case 0: // error?!
181 0 : EQ_GL_ERROR( "glCheckFramebufferStatusEXT" );
182 0 : return Error( ERROR_FRAMEBUFFER_STATUS );
183 :
184 : case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
185 0 : return Error( ERROR_FRAMEBUFFER_UNSUPPORTED );
186 :
187 : case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
188 0 : return Error( ERROR_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT );
189 :
190 : case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
191 0 : return Error( ERROR_FRAMEBUFFER_INCOMPLETE_ATTACHMENT );
192 :
193 : case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
194 0 : return Error( ERROR_FRAMEBUFFER_INCOMPLETE_DIMENSIONS );
195 :
196 : case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
197 0 : return Error( ERROR_FRAMEBUFFER_INCOMPLETE_FORMATS );
198 :
199 : case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
200 0 : return Error( ERROR_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER );
201 :
202 : case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
203 0 : return Error( ERROR_FRAMEBUFFER_INCOMPLETE_READ_BUFFER );
204 :
205 : default:
206 0 : LBWARN << "Unhandled frame buffer status 0x" << std::hex
207 0 : << status << std::dec << std::endl;
208 0 : return Error( ERROR_FRAMEBUFFER_STATUS );
209 : }
210 : }
211 :
212 0 : void FrameBufferObject::bind( const uint32_t target )
213 : {
214 0 : LB_TS_THREAD( _thread );
215 0 : LBASSERT( _fboID );
216 0 : EQ_GL_CALL( glBindFramebufferEXT( target, _fboID ));
217 0 : }
218 :
219 0 : void FrameBufferObject::unbind( const uint32_t target )
220 : {
221 0 : EQ_GL_CALL( glBindFramebufferEXT( target, 0 ));
222 0 : }
223 :
224 0 : Error FrameBufferObject::resize( const int32_t width, const int32_t height )
225 : {
226 0 : LB_TS_THREAD( _thread );
227 0 : LBASSERT( width > 0 && height > 0 );
228 :
229 0 : LBASSERT( !_colors.empty( ));
230 0 : Texture* color = _colors.front();
231 :
232 0 : if( color->getWidth() == width && color->getHeight() == height && _valid )
233 0 : return Error( ERROR_NONE );
234 :
235 0 : for( size_t i = 0; i < _colors.size(); ++i )
236 0 : _colors[i]->resize( width, height );
237 :
238 0 : if ( _depth.isValid( ))
239 0 : _depth.resize( width, height );
240 :
241 0 : return _checkStatus();
242 : }
243 :
244 : }
245 42 : }
|