Chromium Code Reviews| Index: ui/gl/gl_context_glx.cc |
| diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc |
| index 3ca82febfe4d59576a39a6316f8f3a2604836725..0db90861dcee14b124e19523c1048ac141999741 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 profileMask) { |
|
piman
2016/06/24 21:31:45
nit: profile_mask
Corentin Wallez
2016/06/27 15:39:22
Done
|
| + 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 (profileMask != 0 && GLSurfaceGLX::IsCreateContextProfileSupported()) { |
| + attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB); |
| + attribs.push_back(profileMask); |
| + } |
| + |
| + 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 oldErrorHandler = XSetErrorHandler(IgnoreX11Errors); |
|
piman
2016/06/24 21:31:45
nit: old_error_handler
Corentin Wallez
2016/06/27 15:39:22
Done
|
| + GLXContext context = |
| + glXCreateContextAttribsARB(display, config, share, True, attribs.data()); |
| + XSetErrorHandler(oldErrorHandler); |
| + |
| + 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; |
|
piman
2016/06/24 21:31:45
nit: profile_flag
Corentin Wallez
2016/06/27 15:39:22
Done
|
| + 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."; |