168 bool QGLFormat::hasOpenGLOverlays() |
152 bool QGLFormat::hasOpenGLOverlays() |
169 { |
153 { |
170 return false; |
154 return false; |
171 } |
155 } |
172 |
156 |
173 void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device) |
|
174 { |
|
175 if (device->devType() == QInternal::Image) |
|
176 props.setPixelFormat(static_cast<QImage *>(device)->format()); |
|
177 } |
|
178 |
|
179 // Chooses the EGL config and creates the EGL context |
157 // Chooses the EGL config and creates the EGL context |
180 bool QGLContext::chooseContext(const QGLContext* shareContext) |
158 bool QGLContext::chooseContext(const QGLContext* shareContext) |
181 { |
159 { |
182 Q_D(QGLContext); |
160 Q_D(QGLContext); |
183 |
161 |
184 if (!device()) |
162 if (!device()) |
185 return false; |
163 return false; |
186 |
164 |
187 int devType = device()->devType(); |
165 int devType = device()->devType(); |
188 |
166 |
189 // Get the display and initialize it. |
167 QX11PixmapData *x11PixmapData = 0; |
|
168 if (devType == QInternal::Pixmap) { |
|
169 QPixmapData *pmd = static_cast<QPixmap*>(device())->data_ptr().data(); |
|
170 if (pmd->classId() == QPixmapData::X11Class) |
|
171 x11PixmapData = static_cast<QX11PixmapData*>(pmd); |
|
172 else { |
|
173 // TODO: Replace the pixmap's data with a new QX11PixmapData |
|
174 qWarning("WARNING: Creating a QGLContext on a QPixmap is only supported for X11 pixmap backend"); |
|
175 return false; |
|
176 } |
|
177 } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) { |
|
178 qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType); |
|
179 return false; |
|
180 } |
|
181 |
|
182 // Only create the eglContext if we don't already have one: |
190 if (d->eglContext == 0) { |
183 if (d->eglContext == 0) { |
191 d->eglContext = new QEglContext(); |
184 d->eglContext = new QEglContext(); |
|
185 d->ownsEglContext = true; |
192 d->eglContext->setApi(QEgl::OpenGL); |
186 d->eglContext->setApi(QEgl::OpenGL); |
|
187 |
|
188 // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat |
|
189 // has the alpha channel option set: |
|
190 if (devType == QInternal::Widget) { |
|
191 QWidget* widget = static_cast<QWidget*>(device()); |
|
192 if (widget->testAttribute(Qt::WA_TranslucentBackground)) |
|
193 d->glFormat.setAlpha(true); |
|
194 } |
193 |
195 |
194 // Construct the configuration we need for this surface. |
196 // Construct the configuration we need for this surface. |
195 QEglProperties configProps; |
197 QEglProperties configProps; |
196 qt_egl_set_format(configProps, devType, d->glFormat); |
198 configProps.setDeviceType(devType); |
197 qt_egl_add_platform_config(configProps, device()); |
|
198 configProps.setRenderableType(QEgl::OpenGL); |
199 configProps.setRenderableType(QEgl::OpenGL); |
199 |
200 qt_eglproperties_set_glformat(configProps, d->glFormat); |
200 #if We_have_an_EGL_library_which_bothers_to_check_EGL_BUFFER_SIZE |
201 |
201 if (device()->depth() == 16 && configProps.value(EGL_ALPHA_SIZE) <= 0) { |
202 // Set buffer preserved for regular QWidgets, QGLWidgets are ok with either preserved or destroyed: |
202 qDebug("Setting EGL_BUFFER_SIZE to 16"); |
203 if ((devType == QInternal::Widget) && qobject_cast<QGLWidget*>(static_cast<QWidget*>(device())) == 0) |
203 configProps.setValue(EGL_BUFFER_SIZE, 16); |
204 configProps.setValue(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); |
204 configProps.setValue(EGL_ALPHA_SIZE, 0); |
|
205 } |
|
206 |
205 |
207 if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) { |
206 if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) { |
208 delete d->eglContext; |
207 delete d->eglContext; |
209 d->eglContext = 0; |
208 d->eglContext = 0; |
210 return false; |
209 return false; |
211 } |
210 } |
212 #else |
211 |
213 QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat; |
212 // Create a new context for the configuration. |
214 if ((device()->depth() == 16) && configProps.value(EGL_ALPHA_SIZE) == 0) { |
213 QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0; |
215 configProps.setValue(EGL_RED_SIZE, 5); |
214 if (!d->eglContext->createContext(eglSharedContext)) { |
216 configProps.setValue(EGL_GREEN_SIZE, 6); |
|
217 configProps.setValue(EGL_BLUE_SIZE, 5); |
|
218 configProps.setValue(EGL_ALPHA_SIZE, 0); |
|
219 matchType = QEgl::ExactPixelFormat; |
|
220 } |
|
221 |
|
222 // Search for a matching configuration, reducing the complexity |
|
223 // each time until we get something that matches. |
|
224 if (!d->eglContext->chooseConfig(configProps, matchType)) { |
|
225 delete d->eglContext; |
215 delete d->eglContext; |
226 d->eglContext = 0; |
216 d->eglContext = 0; |
227 return false; |
217 return false; |
228 } |
218 } |
229 #endif |
|
230 |
|
231 // qDebug("QGLContext::chooseContext() - using EGL config %d:", d->eglContext->config()); |
|
232 // qDebug() << QEglProperties(d->eglContext->config()).toString(); |
|
233 |
|
234 // Create a new context for the configuration. |
|
235 if (!d->eglContext->createContext |
|
236 (shareContext ? shareContext->d_func()->eglContext : 0)) { |
|
237 delete d->eglContext; |
|
238 d->eglContext = 0; |
|
239 return false; |
|
240 } |
|
241 d->sharing = d->eglContext->isSharing(); |
219 d->sharing = d->eglContext->isSharing(); |
242 if (d->sharing && shareContext) |
220 if (d->sharing && shareContext) |
243 const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; |
221 const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; |
244 |
222 } |
245 #if defined(EGL_VERSION_1_1) |
223 |
246 if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget) |
224 // Inform the higher layers about the actual format properties |
247 eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval()); |
225 qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config()); |
248 #endif |
226 |
249 } |
227 // Do don't create the EGLSurface for everything. |
250 |
228 // QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface |
251 // Inform the higher layers about the actual format properties. |
229 // QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface |
252 qt_egl_update_format(*(d->eglContext), d->glFormat); |
230 // QPixmap - yes, create the EGLSurface but store it in QX11PixmapData::gl_surface |
|
231 // QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf |
|
232 |
|
233 if (devType == QInternal::Widget) { |
|
234 if (d->eglSurface != EGL_NO_SURFACE) |
|
235 eglDestroySurface(d->eglContext->display(), d->eglSurface); |
|
236 d->eglSurface = QEgl::createSurface(device(), d->eglContext->config()); |
|
237 XFlush(X11->display); |
|
238 setWindowCreated(true); |
|
239 } |
|
240 |
|
241 if (x11PixmapData) { |
|
242 // TODO: Actually check to see if the existing surface can be re-used |
|
243 if (x11PixmapData->gl_surface) |
|
244 eglDestroySurface(d->eglContext->display(), (EGLSurface)x11PixmapData->gl_surface); |
|
245 |
|
246 x11PixmapData->gl_surface = (void*)QEgl::createSurface(device(), d->eglContext->config()); |
|
247 } |
253 |
248 |
254 return true; |
249 return true; |
255 } |
250 } |
256 |
251 |
257 void QGLWidget::resizeEvent(QResizeEvent *) |
252 void QGLWidget::resizeEvent(QResizeEvent *) |
279 void QGLWidget::updateOverlayGL() |
274 void QGLWidget::updateOverlayGL() |
280 { |
275 { |
281 //handle overlay |
276 //handle overlay |
282 } |
277 } |
283 |
278 |
284 //#define QT_DEBUG_X11_VISUAL_SELECTION 1 |
|
285 |
|
286 bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual) |
|
287 { |
|
288 bool foundVisualIsArgb = useArgbVisual; |
|
289 |
|
290 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
291 qDebug("qt_egl_setup_x11_visual() - useArgbVisual=%d", useArgbVisual); |
|
292 #endif |
|
293 |
|
294 memset(&vi, 0, sizeof(XVisualInfo)); |
|
295 |
|
296 EGLint eglConfigColorSize; |
|
297 eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &eglConfigColorSize); |
|
298 |
|
299 // Check to see if EGL is suggesting an appropriate visual id: |
|
300 EGLint nativeVisualId; |
|
301 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId); |
|
302 vi.visualid = nativeVisualId; |
|
303 |
|
304 if (vi.visualid) { |
|
305 // EGL has suggested a visual id, so get the rest of the visual info for that id: |
|
306 XVisualInfo *chosenVisualInfo; |
|
307 int matchingCount = 0; |
|
308 chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount); |
|
309 if (chosenVisualInfo) { |
|
310 #if !defined(QT_NO_XRENDER) |
|
311 if (useArgbVisual) { |
|
312 // Check to make sure the visual provided by EGL is ARGB |
|
313 XRenderPictFormat *format; |
|
314 format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual); |
|
315 if (format->type == PictTypeDirect && format->direct.alphaMask) { |
|
316 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
317 qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid); |
|
318 #endif |
|
319 foundVisualIsArgb = true; |
|
320 vi = *chosenVisualInfo; |
|
321 } |
|
322 else { |
|
323 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB", |
|
324 nativeVisualId, (int)config); |
|
325 vi.visualid = 0; |
|
326 } |
|
327 } else |
|
328 #endif |
|
329 { |
|
330 if (eglConfigColorSize == chosenVisualInfo->depth) { |
|
331 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
332 qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid); |
|
333 #endif |
|
334 vi = *chosenVisualInfo; |
|
335 } else |
|
336 qWarning("Warning: EGL suggested using X visual ID %d (%d bpp) for config %d (%d bpp), but the depths do not match!", |
|
337 nativeVisualId, chosenVisualInfo->depth, (int)config, eglConfigColorSize); |
|
338 } |
|
339 XFree(chosenVisualInfo); |
|
340 } |
|
341 else { |
|
342 qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!", |
|
343 nativeVisualId, (int)config); |
|
344 vi.visualid = 0; |
|
345 } |
|
346 } |
|
347 |
|
348 // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first |
|
349 // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo |
|
350 |
|
351 #if !defined(QT_NO_XRENDER) |
|
352 if (vi.visualid == 0 && useArgbVisual) { |
|
353 // Try to use XRender to find an ARGB visual we can use |
|
354 vi.screen = x11Info.screen(); |
|
355 vi.depth = 32; //### We might at some point (soon) get ARGB4444 |
|
356 vi.c_class = TrueColor; |
|
357 XVisualInfo *matchingVisuals; |
|
358 int matchingCount = 0; |
|
359 matchingVisuals = XGetVisualInfo(x11Info.display(), |
|
360 VisualScreenMask|VisualDepthMask|VisualClassMask, |
|
361 &vi, &matchingCount); |
|
362 |
|
363 for (int i = 0; i < matchingCount; ++i) { |
|
364 XRenderPictFormat *format; |
|
365 format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual); |
|
366 if (format->type == PictTypeDirect && format->direct.alphaMask) { |
|
367 vi = matchingVisuals[i]; |
|
368 foundVisualIsArgb = true; |
|
369 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
370 qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid); |
|
371 #endif |
|
372 break; |
|
373 } |
|
374 } |
|
375 XFree(matchingVisuals); |
|
376 } |
|
377 #endif |
|
378 |
|
379 if (vi.visualid == 0) { |
|
380 EGLint depth; |
|
381 eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth); |
|
382 int err; |
|
383 err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi); |
|
384 if (err == 0) { |
|
385 qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!", |
|
386 (int)config, depth); |
|
387 depth = x11Info.depth(); |
|
388 err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi); |
|
389 if (err == 0) { |
|
390 qWarning("Error: Couldn't get any matching X visual!"); |
|
391 return false; |
|
392 } else |
|
393 qWarning(" - Falling back to X11 suggested depth (%d)", depth); |
|
394 } |
|
395 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
396 else |
|
397 qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth); |
|
398 #endif |
|
399 |
|
400 // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-( |
|
401 if (useArgbVisual) |
|
402 foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444 |
|
403 } |
|
404 |
|
405 #ifdef QT_DEBUG_X11_VISUAL_SELECTION |
|
406 qDebug("Visual Info:"); |
|
407 qDebug(" bits_per_rgb=%d", vi.bits_per_rgb); |
|
408 qDebug(" red_mask=0x%x", vi.red_mask); |
|
409 qDebug(" green_mask=0x%x", vi.green_mask); |
|
410 qDebug(" blue_mask=0x%x", vi.blue_mask); |
|
411 qDebug(" colormap_size=%d", vi.colormap_size); |
|
412 qDebug(" c_class=%d", vi.c_class); |
|
413 qDebug(" depth=%d", vi.depth); |
|
414 qDebug(" screen=%d", vi.screen); |
|
415 qDebug(" visualid=%d", vi.visualid); |
|
416 #endif |
|
417 return foundVisualIsArgb; |
|
418 } |
|
419 |
|
420 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext) |
279 void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext) |
421 { |
280 { |
422 Q_D(QGLWidget); |
281 Q_D(QGLWidget); |
423 if (context == 0) { |
282 if (context == 0) { |
424 qWarning("QGLWidget::setContext: Cannot set null context"); |
283 qWarning("QGLWidget::setContext: Cannot set null context"); |
543 |
333 |
544 void QGLWidget::setColormap(const QGLColormap &) |
334 void QGLWidget::setColormap(const QGLColormap &) |
545 { |
335 { |
546 } |
336 } |
547 |
337 |
548 // Re-creates the EGL surface if the window ID has changed or if force is true |
338 // Re-creates the EGL surface if the window ID has changed or if there isn't a surface |
549 void QGLWidgetPrivate::recreateEglSurface(bool force) |
339 void QGLWidgetPrivate::recreateEglSurface() |
550 { |
340 { |
551 Q_Q(QGLWidget); |
341 Q_Q(QGLWidget); |
552 |
342 |
553 Window currentId = q->winId(); |
343 Window currentId = q->winId(); |
554 |
344 |
555 if ( force || (currentId != eglSurfaceWindowId) ) { |
345 // If the window ID has changed since the surface was created, we need to delete the |
556 // The window id has changed so we need to re-create the EGL surface |
346 // old surface before re-creating a new one. Note: This should not be the case as the |
557 QEglContext *ctx = glcx->d_func()->eglContext; |
347 // surface should be deleted before the old window id. |
558 EGLSurface surface = glcx->d_func()->eglSurface; |
348 if (glcx->d_func()->eglSurface != EGL_NO_SURFACE && (currentId != eglSurfaceWindowId)) { |
559 if (surface != EGL_NO_SURFACE) |
349 qWarning("EGL surface for deleted window %x was not destroyed", eglSurfaceWindowId); |
560 ctx->destroySurface(surface); // Will force doneCurrent() if nec. |
350 glcx->d_func()->destroyEglSurfaceForDevice(); |
561 surface = ctx->createSurface(q); |
351 } |
562 if (surface == EGL_NO_SURFACE) |
352 |
563 qWarning("Error creating EGL window surface: 0x%x", eglGetError()); |
353 if (glcx->d_func()->eglSurface == EGL_NO_SURFACE) { |
564 glcx->d_func()->eglSurface = surface; |
354 glcx->d_func()->eglSurface = glcx->d_func()->eglContext->createSurface(q); |
565 |
|
566 eglSurfaceWindowId = currentId; |
355 eglSurfaceWindowId = currentId; |
567 } |
356 } |
568 } |
357 } |
569 |
358 |
570 // Selects which configs should be used |
359 |
571 EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly) |
360 QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, const qint64 key, |
572 { |
|
573 // Cache the configs we select as they wont change: |
|
574 static EGLConfig roPixmapRGBConfig = 0; |
|
575 static EGLConfig roPixmapRGBAConfig = 0; |
|
576 static EGLConfig rwPixmapRGBConfig = 0; |
|
577 static EGLConfig rwPixmapRGBAConfig = 0; |
|
578 |
|
579 EGLConfig* targetConfig; |
|
580 |
|
581 if (hasAlpha) { |
|
582 if (readOnly) |
|
583 targetConfig = &roPixmapRGBAConfig; |
|
584 else |
|
585 targetConfig = &rwPixmapRGBAConfig; |
|
586 } |
|
587 else { |
|
588 if (readOnly) |
|
589 targetConfig = &roPixmapRGBConfig; |
|
590 else |
|
591 targetConfig = &rwPixmapRGBConfig; |
|
592 } |
|
593 |
|
594 if (*targetConfig == 0) { |
|
595 QEglProperties configAttribs; |
|
596 configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT); |
|
597 configAttribs.setRenderableType(QEgl::OpenGL); |
|
598 if (hasAlpha) |
|
599 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); |
|
600 else |
|
601 configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); |
|
602 |
|
603 // If this is going to be a render target, it needs to have a depth, stencil & sample buffer |
|
604 if (!readOnly) { |
|
605 configAttribs.setValue(EGL_DEPTH_SIZE, 1); |
|
606 configAttribs.setValue(EGL_STENCIL_SIZE, 1); |
|
607 configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1); |
|
608 } |
|
609 |
|
610 EGLint configCount = 0; |
|
611 do { |
|
612 eglChooseConfig(QEglContext::display(), configAttribs.properties(), targetConfig, 1, &configCount); |
|
613 if (configCount > 0) { |
|
614 // Got one |
|
615 qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" ) |
|
616 << "config (" << int(*targetConfig) << ") to create a pixmap surface:"; |
|
617 |
|
618 // QEglProperties configProps(*targetConfig); |
|
619 // qDebug() << configProps.toString(); |
|
620 break; |
|
621 } |
|
622 qWarning("choosePixmapConfig() - No suitible config found, reducing requirements"); |
|
623 } while (configAttribs.reduceConfiguration()); |
|
624 } |
|
625 |
|
626 if (*targetConfig == 0) |
|
627 qWarning("choosePixmapConfig() - Couldn't find a suitable config"); |
|
628 |
|
629 return *targetConfig; |
|
630 } |
|
631 |
|
632 bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly) |
|
633 { |
|
634 Q_ASSERT(pmd->classId() == QPixmapData::X11Class); |
|
635 QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd); |
|
636 |
|
637 bool hasAlpha = pixmapData->hasAlphaChannel(); |
|
638 |
|
639 EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly); |
|
640 |
|
641 QEglProperties pixmapAttribs; |
|
642 |
|
643 // If the pixmap can't be bound to a texture, it's pretty useless |
|
644 pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D); |
|
645 if (hasAlpha) |
|
646 pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA); |
|
647 else |
|
648 pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB); |
|
649 |
|
650 EGLSurface pixmapSurface; |
|
651 pixmapSurface = eglCreatePixmapSurface(QEglContext::display(), |
|
652 pixmapConfig, |
|
653 (EGLNativePixmapType) pixmapData->handle(), |
|
654 pixmapAttribs.properties()); |
|
655 // qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x", |
|
656 // pixmapSurface, pixmapData->handle()); |
|
657 if (pixmapSurface == EGL_NO_SURFACE) { |
|
658 qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig |
|
659 << ":" << QEglContext::errorString(eglGetError()); |
|
660 return false; |
|
661 } |
|
662 |
|
663 static bool doneOnce = false; |
|
664 if (!doneOnce) { |
|
665 // Make sure QGLTextureCache is instanciated so it can install cleanup hooks |
|
666 // which cleanup the EGL surface. |
|
667 QGLTextureCache::instance(); |
|
668 doneOnce = true; |
|
669 } |
|
670 |
|
671 Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure! |
|
672 pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; |
|
673 QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData); // Make sure the cleanup hook gets called |
|
674 |
|
675 return true; |
|
676 } |
|
677 |
|
678 |
|
679 QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key, |
|
680 QGLContext::BindOptions options) |
361 QGLContext::BindOptions options) |
681 { |
362 { |
682 Q_Q(QGLContext); |
363 Q_Q(QGLContext); |
683 |
364 |
684 // The EGL texture_from_pixmap has no facility to invert the y coordinate |
365 // The EGL texture_from_pixmap has no facility to invert the y coordinate |
685 if (!(options & QGLContext::CanFlipNativePixmapBindOption)) |
366 if (!(options & QGLContext::CanFlipNativePixmapBindOption)) |
686 return 0; |
367 return 0; |
687 |
368 |
688 Q_ASSERT(pd->classId() == QPixmapData::X11Class); |
|
689 |
369 |
690 static bool checkedForTFP = false; |
370 static bool checkedForTFP = false; |
691 static bool haveTFP = false; |
371 static bool haveTFP = false; |
|
372 static bool checkedForEglImageTFP = false; |
|
373 static bool haveEglImageTFP = false; |
|
374 |
|
375 |
|
376 if (!checkedForEglImageTFP) { |
|
377 checkedForEglImageTFP = true; |
|
378 |
|
379 // We need to be able to create an EGLImage from a native pixmap, which was split |
|
380 // into a seperate EGL extension, EGL_KHR_image_pixmap. It is possible to have |
|
381 // eglCreateImageKHR & eglDestroyImageKHR without support for pixmaps, so we must |
|
382 // check we have the EGLImage from pixmap functionality. |
|
383 if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) { |
|
384 |
|
385 // Being able to create an EGLImage from a native pixmap is also pretty useless |
|
386 // without the ability to bind that EGLImage as a texture, which is provided by |
|
387 // the GL_OES_EGL_image extension, which we try to resolve here: |
|
388 haveEglImageTFP = qt_resolve_eglimage_gl_extensions(q); |
|
389 |
|
390 if (haveEglImageTFP) |
|
391 qDebug("Found EGL_KHR_image_pixmap & GL_OES_EGL_image extensions (preferred method)!"); |
|
392 } |
|
393 } |
692 |
394 |
693 if (!checkedForTFP) { |
395 if (!checkedForTFP) { |
694 // Check for texture_from_pixmap egl extension |
396 // Check for texture_from_pixmap egl extension |
695 checkedForTFP = true; |
397 checkedForTFP = true; |
696 if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") || |
398 if (QEgl::hasExtension("EGL_NOKIA_texture_from_pixmap") || |
697 eglContext->hasExtension("EGL_EXT_texture_from_pixmap")) |
399 QEgl::hasExtension("EGL_EXT_texture_from_pixmap")) |
698 { |
400 { |
699 qDebug("Found texture_from_pixmap EGL extension!"); |
401 qDebug("Found texture_from_pixmap EGL extension!"); |
700 haveTFP = true; |
402 haveTFP = true; |
701 } |
403 } |
702 } |
404 } |
703 |
405 |
704 if (!haveTFP) |
406 if (!haveTFP && !haveEglImageTFP) |
705 return 0; |
407 return 0; |
706 |
408 |
707 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd); |
409 |
708 |
410 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data()); |
|
411 Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); |
709 bool hasAlpha = pixmapData->hasAlphaChannel(); |
412 bool hasAlpha = pixmapData->hasAlphaChannel(); |
710 |
413 bool pixmapHasValidSurface = false; |
711 // Check to see if the surface is still valid |
414 bool textureIsBound = false; |
712 if (pixmapData->gl_surface && |
|
713 hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) |
|
714 { |
|
715 // Surface is invalid! |
|
716 destroyGlSurfaceForPixmap(pixmapData); |
|
717 } |
|
718 |
|
719 if (pixmapData->gl_surface == 0) { |
|
720 bool success = qt_createEGLSurfaceForPixmap(pixmapData, true); |
|
721 if (!success) { |
|
722 haveTFP = false; |
|
723 return 0; |
|
724 } |
|
725 } |
|
726 |
|
727 Q_ASSERT(pixmapData->gl_surface); |
|
728 |
|
729 GLuint textureId; |
415 GLuint textureId; |
730 glGenTextures(1, &textureId); |
416 glGenTextures(1, &textureId); |
731 glBindTexture(GL_TEXTURE_2D, textureId); |
417 glBindTexture(GL_TEXTURE_2D, textureId); |
732 |
418 |
733 // bind the egl pixmap surface to a texture |
419 if (haveTFP && pixmapData->gl_surface && |
734 EGLBoolean success; |
420 hasAlpha == (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) |
735 success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); |
421 { |
736 if (success == EGL_FALSE) { |
422 pixmapHasValidSurface = true; |
737 qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError()); |
423 } |
738 eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface); |
424 |
739 pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE; |
425 // If we already have a valid EGL surface for the pixmap, we should use it |
740 haveTFP = false; |
426 if (pixmapHasValidSurface) { |
741 return 0; |
427 EGLBoolean success; |
742 } |
428 success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); |
743 |
429 if (success == EGL_FALSE) { |
744 QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options); |
430 qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); |
745 pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; |
431 eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); |
746 |
432 pixmapData->gl_surface = (void*)EGL_NO_SURFACE; |
747 // We assume the cost of bound pixmaps is zero |
433 } else |
748 QGLTextureCache::instance()->insert(q, key, texture, 0); |
434 textureIsBound = true; |
749 |
435 } |
750 glBindTexture(GL_TEXTURE_2D, textureId); |
436 |
|
437 // If the pixmap doesn't already have a valid surface, try binding it via EGLImage |
|
438 // first, as going through EGLImage should be faster and better supported: |
|
439 if (!textureIsBound && haveEglImageTFP) { |
|
440 EGLImageKHR eglImage; |
|
441 |
|
442 EGLint attribs[] = { |
|
443 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, |
|
444 EGL_NONE |
|
445 }; |
|
446 eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, |
|
447 (EGLClientBuffer)QEgl::nativePixmap(pixmap), attribs); |
|
448 |
|
449 QGLContext* ctx = q; |
|
450 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage); |
|
451 |
|
452 GLint err = glGetError(); |
|
453 if (err == GL_NO_ERROR) |
|
454 textureIsBound = true; |
|
455 |
|
456 // Once the egl image is bound, the texture becomes a new sibling image and we can safely |
|
457 // destroy the EGLImage we created for the pixmap: |
|
458 if (eglImage != EGL_NO_IMAGE_KHR) |
|
459 QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); |
|
460 } |
|
461 |
|
462 if (!textureIsBound && haveTFP) { |
|
463 // Check to see if the surface is still valid |
|
464 if (pixmapData->gl_surface && |
|
465 hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha)) |
|
466 { |
|
467 // Surface is invalid! |
|
468 destroyGlSurfaceForPixmap(pixmapData); |
|
469 } |
|
470 |
|
471 if (pixmapData->gl_surface == 0) { |
|
472 EGLConfig config = QEgl::defaultConfig(QInternal::Pixmap, |
|
473 QEgl::OpenGL, |
|
474 hasAlpha ? QEgl::Translucent : QEgl::NoOptions); |
|
475 |
|
476 pixmapData->gl_surface = (void*)QEgl::createSurface(pixmap, config); |
|
477 if (pixmapData->gl_surface == (void*)EGL_NO_SURFACE) |
|
478 return false; |
|
479 } |
|
480 |
|
481 EGLBoolean success; |
|
482 success = eglBindTexImage(QEgl::display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); |
|
483 if (success == EGL_FALSE) { |
|
484 qWarning() << "eglBindTexImage() failed:" << QEgl::errorString(); |
|
485 eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); |
|
486 pixmapData->gl_surface = (void*)EGL_NO_SURFACE; |
|
487 haveTFP = false; // If TFP isn't working, disable it's use |
|
488 } else |
|
489 textureIsBound = true; |
|
490 } |
|
491 |
|
492 QGLTexture *texture = 0; |
|
493 |
|
494 if (textureIsBound) { |
|
495 texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options); |
|
496 pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture; |
|
497 |
|
498 // We assume the cost of bound pixmaps is zero |
|
499 QGLTextureCache::instance()->insert(q, key, texture, 0); |
|
500 |
|
501 glBindTexture(GL_TEXTURE_2D, textureId); |
|
502 } else |
|
503 glDeleteTextures(1, &textureId); |
|
504 |
751 return texture; |
505 return texture; |
752 } |
506 } |
|
507 |
753 |
508 |
754 void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd) |
509 void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd) |
755 { |
510 { |
756 Q_ASSERT(pmd->classId() == QPixmapData::X11Class); |
511 Q_ASSERT(pmd->classId() == QPixmapData::X11Class); |
757 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); |
512 QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd); |
758 if (pixmapData->gl_surface) { |
513 if (pixmapData->gl_surface) { |
759 EGLBoolean success; |
514 EGLBoolean success; |
760 success = eglDestroySurface(QEglContext::display(), (EGLSurface)pixmapData->gl_surface); |
515 success = eglDestroySurface(QEgl::display(), (EGLSurface)pixmapData->gl_surface); |
761 if (success == EGL_FALSE) { |
516 if (success == EGL_FALSE) { |
762 qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: " |
517 qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: " |
763 << QEglContext::errorString(eglGetError()); |
518 << QEgl::errorString(); |
764 } |
519 } |
765 pixmapData->gl_surface = 0; |
520 pixmapData->gl_surface = 0; |
766 } |
521 } |
767 } |
522 } |
768 |
523 |