EGLConfig QEglConfigChooser::chooseConfig() { QVector<EGLint> configureAttributes = q_createConfigAttributesFromFormat(m_format); configureAttributes.append(EGL_SURFACE_TYPE); configureAttributes.append(surfaceType()); configureAttributes.append(EGL_RENDERABLE_TYPE); bool needsES2Plus = false; switch (m_format.renderableType()) { case QSurfaceFormat::OpenVG: configureAttributes.append(EGL_OPENVG_BIT); break; #ifdef EGL_VERSION_1_4 case QSurfaceFormat::DefaultRenderableType: #ifndef QT_NO_OPENGL if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) configureAttributes.append(EGL_OPENGL_BIT); else #endif // QT_NO_OPENGL needsES2Plus = true; break; case QSurfaceFormat::OpenGL: configureAttributes.append(EGL_OPENGL_BIT); break; #endif case QSurfaceFormat::OpenGLES: if (m_format.majorVersion() == 1) { configureAttributes.append(EGL_OPENGL_ES_BIT); break; } // fall through default: needsES2Plus = true; break; } if (needsES2Plus) { if (m_format.majorVersion() >= 3 && q_hasEglExtension(display(), "EGL_KHR_create_context")) configureAttributes.append(EGL_OPENGL_ES3_BIT_KHR); else configureAttributes.append(EGL_OPENGL_ES2_BIT); } configureAttributes.append(EGL_NONE); EGLConfig cfg = 0; do { // Get the number of matching configurations for this set of properties. EGLint matching = 0; if (!eglChooseConfig(display(), configureAttributes.constData(), 0, 0, &matching) || !matching) continue; // Fetch all of the matching configurations and find the // first that matches the pixel format we wanted. int i = configureAttributes.indexOf(EGL_RED_SIZE); m_confAttrRed = configureAttributes.at(i+1); i = configureAttributes.indexOf(EGL_GREEN_SIZE); m_confAttrGreen = configureAttributes.at(i+1); i = configureAttributes.indexOf(EGL_BLUE_SIZE); m_confAttrBlue = configureAttributes.at(i+1); i = configureAttributes.indexOf(EGL_ALPHA_SIZE); m_confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i+1); QVector<EGLConfig> configs(matching); eglChooseConfig(display(), configureAttributes.constData(), configs.data(), configs.size(), &matching); if (!cfg && matching > 0) cfg = configs.first(); // Filter the list. Due to the EGL sorting rules configs with higher depth are // placed first when the minimum color channel sizes have been specified (i.e. the // QSurfaceFormat contains color sizes > 0). To prevent returning a 888 config // when the QSurfaceFormat explicitly asked for 565, go through the returned // configs and look for one that exactly matches the requested sizes. When no // sizes have been given, take the first, which will be a config with the smaller // (e.g. 16-bit) depth. for (int i = 0; i < configs.size(); ++i) { if (filterConfig(configs[i])) return configs.at(i); } } while (q_reduceConfigAttributes(&configureAttributes)); if (!cfg) qWarning("Cant find EGLConfig, returning null config"); return cfg; }
void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share) { m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig); // m_format now has the renderableType() resolved (it cannot be Default anymore) // but does not yet contain version, profile, options. m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0; QVector<EGLint> contextAttrs; contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); contextAttrs.append(format.majorVersion()); const bool hasKHRCreateContext = q_hasEglExtension(m_eglDisplay, "EGL_KHR_create_context"); if (hasKHRCreateContext) { contextAttrs.append(EGL_CONTEXT_MINOR_VERSION_KHR); contextAttrs.append(format.minorVersion()); int flags = 0; // The debug bit is supported both for OpenGL and OpenGL ES. if (format.testOption(QSurfaceFormat::DebugContext)) flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; // The fwdcompat bit is only for OpenGL 3.0+. if (m_format.renderableType() == QSurfaceFormat::OpenGL && format.majorVersion() >= 3 && !format.testOption(QSurfaceFormat::DeprecatedFunctions)) flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; if (flags) { contextAttrs.append(EGL_CONTEXT_FLAGS_KHR); contextAttrs.append(flags); } // Profiles are OpenGL only and mandatory in 3.2+. The value is silently ignored for < 3.2. if (m_format.renderableType() == QSurfaceFormat::OpenGL) { contextAttrs.append(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); contextAttrs.append(format.profile() == QSurfaceFormat::CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); } } contextAttrs.append(EGL_NONE); switch (m_format.renderableType()) { case QSurfaceFormat::OpenVG: m_api = EGL_OPENVG_API; break; #ifdef EGL_VERSION_1_4 case QSurfaceFormat::OpenGL: m_api = EGL_OPENGL_API; break; #endif // EGL_VERSION_1_4 default: m_api = EGL_OPENGL_ES_API; break; } eglBindAPI(m_api); m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData()); if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) { m_shareContext = 0; m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, 0, contextAttrs.constData()); } if (m_eglContext == EGL_NO_CONTEXT) { qWarning("QEGLPlatformContext: Failed to create context: %x", eglGetError()); return; } static const bool printConfig = qEnvironmentVariableIntValue("QT_QPA_EGLFS_DEBUG"); if (printConfig) { qDebug() << "Created context for format" << format << "with config:"; q_printEglConfig(m_eglDisplay, m_eglConfig); } // Cannot just call updateFormatFromGL() since it relies on virtuals. Defer it to initialize(). }
void QEGLPlatformContext::updateFormatFromGL() { #ifndef QT_NO_OPENGL // Have to save & restore to prevent QOpenGLContext::currentContext() from becoming // inconsistent after QOpenGLContext::create(). EGLDisplay prevDisplay = eglGetCurrentDisplay(); if (prevDisplay == EGL_NO_DISPLAY) // when no context is current prevDisplay = m_eglDisplay; EGLContext prevContext = eglGetCurrentContext(); EGLSurface prevSurfaceDraw = eglGetCurrentSurface(EGL_DRAW); EGLSurface prevSurfaceRead = eglGetCurrentSurface(EGL_READ); // Rely on the surfaceless extension, if available. This is beneficial since we can // avoid creating an extra pbuffer surface which is apparently troublesome with some // drivers (Mesa) when certain attributes are present (multisampling). EGLSurface tempSurface = EGL_NO_SURFACE; if (!q_hasEglExtension(m_eglDisplay, "EGL_KHR_surfaceless_context")) tempSurface = createTemporaryOffscreenSurface(); if (eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, m_eglContext)) { if (m_format.renderableType() == QSurfaceFormat::OpenGL || m_format.renderableType() == QSurfaceFormat::OpenGLES) { const GLubyte *s = glGetString(GL_VERSION); if (s) { QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); int major, minor; if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { #ifdef Q_OS_ANDROID // Some Android 4.2.2 devices report OpenGL ES 3.0 without the functions being available. static int apiLevel = QtAndroidPrivate::androidSdkVersion(); if (apiLevel <= 17 && major >= 3) { major = 2; minor = 0; } #endif m_format.setMajorVersion(major); m_format.setMinorVersion(minor); } } m_format.setProfile(QSurfaceFormat::NoProfile); m_format.setOptions(QSurfaceFormat::FormatOptions()); if (m_format.renderableType() == QSurfaceFormat::OpenGL) { // Check profile and options. if (m_format.majorVersion() < 3) { m_format.setOption(QSurfaceFormat::DeprecatedFunctions); } else { GLint value = 0; glGetIntegerv(GL_CONTEXT_FLAGS, &value); if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) m_format.setOption(QSurfaceFormat::DeprecatedFunctions); if (value & GL_CONTEXT_FLAG_DEBUG_BIT) m_format.setOption(QSurfaceFormat::DebugContext); if (m_format.version() >= qMakePair(3, 2)) { value = 0; glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); if (value & GL_CONTEXT_CORE_PROFILE_BIT) m_format.setProfile(QSurfaceFormat::CoreProfile); else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) m_format.setProfile(QSurfaceFormat::CompatibilityProfile); } } } } eglMakeCurrent(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext); } else { qWarning("QEGLPlatformContext: Failed to make temporary surface current, format not updated"); } if (tempSurface != EGL_NO_SURFACE) destroyTemporaryOffscreenSurface(tempSurface); #endif // QT_NO_OPENGL }
VisualID QXlibEglIntegration::getCompatibleVisualId(Display *display, EGLDisplay eglDisplay, EGLConfig config) { VisualID visualId = 0; EGLint eglValue = 0; EGLint configRedSize = 0; eglGetConfigAttrib(eglDisplay, config, EGL_RED_SIZE, &configRedSize); EGLint configGreenSize = 0; eglGetConfigAttrib(eglDisplay, config, EGL_GREEN_SIZE, &configGreenSize); EGLint configBlueSize = 0; eglGetConfigAttrib(eglDisplay, config, EGL_BLUE_SIZE, &configBlueSize); EGLint configAlphaSize = 0; eglGetConfigAttrib(eglDisplay, config, EGL_ALPHA_SIZE, &configAlphaSize); eglGetConfigAttrib(eglDisplay, config, EGL_CONFIG_ID, &eglValue); int configId = eglValue; // See if EGL provided a valid VisualID: eglGetConfigAttrib(eglDisplay, config, EGL_NATIVE_VISUAL_ID, &eglValue); visualId = (VisualID)eglValue; if (visualId) { // EGL has suggested a visual id, so get the rest of the visual info for that id: XVisualInfo visualInfoTemplate; memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); visualInfoTemplate.visualid = visualId; XVisualInfo *chosenVisualInfo; int matchingCount = 0; chosenVisualInfo = XGetVisualInfo(display, VisualIDMask, &visualInfoTemplate, &matchingCount); if (chosenVisualInfo) { // Skip size checks if implementation supports non-matching visual // and config (http://bugreports.qt-project.org/browse/QTBUG-9444). if (q_hasEglExtension(eglDisplay,"EGL_NV_post_convert_rounding")) { XFree(chosenVisualInfo); return visualId; } int visualRedSize = countBits(chosenVisualInfo->red_mask); int visualGreenSize = countBits(chosenVisualInfo->green_mask); int visualBlueSize = countBits(chosenVisualInfo->blue_mask); int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size bool visualMatchesConfig = false; if ( visualRedSize == configRedSize && visualGreenSize == configGreenSize && visualBlueSize == configBlueSize ) { // We need XRender to check the alpha channel size of the visual. If we don't have // the alpha size, we don't check it against the EGL config's alpha size. if (visualAlphaSize >= 0) visualMatchesConfig = visualAlphaSize == configAlphaSize; else visualMatchesConfig = true; } if (!visualMatchesConfig) { if (visualAlphaSize >= 0) { 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", (int)visualId, visualAlphaSize, visualRedSize, visualGreenSize, visualBlueSize, configId, configAlphaSize, configRedSize, configGreenSize, configBlueSize); } else { 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", (int)visualId, visualRedSize, visualGreenSize, visualBlueSize, configId, configRedSize, configGreenSize, configBlueSize); } visualId = 0; } } else { qWarning("Warning: EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID", (int)visualId, configId); visualId = 0; } XFree(chosenVisualInfo); } #ifdef QT_DEBUG_X11_VISUAL_SELECTION else qDebug("EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId); #endif if (visualId) { #ifdef QT_DEBUG_X11_VISUAL_SELECTION if (configAlphaSize > 0) qDebug("Using ARGB Visual ID %d provided by EGL for config %d", (int)visualId, configId); else qDebug("Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId); #endif return visualId; } // Finally, try to // use XGetVisualInfo and only use the bit depths to match on: if (!visualId) { XVisualInfo visualInfoTemplate; memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); XVisualInfo *matchingVisuals; int matchingCount = 0; visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize; matchingVisuals = XGetVisualInfo(display, VisualDepthMask, &visualInfoTemplate, &matchingCount); if (!matchingVisuals) { // Try again without taking the alpha channel into account: visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize; matchingVisuals = XGetVisualInfo(display, VisualDepthMask, &visualInfoTemplate, &matchingCount); } if (matchingVisuals) { visualId = matchingVisuals[0].visualid; XFree(matchingVisuals); } } if (visualId) { #ifdef QT_DEBUG_X11_VISUAL_SELECTION qDebug("Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId); #endif return visualId; } qWarning("Unable to find an X11 visual which matches EGL config %d", configId); return (VisualID)0; }