Line data Source code
1 :
2 : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Makhinya Maxim
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 "glWindow.h"
21 :
22 : #include "error.h"
23 : #include "gl.h"
24 : #include "global.h"
25 : #include "pipe.h"
26 :
27 : #include <eq/fabric/drawableConfig.h>
28 : #include <eq/util/frameBufferObject.h>
29 : #include <lunchbox/os.h>
30 : #include <lunchbox/perThread.h>
31 :
32 : template void lunchbox::perThreadNoDelete<const eq::GLWindow>(
33 : const eq::GLWindow*);
34 :
35 : namespace eq
36 : {
37 : namespace
38 : {
39 10 : lunchbox::PerThread<const GLWindow, lunchbox::perThreadNoDelete> _current;
40 : }
41 : namespace detail
42 : {
43 : class GLWindow
44 : {
45 : public:
46 3 : GLWindow()
47 3 : : glewContext(nullptr)
48 : , fbo(nullptr)
49 3 : , fboMultiSample(nullptr)
50 : {
51 3 : }
52 :
53 3 : ~GLWindow() { delete glewContext; }
54 : /** Extended OpenGL function entries when window has a context. */
55 : GLEWContext* glewContext;
56 :
57 : /** Frame buffer object for FBO drawables. */
58 : util::FrameBufferObject* fbo;
59 :
60 : util::FrameBufferObject* fboMultiSample;
61 : };
62 : }
63 :
64 3 : GLWindow::GLWindow(NotifierInterface& parent, const WindowSettings& settings)
65 : : SystemWindow(parent, settings)
66 3 : , _impl(new detail::GLWindow)
67 : {
68 3 : }
69 :
70 6 : GLWindow::~GLWindow()
71 : {
72 3 : if (_current == this)
73 3 : _current = 0;
74 3 : delete _impl;
75 3 : }
76 :
77 0 : void GLWindow::resize(const PixelViewport& pvp)
78 : {
79 0 : if (_impl->fbo)
80 : {
81 0 : _impl->fbo->bind();
82 0 : _impl->fbo->resize(pvp.w, pvp.h);
83 0 : _impl->fbo->unbind();
84 0 : if (_impl->fboMultiSample)
85 : {
86 0 : _impl->fboMultiSample->bind(GL_DRAW_FRAMEBUFFER_EXT);
87 0 : _impl->fboMultiSample->resize(pvp.w, pvp.h);
88 0 : _impl->fboMultiSample->unbind(GL_DRAW_FRAMEBUFFER_EXT);
89 : }
90 : }
91 : else
92 0 : _resize(pvp);
93 0 : }
94 :
95 5 : void GLWindow::makeCurrent(const bool useCache) const
96 : {
97 5 : if (useCache && _current == this)
98 0 : return;
99 :
100 5 : bindFrameBuffer();
101 5 : _current = this;
102 : }
103 :
104 1 : void GLWindow::doneCurrent() const
105 : {
106 1 : if (!_current)
107 0 : return;
108 :
109 1 : if (_impl->fbo)
110 0 : _impl->fbo->unbind();
111 1 : _current = 0;
112 : }
113 :
114 16 : bool GLWindow::isCurrent() const
115 : {
116 16 : return _current == this;
117 : }
118 :
119 3 : void GLWindow::initGLEW()
120 : {
121 3 : if (_impl->glewContext)
122 0 : return;
123 :
124 3 : _impl->glewContext = new GLEWContext;
125 :
126 : #ifdef __linux__
127 : // http://sourceforge.net/p/glew/patches/40/
128 3 : glewExperimental = true;
129 : #endif
130 :
131 3 : const GLenum result = glewInit();
132 3 : glGetError(); // eat GL errors from buggy glew implementation
133 3 : if (result == GLEW_OK)
134 3 : return;
135 :
136 0 : LBWARN << "GLEW initialization failed: " << result << std::endl;
137 0 : delete _impl->glewContext;
138 0 : _impl->glewContext = nullptr;
139 : }
140 :
141 3 : void GLWindow::exitGLEW()
142 : {
143 3 : delete _impl->glewContext;
144 3 : _impl->glewContext = nullptr;
145 3 : }
146 :
147 5 : const util::FrameBufferObject* GLWindow::getFrameBufferObject() const
148 : {
149 5 : return _impl->fbo;
150 : }
151 :
152 0 : util::FrameBufferObject* GLWindow::getFrameBufferObject()
153 : {
154 0 : return _impl->fbo;
155 : }
156 :
157 26 : const GLEWContext* GLWindow::glewGetContext() const
158 : {
159 26 : return _impl->glewContext;
160 : }
161 :
162 34 : GLEWContext* GLWindow::glewGetContext()
163 : {
164 34 : return _impl->glewContext;
165 : }
166 :
167 1 : bool GLWindow::configInitFBO()
168 : {
169 1 : if (!_impl->glewContext || !GLEW_EXT_framebuffer_object)
170 : {
171 0 : sendError(ERROR_FBO_UNSUPPORTED);
172 0 : return false;
173 : }
174 :
175 1 : if (!_createFBO(_impl->fbo, 0))
176 0 : return false;
177 :
178 1 : const int samplesSize = getIAttribute(WindowSettings::IATTR_PLANES_SAMPLES);
179 1 : if (samplesSize <= 0)
180 1 : return true;
181 :
182 0 : return _createFBO(_impl->fboMultiSample, samplesSize);
183 : }
184 :
185 3 : void GLWindow::configExitFBO()
186 : {
187 3 : _destroyFBO(_impl->fboMultiSample);
188 3 : _destroyFBO(_impl->fbo);
189 3 : }
190 :
191 1 : bool GLWindow::_createFBO(util::FrameBufferObject*& fbo, const int samplesSize)
192 : {
193 1 : const PixelViewport& pvp = getPixelViewport();
194 1 : const GLuint colorFormat = getColorFormat();
195 :
196 1 : int depthSize = getIAttribute(WindowSettings::IATTR_PLANES_DEPTH);
197 1 : if (depthSize == AUTO)
198 1 : depthSize = 24;
199 :
200 1 : int stencilSize = getIAttribute(WindowSettings::IATTR_PLANES_STENCIL);
201 1 : if (stencilSize == AUTO)
202 1 : stencilSize = 1;
203 :
204 2 : fbo = new util::FrameBufferObject(_impl->glewContext,
205 : samplesSize ? GL_TEXTURE_2D_MULTISAMPLE
206 2 : : GL_TEXTURE_RECTANGLE_ARB);
207 1 : Error error = fbo->init(pvp.w, pvp.h, colorFormat, depthSize, stencilSize,
208 1 : samplesSize);
209 1 : if (!error)
210 1 : return true;
211 :
212 0 : if (getIAttribute(WindowSettings::IATTR_PLANES_STENCIL) == AUTO)
213 0 : error = fbo->init(pvp.w, pvp.h, colorFormat, depthSize, 0, samplesSize);
214 :
215 0 : if (!error)
216 0 : return true;
217 :
218 0 : sendError(error.getCode());
219 0 : delete fbo;
220 0 : fbo = 0;
221 0 : return false;
222 : }
223 :
224 6 : void GLWindow::_destroyFBO(util::FrameBufferObject*& fbo)
225 : {
226 6 : if (!fbo)
227 5 : return;
228 :
229 1 : fbo->exit();
230 1 : delete fbo;
231 1 : fbo = 0;
232 : }
233 :
234 16 : void GLWindow::bindFrameBuffer() const
235 : {
236 16 : if (!_impl->glewContext)
237 3 : return;
238 :
239 13 : if (_impl->fbo)
240 6 : _impl->fbo->bind();
241 7 : else if (GLEW_EXT_framebuffer_object)
242 7 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
243 : }
244 :
245 5 : void GLWindow::bindDrawFrameBuffer() const
246 : {
247 5 : if (!_impl->glewContext)
248 0 : return;
249 :
250 5 : if (_impl->fboMultiSample)
251 0 : _impl->fboMultiSample->bind(GL_DRAW_FRAMEBUFFER_EXT);
252 5 : else if (_impl->fbo)
253 2 : _impl->fbo->bind(GL_DRAW_FRAMEBUFFER_EXT);
254 3 : else if (GLEW_EXT_framebuffer_object)
255 3 : glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
256 : }
257 :
258 5 : void GLWindow::updateFrameBuffer() const
259 : {
260 5 : if (!_impl->glewContext || !_impl->fboMultiSample)
261 5 : return;
262 :
263 0 : _impl->fboMultiSample->bind(GL_READ_FRAMEBUFFER_EXT);
264 0 : _impl->fbo->bind(GL_DRAW_FRAMEBUFFER_EXT);
265 0 : const PixelViewport& pvp = getPixelViewport();
266 0 : EQ_GL_CALL(glBlitFramebuffer(0, 0, pvp.w, pvp.h, 0, 0, pvp.w, pvp.h,
267 : GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
268 : GL_STENCIL_BUFFER_BIT,
269 : GL_NEAREST));
270 : }
271 :
272 2 : void GLWindow::flush()
273 : {
274 2 : glFlush();
275 2 : }
276 :
277 25 : void GLWindow::finish()
278 : {
279 25 : glFinish();
280 25 : }
281 :
282 : #define TEST_GLEW_VERSION(MAJOR, MINOR) \
283 : if (GLEW_VERSION_##MAJOR##_##MINOR) \
284 : dc.glewGLVersion = MAJOR##.##MINOR##f;
285 :
286 2 : void GLWindow::queryDrawableConfig(DrawableConfig& dc)
287 : {
288 2 : dc = DrawableConfig();
289 :
290 : // GL version
291 2 : const char* glVersion = (const char*)glGetString(GL_VERSION);
292 2 : if (!glVersion) // most likely no context
293 : {
294 0 : LBWARN << "glGetString(GL_VERSION) returned 0, assuming GL version 1.1"
295 0 : << std::endl;
296 0 : dc.glVersion = 1.1f;
297 : }
298 : else
299 2 : dc.glVersion = static_cast<float>(std::atof(glVersion));
300 :
301 2 : if (dc.glVersion >= 3.2f)
302 : {
303 : GLint mask;
304 2 : EQ_GL_CALL(glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask));
305 2 : dc.coreProfile = mask & GL_CONTEXT_CORE_PROFILE_BIT;
306 : }
307 :
308 2 : TEST_GLEW_VERSION(1, 1);
309 2 : TEST_GLEW_VERSION(1, 2);
310 2 : TEST_GLEW_VERSION(1, 3);
311 2 : TEST_GLEW_VERSION(1, 4);
312 2 : TEST_GLEW_VERSION(1, 5);
313 2 : TEST_GLEW_VERSION(2, 0);
314 2 : TEST_GLEW_VERSION(2, 1);
315 2 : TEST_GLEW_VERSION(3, 0);
316 2 : TEST_GLEW_VERSION(3, 1);
317 2 : TEST_GLEW_VERSION(3, 2);
318 2 : TEST_GLEW_VERSION(3, 3);
319 2 : TEST_GLEW_VERSION(4, 0);
320 2 : TEST_GLEW_VERSION(4, 1);
321 2 : TEST_GLEW_VERSION(4, 2);
322 2 : TEST_GLEW_VERSION(4, 3);
323 : #ifdef GLEW_VERSION_4_5
324 : TEST_GLEW_VERSION(4, 4);
325 : TEST_GLEW_VERSION(4, 5);
326 : #endif
327 :
328 : // Framebuffer capabilities
329 : GLboolean result;
330 2 : EQ_GL_CALL(glGetBooleanv(GL_STEREO, &result));
331 2 : dc.stereo = result;
332 :
333 2 : EQ_GL_CALL(glGetBooleanv(GL_DOUBLEBUFFER, &result));
334 2 : dc.doublebuffered = result;
335 :
336 2 : if (dc.coreProfile)
337 : {
338 0 : if (getFrameBufferObject())
339 : {
340 0 : glGetFramebufferAttachmentParameteriv(
341 : GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
342 0 : GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &dc.stencilBits);
343 : // eat GL error if no stencil attachment; should return '0' bits
344 : // according to spec, but gives GL_INVALID_OPERATION
345 0 : glGetError();
346 0 : EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
347 : GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
348 : GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &dc.colorBits));
349 0 : EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
350 : GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
351 : GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, &dc.alphaBits));
352 : }
353 : else
354 : {
355 0 : EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
356 : GL_FRAMEBUFFER, GL_FRONT_LEFT,
357 : GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &dc.stencilBits));
358 0 : EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
359 : GL_FRAMEBUFFER, GL_FRONT_LEFT,
360 : GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &dc.colorBits));
361 0 : EQ_GL_CALL(glGetFramebufferAttachmentParameteriv(
362 : GL_FRAMEBUFFER, GL_FRONT_LEFT,
363 : GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, &dc.alphaBits));
364 : }
365 : }
366 : else
367 : {
368 2 : EQ_GL_CALL(glGetIntegerv(GL_STENCIL_BITS, &dc.stencilBits));
369 2 : EQ_GL_CALL(glGetIntegerv(GL_RED_BITS, &dc.colorBits));
370 2 : EQ_GL_CALL(glGetIntegerv(GL_ALPHA_BITS, &dc.alphaBits));
371 2 : EQ_GL_CALL(glGetIntegerv(GL_ACCUM_RED_BITS, &dc.accumBits));
372 : }
373 :
374 2 : dc.accumBits *= 4;
375 2 : LBDEBUG << "Window drawable config: " << dc << std::endl;
376 2 : }
377 30 : }
|