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