egl::Error DisplayD3D::createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, const egl::AttributeMap &attribs, SurfaceImpl **outSurface) { ASSERT(mRenderer != nullptr); EGLint width = attribs.get(EGL_WIDTH, 0); EGLint height = attribs.get(EGL_HEIGHT, 0); EGLint fixedSize = attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE); if (!fixedSize) { width = -1; height = -1; } SurfaceD3D *surface = SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize, width, height); egl::Error error = surface->initialize(); if (error.isError()) { SafeDelete(surface); return error; } *outSurface = surface; return egl::Error(EGL_SUCCESS); }
EGLImageD3D::EGLImageD3D(RendererD3D *renderer, EGLenum target, egl::ImageSibling *buffer, const egl::AttributeMap &attribs) : mRenderer(renderer), mBuffer(buffer), mAttachmentBuffer(nullptr), mRenderTarget(nullptr) { ASSERT(renderer != nullptr); ASSERT(buffer != nullptr); if (egl::IsTextureTarget(target)) { mAttachmentBuffer = GetImplAs<TextureD3D>(GetAs<gl::Texture>(buffer)); mAttachmentTarget = gl::FramebufferAttachment::Target( GL_NONE, GetImageIndex(egl_gl::EGLImageTargetToGLTextureTarget(target), attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0), attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0))); } else if (egl::IsRenderbufferTarget(target)) { mAttachmentBuffer = GetImplAs<RenderbufferD3D>(GetAs<gl::Renderbuffer>(buffer)); mAttachmentTarget = gl::FramebufferAttachment::Target(GL_NONE, gl::ImageIndex::MakeInvalid()); } else { UNREACHABLE(); } }
egl::Error DisplayGL::createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, gl::Context **outContext) { ASSERT(mRenderer != nullptr); EGLint clientVersion = attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1); bool notifyResets = (attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION_EXT) == EGL_LOSE_CONTEXT_ON_RESET_EXT); bool robustAccess = (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE); *outContext = new gl::Context(config, clientVersion, shareContext, mRenderer, notifyResets, robustAccess); return egl::Error(EGL_SUCCESS); }
RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &attribMap) : Renderer(), mMaxSupportedESVersion(0, 0), mFunctions(functions), mStateManager(nullptr), mBlitter(nullptr), mSkipDrawCalls(false) { ASSERT(mFunctions); mStateManager = new StateManagerGL(mFunctions, getRendererCaps()); nativegl_gl::GenerateWorkarounds(mFunctions, &mWorkarounds); mBlitter = new BlitGL(functions, mWorkarounds, mStateManager); #ifndef NDEBUG if (mFunctions->debugMessageControl && mFunctions->debugMessageCallback) { mFunctions->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, nullptr, GL_FALSE); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE); mFunctions->debugMessageCallback(&LogGLDebugMessage, nullptr); } #endif EGLint deviceType = attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_NONE); if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE) { mSkipDrawCalls = true; } }
SurfaceD3D::SurfaceD3D(const egl::SurfaceState &state, RendererD3D *renderer, egl::Display *display, EGLNativeWindowType window, EGLenum buftype, EGLClientBuffer clientBuffer, const egl::AttributeMap &attribs) : SurfaceImpl(state), mRenderer(renderer), mDisplay(display), mFixedSize(window == nullptr || attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE), mOrientation(static_cast<EGLint>(attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0))), mRenderTargetFormat(state.config->renderTargetFormat), mDepthStencilFormat(state.config->depthStencilFormat), mSwapChain(nullptr), mSwapIntervalDirty(true), mNativeWindow(renderer->createNativeWindow(window, state.config, attribs)), mWidth(static_cast<EGLint>(attribs.get(EGL_WIDTH, 0))), mHeight(static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0))), mSwapInterval(1), mShareHandle(0), mD3DTexture(nullptr) { if (window != nullptr && !mFixedSize) { mWidth = -1; mHeight = -1; } switch (buftype) { case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: mShareHandle = static_cast<HANDLE>(clientBuffer); break; case EGL_D3D_TEXTURE_ANGLE: mD3DTexture = static_cast<IUnknown *>(clientBuffer); ASSERT(mD3DTexture != nullptr); mD3DTexture->AddRef(); mRenderer->getD3DTextureInfo(state.config, mD3DTexture, &mWidth, &mHeight, &mRenderTargetFormat); break; default: break; } }
RendererGL::RendererGL(const FunctionsGL *functions, const egl::AttributeMap &attribMap) : mMaxSupportedESVersion(0, 0), mFunctions(functions), mStateManager(nullptr), mBlitter(nullptr), mMultiviewClearer(nullptr), mUseDebugOutput(false), mSkipDrawCalls(false), mCapsInitialized(false), mMultiviewImplementationType(MultiviewImplementationTypeGL::UNSPECIFIED) { ASSERT(mFunctions); nativegl_gl::GenerateWorkarounds(mFunctions, &mWorkarounds); mStateManager = new StateManagerGL(mFunctions, getNativeCaps(), getNativeExtensions()); mBlitter = new BlitGL(functions, mWorkarounds, mStateManager); mMultiviewClearer = new ClearMultiviewGL(functions, mStateManager); bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) || mFunctions->hasGLExtension("GL_KHR_debug") || mFunctions->isAtLeastGLES(gl::Version(3, 2)) || mFunctions->hasGLESExtension("GL_KHR_debug"); mUseDebugOutput = hasDebugOutput && ShouldUseDebugLayers(attribMap); if (mUseDebugOutput) { mFunctions->enable(GL_DEBUG_OUTPUT); mFunctions->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, nullptr, GL_FALSE); mFunctions->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE); mFunctions->debugMessageCallback(&LogGLDebugMessage, nullptr); } EGLint deviceType = static_cast<EGLint>(attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_NONE)); if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE) { mSkipDrawCalls = true; } if (mWorkarounds.initializeCurrentVertexAttributes) { GLint maxVertexAttribs = 0; mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); for (GLint i = 0; i < maxVertexAttribs; ++i) { mFunctions->vertexAttrib4f(i, 0.0f, 0.0f, 0.0f, 1.0f); } } }
egl::Error DisplayD3D::createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs, SurfaceImpl **outSurface) { ASSERT(mRenderer != nullptr); EGLint width = attribs.get(EGL_WIDTH, 0); EGLint height = attribs.get(EGL_HEIGHT, 0); SurfaceD3D *surface = SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, NULL, width, height); egl::Error error = surface->initialize(); if (error.isError()) { SafeDelete(surface); return error; } *outSurface = surface; return egl::Error(EGL_SUCCESS); }
bool ShouldUseDebugLayers(const egl::AttributeMap &attribs) { EGLAttrib debugSetting = attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE); // Prefer to enable debug layers if compiling in Debug, and disabled in Release. #if defined(ANGLE_ENABLE_ASSERTS) return (debugSetting != EGL_FALSE); #else return (debugSetting == EGL_TRUE); #endif // defined(ANGLE_ENABLE_ASSERTS) }
bool ShouldUseVirtualizedContexts(const egl::AttributeMap &attribs, bool defaultValue) { EGLAttrib virtualizedContextRequest = attribs.get(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE, EGL_DONT_CARE); if (defaultValue) { return (virtualizedContextRequest != EGL_FALSE); } else { return (virtualizedContextRequest == EGL_TRUE); } }
ImageEGL::ImageEGL(const egl::ImageState &state, const gl::Context *context, EGLenum target, const egl::AttributeMap &attribs, const FunctionsEGL *egl) : ImageGL(state), mEGL(egl), mContext(EGL_NO_CONTEXT), mTarget(target), mPreserveImage(false), mImage(EGL_NO_IMAGE) { if (context) { mContext = GetImplAs<ContextEGL>(context)->getContext(); } mPreserveImage = attribs.get(EGL_IMAGE_PRESERVED, EGL_FALSE) == EGL_TRUE; }
egl::Error DisplayGLX::initializeContext(glx::FBConfig config, const egl::AttributeMap &eglAttributes, glx::Context *context) { int profileMask = 0; EGLint requestedDisplayType = eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) { if (!mHasEXTCreateContextES2Profile) { return egl::Error(EGL_NOT_INITIALIZED, "Cannot create an OpenGL ES platform on GLX without the " "GLX_EXT_create_context_es_profile extension."); } ASSERT(mHasARBCreateContextProfile); profileMask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; } // Create a context of the requested version, if any. gl::Version requestedVersion( eglAttributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE), eglAttributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE)); if (static_cast<EGLint>(requestedVersion.major) != EGL_DONT_CARE && static_cast<EGLint>(requestedVersion.minor) != EGL_DONT_CARE) { if (!(profileMask & GLX_CONTEXT_ES2_PROFILE_BIT_EXT) && requestedVersion >= gl::Version(3, 2)) { profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; } return createContextAttribs(config, requestedVersion, profileMask, context); } // It is commonly assumed that glXCreateContextAttrib will create a context // of the highest version possible but it is not specified in the spec and // is not true on the Mesa drivers. Instead we try to create a context per // GL version until we succeed, starting from newer version. When the default // platform is selected, if no desktop context can be created, we fallback to // an ES context. // clang-format off const gl::Version desktopVersionsFrom3_2[] = { gl::Version(4, 5), gl::Version(4, 4), gl::Version(4, 3), gl::Version(4, 2), gl::Version(4, 1), gl::Version(4, 0), gl::Version(3, 3), gl::Version(3, 2), }; const gl::Version desktopVersionsPre3_2[] = { gl::Version(3, 1), gl::Version(3, 0), gl::Version(2, 0), gl::Version(1, 5), gl::Version(1, 4), gl::Version(1, 3), gl::Version(1, 2), gl::Version(1, 1), gl::Version(1, 0), }; const gl::Version esVersionsFrom2_0[] = { gl::Version(3, 2), gl::Version(3, 1), gl::Version(3, 0), gl::Version(2, 0), }; // clang-format on // NOTE: below we return as soon as we're able to create a context so the // "error" variable is EGL_SUCCESS when returned contrary to the common idiom // of returning "error" when there is an actual error. if (requestedDisplayType != EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) { for (auto &version : desktopVersionsFrom3_2) { egl::Error error = createContextAttribs(config, version, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, context); if (!error.isError()) { return error; } } for (auto &version : desktopVersionsPre3_2) { egl::Error error = createContextAttribs(config, version, 0, context); if (!error.isError()) { return error; } } } if (requestedDisplayType != EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE) { for (auto &version : esVersionsFrom2_0) { egl::Error error = createContextAttribs(config, version, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, context); if (!error.isError()) { return error; } } } return egl::Error(EGL_NOT_INITIALIZED, "Could not create a backing OpenGL context."); }
glx::Context DisplayGLX::initializeContext(glx::FBConfig config, const egl::AttributeMap &eglAttributes) { // Create a context of the requested version, if any. EGLint requestedMajorVersion = eglAttributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE); EGLint requestedMinorVersion = eglAttributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE); if (requestedMajorVersion != EGL_DONT_CARE && requestedMinorVersion != EGL_DONT_CARE) { std::vector<int> contextAttributes; contextAttributes.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB); contextAttributes.push_back(requestedMajorVersion); contextAttributes.push_back(GLX_CONTEXT_MINOR_VERSION_ARB); contextAttributes.push_back(requestedMinorVersion); contextAttributes.push_back(None); return createContextAttribs(config, contextAttributes); } // It is commonly assumed that glXCreateContextAttrib will create a context // of the highest version possible but it is not specified in the spec and // is not true on the Mesa drivers. Instead we try to create a context per // desktop GL version until we succeed, starting from newer version. // clang-format off const gl::Version desktopVersions[] = { gl::Version(4, 5), gl::Version(4, 4), gl::Version(4, 3), gl::Version(4, 2), gl::Version(4, 1), gl::Version(4, 0), gl::Version(3, 3), gl::Version(3, 2), gl::Version(3, 1), gl::Version(3, 0), gl::Version(2, 0), gl::Version(1, 5), gl::Version(1, 4), gl::Version(1, 3), gl::Version(1, 2), gl::Version(1, 1), gl::Version(1, 0), }; // clang-format on bool useProfile = mGLX.hasExtension("GLX_ARB_create_context_profile"); for (size_t i = 0; i < ArraySize(desktopVersions); ++i) { const auto &version = desktopVersions[i]; std::vector<int> contextAttributes; contextAttributes.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB); contextAttributes.push_back(version.major); contextAttributes.push_back(GLX_CONTEXT_MINOR_VERSION_ARB); contextAttributes.push_back(version.minor); if (useProfile && version >= gl::Version(3, 2)) { contextAttributes.push_back(GLX_CONTEXT_PROFILE_MASK_ARB); contextAttributes.push_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB); } contextAttributes.push_back(None); auto context = createContextAttribs(config, contextAttributes); if (context) { return context; } } return nullptr; }
egl::Error DisplayGLX::initializeContext(glx::FBConfig config, const egl::AttributeMap &eglAttributes, glx::Context *context) { int profileMask = 0; EGLint requestedDisplayType = static_cast<EGLint>( eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)); if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) { if (!mHasEXTCreateContextES2Profile) { return egl::Error(EGL_NOT_INITIALIZED, "Cannot create an OpenGL ES platform on GLX without the " "GLX_EXT_create_context_es_profile extension."); } ASSERT(mHasARBCreateContextProfile); profileMask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; } // Create a context of the requested version, if any. gl::Version requestedVersion(static_cast<EGLint>(eglAttributes.get( EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)), static_cast<EGLint>(eglAttributes.get( EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE))); if (static_cast<EGLint>(requestedVersion.major) != EGL_DONT_CARE && static_cast<EGLint>(requestedVersion.minor) != EGL_DONT_CARE) { if (!(profileMask & GLX_CONTEXT_ES2_PROFILE_BIT_EXT) && requestedVersion >= gl::Version(3, 2)) { profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; } return createContextAttribs(config, requestedVersion, profileMask, context); } // It is commonly assumed that glXCreateContextAttrib will create a context // of the highest version possible but it is not specified in the spec and // is not true on the Mesa drivers. On Mesa, Instead we try to create a // context per GL version until we succeed, starting from newer version. // On both Mesa and other drivers we try to create a desktop context and fall // back to ES context. // The code could be simpler if the Mesa code path was used for all drivers, // however the cost of failing a context creation can be high (3 milliseconds // for the NVIDIA driver). The good thing is that failed context creation only // takes 0.1 milliseconds on Mesa. struct ContextCreationInfo { EGLint displayType; int profileFlag; Optional<gl::Version> version; }; // clang-format off // For regular drivers we try to create a core, compatibility, then ES context. // Without requiring any specific version (the Optional version is undefined). const ContextCreationInfo contextsToTry[] = { { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, {} }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, {} }, { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, {} }, }; // On Mesa we try to create a core context, except for versions below 3.2 // where it is not applicable. (and fallback to ES as well) const ContextCreationInfo mesaContextsToTry[] = { { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 5) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 4) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 3) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 2) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 1) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(4, 0) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(3, 3) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { gl::Version(3, 2) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(3, 1) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(3, 0) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(2, 0) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 5) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 4) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 3) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 2) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 1) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, 0, { gl::Version(1, 0) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(3, 2) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(3, 1) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(3, 0) } }, { EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { gl::Version(2, 0) } }, }; // clang-format on const ContextCreationInfo *toTry = contextsToTry; size_t toTryLength = ArraySize(contextsToTry); if (mIsMesa) { toTry = mesaContextsToTry; toTryLength = ArraySize(mesaContextsToTry); } // NOTE: below we return as soon as we're able to create a context so the // "error" variable is EGL_SUCCESS when returned contrary to the common idiom // of returning "error" when there is an actual error. for (size_t i = 0; i < toTryLength; ++i) { const ContextCreationInfo &info = toTry[i]; if (requestedDisplayType != EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE && requestedDisplayType != info.displayType) { continue; } egl::Error error = createContextAttribs(config, info.version, info.profileFlag, context); if (!error.isError()) { return error; } } return egl::Error(EGL_NOT_INITIALIZED, "Could not create a backing OpenGL context."); }
egl::Error DisplayGLX::initializeContext(glx::FBConfig config, const egl::AttributeMap &eglAttributes, glx::Context *context) { int profileMask = 0; EGLint requestedDisplayType = static_cast<EGLint>( eglAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)); if (requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) { if (!mHasEXTCreateContextES2Profile) { return egl::EglNotInitialized() << "Cannot create an OpenGL ES platform on GLX without " "the GLX_EXT_create_context_es_profile extension."; } ASSERT(mHasARBCreateContextProfile); profileMask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; } // Create a context of the requested version, if any. gl::Version requestedVersion(static_cast<EGLint>(eglAttributes.get( EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE)), static_cast<EGLint>(eglAttributes.get( EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE))); if (static_cast<EGLint>(requestedVersion.major) != EGL_DONT_CARE && static_cast<EGLint>(requestedVersion.minor) != EGL_DONT_CARE) { if (!(profileMask & GLX_CONTEXT_ES2_PROFILE_BIT_EXT) && requestedVersion >= gl::Version(3, 2)) { profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; } return createContextAttribs(config, requestedVersion, profileMask, context); } // The only way to get a core profile context of the highest version using // glXCreateContextAttrib is to try creationg contexts in decreasing version // numbers. It might look that asking for a core context of version (0, 0) // works on some driver but it create a _compatibility_ context of the highest // version instead. The cost of failing a context creation is small (< 0.1 ms) // on Mesa but is unfortunately a bit expensive on the Nvidia driver (~3ms). // Also try to get any Desktop GL context, but if that fails fallback to // asking for OpenGL ES contexts. // NOTE: below we return as soon as we're able to create a context so the // "error" variable is EGL_SUCCESS when returned contrary to the common idiom // of returning "error" when there is an actual error. for (const auto &info : GenerateContextCreationToTry(requestedDisplayType, mIsMesa)) { int profileFlag = 0; if (info.type == ContextCreationTry::Type::DESKTOP_CORE) { profileFlag |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; } else if (info.type == ContextCreationTry::Type::ES) { profileFlag |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; } egl::Error error = createContextAttribs(config, info.version, profileFlag, context); if (!error.isError()) { return error; } } return egl::EglNotInitialized() << "Could not create a backing OpenGL context."; }