// Chooses the EGL config and creates the EGL context bool QGLContext::chooseContext(const QGLContext* shareContext) // almost same as in qgl_x11egl.cpp { Q_D(QGLContext); if (!device()) return false; int devType = device()->devType(); if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) { qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType); return false; } // Get the display and initialize it. if (d->eglContext == 0) { d->eglContext = new QEglContext(); d->ownsEglContext = true; d->eglContext->setApi(QEgl::OpenGL); if (d->glFormat.samples() == EGL_DONT_CARE) { // Allow apps to override ability to use multisampling by setting an environment variable. Eg: // qputenv("QT_SYMBIAN_DISABLE_GL_MULTISAMPLE", "1"); // Added to allow camera app to start with limited memory. if (!QSymbianGraphicsSystemEx::hasBCM2727() && !qgetenv("QT_SYMBIAN_DISABLE_GL_MULTISAMPLE").toInt()) { // Most likely we have hw support for multisampling // so let's enable it. d->glFormat.setSampleBuffers(1); d->glFormat.setSamples(4); } else { d->glFormat.setSampleBuffers(0); d->glFormat.setSamples(0); } } // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat // has the alpha channel option set: if (devType == QInternal::Widget) { QWidget* widget = static_cast<QWidget*>(device()); if (widget->testAttribute(Qt::WA_TranslucentBackground)) d->glFormat.setAlpha(true); } // Construct the configuration we need for this surface. QEglProperties configProps; configProps.setDeviceType(devType); configProps.setPaintDeviceFormat(device()); configProps.setRenderableType(QEgl::OpenGL); configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_SWAP_BEHAVIOR_PRESERVED_BIT); qt_eglproperties_set_glformat(configProps, d->glFormat); if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) { delete d->eglContext; d->eglContext = 0; return false; } // Create a new context for the configuration. QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0; if (!d->eglContext->createContext(eglSharedContext)) { delete d->eglContext; d->eglContext = 0; return false; } d->sharing = d->eglContext->isSharing(); if (d->sharing && shareContext) const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; } // Inform the higher layers about the actual format properties qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config()); // Do don't create the EGLSurface for everything. // QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface // QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface // QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf if (devType == QInternal::Widget) { if (d->eglSurface != EGL_NO_SURFACE) eglDestroySurface(d->eglContext->display(), d->eglSurface); d->eglSurface = QEgl::createSurface(device(), d->eglContext->config()); eglGetError(); // Clear error state first. #ifdef QGL_NO_PRESERVED_SWAP eglSurfaceAttrib(QEgl::display(), d->eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); if (eglGetError() != EGL_SUCCESS) qWarning("QGLContext: could not enable destroyed swap behaviour"); #else eglSurfaceAttrib(QEgl::display(), d->eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); if (eglGetError() != EGL_SUCCESS) qWarning("QGLContext: could not enable preserved swap behaviour"); #endif setWindowCreated(true); } return true; }
bool QGLContext::chooseContext(const QGLContext* shareContext) { Q_D(QGLContext); // Validate the device. if (!device()) return false; int devType = device()->devType(); if (devType != QInternal::Pixmap && devType != QInternal::Image && devType != QInternal::Widget) { qWarning("QGLContext::chooseContext(): Cannot create QGLContext's for paint device type %d", devType); return false; } // Get the display and initialize it. d->eglContext = new QEglContext(); d->ownsEglContext = true; d->eglContext->setApi(QEgl::OpenGL); // Construct the configuration we need for this surface. QEglProperties configProps; qt_eglproperties_set_glformat(configProps, d->glFormat); configProps.setDeviceType(devType); configProps.setPaintDeviceFormat(device()); configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. if (!d->eglContext->chooseConfig(configProps)) { delete d->eglContext; d->eglContext = 0; return false; } // Inform the higher layers about the actual format properties. qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config()); // Create a new context for the configuration. if (!d->eglContext->createContext (shareContext ? shareContext->d_func()->eglContext : 0)) { delete d->eglContext; d->eglContext = 0; return false; } d->sharing = d->eglContext->isSharing(); if (d->sharing && shareContext) const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; #if defined(EGL_VERSION_1_1) if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget) eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval()); #endif // Create the EGL surface to draw into. d->eglSurface = d->eglContext->createSurface(device()); if (d->eglSurface == EGL_NO_SURFACE) { delete d->eglContext; d->eglContext = 0; return false; } return true; }
QT_BEGIN_NAMESPACE #ifdef EGL_BIND_TO_TEXTURE_RGBA #define QGL_RENDER_TEXTURE 1 #else #define QGL_RENDER_TEXTURE 0 #endif bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget) { // Create the EGL context. ctx = new QEglContext(); ctx->setApi(QEgl::OpenGL); // Find the shared context. QEglContext *shareContext = 0; if (shareWidget && shareWidget->d_func()->glcx) shareContext = shareWidget->d_func()->glcx->d_func()->eglContext; // Choose an appropriate configuration. We use the best format // we can find, even if it is greater than the requested format. // We try for a pbuffer that is capable of texture rendering if possible. textureFormat = EGL_NONE; if (shareContext) { // Use the same configuration as the widget we are sharing with. ctx->setConfig(shareContext->config()); #if QGL_RENDER_TEXTURE if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGBA) == EGL_TRUE) textureFormat = EGL_TEXTURE_RGBA; else if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGB) == EGL_TRUE) textureFormat = EGL_TEXTURE_RGB; #endif } else { QEglProperties configProps; qt_eglproperties_set_glformat(configProps, f); configProps.setDeviceType(QInternal::Pbuffer); configProps.setRenderableType(ctx->api()); bool ok = false; #if QGL_RENDER_TEXTURE textureFormat = EGL_TEXTURE_RGBA; configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat); if (!ok) { // Try again with RGB texture rendering. textureFormat = EGL_TEXTURE_RGB; configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA); configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat); if (!ok) { // One last try for a pbuffer with no texture rendering. configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB); textureFormat = EGL_NONE; } } #endif if (!ok) { if (!ctx->chooseConfig(configProps, QEgl::BestPixelFormat)) { delete ctx; ctx = 0; return false; } } } // Retrieve the actual format properties. qt_glformat_from_eglconfig(format, ctx->config()); // Create the attributes needed for the pbuffer. QEglProperties attribs; attribs.setValue(EGL_WIDTH, size.width()); attribs.setValue(EGL_HEIGHT, size.height()); #if QGL_RENDER_TEXTURE if (textureFormat != EGL_NONE) { attribs.setValue(EGL_TEXTURE_FORMAT, textureFormat); attribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D); } #endif // Create the pbuffer surface. pbuf = eglCreatePbufferSurface(ctx->display(), ctx->config(), attribs.properties()); #if QGL_RENDER_TEXTURE if (pbuf == EGL_NO_SURFACE && textureFormat != EGL_NONE) { // Try again with texture rendering disabled. textureFormat = EGL_NONE; attribs.removeValue(EGL_TEXTURE_FORMAT); attribs.removeValue(EGL_TEXTURE_TARGET); pbuf = eglCreatePbufferSurface(ctx->display(), ctx->config(), attribs.properties()); } #endif if (pbuf == EGL_NO_SURFACE) { qWarning() << "QGLPixelBufferPrivate::init(): Unable to create EGL pbuffer surface:" << QEgl::errorString(); return false; } // Create a new context for the configuration. if (!ctx->createContext(shareContext)) { delete ctx; ctx = 0; return false; } return true; }
QX11GLSharedContexts() : rgbContext(0) , argbContext(0) , sharedQGLContext(0) , sharePixmap(0) { EGLint rgbConfigId; EGLint argbConfigId; do { EGLConfig rgbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable); EGLConfig argbConfig = QEgl::defaultConfig(QInternal::Pixmap, QEgl::OpenGL, QEgl::Renderable | QEgl::Translucent); eglGetConfigAttrib(QEgl::display(), rgbConfig, EGL_CONFIG_ID, &rgbConfigId); eglGetConfigAttrib(QEgl::display(), argbConfig, EGL_CONFIG_ID, &argbConfigId); rgbContext = new QEglContext; rgbContext->setConfig(rgbConfig); rgbContext->createContext(); if (!rgbContext->isValid()) break; // If the RGB & ARGB configs are the same, use the same egl context for both: if (rgbConfig == argbConfig) argbContext = rgbContext; // Otherwise, create a separate context to be used for ARGB pixmaps: if (!argbContext) { argbContext = new QEglContext; argbContext->setConfig(argbConfig); bool success = argbContext->createContext(rgbContext); if (!success) { qWarning("QX11GLPixmapData - RGB & ARGB contexts aren't shared"); success = argbContext->createContext(); if (!success) argbContext = rgbContext; // Might work, worth a shot at least. } } if (!argbContext->isValid()) break; // Create the pixmap which will be used to create the egl surface for the share QGLContext QX11PixmapData *rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); rgbPixmapData->resize(8, 8); rgbPixmapData->fill(Qt::red); sharePixmap = new QPixmap(rgbPixmapData); EGLSurface sharePixmapSurface = QEgl::createSurface(sharePixmap, rgbConfig); rgbPixmapData->gl_surface = (void*)sharePixmapSurface; // Create the actual QGLContext which will be used for sharing sharedQGLContext = new QGLContext(QX11GLPixmapData::glFormat()); sharedQGLContext->d_func()->eglContext = rgbContext; sharedQGLContext->d_func()->eglSurface = sharePixmapSurface; sharedQGLContext->d_func()->valid = true; qt_glformat_from_eglconfig(sharedQGLContext->d_func()->glFormat, rgbConfig); valid = rgbContext->makeCurrent(sharePixmapSurface); // If the ARGB & RGB configs are different, check ARGB works too: if (argbConfig != rgbConfig) { QX11PixmapData *argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); argbPixmapData->resize(8, 8); argbPixmapData->fill(Qt::transparent); // Force ARGB QPixmap argbPixmap(argbPixmapData); // destroys pixmap data when goes out of scope EGLSurface argbPixmapSurface = QEgl::createSurface(&argbPixmap, argbConfig); valid = argbContext->makeCurrent(argbPixmapSurface); argbContext->doneCurrent(); eglDestroySurface(QEgl::display(), argbPixmapSurface); argbPixmapData->gl_surface = 0; } if (!valid) { qWarning() << "Unable to make pixmap surface current:" << QEgl::errorString(); break; } // The pixmap surface destruction hooks are installed by QGLTextureCache, so we // must make sure this is instanciated: QGLTextureCache::instance(); } while(0); if (!valid) cleanup(); else qDebug("Using QX11GLPixmapData with EGL config %d for ARGB and config %d for RGB", argbConfigId, rgbConfigId); }
// Chooses the EGL config and creates the EGL context bool QGLContext::chooseContext(const QGLContext* shareContext) { Q_D(QGLContext); if (!device()) return false; int devType = device()->devType(); QX11PixmapData *x11PixmapData = 0; if (devType == QInternal::Pixmap) { QPixmapData *pmd = static_cast<QPixmap*>(device())->data_ptr().data(); if (pmd->classId() == QPixmapData::X11Class) x11PixmapData = static_cast<QX11PixmapData*>(pmd); else { // TODO: Replace the pixmap's data with a new QX11PixmapData qWarning("WARNING: Creating a QGLContext on a QPixmap is only supported for X11 pixmap backend"); return false; } } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) { qWarning("WARNING: Creating a QGLContext not supported on device type %d", devType); return false; } // Only create the eglContext if we don't already have one: if (d->eglContext == 0) { d->eglContext = new QEglContext(); d->ownsEglContext = true; d->eglContext->setApi(QEgl::OpenGL); // If the device is a widget with WA_TranslucentBackground set, make sure the glFormat // has the alpha channel option set: if (devType == QInternal::Widget) { QWidget* widget = static_cast<QWidget*>(device()); if (widget->testAttribute(Qt::WA_TranslucentBackground)) d->glFormat.setAlpha(true); } // Construct the configuration we need for this surface. QEglProperties configProps; configProps.setDeviceType(devType); configProps.setRenderableType(QEgl::OpenGL); qt_eglproperties_set_glformat(configProps, d->glFormat); // Set buffer preserved for regular QWidgets, QGLWidgets are ok with either preserved or destroyed: if ((devType == QInternal::Widget) && qobject_cast<QGLWidget*>(static_cast<QWidget*>(device())) == 0) configProps.setValue(EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) { delete d->eglContext; d->eglContext = 0; return false; } // Create a new context for the configuration. QEglContext* eglSharedContext = shareContext ? shareContext->d_func()->eglContext : 0; if (!d->eglContext->createContext(eglSharedContext)) { delete d->eglContext; d->eglContext = 0; return false; } d->sharing = d->eglContext->isSharing(); if (d->sharing && shareContext) const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; } // Inform the higher layers about the actual format properties qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config()); // Do don't create the EGLSurface for everything. // QWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface // QGLWidget - yes, create the EGLSurface and store it in QGLContextPrivate::eglSurface // QPixmap - yes, create the EGLSurface but store it in QX11PixmapData::gl_surface // QGLPixelBuffer - no, it creates the surface itself and stores it in QGLPixelBufferPrivate::pbuf if (devType == QInternal::Widget) { if (d->eglSurface != EGL_NO_SURFACE) eglDestroySurface(d->eglContext->display(), d->eglSurface); // extraWindowSurfaceCreationProps default to NULL unless were specifically set before d->eglSurface = QEgl::createSurface(device(), d->eglContext->config(), d->extraWindowSurfaceCreationProps); XFlush(X11->display); setWindowCreated(true); } if (x11PixmapData) { // TODO: Actually check to see if the existing surface can be re-used if (x11PixmapData->gl_surface) eglDestroySurface(d->eglContext->display(), (EGLSurface)x11PixmapData->gl_surface); x11PixmapData->gl_surface = (void*)QEgl::createSurface(device(), d->eglContext->config()); } return true; }