Line data Source code
1 :
2 : /* Copyright (c) 2014-2017, Daniel Nachbaur <danielnachbaur@gmail.com>
3 : * Juan Hernando <jhernando@fi.upm.es>
4 : * Stefan.Eilemann@epfl.ch
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 : #ifndef EQ_QT_WINDOWIMPL_H
21 : #define EQ_QT_WINDOWIMPL_H
22 :
23 : #include "../eventHandler.h"
24 :
25 : #include <eq/util/frameBufferObject.h>
26 : #include <lunchbox/monitor.h>
27 :
28 : #include <QApplication>
29 : #include <QExposeEvent>
30 : #include <QOffscreenSurface>
31 : #include <QOpenGLContext>
32 : #include <QWindow>
33 :
34 : namespace eq
35 : {
36 : namespace qt
37 : {
38 : namespace detail
39 : {
40 : namespace
41 : {
42 : #define getAttribute(attr) settings.getIAttribute(WindowSettings::attr)
43 :
44 0 : QSurfaceFormat _createFormat(const WindowSettings& settings)
45 : {
46 : // defaults: http://doc.qt.io/qt-5/qsurfaceformat.html
47 0 : QSurfaceFormat format;
48 :
49 0 : const int coreProfile = getAttribute(IATTR_HINT_CORE_PROFILE);
50 0 : if (coreProfile == ON)
51 : {
52 0 : format.setMajorVersion(getAttribute(IATTR_HINT_OPENGL_MAJOR));
53 0 : format.setMinorVersion(getAttribute(IATTR_HINT_OPENGL_MINOR));
54 0 : format.setProfile(QSurfaceFormat::CoreProfile);
55 : }
56 :
57 0 : const int colorSize = getAttribute(IATTR_PLANES_COLOR);
58 0 : if (colorSize > 0 || colorSize == eq::AUTO)
59 : {
60 0 : const int colorBits = (colorSize > 0 ? colorSize : 8);
61 0 : format.setRedBufferSize(colorBits);
62 0 : format.setGreenBufferSize(colorBits);
63 0 : format.setBlueBufferSize(colorBits);
64 : }
65 :
66 0 : const int alphaPlanes = getAttribute(IATTR_PLANES_ALPHA);
67 0 : if (alphaPlanes > 0 || alphaPlanes == eq::AUTO)
68 : {
69 0 : const int alphaBits = (alphaPlanes > 0 ? alphaPlanes : 8);
70 0 : format.setAlphaBufferSize(alphaBits);
71 : }
72 :
73 0 : const int depthPlanes = getAttribute(IATTR_PLANES_DEPTH);
74 0 : if (depthPlanes > 0 || depthPlanes == eq::AUTO)
75 : {
76 0 : const int depthBits = (depthPlanes > 0 ? depthPlanes : 8);
77 0 : format.setDepthBufferSize(depthBits);
78 : }
79 : else
80 0 : format.setDepthBufferSize(0);
81 :
82 0 : const int stencilPlanes = getAttribute(IATTR_PLANES_STENCIL);
83 0 : if (stencilPlanes > 0 || stencilPlanes == eq::AUTO)
84 : {
85 0 : const int stencilBits = (stencilPlanes > 0 ? stencilPlanes : 8);
86 0 : format.setStencilBufferSize(stencilBits);
87 : }
88 : else
89 0 : format.setStencilBufferSize(0);
90 :
91 0 : const int samplesPlanes = getAttribute(IATTR_PLANES_SAMPLES);
92 0 : if (samplesPlanes >= 0)
93 : {
94 0 : format.setSamples(samplesPlanes);
95 : }
96 :
97 0 : if (getAttribute(IATTR_HINT_STEREO) == eq::ON)
98 : {
99 0 : format.setStereo(true);
100 : }
101 :
102 0 : if (getAttribute(IATTR_HINT_DOUBLEBUFFER) == eq::ON ||
103 0 : (getAttribute(IATTR_HINT_DOUBLEBUFFER) == eq::AUTO &&
104 0 : getAttribute(IATTR_HINT_DRAWABLE) == eq::WINDOW))
105 : {
106 0 : format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
107 : }
108 : else
109 0 : format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
110 :
111 0 : return format;
112 : }
113 : #undef getAttribute
114 : }
115 :
116 : class Window
117 : {
118 : public:
119 0 : Window(WindowIF& window, QThread* qThread)
120 0 : : _eventHandler(window)
121 : {
122 0 : if (qThread)
123 0 : _eventHandler.moveToThread(qThread);
124 0 : }
125 :
126 0 : virtual ~Window() {}
127 : virtual QOpenGLContext* getContext() const = 0;
128 : virtual bool configInit() = 0;
129 : virtual void makeCurrent() = 0;
130 : virtual void doneCurrent() = 0;
131 : virtual void swapBuffers() = 0;
132 0 : virtual void resize(const PixelViewport&){};
133 0 : virtual QObject* getEventProcessor() { return &_eventHandler; }
134 : protected:
135 : EventHandler _eventHandler;
136 : };
137 :
138 0 : class QWindowWrapper : public Window, public QWindow
139 : {
140 : public:
141 0 : QWindowWrapper(WindowIF& window, QThread* qThread,
142 : const WindowSettings& settings, QScreen* screen_,
143 : QOpenGLContext* shareContext)
144 0 : : detail::Window(window, qThread)
145 0 : , _context(new QOpenGLContext)
146 0 : , _realized(false)
147 : {
148 0 : setScreen(screen_);
149 0 : const QSurfaceFormat& format_ = _createFormat(settings);
150 0 : setFormat(format_);
151 0 : const PixelViewport& pvp = settings.getPixelViewport();
152 0 : setGeometry(pvp.x, pvp.y, pvp.w, pvp.h);
153 0 : setSurfaceType(QSurface::OpenGLSurface);
154 :
155 0 : _context->setFormat(format());
156 0 : _context->setShareContext(shareContext);
157 :
158 0 : if (settings.getIAttribute(WindowSettings::IATTR_HINT_FULLSCREEN) ==
159 : eq::ON)
160 : {
161 0 : showFullScreen();
162 : }
163 : else
164 0 : show();
165 0 : }
166 :
167 0 : QOpenGLContext* getContext() const final { return _context.data(); }
168 0 : void makeCurrent() final
169 : {
170 0 : if (!_context->makeCurrent(this))
171 0 : LBWARN << "QOpenGLContext::makeCurrent failed: " << _context.data()
172 0 : << std::endl;
173 0 : }
174 :
175 0 : void doneCurrent() final { _context->doneCurrent(); }
176 0 : void swapBuffers() final
177 : {
178 0 : if (isExposed())
179 0 : _context->swapBuffers(this);
180 0 : }
181 :
182 0 : void resize(const PixelViewport& pvp) final
183 : {
184 0 : setPosition(pvp.x, pvp.y);
185 0 : QWindow::resize(pvp.w, pvp.h);
186 0 : }
187 :
188 0 : bool configInit() final
189 : {
190 : // The application thread must be running the event loop somewhere
191 : // else. Otherwise this code will wait forever.
192 0 : _realized.waitEQ(true);
193 :
194 0 : if (!_context->create())
195 0 : return false;
196 :
197 : // Adjusting the actual window viewport in case the window manager
198 : // disobeyed the requested geometry.
199 0 : WindowIF& window = _eventHandler.getWindow();
200 0 : window.setPixelViewport(PixelViewport(x(), y(), width(), height()));
201 0 : return true;
202 : }
203 :
204 0 : QObject* getEventProcessor() final { return this; }
205 : protected:
206 0 : bool event(QEvent* qevent) final
207 : {
208 0 : if (qevent->type() == QEvent::Expose)
209 : {
210 0 : const QExposeEvent* expose = static_cast<QExposeEvent*>(qevent);
211 0 : _realized = !expose->region().isEmpty();
212 : }
213 :
214 0 : QApplication::sendEvent(&_eventHandler, qevent);
215 0 : return true;
216 : }
217 :
218 : private:
219 : QScopedPointer<QOpenGLContext> _context;
220 :
221 : lunchbox::Monitorb _realized;
222 : };
223 :
224 0 : class QOffscreenSurfaceWrapper : public Window, public QOffscreenSurface
225 : {
226 : public:
227 0 : QOffscreenSurfaceWrapper(WindowIF& window, QThread* qThread,
228 : const WindowSettings& settings, QScreen* screen_,
229 : QOpenGLContext* shareContext)
230 0 : : detail::Window(window, qThread)
231 0 : , _context(new QOpenGLContext)
232 : {
233 0 : setScreen(screen_);
234 0 : const QSurfaceFormat& format_ = _createFormat(settings);
235 0 : setFormat(format_);
236 :
237 0 : _context->setFormat(format());
238 0 : _context->setShareContext(shareContext);
239 0 : create();
240 0 : }
241 :
242 0 : QOpenGLContext* getContext() const final { return _context.data(); }
243 0 : void makeCurrent() final
244 : {
245 0 : if (!_context->makeCurrent(this))
246 0 : LBWARN << "QOpenGLContext::makeCurrent failed: " << _context.data()
247 0 : << std::endl;
248 0 : }
249 :
250 0 : void doneCurrent() final { _context->doneCurrent(); }
251 0 : void swapBuffers() final
252 : {
253 0 : if (isValid())
254 0 : _context->swapBuffers(this);
255 0 : }
256 :
257 0 : bool configInit() final { return isValid() && _context->create(); }
258 : private:
259 : QScopedPointer<QOpenGLContext> _context;
260 : };
261 : }
262 : }
263 : }
264 :
265 : #endif
|