Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtOpenGL module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include <QDebug> |
43 | |
44 | #include <QtGui/private/qt_x11_p.h> |
45 | #include <QtGui/private/qegl_p.h> |
46 | #include <QtGui/private/qeglproperties_p.h> |
47 | #include <QtGui/private/qeglcontext_p.h> |
48 | |
49 | #if !defined(QT_OPENGL_ES_1) |
50 | #include <QtOpenGL/private/qpaintengineex_opengl2_p.h> |
51 | #endif |
52 | |
53 | #ifndef QT_OPENGL_ES_2 |
54 | #include <QtOpenGL/private/qpaintengine_opengl_p.h> |
55 | #endif |
56 | |
57 | #include <QtOpenGL/private/qgl_p.h> |
58 | #include <QtOpenGL/private/qgl_egl_p.h> |
59 | |
60 | #include "qpixmapdata_x11gl_p.h" |
61 | |
62 | QT_BEGIN_NAMESPACE |
63 | |
64 | |
65 | class QX11GLSharedContexts |
66 | { |
67 | public: |
68 | QX11GLSharedContexts() |
69 | : rgbContext(0) |
70 | , argbContext(0) |
71 | , sharedQGLContext(0) |
72 | , sharePixmap(0) |
73 | { |
74 | EGLint rgbConfigId; |
75 | EGLint argbConfigId; |
76 | |
77 | do { |
78 | EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); |
79 | EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, |
80 | QEgl::Renderable | QEgl::Translucent); |
81 | |
82 | eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); |
83 | eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); |
84 | |
85 | rgbContext = new QEglContext; |
86 | rgbContext->setConfig(rgbConfig); |
87 | rgbContext->createContext(); |
88 | |
89 | if (!rgbContext->isValid()) |
90 | break; |
91 | |
92 | // If the RGB & ARGB configs are the same, use the same egl context for both: |
93 | if (rgbConfig == argbConfig) |
94 | argbContext = rgbContext; |
95 | |
96 | // Otherwise, create a separate context to be used for ARGB pixmaps: |
97 | if (!argbContext) { |
98 | argbContext = new QEglContext; |
99 | argbContext->setConfig(argbConfig); |
100 | bool success = argbContext->createContext(rgbContext); |
101 | if (!success) { |
102 | qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); |
103 | success = argbContext->createContext(); |
104 | if (!success) |
105 | argbContext = rgbContext; // Might work, worth a shot at least. |
106 | } |
107 | } |
108 | |
109 | if (!argbContext->isValid()) |
110 | break; |
111 | |
112 | // Create the pixmap which will be used to create the egl surface for the share QGLContext |
113 | QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); |
114 | rgbPixmapData->resize(8, 8); |
115 | rgbPixmapData->fill(Qt::red); |
116 | sharePixmap = new QPixmap(rgbPixmapData); |
117 | EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig); |
118 | rgbPixmapData->gl_surface = (void*)sharePixmapSurface; |
119 | |
120 | // Create the actual QGLContext which will be used for sharing |
121 | sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat()); |
122 | sharedQGLContext->d_func()->eglContext = rgbContext; |
123 | sharedQGLContext->d_func()->eglSurface = sharePixmapSurface; |
124 | sharedQGLContext->d_func()->valid = true; |
125 | qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig); |
126 | |
127 | |
128 | valid = rgbContext->makeCurrent(sharePixmapSurface); |
129 | |
130 | // If the ARGB & RGB configs are different, check ARGB works too: |
131 | if (argbConfig != rgbConfig) { |
132 | QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); |
133 | argbPixmapData->resize(8, 8); |
134 | argbPixmapData->fill(Qt::transparent); // Force ARGB |
135 | QPixmap argbPixmap(argbPixmapData); // destroys pixmap data when goes out of scope |
136 | EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); |
137 | valid = argbContext->makeCurrent(argbPixmapSurface); |
138 | argbContext->doneCurrent(); |
139 | eglDestroySurface(QEgl::display(), argbPixmapSurface); |
140 | argbPixmapData->gl_surface = 0; |
141 | } |
142 | |
143 | if (!valid) { |
144 | qWarning() << "Unable to make pixmap surface current:"<< QEgl::errorString(); |
145 | break; |
146 | } |
147 | |
148 | // The pixmap surface destruction hooks are installed by QGLTextureCache, so we |
149 | // must make sure this is instanciated: |
150 | QGLTextureCache::instance(); |
151 | } while(0); |
152 | |
153 | if (!valid) |
154 | cleanup(); |
155 | else |
156 | qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); |
157 | |
158 | } |
159 | |
160 | ~QX11GLSharedContexts() { |
161 | cleanup(); |
162 | } |
163 | |
164 | void cleanup() { |
165 | if (sharedQGLContext) { |
166 | delete sharedQGLContext; |
167 | sharedQGLContext = 0; |
168 | } |
169 | if (argbContext && argbContext != rgbContext) |
170 | delete argbContext; |
171 | argbContext = 0; |
172 | |
173 | if (rgbContext) { |
174 | delete rgbContext; |
175 | rgbContext = 0; |
176 | } |
177 | |
178 | // Deleting the QPixmap will fire the pixmap destruction cleanup hooks which in turn |
179 | // will destroy the egl surface: |
180 | if (sharePixmap) { |
181 | delete sharePixmap; |
182 | sharePixmap = 0; |
183 | } |
184 | } |
185 | |
186 | bool isValid() { return valid;} |
187 | |
188 | // On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need |
189 | // different contexts: |
190 | QEglContext *rgbContext; |
191 | QEglContext *argbContext; |
192 | |
193 | // The share context wraps the rgbContext and is used as the master of the context share |
194 | // group. As all other contexts will have the same egl context (or a shared one if rgb != argb) |
195 | // all QGLContexts will actually be sharing and can be in the same context group. |
196 | QGLContext *sharedQGLContext; |
197 | private: |
198 | QPixmap *sharePixmap; |
199 | bool valid; |
200 | }; |
201 | |
202 | static void qt_cleanup_x11gl_share_contexts(); |
203 | |
204 | Q_GLOBAL_STATIC_WITH_INITIALIZER(QX11GLSharedContexts, qt_x11gl_share_contexts, |
205 | { |
206 | qAddPostRoutine(qt_cleanup_x11gl_share_contexts); |
207 | }) |
208 | |
209 | static void qt_cleanup_x11gl_share_contexts() |
210 | { |
211 | qt_x11gl_share_contexts()->cleanup(); |
212 | } |
213 | |
214 | |
215 | QX11GLSharedContexts* QX11GLPixmapData::sharedContexts() |
216 | { |
217 | return qt_x11gl_share_contexts(); |
218 | } |
219 | |
220 | bool QX11GLPixmapData::hasX11GLPixmaps() |
221 | { |
222 | static bool checkedForX11GLPixmaps = false; |
223 | static bool haveX11GLPixmaps = false; |
224 | |
225 | if (checkedForX11GLPixmaps) |
226 | return haveX11GLPixmaps; |
227 | |
228 | haveX11GLPixmaps = qt_x11gl_share_contexts()->isValid(); |
229 | checkedForX11GLPixmaps = true; |
230 | |
231 | return haveX11GLPixmaps; |
232 | } |
233 | |
234 | QX11GLPixmapData::QX11GLPixmapData() |
235 | : QX11PixmapData(QPixmapData::PixmapType), |
236 | ctx(0) |
237 | { |
238 | } |
239 | |
240 | QX11GLPixmapData::~QX11GLPixmapData() |
241 | { |
242 | if (ctx) |
243 | delete ctx; |
244 | } |
245 | |
246 | |
247 | void QX11GLPixmapData::fill(const QColor &color) |
248 | { |
249 | if (ctx) { |
250 | ctx->makeCurrent(); |
251 | glFinish(); |
252 | eglWaitClient(); |
253 | } |
254 | |
255 | QX11PixmapData::fill(color); |
256 | XSync(X11->display, False); |
257 | |
258 | if (ctx) { |
259 | ctx->makeCurrent(); |
260 | eglWaitNative(EGL_CORE_NATIVE_ENGINE); |
261 | } |
262 | } |
263 | |
264 | void QX11GLPixmapData::copy(const QPixmapData *data, const QRect &rect) |
265 | { |
266 | if (ctx) { |
267 | ctx->makeCurrent(); |
268 | glFinish(); |
269 | eglWaitClient(); |
270 | } |
271 | |
272 | QX11PixmapData::copy(data, rect); |
273 | XSync(X11->display, False); |
274 | |
275 | if (ctx) { |
276 | ctx->makeCurrent(); |
277 | eglWaitNative(EGL_CORE_NATIVE_ENGINE); |
278 | } |
279 | } |
280 | |
281 | bool QX11GLPixmapData::scroll(int dx, int dy, const QRect &rect) |
282 | { |
283 | if (ctx) { |
284 | ctx->makeCurrent(); |
285 | glFinish(); |
286 | eglWaitClient(); |
287 | } |
288 | |
289 | bool success = QX11PixmapData::scroll(dx, dy, rect); |
290 | XSync(X11->display, False); |
291 | |
292 | if (ctx) { |
293 | ctx->makeCurrent(); |
294 | eglWaitNative(EGL_CORE_NATIVE_ENGINE); |
295 | } |
296 | |
297 | return success; |
298 | } |
299 | |
300 | #if !defined(QT_OPENGL_ES_1) |
301 | Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_pixmap_2_engine) |
302 | #endif |
303 | |
304 | #ifndef QT_OPENGL_ES_2 |
305 | Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_pixmap_engine) |
306 | #endif |
307 | |
308 | |
309 | QPaintEngine* QX11GLPixmapData::paintEngine() const |
310 | { |
311 | // We need to create the context before beginPaint - do it here: |
312 | if (!ctx) { |
313 | ctx = new QGLContext(glFormat()); |
314 | Q_ASSERT(ctx->d_func()->eglContext == 0); |
315 | ctx->d_func()->eglContext = hasAlphaChannel() ? sharedContexts()->argbContext : sharedContexts()->rgbContext; |
316 | |
317 | // While we use a separate QGLContext for each pixmap, the underlying QEglContext is |
318 | // the same. So we must use a "fake" QGLContext and fool the texture cache into thinking |
319 | // each pixmap's QGLContext is sharing with this central one. The only place this is |
320 | // going to fail is where we the underlying EGL RGB and ARGB contexts aren't sharing. |
321 | ctx->d_func()->sharing = true; |
322 | QGLContextGroup::addShare(ctx, sharedContexts()->sharedQGLContext); |
323 | |
324 | // Update the glFormat for the QGLContext: |
325 | qt_glformat_from_eglconfig(ctx->d_func()->glFormat, ctx->d_func()->eglContext->config()); |
326 | } |
327 | |
328 | QPaintEngine* engine; |
329 | |
330 | #if defined(QT_OPENGL_ES_1) |
331 | engine = qt_gl_pixmap_engine(); |
332 | #elif defined(QT_OPENGL_ES_2) |
333 | engine = qt_gl_pixmap_2_engine(); |
334 | #else |
335 | if (qt_gl_preferGL2Engine()) |
336 | engine = qt_gl_pixmap_2_engine(); |
337 | else |
338 | engine = qt_gl_pixmap_engine(); |
339 | #endif |
340 | |
341 | |
342 | |
343 | // Support multiple painters on multiple pixmaps simultaniously |
344 | if (engine->isActive()) { |
345 | qWarning("Pixmap paint engine already active"); |
346 | |
347 | #if defined(QT_OPENGL_ES_1) |
348 | engine = new QOpenGLPaintEngine; |
349 | #elif defined(QT_OPENGL_ES_2) |
350 | engine = new QGL2PaintEngineEx; |
351 | #else |
352 | if (qt_gl_preferGL2Engine()) |
353 | engine = new QGL2PaintEngineEx; |
354 | else |
355 | engine = new QOpenGLPaintEngine; |
356 | #endif |
357 | |
358 | engine->setAutoDestruct(true); |
359 | return engine; |
360 | } |
361 | |
362 | return engine; |
363 | } |
364 | |
365 | void QX11GLPixmapData::beginPaint() |
366 | { |
367 | // qDebug("QX11GLPixmapData::beginPaint()"); |
368 | // TODO: Check to see if the surface is renderable |
369 | if ((EGLSurface)gl_surface == EGL_NO_SURFACE) { |
370 | QPixmap tmpPixmap(this); |
371 | EGLConfig cfg = ctx->d_func()->eglContext->config(); |
372 | Q_ASSERT(cfg != QEGL_NO_CONFIG); |
373 | |
374 | // qDebug("QX11GLPixmapData - using EGL Config ID %d", ctx->d_func()->eglContext->configAttrib(EGL_CONFIG_ID)); |
375 | EGLSurface surface = QEgl::createSurface(&tmpPixmap, cfg); |
376 | if (surface == EGL_NO_SURFACE) { |
377 | qWarning() << "Error creating EGL surface for pixmap:"<< QEgl::errorString(); |
378 | return; |
379 | } |
380 | gl_surface = (void*)surface; |
381 | ctx->d_func()->eglSurface = surface; |
382 | ctx->d_func()->valid = true; |
383 | } |
384 | QGLPaintDevice::beginPaint(); |
385 | } |
386 | |
387 | QGLContext* QX11GLPixmapData::context() const |
388 | { |
389 | return ctx; |
390 | } |
391 | |
392 | QSize QX11GLPixmapData::size() const |
393 | { |
394 | return QSize(w, h); |
395 | } |
396 | |
397 | |
398 | QGLFormat QX11GLPixmapData::glFormat() |
399 | { |
400 | return QGLFormat::defaultFormat(); //### |
401 | } |
402 | |
403 | QT_END_NAMESPACE |
404 |
Warning: That file was not part of the compilation database. It may have many parsing errors.