static QEglContext *createContext(QPaintDevice *device) { QEglContext *context; // Create the context object and open the display. context = new QEglContext(); context->setApi(QEgl::OpenVG); if (!context->openDisplay(device)) { delete context; return 0; } // Set the swap interval for the display. QByteArray interval = qgetenv("QT_VG_SWAP_INTERVAL"); if (!interval.isEmpty()) eglSwapInterval(context->display(), interval.toInt()); else eglSwapInterval(context->display(), 1); // Choose an appropriate configuration for rendering into the device. QEglProperties configProps; configProps.setPaintDeviceFormat(device); int redSize = configProps.value(EGL_RED_SIZE); if (redSize == EGL_DONT_CARE || redSize == 0) configProps.setPixelFormat(QImage::Format_ARGB32); // XXX #ifndef QVG_SCISSOR_CLIP // If we are using the mask to clip, then explicitly request a mask. configProps.setValue(EGL_ALPHA_MASK_SIZE, 1); #endif #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT); configProps.setRenderableType(QEgl::OpenVG); if (!context->chooseConfig(configProps)) { // Try again without the "pre" bit. configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); if (!context->chooseConfig(configProps)) { delete context; return 0; } } #else configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); configProps.setRenderableType(QEgl::OpenVG); if (!context->chooseConfig(configProps)) { delete context; return 0; } #endif // Construct a new EGL context for the selected configuration. if (!context->createContext()) { delete context; return 0; } return context; }
QT_BEGIN_NAMESPACE void qt_eglproperties_set_glformat(QEglProperties& eglProperties, const QGLFormat& glFormat) { int redSize = glFormat.redBufferSize(); int greenSize = glFormat.greenBufferSize(); int blueSize = glFormat.blueBufferSize(); int alphaSize = glFormat.alphaBufferSize(); int depthSize = glFormat.depthBufferSize(); int stencilSize = glFormat.stencilBufferSize(); int sampleCount = glFormat.samples(); // QGLFormat uses a magic value of -1 to indicate "don't care", even when a buffer of that // type has been requested. So we must check QGLFormat's booleans too if size is -1: if (glFormat.alpha() && alphaSize <= 0) alphaSize = 1; if (glFormat.depth() && depthSize <= 0) depthSize = 1; if (glFormat.stencil() && stencilSize <= 0) stencilSize = 1; if (glFormat.sampleBuffers() && sampleCount <= 0) sampleCount = 1; // We want to make sure 16-bit configs are chosen over 32-bit configs as they will provide // the best performance. The EGL config selection algorithm is a bit stange in this regard: // The selection criteria for EGL_BUFFER_SIZE is "AtLeast", so we can't use it to discard // 32-bit configs completely from the selection. So it then comes to the sorting algorithm. // The red/green/blue sizes have a sort priority of 3, so they are sorted by first. The sort // order is special and described as "by larger _total_ number of color bits.". So EGL will // put 32-bit configs in the list before the 16-bit configs. However, the spec also goes on // to say "If the requested number of bits in attrib_list for a particular component is 0, // then the number of bits for that component is not considered". This part of the spec also // seems to imply that setting the red/green/blue bits to zero means none of the components // are considered and EGL disregards the entire sorting rule. It then looks to the next // highest priority rule, which is EGL_BUFFER_SIZE. Despite the selection criteria being // "AtLeast" for EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit, // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that // if the application sets the red/green/blue size to 5/6/5 on the QGLFormat, they will // probably get a 32-bit config, even when there's an RGB565 config avaliable. Oh well. // Now normalize the values so -1 becomes 0 redSize = redSize > 0 ? redSize : 0; greenSize = greenSize > 0 ? greenSize : 0; blueSize = blueSize > 0 ? blueSize : 0; alphaSize = alphaSize > 0 ? alphaSize : 0; depthSize = depthSize > 0 ? depthSize : 0; stencilSize = stencilSize > 0 ? stencilSize : 0; sampleCount = sampleCount > 0 ? sampleCount : 0; eglProperties.setValue(EGL_RED_SIZE, redSize); eglProperties.setValue(EGL_GREEN_SIZE, greenSize); eglProperties.setValue(EGL_BLUE_SIZE, blueSize); eglProperties.setValue(EGL_ALPHA_SIZE, alphaSize); eglProperties.setValue(EGL_DEPTH_SIZE, depthSize); eglProperties.setValue(EGL_STENCIL_SIZE, stencilSize); eglProperties.setValue(EGL_SAMPLES, sampleCount); eglProperties.setValue(EGL_SAMPLE_BUFFERS, sampleCount ? 1 : 0); }
// Retrieve all of the properties on "cfg". If zero, return // the context's configuration. QEglProperties QEglContext::configProperties(EGLConfig cfg) const { if (!cfg) cfg = config(); QEglProperties props; for (int name = 0x3020; name <= 0x304F; ++name) { EGLint value; if (name != EGL_NONE && eglGetConfigAttrib(dpy, cfg, name, &value)) props.setValue(name, value); } eglGetError(); // Clear the error state. return props; }
// Create the EGLContext. bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties *properties) { // We need to select the correct API before calling eglCreateContext(). #ifdef QT_OPENGL_ES #ifdef EGL_OPENGL_ES_API if (apiType == QEgl::OpenGL) eglBindAPI(EGL_OPENGL_ES_API); #endif #else #ifdef EGL_OPENGL_API if (apiType == QEgl::OpenGL) eglBindAPI(EGL_OPENGL_API); #endif #endif //defined(QT_OPENGL_ES) #ifdef EGL_OPENVG_API if (apiType == QEgl::OpenVG) eglBindAPI(EGL_OPENVG_API); #endif // Create a new context for the configuration. QEglProperties contextProps; if (properties) contextProps = *properties; #ifdef QT_OPENGL_ES_2 if (apiType == QEgl::OpenGL) contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); #endif sharing = false; if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) shareContext = 0; if (shareContext) { ctx = eglCreateContext(QEgl::display(), cfg, shareContext->ctx, contextProps.properties()); if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::createContext(): Could not share context:" << QEgl::errorString(); shareContext = 0; } else { sharing = true; } } if (ctx == EGL_NO_CONTEXT) { ctx = eglCreateContext(display(), cfg, EGL_NO_CONTEXT, contextProps.properties()); if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << QEgl::errorString(); #ifdef Q_OS_SYMBIAN S60->eglSurfaceCreationError = true; #endif return false; } } return true; }
// Create the EGLContext. bool QEglContext::createContext(QEglContext *shareContext) { // We need to select the correct API before calling eglCreateContext(). #ifdef EGL_OPENGL_ES_API if (apiType == OpenGL) eglBindAPI(EGL_OPENGL_ES_API); #endif #ifdef EGL_OPENVG_API if (apiType == OpenVG) eglBindAPI(EGL_OPENVG_API); #endif // Create a new context for the configuration. QEglProperties contextProps; #if defined(QT_OPENGL_ES_2) if (apiType == OpenGL) contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); #endif if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) shareContext = 0; if (shareContext) { ctx = eglCreateContext(dpy, cfg, shareContext->ctx, contextProps.properties()); if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); shareContext = 0; } } if (ctx == EGL_NO_CONTEXT) { ctx = eglCreateContext(dpy, cfg, 0, contextProps.properties()); if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError()); return false; } } share = (shareContext != 0); return true; }
// NOTE: The X11 version of createSurface will re-create the native drawable if it's visual doesn't // match the one for the passed in EGLConfig EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *unusedProperties) { Q_UNUSED(unusedProperties); int devType = device->devType(); if (devType == QInternal::Pbuffer) { // TODO return EGL_NO_SURFACE; } 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 an EGL surface on a QPixmap is only supported for QX11PixmapData"); return EGL_NO_SURFACE; } } else if ((devType != QInternal::Widget) && (devType != QInternal::Pbuffer)) { qWarning("WARNING: Creating an EGLSurface for device type %d isn't supported", devType); return EGL_NO_SURFACE; } VisualID visualId = QEgl::getCompatibleVisualId(config); EGLint alphaSize; eglGetConfigAttrib(QEgl::display(), config, EGL_ALPHA_SIZE, &alphaSize); if (devType == QInternal::Widget) { QWidget *widget = static_cast<QWidget*>(device); VisualID currentVisualId = 0; if (widget->testAttribute(Qt::WA_WState_Created)) currentVisualId = XVisualIDFromVisual((Visual*)widget->x11Info().visual()); if (currentVisualId != visualId) { // The window is either not created or has the wrong visual. Either way, we need // to create a window with the correct visual and call create() on the widget: bool visible = widget->isVisible(); if (visible) widget->hide(); XVisualInfo visualInfo; visualInfo.visualid = visualId; { XVisualInfo *visualInfoPtr; int matchingCount = 0; visualInfoPtr = XGetVisualInfo(widget->x11Info().display(), VisualIDMask, &visualInfo, &matchingCount); Q_ASSERT(visualInfoPtr); // visualId really should be valid! visualInfo = *visualInfoPtr; XFree(visualInfoPtr); } Window parentWindow = RootWindow(widget->x11Info().display(), widget->x11Info().screen()); if (widget->parentWidget()) parentWindow = widget->parentWidget()->winId(); XSetWindowAttributes windowAttribs; QColormap colmap = QColormap::instance(widget->x11Info().screen()); windowAttribs.background_pixel = colmap.pixel(widget->palette().color(widget->backgroundRole())); windowAttribs.border_pixel = colmap.pixel(Qt::black); unsigned int valueMask = CWBackPixel|CWBorderPixel; if (alphaSize > 0) { windowAttribs.colormap = XCreateColormap(widget->x11Info().display(), parentWindow, visualInfo.visual, AllocNone); valueMask |= CWColormap; } Window window = XCreateWindow(widget->x11Info().display(), parentWindow, widget->x(), widget->y(), widget->width(), widget->height(), 0, visualInfo.depth, InputOutput, visualInfo.visual, valueMask, &windowAttribs); // This is a nasty hack to get round the fact that we can't be a friend of QWidget: qt_set_winid_on_widget(widget, window); if (visible) widget->show(); } // At this point, the widget's window should be created and have the correct visual. Now we // just need to create the EGL surface for it: EGLSurface surf = eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), 0); if (surf == EGL_NO_SURFACE) qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); return surf; } if (x11PixmapData) { // X11 Pixmaps are only created with a depth, so that's all we need to check EGLint configDepth; eglGetConfigAttrib(QEgl::display(), config, EGL_BUFFER_SIZE , &configDepth); if (x11PixmapData->depth() != configDepth) { // The bit depths are wrong which means the EGLConfig isn't compatable with // this pixmap. So we need to replace the pixmap's existing data with a new // one which is created with the correct depth: #ifndef QT_NO_XRENDER if (configDepth == 32) { qWarning("Warning: EGLConfig's depth (32) != pixmap's depth (%d), converting to ARGB32", x11PixmapData->depth()); x11PixmapData->convertToARGB32(true); } else #endif { qWarning("Warning: EGLConfig's depth (%d) != pixmap's depth (%d)", configDepth, x11PixmapData->depth()); } } QEglProperties surfaceAttribs; // If the pixmap can't be bound to a texture, it's pretty useless surfaceAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D); if (alphaSize > 0) surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA); else surfaceAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB); EGLSurface surf = eglCreatePixmapSurface(QEgl::display(), config, (EGLNativePixmapType) x11PixmapData->handle(), surfaceAttribs.properties()); x11PixmapData->gl_surface = (void*)surf; QImagePixmapCleanupHooks::enableCleanupHooks(x11PixmapData); return surf; } return EGL_NO_SURFACE; }
EGLConfig QEgl::defaultConfig(int devType, API api, ConfigOptions options) { if ( (devType != QInternal::Pixmap) && ((options & Renderable) == 0)) qWarning("QEgl::defaultConfig() - Only configs for pixmaps make sense to be read-only!"); EGLConfig* targetConfig = 0; static EGLConfig defaultVGConfigs[] = { QEGL_NO_CONFIG, // 0 Window Renderable Translucent QEGL_NO_CONFIG, // 1 Window Renderable Opaque QEGL_NO_CONFIG, // 2 Pixmap Renderable Translucent QEGL_NO_CONFIG, // 3 Pixmap Renderable Opaque QEGL_NO_CONFIG, // 4 Pixmap ReadOnly Translucent QEGL_NO_CONFIG // 5 Pixmap ReadOnly Opaque }; if (api == OpenVG) { if (devType == QInternal::Widget) { if (options & Translucent) targetConfig = &(defaultVGConfigs[0]); else targetConfig = &(defaultVGConfigs[1]); } else if (devType == QInternal::Pixmap) { if (options & Renderable) { if (options & Translucent) targetConfig = &(defaultVGConfigs[2]); else // Opaque targetConfig = &(defaultVGConfigs[3]); } else { // Read-only if (options & Translucent) targetConfig = &(defaultVGConfigs[4]); else // Opaque targetConfig = &(defaultVGConfigs[5]); } } } static EGLConfig defaultGLConfigs[] = { QEGL_NO_CONFIG, // 0 Window Renderable Translucent QEGL_NO_CONFIG, // 1 Window Renderable Opaque QEGL_NO_CONFIG, // 2 PBuffer Renderable Translucent QEGL_NO_CONFIG, // 3 PBuffer Renderable Opaque QEGL_NO_CONFIG, // 4 Pixmap Renderable Translucent QEGL_NO_CONFIG, // 5 Pixmap Renderable Opaque QEGL_NO_CONFIG, // 6 Pixmap ReadOnly Translucent QEGL_NO_CONFIG // 7 Pixmap ReadOnly Opaque }; if (api == OpenGL) { if (devType == QInternal::Widget) { if (options & Translucent) targetConfig = &(defaultGLConfigs[0]); else // Opaque targetConfig = &(defaultGLConfigs[1]); } else if (devType == QInternal::Pbuffer) { if (options & Translucent) targetConfig = &(defaultGLConfigs[2]); else // Opaque targetConfig = &(defaultGLConfigs[3]); } else if (devType == QInternal::Pixmap) { if (options & Renderable) { if (options & Translucent) targetConfig = &(defaultGLConfigs[4]); else // Opaque targetConfig = &(defaultGLConfigs[5]); } else { // ReadOnly if (options & Translucent) targetConfig = &(defaultGLConfigs[6]); else // Opaque targetConfig = &(defaultGLConfigs[7]); } } } if (!targetConfig) { qWarning("QEgl::defaultConfig() - No default config for device/api/options combo"); return QEGL_NO_CONFIG; } if (*targetConfig != QEGL_NO_CONFIG) return *targetConfig; // We haven't found an EGL config for the target config yet, so do it now: // Allow overriding from an environment variable: QByteArray configId; if (api == OpenVG) configId = qgetenv("QT_VG_EGL_CONFIG"); else configId = qgetenv("QT_GL_EGL_CONFIG"); if (!configId.isEmpty()) { // Overridden, so get the EGLConfig for the specified config ID: EGLint properties[] = { EGL_CONFIG_ID, (EGLint)configId.toInt(), EGL_NONE }; EGLint configCount = 0; eglChooseConfig(display(), properties, targetConfig, 1, &configCount); if (configCount > 0) return *targetConfig; qWarning() << "QEgl::defaultConfig() -" << configId << "appears to be invalid"; } QEglProperties configAttribs; configAttribs.setRenderableType(api); EGLint surfaceType; switch (devType) { case QInternal::Widget: surfaceType = EGL_WINDOW_BIT; break; case QInternal::Pixmap: surfaceType = EGL_PIXMAP_BIT; break; case QInternal::Pbuffer: surfaceType = EGL_PBUFFER_BIT; break; default: qWarning("QEgl::defaultConfig() - Can't create EGL surface for %d device type", devType); return QEGL_NO_CONFIG; }; #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT // For OpenVG, we try to create a surface using a pre-multiplied format if // the surface needs to have an alpha channel: if (api == OpenVG && (options & Translucent)) surfaceType |= EGL_VG_ALPHA_FORMAT_PRE_BIT; #endif configAttribs.setValue(EGL_SURFACE_TYPE, surfaceType); #ifdef EGL_BIND_TO_TEXTURE_RGBA if (devType == QInternal::Pixmap || devType == QInternal::Pbuffer) { if (options & Translucent) configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); else configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); } #endif // Add paint engine requirements if (api == OpenVG) { #if !defined(QVG_SCISSOR_CLIP) && defined(EGL_ALPHA_MASK_SIZE) configAttribs.setValue(EGL_ALPHA_MASK_SIZE, 1); #endif } else { // Both OpenGL paint engines need to have stencil and sample buffers configAttribs.setValue(EGL_STENCIL_SIZE, 1); configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1); #ifndef QT_OPENGL_ES_2 // Additionally, the GL1 engine likes to have a depth buffer for clipping configAttribs.setValue(EGL_DEPTH_SIZE, 1); #endif } if (options & Translucent) configAttribs.setValue(EGL_ALPHA_SIZE, 1); *targetConfig = chooseConfig(&configAttribs, QEgl::BestPixelFormat); return *targetConfig; }
QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) { QSize newSize = windowSurfaceSize(widget); QEglProperties surfaceProps; #if defined(QVG_RECREATE_ON_SIZE_CHANGE) #if !defined(QVG_NO_SINGLE_CONTEXT) if (context && size != newSize) { // The surface size has changed, so we need to recreate it. // We can keep the same context and paint engine. size = newSize; if (isPaintingActive) context->doneCurrent(); context->destroySurface(windowSurface); #if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) if (isPremultipliedContext(context)) { surfaceProps.setValue (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); } else { surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); } #endif windowSurface = context->createSurface(widget, &surfaceProps); isPaintingActive = false; needToSwap = true; } #else if (context && size != newSize) { // The surface size has changed, so we need to recreate // the EGL context for the widget. We also need to recreate // the surface's paint engine if context sharing is not // enabled because we cannot reuse the existing paint objects // in the new context. qt_vg_destroy_paint_engine(engine); engine = 0; context->destroySurface(windowSurface); qt_vg_destroy_context(context, QInternal::Widget); context = 0; windowSurface = EGL_NO_SURFACE; } #endif #endif if (!context) { // Create a new EGL context and bind it to the widget surface. size = newSize; context = qt_vg_create_context(widget, QInternal::Widget); if (!context) return 0; // We want a direct to window rendering surface if possible. #if defined(QVG_DIRECT_TO_WINDOW) surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); #endif #if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) if (isPremultipliedContext(context)) { surfaceProps.setValue (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); } else { surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); } #endif EGLSurface surface = context->createSurface(widget, &surfaceProps); if (surface == EGL_NO_SURFACE) { qt_vg_destroy_context(context, QInternal::Widget); context = 0; return 0; } needToSwap = true; #if defined(QVG_DIRECT_TO_WINDOW) // Did we get a direct to window rendering surface? EGLint buffer = 0; if (eglQueryContext(QEgl::display(), context->context(), EGL_RENDER_BUFFER, &buffer) && buffer == EGL_SINGLE_BUFFER) { needToSwap = false; } #endif windowSurface = surface; isPaintingActive = false; } #if !defined(QVG_NO_PRESERVED_SWAP) // Try to force the surface back buffer to preserve its contents. if (needToSwap) { eglGetError(); // Clear error state first. eglSurfaceAttrib(QEgl::display(), windowSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); if (eglGetError() != EGL_SUCCESS) { qWarning("QVG: could not enable preserved swap"); } } #endif return context; }
static QEglContext *createContext(QPaintDevice *device) { QEglContext *context; // Create the context object and open the display. context = new QEglContext(); context->setApi(QEgl::OpenVG); // Set the swap interval for the display. QByteArray interval = qgetenv("QT_VG_SWAP_INTERVAL"); if (!interval.isEmpty()) eglSwapInterval(QEgl::display(), interval.toInt()); else eglSwapInterval(QEgl::display(), 1); #ifdef EGL_RENDERABLE_TYPE // Has the user specified an explicit EGL configuration to use? QByteArray configId = qgetenv("QT_VG_EGL_CONFIG"); if (!configId.isEmpty()) { EGLint cfgId = configId.toInt(); EGLint properties[] = { EGL_CONFIG_ID, cfgId, EGL_NONE }; EGLint matching = 0; EGLConfig cfg; if (eglChooseConfig (QEgl::display(), properties, &cfg, 1, &matching) && matching > 0) { // Check that the selected configuration actually supports OpenVG // and then create the context with it. EGLint id = 0; EGLint type = 0; eglGetConfigAttrib (QEgl::display(), cfg, EGL_CONFIG_ID, &id); eglGetConfigAttrib (QEgl::display(), cfg, EGL_RENDERABLE_TYPE, &type); if (cfgId == id && (type & EGL_OPENVG_BIT) != 0) { context->setConfig(cfg); if (!context->createContext()) { delete context; return 0; } return context; } else { qWarning("QT_VG_EGL_CONFIG: %d is not a valid OpenVG configuration", int(cfgId)); } } } #endif // Choose an appropriate configuration for rendering into the device. QEglProperties configProps; configProps.setPaintDeviceFormat(device); int redSize = configProps.value(EGL_RED_SIZE); if (redSize == EGL_DONT_CARE || redSize == 0) configProps.setPixelFormat(QImage::Format_ARGB32); // XXX #ifndef QVG_SCISSOR_CLIP // If we are using the mask to clip, then explicitly request a mask. configProps.setValue(EGL_ALPHA_MASK_SIZE, 1); #endif #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT); configProps.setRenderableType(QEgl::OpenVG); if (!context->chooseConfig(configProps)) { // Try again without the "pre" bit. configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); if (!context->chooseConfig(configProps)) { delete context; return 0; } } #else configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); configProps.setRenderableType(QEgl::OpenVG); if (!context->chooseConfig(configProps)) { delete context; return 0; } #endif // Construct a new EGL context for the selected configuration. if (!context->createContext()) { delete context; return 0; } return context; }
// 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; }
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(QEglContext::OpenGL); // Open the EGL display. if (!ctx->openDisplay(0)) { delete ctx; ctx = 0; return false; } // 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. QEglProperties configProps; qt_egl_set_format(configProps, QInternal::Pbuffer, f); 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, QEglContext::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, QEglContext::BestPixelFormat); if (!ok) { // One last try for a pbuffer with no texture rendering. configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB); textureFormat = EGL_NONE; } } #else textureFormat = EGL_NONE; #endif if (!ok) { if (!ctx->chooseConfig(configProps, QEglContext::BestPixelFormat)) { delete ctx; ctx = 0; return false; } } // Retrieve the actual format properties. qt_egl_update_format(*ctx, format); // 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:" << QEglContext::errorString(eglGetError()); return false; } ctx->setSurface(pbuf); // Create a new context for the configuration. QEglContext *shareContext = 0; if (shareWidget && shareWidget->d_func()->glcx) shareContext = shareWidget->d_func()->glcx->d_func()->eglContext; if (!ctx->createContext(shareContext)) { delete ctx; ctx = 0; return false; } return true; }
// 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; }