39 ** |
39 ** |
40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include <QDebug> |
42 #include <QDebug> |
43 |
43 |
44 #include <private/qgl_p.h> |
44 #include <QtGui/private/qt_x11_p.h> |
45 #include <private/qegl_p.h> |
45 #include <QtGui/private/qegl_p.h> |
46 #include <private/qeglproperties_p.h> |
46 #include <QtGui/private/qeglproperties_p.h> |
47 |
47 #include <QtGui/private/qeglcontext_p.h> |
48 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) |
48 |
49 #include <private/qpaintengineex_opengl2_p.h> |
49 #if !defined(QT_OPENGL_ES_1) |
|
50 #include <QtOpenGL/private/qpaintengineex_opengl2_p.h> |
50 #endif |
51 #endif |
51 |
52 |
52 #ifndef QT_OPENGL_ES_2 |
53 #ifndef QT_OPENGL_ES_2 |
53 #include <private/qpaintengine_opengl_p.h> |
54 #include <QtOpenGL/private/qpaintengine_opengl_p.h> |
54 #endif |
55 #endif |
|
56 |
|
57 #include <QtOpenGL/private/qgl_p.h> |
|
58 #include <QtOpenGL/private/qgl_egl_p.h> |
55 |
59 |
56 #include "qpixmapdata_x11gl_p.h" |
60 #include "qpixmapdata_x11gl_p.h" |
57 |
61 |
58 QT_BEGIN_NAMESPACE |
62 QT_BEGIN_NAMESPACE |
59 |
63 |
60 extern EGLConfig qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly); // in qgl_x11egl.cpp |
64 |
61 extern bool qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly); // in qgl_x11egl.cpp |
65 class QX11GLSharedContexts |
62 |
66 { |
63 // On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need |
67 public: |
64 // different contexts: |
68 QX11GLSharedContexts() |
65 static EGLContext qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; |
69 : rgbContext(0) |
66 static EGLContext qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; |
70 , argbContext(0) |
67 |
71 , sharedQGLContext(0) |
68 bool QX11GLPixmapData::hasX11GLPixmaps() |
72 , sharePixmap(0) |
69 { |
73 { |
70 static bool checkedForX11Pixmaps = false; |
74 EGLint rgbConfigId; |
71 static bool haveX11Pixmaps = false; |
75 EGLint argbConfigId; |
72 |
76 |
73 if (checkedForX11Pixmaps) |
77 do { |
74 return haveX11Pixmaps; |
78 EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); |
75 |
79 EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, |
76 checkedForX11Pixmaps = true; |
80 QEgl::Renderable | QEgl::Translucent); |
77 |
81 |
78 QX11PixmapData *argbPixmapData = 0; |
82 eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); |
79 QX11PixmapData *rgbPixmapData = 0; |
83 eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); |
80 do { |
84 |
81 if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) |
85 rgbContext = new QEglContext; |
82 break; |
86 rgbContext->setConfig(rgbConfig); |
83 |
87 rgbContext->createContext(); |
84 // Check we actually have EGL configs which support pixmaps |
88 |
85 EGLConfig argbConfig = qt_chooseEGLConfigForPixmap(true, false); |
89 if (!rgbContext->isValid()) |
86 EGLConfig rgbConfig = qt_chooseEGLConfigForPixmap(false, false); |
90 break; |
87 |
91 |
88 if (argbConfig == 0 || rgbConfig == 0) |
92 // If the RGB & ARGB configs are the same, use the same egl context for both: |
89 break; |
93 if (rgbConfig == argbConfig) |
90 |
94 argbContext = rgbContext; |
91 // Create the shared contexts: |
95 |
92 eglBindAPI(EGL_OPENGL_ES_API); |
96 // Otherwise, create a seperate context to be used for ARGB pixmaps: |
93 EGLint contextAttribs[] = { |
97 if (!argbContext) { |
94 #if defined(QT_OPENGL_ES_2) |
98 argbContext = new QEglContext; |
95 EGL_CONTEXT_CLIENT_VERSION, 2, |
99 argbContext->setConfig(argbConfig); |
96 #endif |
100 bool success = argbContext->createContext(rgbContext); |
97 EGL_NONE |
101 if (!success) { |
98 }; |
102 qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); |
99 qPixmapARGBSharedEglContext = eglCreateContext(QEglContext::display(), |
103 success = argbContext->createContext(); |
100 argbConfig, 0, contextAttribs); |
104 if (!success) |
101 |
105 argbContext = rgbContext; // Might work, worth a shot at least. |
102 if (argbConfig == rgbConfig) { |
106 } |
103 // If the configs are the same, we can re-use the same context. |
107 } |
104 qPixmapRGBSharedEglContext = qPixmapARGBSharedEglContext; |
108 |
105 } else { |
109 if (!argbContext->isValid()) |
106 qPixmapRGBSharedEglContext = eglCreateContext(QEglContext::display(), |
110 break; |
107 rgbConfig, 0, contextAttribs); |
111 |
108 } |
112 // Create the pixmap which will be used to create the egl surface for the share QGLContext |
109 |
113 QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); |
110 argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); |
114 rgbPixmapData->resize(8, 8); |
111 argbPixmapData->resize(100, 100); |
|
112 argbPixmapData->fill(Qt::transparent); // Force ARGB |
|
113 |
|
114 if (!qt_createEGLSurfaceForPixmap(argbPixmapData, false)) |
|
115 break; |
|
116 |
|
117 haveX11Pixmaps = eglMakeCurrent(QEglContext::display(), |
|
118 (EGLSurface)argbPixmapData->gl_surface, |
|
119 (EGLSurface)argbPixmapData->gl_surface, |
|
120 qPixmapARGBSharedEglContext); |
|
121 if (!haveX11Pixmaps) { |
|
122 EGLint err = eglGetError(); |
|
123 qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); |
|
124 break; |
|
125 } |
|
126 |
|
127 // If the ARGB & RGB configs are the same, we don't need to check RGB too |
|
128 if (haveX11Pixmaps && (argbConfig != rgbConfig)) { |
|
129 rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); |
|
130 rgbPixmapData->resize(100, 100); |
|
131 rgbPixmapData->fill(Qt::red); |
115 rgbPixmapData->fill(Qt::red); |
132 |
116 sharePixmap = new QPixmap(rgbPixmapData); |
133 // Try to actually create an EGL pixmap surface |
117 EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig); |
134 if (!qt_createEGLSurfaceForPixmap(rgbPixmapData, false)) |
118 rgbPixmapData->gl_surface = (void*)sharePixmapSurface; |
135 break; |
119 |
136 |
120 // Create the actual QGLContext which will be used for sharing |
137 haveX11Pixmaps = eglMakeCurrent(QEglContext::display(), |
121 sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat()); |
138 (EGLSurface)rgbPixmapData->gl_surface, |
122 sharedQGLContext->d_func()->eglContext = rgbContext; |
139 (EGLSurface)rgbPixmapData->gl_surface, |
123 sharedQGLContext->d_func()->eglSurface = sharePixmapSurface; |
140 qPixmapRGBSharedEglContext); |
124 sharedQGLContext->d_func()->valid = true; |
141 if (!haveX11Pixmaps) { |
125 qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig); |
142 EGLint err = eglGetError(); |
126 |
143 qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); |
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(); |
144 break; |
145 break; |
145 } |
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; |
146 } |
168 } |
147 } while (0); |
169 if (argbContext && argbContext != rgbContext) |
148 |
170 delete argbContext; |
149 if (qPixmapARGBSharedEglContext || qPixmapRGBSharedEglContext) { |
171 argbContext = 0; |
150 eglMakeCurrent(QEglContext::display(), |
172 |
151 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
173 if (rgbContext) { |
152 } |
174 delete rgbContext; |
153 |
175 rgbContext = 0; |
154 if (argbPixmapData) { |
|
155 if (argbPixmapData->gl_surface) |
|
156 QGLContextPrivate::destroyGlSurfaceForPixmap(argbPixmapData); |
|
157 delete argbPixmapData; |
|
158 argbPixmapData = 0; |
|
159 } |
|
160 if (rgbPixmapData) { |
|
161 if (rgbPixmapData->gl_surface) |
|
162 QGLContextPrivate::destroyGlSurfaceForPixmap(rgbPixmapData); |
|
163 delete rgbPixmapData; |
|
164 rgbPixmapData = 0; |
|
165 } |
|
166 |
|
167 if (!haveX11Pixmaps) { |
|
168 // Clean up the context(s) if we can't use X11GL pixmaps |
|
169 if (qPixmapARGBSharedEglContext != EGL_NO_CONTEXT) |
|
170 eglDestroyContext(QEglContext::display(), qPixmapARGBSharedEglContext); |
|
171 |
|
172 if (qPixmapRGBSharedEglContext != qPixmapARGBSharedEglContext && |
|
173 qPixmapRGBSharedEglContext != EGL_NO_CONTEXT) |
|
174 { |
|
175 eglDestroyContext(QEglContext::display(), qPixmapRGBSharedEglContext); |
|
176 } |
176 } |
177 qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; |
177 |
178 qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; |
178 // Deleting the QPixmap will fire the pixmap destruction cleanup hooks which in turn |
179 } |
179 // will destroy the egl surface: |
180 |
180 if (sharePixmap) { |
181 if (haveX11Pixmaps) |
181 delete sharePixmap; |
182 qDebug("QX11GLPixmapData is supported"); |
182 sharePixmap = 0; |
183 else |
183 } |
184 qDebug("QX11GLPixmapData is *NOT* being used"); |
184 } |
185 |
185 |
186 return haveX11Pixmaps; |
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; |
187 } |
232 } |
188 |
233 |
189 QX11GLPixmapData::QX11GLPixmapData() |
234 QX11GLPixmapData::QX11GLPixmapData() |
190 : QX11PixmapData(QPixmapData::PixmapType), |
235 : QX11PixmapData(QPixmapData::PixmapType), |
191 ctx(0) |
236 ctx(0) |
192 { |
237 { |
193 } |
238 } |
194 |
239 |
195 QX11GLPixmapData::~QX11GLPixmapData() |
240 QX11GLPixmapData::~QX11GLPixmapData() |
196 { |
241 { |
197 } |
242 if (ctx) |
198 |
243 delete ctx; |
199 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) |
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) |
200 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_pixmap_2_engine) |
301 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_pixmap_2_engine) |
201 #endif |
302 #endif |
202 |
303 |
203 #ifndef QT_OPENGL_ES_2 |
304 #ifndef QT_OPENGL_ES_2 |
204 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_pixmap_engine) |
305 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_pixmap_engine) |