40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include <QtGui/qpaintdevice.h> |
42 #include <QtGui/qpaintdevice.h> |
43 #include <QtGui/qpixmap.h> |
43 #include <QtGui/qpixmap.h> |
44 #include <QtGui/qwidget.h> |
44 #include <QtGui/qwidget.h> |
45 #include <QtCore/qatomic.h> |
|
46 #include <QtCore/qdebug.h> |
45 #include <QtCore/qdebug.h> |
|
46 |
47 #include "qegl_p.h" |
47 #include "qegl_p.h" |
|
48 #include "qeglcontext_p.h" |
|
49 |
48 |
50 |
49 QT_BEGIN_NAMESPACE |
51 QT_BEGIN_NAMESPACE |
50 |
|
51 |
|
52 /* |
|
53 QEglContextTracker is used to track the EGL contexts that we |
|
54 create internally in Qt, so that we can call eglTerminate() to |
|
55 free additional EGL resources when the last context is destroyed. |
|
56 */ |
|
57 |
|
58 class QEglContextTracker |
|
59 { |
|
60 public: |
|
61 static void ref() { contexts.ref(); } |
|
62 static void deref() { |
|
63 if (!contexts.deref()) { |
|
64 eglTerminate(QEglContext::display()); |
|
65 displayOpen = 0; |
|
66 } |
|
67 } |
|
68 static void setDisplayOpened() { displayOpen = 1; } |
|
69 static bool displayOpened() { return displayOpen; } |
|
70 |
|
71 private: |
|
72 static QBasicAtomicInt contexts; |
|
73 static QBasicAtomicInt displayOpen; |
|
74 }; |
|
75 |
|
76 QBasicAtomicInt QEglContextTracker::contexts = Q_BASIC_ATOMIC_INITIALIZER(0); |
|
77 QBasicAtomicInt QEglContextTracker::displayOpen = Q_BASIC_ATOMIC_INITIALIZER(0); |
|
78 |
52 |
79 // Current GL and VG contexts. These are used to determine if |
53 // Current GL and VG contexts. These are used to determine if |
80 // we can avoid an eglMakeCurrent() after a call to lazyDoneCurrent(). |
54 // we can avoid an eglMakeCurrent() after a call to lazyDoneCurrent(). |
81 // If a background thread modifies the value, the worst that will |
55 // If a background thread modifies the value, the worst that will |
82 // happen is a redundant eglMakeCurrent() in the foreground thread. |
56 // happen is a redundant eglMakeCurrent() in the foreground thread. |
83 static QEglContext * volatile currentGLContext = 0; |
57 static QEglContext * volatile currentGLContext = 0; |
84 static QEglContext * volatile currentVGContext = 0; |
58 static QEglContext * volatile currentVGContext = 0; |
85 |
59 |
86 EGLDisplay QEglContext::dpy = EGL_NO_DISPLAY; |
|
87 |
|
88 QEglContext::QEglContext() |
60 QEglContext::QEglContext() |
89 : apiType(QEgl::OpenGL) |
61 : apiType(QEgl::OpenGL) |
90 , ctx(EGL_NO_CONTEXT) |
62 , ctx(EGL_NO_CONTEXT) |
91 , cfg(0) |
63 , cfg(QEGL_NO_CONFIG) |
92 , currentSurface(EGL_NO_SURFACE) |
64 , currentSurface(EGL_NO_SURFACE) |
93 , current(false) |
65 , current(false) |
94 , ownsContext(true) |
66 , ownsContext(true) |
95 , sharing(false) |
67 , sharing(false) |
96 { |
68 { |
97 QEglContextTracker::ref(); |
|
98 } |
69 } |
99 |
70 |
100 QEglContext::~QEglContext() |
71 QEglContext::~QEglContext() |
101 { |
72 { |
102 destroyContext(); |
73 destroyContext(); |
103 |
74 |
104 if (currentGLContext == this) |
75 if (currentGLContext == this) |
105 currentGLContext = 0; |
76 currentGLContext = 0; |
106 if (currentVGContext == this) |
77 if (currentVGContext == this) |
107 currentVGContext = 0; |
78 currentVGContext = 0; |
108 QEglContextTracker::deref(); |
|
109 } |
79 } |
110 |
80 |
111 bool QEglContext::isValid() const |
81 bool QEglContext::isValid() const |
112 { |
82 { |
113 return (ctx != EGL_NO_CONTEXT); |
83 return (ctx != EGL_NO_CONTEXT); |
116 bool QEglContext::isCurrent() const |
86 bool QEglContext::isCurrent() const |
117 { |
87 { |
118 return current; |
88 return current; |
119 } |
89 } |
120 |
90 |
|
91 EGLConfig QEgl::defaultConfig(int devType, API api, ConfigOptions options) |
|
92 { |
|
93 if ( (devType != QInternal::Pixmap) && ((options & Renderable) == 0)) |
|
94 qWarning("QEgl::defaultConfig() - Only configs for pixmaps make sense to be read-only!"); |
|
95 |
|
96 EGLConfig* targetConfig = 0; |
|
97 |
|
98 static EGLConfig defaultVGConfigs[] = { |
|
99 QEGL_NO_CONFIG, // 0 Window Renderable Translucent |
|
100 QEGL_NO_CONFIG, // 1 Window Renderable Opaque |
|
101 QEGL_NO_CONFIG, // 2 Pixmap Renderable Translucent |
|
102 QEGL_NO_CONFIG, // 3 Pixmap Renderable Opaque |
|
103 QEGL_NO_CONFIG, // 4 Pixmap ReadOnly Translucent |
|
104 QEGL_NO_CONFIG // 5 Pixmap ReadOnly Opaque |
|
105 }; |
|
106 if (api == OpenVG) { |
|
107 if (devType == QInternal::Widget) { |
|
108 if (options & Translucent) |
|
109 targetConfig = &(defaultVGConfigs[0]); |
|
110 else |
|
111 targetConfig = &(defaultVGConfigs[1]); |
|
112 } else if (devType == QInternal::Pixmap) { |
|
113 if (options & Renderable) { |
|
114 if (options & Translucent) |
|
115 targetConfig = &(defaultVGConfigs[2]); |
|
116 else // Opaque |
|
117 targetConfig = &(defaultVGConfigs[3]); |
|
118 } else { // Read-only |
|
119 if (options & Translucent) |
|
120 targetConfig = &(defaultVGConfigs[4]); |
|
121 else // Opaque |
|
122 targetConfig = &(defaultVGConfigs[5]); |
|
123 } |
|
124 } |
|
125 } |
|
126 |
|
127 |
|
128 static EGLConfig defaultGLConfigs[] = { |
|
129 QEGL_NO_CONFIG, // 0 Window Renderable Translucent |
|
130 QEGL_NO_CONFIG, // 1 Window Renderable Opaque |
|
131 QEGL_NO_CONFIG, // 2 PBuffer Renderable Translucent |
|
132 QEGL_NO_CONFIG, // 3 PBuffer Renderable Opaque |
|
133 QEGL_NO_CONFIG, // 4 Pixmap Renderable Translucent |
|
134 QEGL_NO_CONFIG, // 5 Pixmap Renderable Opaque |
|
135 QEGL_NO_CONFIG, // 6 Pixmap ReadOnly Translucent |
|
136 QEGL_NO_CONFIG // 7 Pixmap ReadOnly Opaque |
|
137 }; |
|
138 if (api == OpenGL) { |
|
139 if (devType == QInternal::Widget) { |
|
140 if (options & Translucent) |
|
141 targetConfig = &(defaultGLConfigs[0]); |
|
142 else // Opaque |
|
143 targetConfig = &(defaultGLConfigs[1]); |
|
144 } else if (devType == QInternal::Pbuffer) { |
|
145 if (options & Translucent) |
|
146 targetConfig = &(defaultGLConfigs[2]); |
|
147 else // Opaque |
|
148 targetConfig = &(defaultGLConfigs[3]); |
|
149 } else if (devType == QInternal::Pixmap) { |
|
150 if (options & Renderable) { |
|
151 if (options & Translucent) |
|
152 targetConfig = &(defaultGLConfigs[4]); |
|
153 else // Opaque |
|
154 targetConfig = &(defaultGLConfigs[5]); |
|
155 } else { // ReadOnly |
|
156 if (options & Translucent) |
|
157 targetConfig = &(defaultGLConfigs[6]); |
|
158 else // Opaque |
|
159 targetConfig = &(defaultGLConfigs[7]); |
|
160 } |
|
161 } |
|
162 } |
|
163 |
|
164 if (!targetConfig) { |
|
165 qWarning("QEgl::defaultConfig() - No default config for device/api/options combo"); |
|
166 return QEGL_NO_CONFIG; |
|
167 } |
|
168 if (*targetConfig != QEGL_NO_CONFIG) |
|
169 return *targetConfig; |
|
170 |
|
171 |
|
172 // We haven't found an EGL config for the target config yet, so do it now: |
|
173 |
|
174 |
|
175 // Allow overriding from an environment variable: |
|
176 QByteArray configId; |
|
177 if (api == OpenVG) |
|
178 configId = qgetenv("QT_VG_EGL_CONFIG"); |
|
179 else |
|
180 configId = qgetenv("QT_GL_EGL_CONFIG"); |
|
181 if (!configId.isEmpty()) { |
|
182 // Overriden, so get the EGLConfig for the specified config ID: |
|
183 EGLint properties[] = { |
|
184 EGL_CONFIG_ID, (EGLint)configId.toInt(), |
|
185 EGL_NONE |
|
186 }; |
|
187 EGLint configCount = 0; |
|
188 eglChooseConfig(display(), properties, targetConfig, 1, &configCount); |
|
189 if (configCount > 0) |
|
190 return *targetConfig; |
|
191 qWarning() << "QEgl::defaultConfig() -" << configId << "appears to be invalid"; |
|
192 } |
|
193 |
|
194 QEglProperties configAttribs; |
|
195 configAttribs.setRenderableType(api); |
|
196 |
|
197 EGLint surfaceType; |
|
198 switch (devType) { |
|
199 case QInternal::Widget: |
|
200 surfaceType = EGL_WINDOW_BIT; |
|
201 break; |
|
202 case QInternal::Pixmap: |
|
203 surfaceType = EGL_PIXMAP_BIT; |
|
204 break; |
|
205 case QInternal::Pbuffer: |
|
206 surfaceType = EGL_PBUFFER_BIT; |
|
207 break; |
|
208 default: |
|
209 qWarning("QEgl::defaultConfig() - Can't create EGL surface for %d device type", devType); |
|
210 return QEGL_NO_CONFIG; |
|
211 }; |
|
212 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
213 // For OpenVG, we try to create a surface using a pre-multiplied format if |
|
214 // the surface needs to have an alpha channel: |
|
215 if (api == OpenVG && (options & Translucent)) |
|
216 surfaceType |= EGL_VG_ALPHA_FORMAT_PRE_BIT; |
|
217 #endif |
|
218 configAttribs.setValue(EGL_SURFACE_TYPE, surfaceType); |
|
219 |
|
220 #ifdef EGL_BIND_TO_TEXTURE_RGBA |
|
221 if (devType == QInternal::Pixmap || devType == QInternal::Pbuffer) { |
|
222 if (options & Translucent) |
|
223 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); |
|
224 else |
|
225 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); |
|
226 } |
|
227 #endif |
|
228 |
|
229 // Add paint engine requirements |
|
230 if (api == OpenVG) { |
|
231 #ifndef QVG_SCISSOR_CLIP |
|
232 configAttribs.setValue(EGL_ALPHA_MASK_SIZE, 1); |
|
233 #endif |
|
234 } else { |
|
235 // Both OpenGL paint engines need to have stencil and sample buffers |
|
236 configAttribs.setValue(EGL_STENCIL_SIZE, 1); |
|
237 configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1); |
|
238 #ifndef QT_OPENGL_ES_2 |
|
239 // Aditionally, the GL1 engine likes to have a depth buffer for clipping |
|
240 configAttribs.setValue(EGL_DEPTH_SIZE, 1); |
|
241 #endif |
|
242 } |
|
243 |
|
244 if (options & Translucent) |
|
245 configAttribs.setValue(EGL_ALPHA_SIZE, 1); |
|
246 |
|
247 *targetConfig = chooseConfig(&configAttribs, QEgl::BestPixelFormat); |
|
248 return *targetConfig; |
|
249 } |
|
250 |
|
251 |
121 // Choose a configuration that matches "properties". |
252 // Choose a configuration that matches "properties". |
122 bool QEglContext::chooseConfig |
253 EGLConfig QEgl::chooseConfig(const QEglProperties* properties, QEgl::PixelFormatMatch match) |
123 (const QEglProperties& properties, QEgl::PixelFormatMatch match) |
254 { |
124 { |
255 QEglProperties props(*properties); |
125 QEglProperties props(properties); |
256 EGLConfig cfg = QEGL_NO_CONFIG; |
126 do { |
257 do { |
127 // Get the number of matching configurations for this set of properties. |
258 // Get the number of matching configurations for this set of properties. |
128 EGLint matching = 0; |
259 EGLint matching = 0; |
129 if (!eglChooseConfig(display(), props.properties(), 0, 0, &matching) || !matching) |
260 EGLDisplay dpy = QEgl::display(); |
|
261 if (!eglChooseConfig(dpy, props.properties(), 0, 0, &matching) || !matching) |
130 continue; |
262 continue; |
131 |
263 |
132 // If we want the best pixel format, then return the first |
264 // If we want the best pixel format, then return the first |
133 // matching configuration. |
265 // matching configuration. |
134 if (match == QEgl::BestPixelFormat) { |
266 if (match == QEgl::BestPixelFormat) { |
135 eglChooseConfig(display(), props.properties(), &cfg, 1, &matching); |
267 eglChooseConfig(display(), props.properties(), &cfg, 1, &matching); |
136 if (matching < 1) |
268 if (matching < 1) |
137 continue; |
269 continue; |
138 return true; |
270 return cfg; |
139 } |
271 } |
140 |
272 |
141 // Fetch all of the matching configurations and find the |
273 // Fetch all of the matching configurations and find the |
142 // first that matches the pixel format we wanted. |
274 // first that matches the pixel format we wanted. |
143 EGLint size = matching; |
275 EGLint size = matching; |
171 #endif |
303 #endif |
172 { |
304 { |
173 qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration"; |
305 qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration"; |
174 qWarning() << "Requested:" << props.toString(); |
306 qWarning() << "Requested:" << props.toString(); |
175 qWarning() << "Available:"; |
307 qWarning() << "Available:"; |
176 dumpAllConfigs(); |
308 QEgl::dumpAllConfigs(); |
177 } |
309 } |
178 return false; |
310 return QEGL_NO_CONFIG; |
179 } |
311 } |
|
312 |
|
313 bool QEglContext::chooseConfig(const QEglProperties& properties, QEgl::PixelFormatMatch match) |
|
314 { |
|
315 cfg = QEgl::chooseConfig(&properties, match); |
|
316 return cfg != QEGL_NO_CONFIG; |
|
317 } |
|
318 |
|
319 EGLSurface QEglContext::createSurface(QPaintDevice* device, const QEglProperties *properties) |
|
320 { |
|
321 return QEgl::createSurface(device, cfg, properties); |
|
322 } |
|
323 |
180 |
324 |
181 // Create the EGLContext. |
325 // Create the EGLContext. |
182 bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties *properties) |
326 bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties *properties) |
183 { |
327 { |
184 // We need to select the correct API before calling eglCreateContext(). |
328 // We need to select the correct API before calling eglCreateContext(). |
|
329 #ifdef QT_OPENGL_ES |
185 #ifdef EGL_OPENGL_ES_API |
330 #ifdef EGL_OPENGL_ES_API |
186 if (apiType == QEgl::OpenGL) |
331 if (apiType == QEgl::OpenGL) |
187 eglBindAPI(EGL_OPENGL_ES_API); |
332 eglBindAPI(EGL_OPENGL_ES_API); |
188 #endif |
333 #endif |
|
334 #else |
|
335 #ifdef EGL_OPENGL_API |
|
336 if (apiType == QEgl::OpenGL) |
|
337 eglBindAPI(EGL_OPENGL_API); |
|
338 #endif |
|
339 #endif //defined(QT_OPENGL_ES) |
189 #ifdef EGL_OPENVG_API |
340 #ifdef EGL_OPENVG_API |
190 if (apiType == QEgl::OpenVG) |
341 if (apiType == QEgl::OpenVG) |
191 eglBindAPI(EGL_OPENVG_API); |
342 eglBindAPI(EGL_OPENVG_API); |
192 #endif |
343 #endif |
193 |
344 |
194 // Create a new context for the configuration. |
345 // Create a new context for the configuration. |
195 QEglProperties contextProps; |
346 QEglProperties contextProps; |
196 if (properties) |
347 if (properties) |
197 contextProps = *properties; |
348 contextProps = *properties; |
198 #if defined(QT_OPENGL_ES_2) |
349 #ifdef QT_OPENGL_ES_2 |
199 if (apiType == QEgl::OpenGL) |
350 if (apiType == QEgl::OpenGL) |
200 contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); |
351 contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); |
201 #endif |
352 #endif |
202 sharing = false; |
353 sharing = false; |
203 if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) |
354 if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) |
204 shareContext = 0; |
355 shareContext = 0; |
205 if (shareContext) { |
356 if (shareContext) { |
206 ctx = eglCreateContext(display(), cfg, shareContext->ctx, contextProps.properties()); |
357 ctx = eglCreateContext(QEgl::display(), cfg, shareContext->ctx, contextProps.properties()); |
207 if (ctx == EGL_NO_CONTEXT) { |
358 if (ctx == EGL_NO_CONTEXT) { |
208 qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); |
359 qWarning() << "QEglContext::createContext(): Could not share context:" << QEgl::errorString(); |
209 shareContext = 0; |
360 shareContext = 0; |
210 } else { |
361 } else { |
211 sharing = true; |
362 sharing = true; |
212 } |
363 } |
213 } |
364 } |
214 if (ctx == EGL_NO_CONTEXT) { |
365 if (ctx == EGL_NO_CONTEXT) { |
215 ctx = eglCreateContext(display(), cfg, 0, contextProps.properties()); |
366 ctx = eglCreateContext(display(), cfg, 0, contextProps.properties()); |
216 if (ctx == EGL_NO_CONTEXT) { |
367 if (ctx == EGL_NO_CONTEXT) { |
217 qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError()); |
368 qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << QEgl::errorString(); |
218 return false; |
369 return false; |
219 } |
370 } |
220 } |
371 } |
221 return true; |
372 return true; |
222 } |
373 } |
320 bool QEglContext::swapBuffers(EGLSurface surface) |
476 bool QEglContext::swapBuffers(EGLSurface surface) |
321 { |
477 { |
322 if(ctx == EGL_NO_CONTEXT) |
478 if(ctx == EGL_NO_CONTEXT) |
323 return false; |
479 return false; |
324 |
480 |
325 bool ok = eglSwapBuffers(display(), surface); |
481 bool ok = eglSwapBuffers(QEgl::display(), surface); |
326 if (!ok) |
482 if (!ok) |
327 qWarning() << "QEglContext::swapBuffers():" << errorString(eglGetError()); |
483 qWarning() << "QEglContext::swapBuffers():" << QEgl::errorString(); |
328 return ok; |
484 return ok; |
329 } |
485 } |
330 |
486 |
331 // Wait for native rendering operations to complete before starting |
487 int QEglContext::configAttrib(int name) const |
332 // to use OpenGL/OpenVG operations. |
488 { |
333 void QEglContext::waitNative() |
489 EGLint value; |
334 { |
490 EGLBoolean success = eglGetConfigAttrib(QEgl::display(), cfg, name, &value); |
335 #ifdef EGL_CORE_NATIVE_ENGINE |
491 if (success) |
336 eglWaitNative(EGL_CORE_NATIVE_ENGINE); |
492 return value; |
337 #endif |
493 else |
338 } |
494 return EGL_DONT_CARE; |
339 |
495 } |
340 // Wait for client OpenGL/OpenVG operations to complete before |
496 |
341 // using native rendering operations. |
497 typedef EGLImageKHR (EGLAPIENTRY *_eglCreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint*); |
342 void QEglContext::waitClient() |
498 typedef EGLBoolean (EGLAPIENTRY *_eglDestroyImageKHR)(EGLDisplay, EGLImageKHR); |
343 { |
499 |
344 #ifdef EGL_OPENGL_ES_API |
500 // Defined in qegl.cpp: |
345 if (apiType == QEgl::OpenGL) { |
501 static _eglCreateImageKHR qt_eglCreateImageKHR = 0; |
346 eglBindAPI(EGL_OPENGL_ES_API); |
502 static _eglDestroyImageKHR qt_eglDestroyImageKHR = 0; |
347 eglWaitClient(); |
503 |
348 } |
504 |
349 #else |
505 EGLDisplay QEgl::display() |
350 if (apiType == QEgl::OpenGL) |
506 { |
351 eglWaitGL(); |
507 static EGLDisplay dpy = EGL_NO_DISPLAY; |
352 #endif |
508 static bool openedDisplay = false; |
353 #ifdef EGL_OPENVG_API |
509 |
354 if (apiType == QEgl::OpenVG) { |
510 if (!openedDisplay) { |
355 eglBindAPI(EGL_OPENVG_API); |
|
356 eglWaitClient(); |
|
357 } |
|
358 #endif |
|
359 } |
|
360 |
|
361 // Query the value of a configuration attribute. |
|
362 bool QEglContext::configAttrib(int name, EGLint *value) const |
|
363 { |
|
364 return eglGetConfigAttrib(display(), cfg, name, value); |
|
365 } |
|
366 |
|
367 void QEglContext::clearError() |
|
368 { |
|
369 eglGetError(); |
|
370 } |
|
371 |
|
372 EGLint QEglContext::error() |
|
373 { |
|
374 return eglGetError(); |
|
375 } |
|
376 |
|
377 // Retrieve all of the properties on "cfg". If zero, return |
|
378 // the context's configuration. |
|
379 QEglProperties QEglContext::configProperties(EGLConfig cfg) const |
|
380 { |
|
381 if (!cfg) |
|
382 cfg = config(); |
|
383 QEglProperties props; |
|
384 for (int name = 0x3020; name <= 0x304F; ++name) { |
|
385 EGLint value; |
|
386 if (name != EGL_NONE && eglGetConfigAttrib(display(), cfg, name, &value)) |
|
387 props.setValue(name, value); |
|
388 } |
|
389 eglGetError(); // Clear the error state. |
|
390 return props; |
|
391 } |
|
392 |
|
393 EGLDisplay QEglContext::display() |
|
394 { |
|
395 if (!QEglContextTracker::displayOpened()) { |
|
396 dpy = eglGetDisplay(nativeDisplay()); |
511 dpy = eglGetDisplay(nativeDisplay()); |
397 QEglContextTracker::setDisplayOpened(); |
512 openedDisplay = true; |
398 if (dpy == EGL_NO_DISPLAY) { |
513 if (dpy == EGL_NO_DISPLAY) { |
399 qWarning("QEglContext::display(): Falling back to EGL_DEFAULT_DISPLAY"); |
514 qWarning("QEgl::display(): Falling back to EGL_DEFAULT_DISPLAY"); |
400 dpy = eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); |
515 dpy = eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); |
401 } |
516 } |
402 if (dpy == EGL_NO_DISPLAY) { |
517 if (dpy == EGL_NO_DISPLAY) { |
403 qWarning("QEglContext::display(): Can't even open the default display"); |
518 qWarning("QEgl::display(): Can't even open the default display"); |
404 return EGL_NO_DISPLAY; |
519 return EGL_NO_DISPLAY; |
405 } |
520 } |
406 |
521 |
407 if (!eglInitialize(dpy, NULL, NULL)) { |
522 if (!eglInitialize(dpy, NULL, NULL)) { |
408 qWarning() << "QEglContext::display(): Cannot initialize EGL display:" << errorString(eglGetError()); |
523 qWarning() << "QEgl::display(): Cannot initialize EGL display:" << QEgl::errorString(); |
409 return EGL_NO_DISPLAY; |
524 return EGL_NO_DISPLAY; |
410 } |
525 } |
|
526 |
|
527 // Resolve the egl extension function pointers: |
|
528 #if (defined(EGL_KHR_image) || defined(EGL_KHR_image_base)) && !defined(EGL_EGLEXT_PROTOTYPES) |
|
529 if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_base")) { |
|
530 qt_eglCreateImageKHR = (_eglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); |
|
531 qt_eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); |
|
532 } |
|
533 #endif |
411 } |
534 } |
412 |
535 |
413 return dpy; |
536 return dpy; |
414 } |
537 } |
415 |
538 |
416 #if !defined(Q_WS_X11) && !defined(Q_WS_WINCE) // WinCE & X11 implement this properly |
539 EGLImageKHR QEgl::eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) |
417 EGLNativeDisplayType QEglContext::nativeDisplay() |
540 { |
418 { |
541 if (qt_eglCreateImageKHR) |
419 return EGL_DEFAULT_DISPLAY; |
542 return qt_eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); |
420 } |
543 |
421 #endif |
544 QEgl::display(); // Initialises function pointers |
|
545 if (qt_eglCreateImageKHR) |
|
546 return qt_eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); |
|
547 |
|
548 qWarning("QEgl::eglCreateImageKHR() called but EGL_KHR_image(_base) extension not present"); |
|
549 return 0; |
|
550 } |
|
551 |
|
552 EGLBoolean QEgl::eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) |
|
553 { |
|
554 if (qt_eglDestroyImageKHR) |
|
555 return qt_eglDestroyImageKHR(dpy, img); |
|
556 |
|
557 QEgl::display(); // Initialises function pointers |
|
558 if (qt_eglDestroyImageKHR) |
|
559 return qt_eglDestroyImageKHR(dpy, img); |
|
560 |
|
561 qWarning("QEgl::eglDestroyImageKHR() called but EGL_KHR_image(_base) extension not present"); |
|
562 return 0; |
|
563 } |
|
564 |
|
565 |
|
566 #ifndef Q_WS_X11 |
|
567 EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties) |
|
568 { |
|
569 // Create the native drawable for the paint device. |
|
570 int devType = device->devType(); |
|
571 EGLNativePixmapType pixmapDrawable = 0; |
|
572 EGLNativeWindowType windowDrawable = 0; |
|
573 bool ok; |
|
574 if (devType == QInternal::Pixmap) { |
|
575 pixmapDrawable = nativePixmap(static_cast<QPixmap *>(device)); |
|
576 ok = (pixmapDrawable != 0); |
|
577 } else if (devType == QInternal::Widget) { |
|
578 windowDrawable = nativeWindow(static_cast<QWidget *>(device)); |
|
579 ok = (windowDrawable != 0); |
|
580 } else { |
|
581 ok = false; |
|
582 } |
|
583 if (!ok) { |
|
584 qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); |
|
585 return EGL_NO_SURFACE; |
|
586 } |
|
587 |
|
588 // Create the EGL surface to draw into, based on the native drawable. |
|
589 const int *props; |
|
590 if (properties) |
|
591 props = properties->properties(); |
|
592 else |
|
593 props = 0; |
|
594 EGLSurface surf; |
|
595 if (devType == QInternal::Widget) |
|
596 surf = eglCreateWindowSurface(QEgl::display(), cfg, windowDrawable, props); |
|
597 else |
|
598 surf = eglCreatePixmapSurface(QEgl::display(), cfg, pixmapDrawable, props); |
|
599 if (surf == EGL_NO_SURFACE) { |
|
600 qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); |
|
601 } |
|
602 return surf; |
|
603 } |
|
604 #endif |
|
605 |
422 |
606 |
423 // Return the error string associated with a specific code. |
607 // Return the error string associated with a specific code. |
424 QString QEglContext::errorString(EGLint code) |
608 QString QEgl::errorString(EGLint code) |
425 { |
609 { |
426 static const char * const errors[] = { |
610 static const char * const errors[] = { |
427 "Success (0x3000)", // No tr |
611 "Success (0x3000)", // No tr |
428 "Not initialized (0x3001)", // No tr |
612 "Not initialized (0x3001)", // No tr |
429 "Bad access (0x3002)", // No tr |
613 "Bad access (0x3002)", // No tr |
446 return QLatin1String("0x") + QString::number(int(code), 16); |
630 return QLatin1String("0x") + QString::number(int(code), 16); |
447 } |
631 } |
448 } |
632 } |
449 |
633 |
450 // Dump all of the EGL configurations supported by the system. |
634 // Dump all of the EGL configurations supported by the system. |
451 void QEglContext::dumpAllConfigs() |
635 void QEgl::dumpAllConfigs() |
452 { |
636 { |
453 QEglProperties props; |
637 QEglProperties props; |
454 EGLint count = 0; |
638 EGLint count = 0; |
455 if (!eglGetConfigs(display(), 0, 0, &count) || count < 1) |
639 if (!eglGetConfigs(display(), 0, 0, &count) || count < 1) |
456 return; |
640 return; |
457 EGLConfig *configs = new EGLConfig [count]; |
641 EGLConfig *configs = new EGLConfig [count]; |
458 eglGetConfigs(display(), configs, count, &count); |
642 eglGetConfigs(display(), configs, count, &count); |
459 for (EGLint index = 0; index < count; ++index) { |
643 for (EGLint index = 0; index < count; ++index) { |
460 props = configProperties(configs[index]); |
644 props = QEglProperties(configs[index]); |
461 qWarning() << props.toString(); |
645 qWarning() << props.toString(); |
462 } |
646 } |
463 delete [] configs; |
647 delete [] configs; |
464 } |
648 } |
465 |
649 |
466 QString QEglContext::extensions() |
650 QString QEgl::extensions() |
467 { |
651 { |
468 const char* exts = eglQueryString(QEglContext::display(), EGL_EXTENSIONS); |
652 const char* exts = eglQueryString(QEgl::display(), EGL_EXTENSIONS); |
469 return QString(QLatin1String(exts)); |
653 return QString(QLatin1String(exts)); |
470 } |
654 } |
471 |
655 |
472 bool QEglContext::hasExtension(const char* extensionName) |
656 bool QEgl::hasExtension(const char* extensionName) |
473 { |
657 { |
474 QList<QByteArray> extensions = |
658 QList<QByteArray> extensions = |
475 QByteArray(reinterpret_cast<const char *> |
659 QByteArray(reinterpret_cast<const char *> |
476 (eglQueryString(QEglContext::display(), EGL_EXTENSIONS))).split(' '); |
660 (eglQueryString(QEgl::display(), EGL_EXTENSIONS))).split(' '); |
477 return extensions.contains(extensionName); |
661 return extensions.contains(extensionName); |
478 } |
662 } |
479 |
663 |
480 QEglContext *QEglContext::currentContext(QEgl::API api) |
664 QEglContext *QEglContext::currentContext(QEgl::API api) |
481 { |
665 { |