// 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; }
bool QGLPixelBuffer::hasOpenGLPbuffers() { // See if we have at least 1 configuration that matches the default format. EGLDisplay dpy = QEgl::display(); if (dpy == EGL_NO_DISPLAY) return false; QEglProperties configProps; qt_eglproperties_set_glformat(configProps, QGLFormat::defaultFormat()); configProps.setDeviceType(QInternal::Pbuffer); configProps.setRenderableType(QEgl::OpenGL); do { EGLConfig cfg = 0; EGLint matching = 0; if (eglChooseConfig(dpy, configProps.properties(), &cfg, 1, &matching) && matching > 0) return true; } while (configProps.reduceConfiguration()); return false; }
// 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; }
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; }