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/fabric/pixelViewport.h>
23 : #include <eq/gl.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 1 : FrameBufferObject::FrameBufferObject(const GLEWContext* glewContext,
34 1 : const GLenum textureTarget)
35 : : _fboID(0)
36 : , _depth(textureTarget, glewContext)
37 : , _glewContext(glewContext)
38 1 : , _valid(false)
39 : {
40 1 : LBASSERT(GLEW_EXT_framebuffer_object);
41 1 : _colors.push_back(new Texture(textureTarget, glewContext));
42 1 : }
43 :
44 2 : FrameBufferObject::~FrameBufferObject()
45 : {
46 1 : this->exit();
47 2 : for (Texture* color : _colors)
48 1 : delete color;
49 1 : }
50 :
51 0 : bool FrameBufferObject::addColorTexture()
52 : {
53 0 : if (_colors.size() >= 16)
54 : {
55 0 : LBWARN << "Too many color textures, can't add another one" << std::endl;
56 0 : return false;
57 : }
58 :
59 0 : _colors.push_back(new Texture(_colors.front()->getTarget(), _glewContext));
60 0 : _valid = false;
61 0 : return true;
62 : }
63 :
64 1 : Error FrameBufferObject::init(const int32_t width, const int32_t height,
65 : const GLuint colorFormat, const int32_t depthSize,
66 : const int32_t stencilSize,
67 : const int32_t samplesSize)
68 : {
69 1 : LB_TS_THREAD(_thread);
70 :
71 : // Check for frame dimensions
72 : GLint maxViewportDims[2];
73 1 : EQ_GL_CALL(glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &maxViewportDims[0]));
74 1 : if (width > maxViewportDims[0] || height > maxViewportDims[1])
75 0 : return Error(ERROR_FRAMEBUFFER_INVALID_SIZE);
76 :
77 : // Check for MAX_SAMPLES
78 : GLint maxSamples;
79 1 : glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
80 1 : if (samplesSize < 0 || samplesSize > maxSamples)
81 0 : return Error(ERROR_FRAMEBUFFER_INVALID_SAMPLES);
82 :
83 1 : if (_fboID)
84 0 : return Error(ERROR_FRAMEBUFFER_INITIALIZED);
85 :
86 : // generate and bind the framebuffer
87 1 : EQ_GL_CALL(glGenFramebuffersEXT(1, &_fboID));
88 1 : EQ_GL_CALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fboID));
89 :
90 : GLint mask;
91 1 : glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
92 1 : const GLenum glError = glGetError(); // might get GL_INVALID_ENUM
93 : const bool coreContext =
94 1 : glError ? false : mask & GL_CONTEXT_CORE_PROFILE_BIT;
95 :
96 : // create and bind textures
97 2 : for (unsigned i = 0; i < _colors.size(); ++i)
98 : {
99 1 : _colors[i]->init(colorFormat, width, height);
100 1 : _colors[i]->bindToFBO(GL_COLOR_ATTACHMENT0 + i, width, height,
101 1 : samplesSize);
102 1 : const Error error = _checkStatus();
103 1 : if (error)
104 : {
105 0 : LBDEBUG << "FrameBufferObject::init: " << error << " when binding "
106 0 : << _colors.size() << " color texture(s) of format 0x"
107 0 : << std::hex << colorFormat << std::dec << " size " << width
108 0 : << "x" << height << " FBO " << _fboID << std::endl;
109 0 : exit();
110 0 : return error;
111 : }
112 : }
113 1 : if (stencilSize > 0 && (GLEW_EXT_packed_depth_stencil || coreContext))
114 : {
115 1 : _depth.init(GL_DEPTH24_STENCIL8, width, height);
116 1 : _depth.bindToFBO(GL_DEPTH_STENCIL_ATTACHMENT, width, height,
117 1 : samplesSize);
118 1 : const Error error = _checkStatus();
119 1 : if (error)
120 : {
121 0 : LBDEBUG << "FrameBufferObject::init: " << error
122 0 : << " when binding GL_DEPTH24_STENCIL8 texture" << std::endl;
123 0 : exit();
124 0 : return error;
125 : }
126 : }
127 0 : else if (depthSize > 0)
128 : {
129 0 : _depth.init(GL_DEPTH_COMPONENT, width, height);
130 0 : _depth.bindToFBO(GL_DEPTH_ATTACHMENT, width, height, samplesSize);
131 0 : const Error error = _checkStatus();
132 0 : if (error)
133 : {
134 0 : LBDEBUG << "FrameBufferObject::init: " << error
135 0 : << " when binding GL_DEPTH_COMPONENT texture" << std::endl;
136 0 : exit();
137 0 : return error;
138 : }
139 : }
140 :
141 1 : const Error error = _checkStatus();
142 1 : if (error)
143 : {
144 0 : LBDEBUG << "FrameBufferObject::init: " << error << std::endl;
145 0 : exit();
146 : }
147 1 : return error;
148 : }
149 :
150 2 : void FrameBufferObject::exit()
151 : {
152 2 : LB_TS_THREAD(_thread);
153 2 : if (_fboID)
154 : {
155 1 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
156 1 : glDeleteFramebuffersEXT(1, &_fboID);
157 1 : _fboID = 0;
158 : }
159 :
160 4 : for (size_t i = 0; i < _colors.size(); ++i)
161 2 : _colors[i]->flush();
162 2 : _depth.flush();
163 :
164 2 : _valid = false;
165 2 : }
166 :
167 3 : Error FrameBufferObject::_checkStatus()
168 : {
169 3 : _valid = false;
170 :
171 3 : const GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
172 3 : switch (status)
173 : {
174 : case GL_FRAMEBUFFER_COMPLETE_EXT:
175 3 : _valid = true;
176 3 : return Error(ERROR_NONE);
177 :
178 : case 0: // error?!
179 0 : EQ_GL_ERROR("glCheckFramebufferStatusEXT");
180 0 : return Error(ERROR_FRAMEBUFFER_STATUS);
181 :
182 : case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
183 0 : return Error(ERROR_FRAMEBUFFER_UNSUPPORTED);
184 :
185 : case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
186 0 : return Error(ERROR_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
187 :
188 : case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
189 0 : return Error(ERROR_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
190 :
191 : case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
192 0 : return Error(ERROR_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
193 :
194 : case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
195 0 : return Error(ERROR_FRAMEBUFFER_INCOMPLETE_FORMATS);
196 :
197 : case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
198 0 : return Error(ERROR_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER);
199 :
200 : case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
201 0 : return Error(ERROR_FRAMEBUFFER_INCOMPLETE_READ_BUFFER);
202 :
203 : default:
204 0 : LBWARN << "Unhandled frame buffer status 0x" << std::hex << status
205 0 : << std::dec << std::endl;
206 0 : return Error(ERROR_FRAMEBUFFER_STATUS);
207 : }
208 : }
209 :
210 8 : void FrameBufferObject::bind(const uint32_t target)
211 : {
212 8 : LB_TS_THREAD(_thread);
213 8 : LBASSERT(_fboID);
214 8 : EQ_GL_CALL(glBindFramebufferEXT(target, _fboID));
215 8 : }
216 :
217 0 : void FrameBufferObject::unbind(const uint32_t target)
218 : {
219 0 : EQ_GL_CALL(glBindFramebufferEXT(target, 0));
220 0 : }
221 :
222 0 : Error FrameBufferObject::resize(const int32_t width, const int32_t height)
223 : {
224 0 : LB_TS_THREAD(_thread);
225 0 : LBASSERT(width > 0 && height > 0);
226 :
227 0 : LBASSERT(!_colors.empty());
228 0 : Texture* color = _colors.front();
229 :
230 0 : if (color->getWidth() == width && color->getHeight() == height && _valid)
231 0 : return Error(ERROR_NONE);
232 :
233 0 : for (size_t i = 0; i < _colors.size(); ++i)
234 0 : _colors[i]->resize(width, height);
235 :
236 0 : if (_depth.isValid())
237 0 : _depth.resize(width, height);
238 :
239 0 : return _checkStatus();
240 : }
241 : }
242 30 : }
|