| Index: ui/gl/gl_context_glx.cc
|
| diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc
|
| index 697807118db3ecb3cc5e3833f19d3a892f4bcda1..e5793f4376ef18db5ff11b115858fd7b75f2363f 100644
|
| --- a/ui/gl/gl_context_glx.cc
|
| +++ b/ui/gl/gl_context_glx.cc
|
| @@ -19,6 +19,134 @@ extern "C" {
|
|
|
| namespace gl {
|
|
|
| +namespace {
|
| +
|
| +static int IgnoreX11Errors(Display*, XErrorEvent*) {
|
| + return 0;
|
| +}
|
| +
|
| +using GLVersion = std::pair<int, int>;
|
| +
|
| +GLXContext CreateContextAttribs(Display* display,
|
| + GLXFBConfig config,
|
| + GLXContext share,
|
| + GLVersion version,
|
| + int profile_mask) {
|
| + std::vector<int> attribs;
|
| +
|
| + if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) {
|
| + attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
|
| + attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
|
| + }
|
| +
|
| + if (version.first != 0 || version.second != 0) {
|
| + attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
|
| + attribs.push_back(version.first);
|
| +
|
| + attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
|
| + attribs.push_back(version.second);
|
| + }
|
| +
|
| + if (profile_mask != 0 && GLSurfaceGLX::IsCreateContextProfileSupported()) {
|
| + attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
|
| + attribs.push_back(profile_mask);
|
| + }
|
| +
|
| + attribs.push_back(0);
|
| +
|
| + // When creating a context with glXCreateContextAttribsARB, a variety of X11
|
| + // errors can be generated. To prevent these errors from crashing our process,
|
| + // we simply ignore them and only look if the GLXContext was created.
|
| + auto old_error_handler = XSetErrorHandler(IgnoreX11Errors);
|
| + GLXContext context =
|
| + glXCreateContextAttribsARB(display, config, share, True, attribs.data());
|
| + XSetErrorHandler(old_error_handler);
|
| +
|
| + return context;
|
| +}
|
| +
|
| +GLXContext CreateHighestVersionContext(Display* display,
|
| + GLXFBConfig config,
|
| + GLXContext share) {
|
| + // 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 {
|
| + int profileFlag;
|
| + GLVersion version;
|
| + };
|
| +
|
| + // clang-format off
|
| + // For regular drivers we try to create a compatibility, core, then ES
|
| + // context. Without requiring any specific version.
|
| + const ContextCreationInfo contexts_to_try[] = {
|
| + { 0, GLVersion(0, 0) },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLVersion(0, 0) },
|
| + { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, GLVersion(0, 0) },
|
| + };
|
| +
|
| + // 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 mesa_contexts_to_try[] = {
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 5) } },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 4) } },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 3) } },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 2) } },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 1) } },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 0) } },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(3, 3) } },
|
| + { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(3, 2) } },
|
| + { 0, { GLVersion(3, 1) } },
|
| + { 0, { GLVersion(3, 0) } },
|
| + { 0, { GLVersion(2, 0) } },
|
| + { 0, { GLVersion(1, 5) } },
|
| + { 0, { GLVersion(1, 4) } },
|
| + { 0, { GLVersion(1, 3) } },
|
| + { 0, { GLVersion(1, 2) } },
|
| + { 0, { GLVersion(1, 1) } },
|
| + { 0, { GLVersion(1, 0) } },
|
| + { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 2) } },
|
| + { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 1) } },
|
| + { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 0) } },
|
| + { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(2, 0) } },
|
| + };
|
| + // clang-format on
|
| +
|
| + std::string client_vendor = glXGetClientString(display, GLX_VENDOR);
|
| + bool is_mesa = client_vendor.find("Mesa") != std::string::npos;
|
| +
|
| + const ContextCreationInfo* to_try = contexts_to_try;
|
| + size_t to_try_length = arraysize(contexts_to_try);
|
| + if (is_mesa) {
|
| + to_try = mesa_contexts_to_try;
|
| + to_try_length = arraysize(mesa_contexts_to_try);
|
| + }
|
| +
|
| + for (size_t i = 0; i < to_try_length; ++i) {
|
| + const ContextCreationInfo& info = to_try[i];
|
| + if (!GLSurfaceGLX::IsCreateContextES2ProfileSupported() &&
|
| + info.profileFlag == GLX_CONTEXT_ES2_PROFILE_BIT_EXT) {
|
| + continue;
|
| + }
|
| + GLXContext context = CreateContextAttribs(display, config, share,
|
| + info.version, info.profileFlag);
|
| + if (context != nullptr) {
|
| + return context;
|
| + }
|
| + }
|
| +
|
| + return nullptr;
|
| +}
|
| +}
|
| +
|
| GLContextGLX::GLContextGLX(GLShareGroup* share_group)
|
| : GLContextReal(share_group),
|
| context_(nullptr),
|
| @@ -38,19 +166,9 @@ bool GLContextGLX::Initialize(
|
|
|
| if (GLSurfaceGLX::IsCreateContextSupported()) {
|
| DVLOG(1) << "GLX_ARB_create_context supported.";
|
| - std::vector<int> attribs;
|
| - if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) {
|
| - DVLOG(1) << "GLX_ARB_create_context_robustness supported.";
|
| - attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
|
| - attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
|
| - }
|
| - attribs.push_back(0);
|
| - context_ = glXCreateContextAttribsARB(
|
| - display_,
|
| - static_cast<GLXFBConfig>(compatible_surface->GetConfig()),
|
| - share_handle,
|
| - True,
|
| - &attribs.front());
|
| + context_ = CreateHighestVersionContext(
|
| + display_, static_cast<GLXFBConfig>(compatible_surface->GetConfig()),
|
| + share_handle);
|
| if (!context_) {
|
| LOG(ERROR) << "Failed to create GL context with "
|
| << "glXCreateContextAttribsARB.";
|
|
|