39 ** |
39 ** |
40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include <QtCore/qdebug.h> |
42 #include <QtCore/qdebug.h> |
43 |
43 |
44 #include <private/qt_x11_p.h> |
44 #include <QtGui/private/qt_x11_p.h> |
45 #include <QtGui/qx11info_x11.h> |
45 #include <QtGui/qx11info_x11.h> |
46 #include <private/qpixmapdata_p.h> |
46 #include <QtGui/private/qpixmapdata_p.h> |
47 #include <private/qpixmap_x11_p.h> |
47 #include <QtGui/private/qpixmap_x11_p.h> |
|
48 #include <QtGui/private/qimagepixmapcleanuphooks_p.h> |
48 |
49 |
49 #include <QtGui/qpaintdevice.h> |
50 #include <QtGui/qpaintdevice.h> |
50 #include <QtGui/qpixmap.h> |
51 #include <QtGui/qpixmap.h> |
51 #include <QtGui/qwidget.h> |
52 #include <QtGui/qwidget.h> |
52 #include "qegl_p.h" |
53 #include <QtGui/qcolormap.h> |
53 |
54 |
|
55 #include "QtGui/private/qegl_p.h" |
|
56 #include "QtGui/private/qeglcontext_p.h" |
54 |
57 |
55 QT_BEGIN_NAMESPACE |
58 QT_BEGIN_NAMESPACE |
56 |
59 |
57 EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) |
60 |
58 { |
61 EGLNativeDisplayType QEgl::nativeDisplay() |
59 // Create the native drawable for the paint device. |
|
60 int devType = device->devType(); |
|
61 EGLNativePixmapType pixmapDrawable = 0; |
|
62 EGLNativeWindowType windowDrawable = 0; |
|
63 bool ok; |
|
64 if (devType == QInternal::Pixmap) { |
|
65 pixmapDrawable = (EGLNativePixmapType)(static_cast<QPixmap *>(device))->handle(); |
|
66 ok = (pixmapDrawable != 0); |
|
67 } else if (devType == QInternal::Widget) { |
|
68 windowDrawable = (EGLNativeWindowType)(static_cast<QWidget *>(device))->winId(); |
|
69 ok = (windowDrawable != 0); |
|
70 } else { |
|
71 ok = false; |
|
72 } |
|
73 if (!ok) { |
|
74 qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); |
|
75 return EGL_NO_SURFACE; |
|
76 } |
|
77 |
|
78 // Create the EGL surface to draw into, based on the native drawable. |
|
79 const int *props; |
|
80 if (properties) |
|
81 props = properties->properties(); |
|
82 else |
|
83 props = 0; |
|
84 EGLSurface surf; |
|
85 if (devType == QInternal::Widget) |
|
86 surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); |
|
87 else |
|
88 surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props); |
|
89 if (surf == EGL_NO_SURFACE) { |
|
90 qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:" |
|
91 << errorString(eglGetError()); |
|
92 } |
|
93 return surf; |
|
94 } |
|
95 |
|
96 EGLNativeDisplayType QEglContext::nativeDisplay() |
|
97 { |
62 { |
98 Display *xdpy = QX11Info::display(); |
63 Display *xdpy = QX11Info::display(); |
99 if (!xdpy) { |
64 if (!xdpy) { |
100 qWarning("QEglContext::getDisplay(): X11 display is not open"); |
65 qWarning("QEglContext::getDisplay(): X11 display is not open"); |
101 return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY); |
66 return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY); |
102 } |
67 } |
103 return EGLNativeDisplayType(xdpy); |
68 return EGLNativeDisplayType(xdpy); |
|
69 } |
|
70 |
|
71 EGLNativeWindowType QEgl::nativeWindow(QWidget* widget) |
|
72 { |
|
73 return (EGLNativeWindowType)(widget->winId()); |
|
74 } |
|
75 |
|
76 EGLNativePixmapType QEgl::nativePixmap(QPixmap* pixmap) |
|
77 { |
|
78 return (EGLNativePixmapType)(pixmap->handle()); |
104 } |
79 } |
105 |
80 |
106 static int countBits(unsigned long mask) |
81 static int countBits(unsigned long mask) |
107 { |
82 { |
108 int count = 0; |
83 int count = 0; |
151 setPixelFormat(static_cast<QImage *>(dev)->format()); |
126 setPixelFormat(static_cast<QImage *>(dev)->format()); |
152 else |
127 else |
153 setVisualFormat(qt_x11Info(dev)); |
128 setVisualFormat(qt_x11Info(dev)); |
154 } |
129 } |
155 |
130 |
|
131 //#define QT_DEBUG_X11_VISUAL_SELECTION 1 |
|
132 |
|
133 VisualID QEgl::getCompatibleVisualId(EGLConfig config) |
|
134 { |
|
135 VisualID visualId = 0; |
|
136 EGLint eglValue = 0; |
|
137 |
|
138 EGLint configRedSize = 0; |
|
139 eglGetConfigAttrib(display(), config, EGL_RED_SIZE, &configRedSize); |
|
140 |
|
141 EGLint configGreenSize = 0; |
|
142 eglGetConfigAttrib(display(), config, EGL_GREEN_SIZE, &configGreenSize); |
|
143 |
|
144 EGLint configBlueSize = 0; |
|
145 eglGetConfigAttrib(display(), config, EGL_BLUE_SIZE, &configBlueSize); |
|
146 |
|
147 EGLint configAlphaSize = 0; |
|
148 eglGetConfigAttrib(display(), config, EGL_ALPHA_SIZE, &configAlphaSize); |
|
149 |
|
150 eglGetConfigAttrib(display(), config, EGL_CONFIG_ID, &eglValue); |
|
151 int configId = eglValue; |
|
152 |
|
153 // See if EGL provided a valid VisualID: |
|
154 eglGetConfigAttrib(display(), config, EGL_NATIVE_VISUAL_ID, &eglValue); |
|
155 visualId = (VisualID)eglValue; |
|
156 if (visualId) { |
|
157 // EGL has suggested a visual id, so get the rest of the visual info for that id: |
|
158 XVisualInfo visualInfoTemplate; |
|
159 memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); |
|
160 visualInfoTemplate.visualid = visualId; |
|
161 |
|
162 XVisualInfo *chosenVisualInfo; |
|
163 int matchingCount = 0; |
|
164 chosenVisualInfo = XGetVisualInfo(X11->display, VisualIDMask, &visualInfoTemplate, &matchingCount); |
|
165 if (chosenVisualInfo) { |
|
166 // Skip size checks if implementation supports non-matching visual |
|
167 // and config (http://bugreports.qt.nokia.com/browse/QTBUG-9444). |
|
168 if (QEgl::hasExtension("EGL_NV_post_convert_replication")) |
|
169 return visualId; |
|
170 |
|
171 int visualRedSize = countBits(chosenVisualInfo->red_mask); |
|
172 int visualGreenSize = countBits(chosenVisualInfo->green_mask); |
|
173 int visualBlueSize = countBits(chosenVisualInfo->blue_mask); |
|
174 int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size |
|
175 |
|
176 #if !defined(QT_NO_XRENDER) |
|
177 if (X11->use_xrender) { |
|
178 // If we have XRender, actually check the visual supplied by EGL is ARGB |
|
179 XRenderPictFormat *format; |
|
180 format = XRenderFindVisualFormat(X11->display, chosenVisualInfo->visual); |
|
181 if (format && (format->type == PictTypeDirect)) |
|
182 visualAlphaSize = countBits(format->direct.alphaMask); |
|
183 } |
|
184 #endif |
|
185 |
|
186 bool visualMatchesConfig = false; |
|
187 if ( visualRedSize == configRedSize && |
|
188 visualGreenSize == configGreenSize && |
|
189 visualBlueSize == configBlueSize ) |
|
190 { |
|
191 // We need XRender to check the alpha channel size of the visual. If we don't have |
|
192 // the alpha size, we don't check it against the EGL config's alpha size. |
|
193 if (visualAlphaSize >= 0) |
|
194 visualMatchesConfig = visualAlphaSize == configAlphaSize; |
|
195 else |
|
196 visualMatchesConfig = true; |
|
197 } |
|
198 |
|
199 if (!visualMatchesConfig) { |
|
200 if (visualAlphaSize >= 0) { |
|
201 qWarning("Warning: EGL suggested using X Visual ID %d (ARGB%d%d%d%d) for EGL config %d (ARGB%d%d%d%d), but this is incompatable", |
|
202 (int)visualId, visualAlphaSize, visualRedSize, visualGreenSize, visualBlueSize, |
|
203 configId, configAlphaSize, configRedSize, configGreenSize, configBlueSize); |
|
204 } else { |
|
205 qWarning("Warning: EGL suggested using X Visual ID %d (RGB%d%d%d) for EGL config %d (RGB%d%d%d), but this is incompatable", |
|
206 (int)visualId, visualRedSize, visualGreenSize, visualBlueSize, |
|
207 configId, configRedSize, configGreenSize, configBlueSize); |
|
208 } |
|
209 visualId = 0; |
|
210 } |
|
211 } else { |
|
212 qWarning("Warning: EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID", |
|
213 (int)visualId, configId); |
|
214 visualId = 0; |
|
215 } |
|
216 XFree(chosenVisualInfo); |
|
217 } |
|
218 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
219 else |
|
220 qDebug("EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId); |
|
221 #endif |
|
222 |
|
223 if (visualId) { |
|
224 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
225 if (configAlphaSize > 0) |
|
226 qDebug("Using ARGB Visual ID %d provided by EGL for config %d", (int)visualId, configId); |
|
227 else |
|
228 qDebug("Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId); |
|
229 #endif |
|
230 return visualId; |
|
231 } |
|
232 |
|
233 |
|
234 // If EGL didn't give us a valid visual ID, try XRender |
|
235 #if !defined(QT_NO_XRENDER) |
|
236 if (!visualId && X11->use_xrender) { |
|
237 XVisualInfo visualInfoTemplate; |
|
238 memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); |
|
239 |
|
240 visualInfoTemplate.c_class = TrueColor; |
|
241 |
|
242 XVisualInfo *matchingVisuals; |
|
243 int matchingCount = 0; |
|
244 matchingVisuals = XGetVisualInfo(X11->display, |
|
245 VisualClassMask, |
|
246 &visualInfoTemplate, |
|
247 &matchingCount); |
|
248 |
|
249 for (int i = 0; i < matchingCount; ++i) { |
|
250 XRenderPictFormat *format; |
|
251 format = XRenderFindVisualFormat(X11->display, matchingVisuals[i].visual); |
|
252 |
|
253 // Check the format for the visual matches the EGL config |
|
254 if ( (countBits(format->direct.redMask) == configRedSize) && |
|
255 (countBits(format->direct.greenMask) == configGreenSize) && |
|
256 (countBits(format->direct.blueMask) == configBlueSize) && |
|
257 (countBits(format->direct.alphaMask) == configAlphaSize) ) |
|
258 { |
|
259 visualId = matchingVisuals[i].visualid; |
|
260 break; |
|
261 } |
|
262 } |
|
263 if (matchingVisuals) |
|
264 XFree(matchingVisuals); |
|
265 |
|
266 } |
|
267 if (visualId) { |
|
268 # ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
269 if (configAlphaSize > 0) |
|
270 qDebug("Using ARGB Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId); |
|
271 else |
|
272 qDebug("Using Opaque Visual ID %d provided by XRender for EGL config %d", (int)visualId, configId); |
|
273 # endif // QT_DEBUG_X11_VISUAL_SELECTION |
|
274 return visualId; |
|
275 } |
|
276 # ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
277 else |
|
278 qDebug("Failed to find an XVisual which matches EGL config %d using XRender", configId); |
|
279 # endif // QT_DEBUG_X11_VISUAL_SELECTION |
|
280 |
|
281 #endif //!defined(QT_NO_XRENDER) |
|
282 |
|
283 |
|
284 // Finally, if XRender also failed to find a visual (or isn't present), try to |
|
285 // use XGetVisualInfo and only use the bit depths to match on: |
|
286 if (!visualId) { |
|
287 XVisualInfo visualInfoTemplate; |
|
288 memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); |
|
289 XVisualInfo *matchingVisuals; |
|
290 int matchingCount = 0; |
|
291 |
|
292 visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize; |
|
293 matchingVisuals = XGetVisualInfo(X11->display, |
|
294 VisualDepthMask, |
|
295 &visualInfoTemplate, |
|
296 &matchingCount); |
|
297 if (!matchingVisuals) { |
|
298 // Try again without taking the alpha channel into account: |
|
299 visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize; |
|
300 matchingVisuals = XGetVisualInfo(X11->display, |
|
301 VisualDepthMask, |
|
302 &visualInfoTemplate, |
|
303 &matchingCount); |
|
304 } |
|
305 |
|
306 if (matchingVisuals) { |
|
307 visualId = matchingVisuals[0].visualid; |
|
308 XFree(matchingVisuals); |
|
309 } |
|
310 } |
|
311 |
|
312 if (visualId) { |
|
313 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
314 qDebug("Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId); |
|
315 #endif |
|
316 return visualId; |
|
317 } |
|
318 |
|
319 qWarning("Unable to find an X11 visual which matches EGL config %d", configId); |
|
320 return (VisualID)0; |
|
321 } |
|
322 |
|
323 void qt_set_winid_on_widget(QWidget* w, Qt::HANDLE id) |
|
324 { |
|
325 w->create(id); |
|
326 } |
|
327 |
|
328 |
|
329 // NOTE: The X11 version of createSurface will re-create the native drawable if it's visual doesn't |
|
330 // match the one for the passed in EGLConfig |
|
331 EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *unusedProperties) |
|
332 { |
|
333 Q_UNUSED(unusedProperties); |
|
334 |
|
335 int devType = device->devType(); |
|
336 |
|
337 if (devType == QInternal::Pbuffer) { |
|
338 // TODO |
|
339 return EGL_NO_SURFACE; |
|
340 } |
|
341 |
|
342 QX11PixmapData *x11PixmapData = 0; |
|
343 if (devType == QInternal::Pixmap) { |
|
344 QPixmapData *pmd = static_cast<QPixmap*>(device)->data_ptr().data(); |
|
345 if (pmd->classId() == QPixmapData::X11Class) |
|
346 x11PixmapData = static_cast<QX11PixmapData*>(pmd); |
|
347 else { |
|
348 // TODO: Replace the pixmap's data with a new QX11PixmapData |
|
349 qWarning("WARNING: Creating an EGL surface on a QPixmap is only supported for QX11PixmapData"); |
|
350 return EGL_NO_SURFACE; |
|
351 } |
|
352 } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) { |
|
353 qWarning("WARNING: Creating an EGLSurface for device type %d isn't supported", devType); |
|
354 return EGL_NO_SURFACE; |
|
355 } |
|
356 |
|
357 VisualID visualId = QEgl::getCompatibleVisualId(config); |
|
358 EGLint alphaSize; |
|
359 eglGetConfigAttrib(QEgl::display(), config, EGL_ALPHA_SIZE, &alphaSize); |
|
360 |
|
361 if (devType == QInternal::Widget) { |
|
362 QWidget *widget = static_cast<QWidget*>(device); |
|
363 |
|
364 VisualID currentVisualId = 0; |
|
365 if (widget->testAttribute(Qt::WA_WState_Created)) |
|
366 currentVisualId = XVisualIDFromVisual((Visual*)widget->x11Info().visual()); |
|
367 |
|
368 if (currentVisualId != visualId) { |
|
369 // The window is either not created or has the wrong visual. Either way, we need |
|
370 // to create a window with the correct visual and call create() on the widget: |
|
371 |
|
372 bool visible = widget->isVisible(); |
|
373 if (visible) |
|
374 widget->hide(); |
|
375 |
|
376 XVisualInfo visualInfo; |
|
377 visualInfo.visualid = visualId; |
|
378 { |
|
379 XVisualInfo *visualInfoPtr; |
|
380 int matchingCount = 0; |
|
381 visualInfoPtr = XGetVisualInfo(widget->x11Info().display(), VisualIDMask, |
|
382 &visualInfo, &matchingCount); |
|
383 Q_ASSERT(visualInfoPtr); // visualId really should be valid! |
|
384 visualInfo = *visualInfoPtr; |
|
385 XFree(visualInfoPtr); |
|
386 } |
|
387 |
|
388 Window parentWindow = RootWindow(widget->x11Info().display(), widget->x11Info().screen()); |
|
389 if (widget->parentWidget()) |
|
390 parentWindow = widget->parentWidget()->winId(); |
|
391 |
|
392 XSetWindowAttributes windowAttribs; |
|
393 QColormap colmap = QColormap::instance(widget->x11Info().screen()); |
|
394 windowAttribs.background_pixel = colmap.pixel(widget->palette().color(widget->backgroundRole())); |
|
395 windowAttribs.border_pixel = colmap.pixel(Qt::black); |
|
396 |
|
397 unsigned int valueMask = CWBackPixel|CWBorderPixel; |
|
398 if (alphaSize > 0) { |
|
399 windowAttribs.colormap = XCreateColormap(widget->x11Info().display(), parentWindow, |
|
400 visualInfo.visual, AllocNone); |
|
401 valueMask |= CWColormap; |
|
402 } |
|
403 |
|
404 Window window = XCreateWindow(widget->x11Info().display(), parentWindow, |
|
405 widget->x(), widget->y(), widget->width(), widget->height(), |
|
406 0, visualInfo.depth, InputOutput, visualInfo.visual, |
|
407 valueMask, &windowAttribs); |
|
408 |
|
409 // This is a nasty hack to get round the fact that we can't be a friend of QWidget: |
|
410 qt_set_winid_on_widget(widget, window); |
|
411 |
|
412 if (visible) |
|
413 widget->show(); |
|
414 } |
|
415 |
|
416 // At this point, the widget's window should be created and have the correct visual. Now we |
|
417 // just need to create the EGL surface for it: |
|
418 return eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), 0); |
|
419 } |
|
420 |
|
421 if (x11PixmapData) { |
|
422 // X11 Pixmaps are only created with a depth, so that's all we need to check |
|
423 EGLint configDepth; |
|
424 eglGetConfigAttrib(QEgl::display(), config, EGL_BUFFER_SIZE , &configDepth); |
|
425 if (x11PixmapData->depth() != configDepth) { |
|
426 // The bit depths are wrong which means the EGLConfig isn't compatable with |
|
427 // this pixmap. So we need to replace the pixmap's existing data with a new |
|
428 // one which is created with the correct depth: |
|
429 |
|
430 #ifndef QT_NO_XRENDER |
|
431 if (configDepth == 32) { |
|
432 qWarning("Warning: EGLConfig's depth (32) != pixmap's depth (%d), converting to ARGB32", |
|
433 x11PixmapData->depth()); |
|
434 x11PixmapData->convertToARGB32(true); |
|
435 } else |
|
436 #endif |
|
437 { |
|
438 qWarning("Warning: EGLConfig's depth (%d) != pixmap's depth (%d)", |
|
439 configDepth, x11PixmapData->depth()); |
|
440 } |
|
441 } |
|
442 |
|
443 QEglProperties surfaceAttribs; |
|
444 |
|
445 // If the pixmap can't be bound to a texture, it's pretty useless |
|
446 surfaceAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D); |
|
447 if (alphaSize > 0) |
|
448 surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA); |
|
449 else |
|
450 surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB); |
|
451 |
|
452 EGLSurface surf = eglCreatePixmapSurface(QEgl::display(), config, |
|
453 (EGLNativePixmapType) x11PixmapData->handle(), |
|
454 surfaceAttribs.properties()); |
|
455 x11PixmapData->gl_surface = (void*)surf; |
|
456 QImagePixmapCleanupHooks::enableCleanupHooks(x11PixmapData); |
|
457 return surf; |
|
458 } |
|
459 |
|
460 return EGL_NO_SURFACE; |
|
461 } |
|
462 |
156 QT_END_NAMESPACE |
463 QT_END_NAMESPACE |