| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gl/gl_context_glx.h" | 5 #include "ui/gl/gl_context_glx.h" |
| 6 | 6 |
| 7 extern "C" { | 7 extern "C" { |
| 8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
| 9 } | 9 } |
| 10 #include <memory> | 10 #include <memory> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/numerics/safe_conversions.h" | 13 #include "base/numerics/safe_conversions.h" |
| 14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
| 15 #include "ui/gl/GL/glextchromium.h" | 15 #include "ui/gl/GL/glextchromium.h" |
| 16 #include "ui/gl/gl_bindings.h" | 16 #include "ui/gl/gl_bindings.h" |
| 17 #include "ui/gl/gl_implementation.h" | 17 #include "ui/gl/gl_implementation.h" |
| 18 #include "ui/gl/gl_surface_glx.h" | 18 #include "ui/gl/gl_surface_glx.h" |
| 19 | 19 |
| 20 namespace gl { | 20 namespace gl { |
| 21 | 21 |
| 22 namespace { |
| 23 |
| 24 static int IgnoreX11Errors(Display*, XErrorEvent*) { |
| 25 return 0; |
| 26 } |
| 27 |
| 28 using GLVersion = std::pair<int, int>; |
| 29 |
| 30 GLXContext CreateContextAttribs(Display* display, |
| 31 GLXFBConfig config, |
| 32 GLXContext share, |
| 33 GLVersion version, |
| 34 int profile_mask) { |
| 35 std::vector<int> attribs; |
| 36 |
| 37 if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) { |
| 38 attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); |
| 39 attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); |
| 40 } |
| 41 |
| 42 if (version.first != 0 || version.second != 0) { |
| 43 attribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB); |
| 44 attribs.push_back(version.first); |
| 45 |
| 46 attribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB); |
| 47 attribs.push_back(version.second); |
| 48 } |
| 49 |
| 50 if (profile_mask != 0 && GLSurfaceGLX::IsCreateContextProfileSupported()) { |
| 51 attribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB); |
| 52 attribs.push_back(profile_mask); |
| 53 } |
| 54 |
| 55 attribs.push_back(0); |
| 56 |
| 57 // When creating a context with glXCreateContextAttribsARB, a variety of X11 |
| 58 // errors can be generated. To prevent these errors from crashing our process, |
| 59 // we simply ignore them and only look if the GLXContext was created. |
| 60 auto old_error_handler = XSetErrorHandler(IgnoreX11Errors); |
| 61 GLXContext context = |
| 62 glXCreateContextAttribsARB(display, config, share, True, attribs.data()); |
| 63 XSetErrorHandler(old_error_handler); |
| 64 |
| 65 return context; |
| 66 } |
| 67 |
| 68 GLXContext CreateHighestVersionContext(Display* display, |
| 69 GLXFBConfig config, |
| 70 GLXContext share) { |
| 71 // It is commonly assumed that glXCreateContextAttrib will create a context |
| 72 // of the highest version possible but it is not specified in the spec and |
| 73 // is not true on the Mesa drivers. On Mesa, Instead we try to create a |
| 74 // context per GL version until we succeed, starting from newer version. |
| 75 // On both Mesa and other drivers we try to create a desktop context and fall |
| 76 // back to ES context. |
| 77 // The code could be simpler if the Mesa code path was used for all drivers, |
| 78 // however the cost of failing a context creation can be high (3 milliseconds |
| 79 // for the NVIDIA driver). The good thing is that failed context creation only |
| 80 // takes 0.1 milliseconds on Mesa. |
| 81 |
| 82 struct ContextCreationInfo { |
| 83 int profileFlag; |
| 84 GLVersion version; |
| 85 }; |
| 86 |
| 87 // clang-format off |
| 88 // For regular drivers we try to create a compatibility, core, then ES |
| 89 // context. Without requiring any specific version. |
| 90 const ContextCreationInfo contexts_to_try[] = { |
| 91 { 0, GLVersion(0, 0) }, |
| 92 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLVersion(0, 0) }, |
| 93 { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, GLVersion(0, 0) }, |
| 94 }; |
| 95 |
| 96 // On Mesa we try to create a core context, except for versions below 3.2 |
| 97 // where it is not applicable. (and fallback to ES as well) |
| 98 const ContextCreationInfo mesa_contexts_to_try[] = { |
| 99 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 5) } }, |
| 100 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 4) } }, |
| 101 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 3) } }, |
| 102 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 2) } }, |
| 103 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 1) } }, |
| 104 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 0) } }, |
| 105 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(3, 3) } }, |
| 106 { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(3, 2) } }, |
| 107 { 0, { GLVersion(3, 1) } }, |
| 108 { 0, { GLVersion(3, 0) } }, |
| 109 { 0, { GLVersion(2, 0) } }, |
| 110 { 0, { GLVersion(1, 5) } }, |
| 111 { 0, { GLVersion(1, 4) } }, |
| 112 { 0, { GLVersion(1, 3) } }, |
| 113 { 0, { GLVersion(1, 2) } }, |
| 114 { 0, { GLVersion(1, 1) } }, |
| 115 { 0, { GLVersion(1, 0) } }, |
| 116 { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 2) } }, |
| 117 { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 1) } }, |
| 118 { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 0) } }, |
| 119 { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(2, 0) } }, |
| 120 }; |
| 121 // clang-format on |
| 122 |
| 123 std::string client_vendor = glXGetClientString(display, GLX_VENDOR); |
| 124 bool is_mesa = client_vendor.find("Mesa") != std::string::npos; |
| 125 |
| 126 const ContextCreationInfo* to_try = contexts_to_try; |
| 127 size_t to_try_length = arraysize(contexts_to_try); |
| 128 if (is_mesa) { |
| 129 to_try = mesa_contexts_to_try; |
| 130 to_try_length = arraysize(mesa_contexts_to_try); |
| 131 } |
| 132 |
| 133 for (size_t i = 0; i < to_try_length; ++i) { |
| 134 const ContextCreationInfo& info = to_try[i]; |
| 135 if (!GLSurfaceGLX::IsCreateContextES2ProfileSupported() && |
| 136 info.profileFlag == GLX_CONTEXT_ES2_PROFILE_BIT_EXT) { |
| 137 continue; |
| 138 } |
| 139 GLXContext context = CreateContextAttribs(display, config, share, |
| 140 info.version, info.profileFlag); |
| 141 if (context != nullptr) { |
| 142 return context; |
| 143 } |
| 144 } |
| 145 |
| 146 return nullptr; |
| 147 } |
| 148 } |
| 149 |
| 22 GLContextGLX::GLContextGLX(GLShareGroup* share_group) | 150 GLContextGLX::GLContextGLX(GLShareGroup* share_group) |
| 23 : GLContextReal(share_group), | 151 : GLContextReal(share_group), |
| 24 context_(nullptr), | 152 context_(nullptr), |
| 25 display_(nullptr) { | 153 display_(nullptr) { |
| 26 } | 154 } |
| 27 | 155 |
| 28 XDisplay* GLContextGLX::display() { | 156 XDisplay* GLContextGLX::display() { |
| 29 return display_; | 157 return display_; |
| 30 } | 158 } |
| 31 | 159 |
| 32 bool GLContextGLX::Initialize( | 160 bool GLContextGLX::Initialize( |
| 33 GLSurface* compatible_surface, GpuPreference gpu_preference) { | 161 GLSurface* compatible_surface, GpuPreference gpu_preference) { |
| 34 display_ = static_cast<XDisplay*>(compatible_surface->GetDisplay()); | 162 display_ = static_cast<XDisplay*>(compatible_surface->GetDisplay()); |
| 35 | 163 |
| 36 GLXContext share_handle = static_cast<GLXContext>( | 164 GLXContext share_handle = static_cast<GLXContext>( |
| 37 share_group() ? share_group()->GetHandle() : nullptr); | 165 share_group() ? share_group()->GetHandle() : nullptr); |
| 38 | 166 |
| 39 if (GLSurfaceGLX::IsCreateContextSupported()) { | 167 if (GLSurfaceGLX::IsCreateContextSupported()) { |
| 40 DVLOG(1) << "GLX_ARB_create_context supported."; | 168 DVLOG(1) << "GLX_ARB_create_context supported."; |
| 41 std::vector<int> attribs; | 169 context_ = CreateHighestVersionContext( |
| 42 if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) { | 170 display_, static_cast<GLXFBConfig>(compatible_surface->GetConfig()), |
| 43 DVLOG(1) << "GLX_ARB_create_context_robustness supported."; | 171 share_handle); |
| 44 attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); | |
| 45 attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); | |
| 46 } | |
| 47 attribs.push_back(0); | |
| 48 context_ = glXCreateContextAttribsARB( | |
| 49 display_, | |
| 50 static_cast<GLXFBConfig>(compatible_surface->GetConfig()), | |
| 51 share_handle, | |
| 52 True, | |
| 53 &attribs.front()); | |
| 54 if (!context_) { | 172 if (!context_) { |
| 55 LOG(ERROR) << "Failed to create GL context with " | 173 LOG(ERROR) << "Failed to create GL context with " |
| 56 << "glXCreateContextAttribsARB."; | 174 << "glXCreateContextAttribsARB."; |
| 57 return false; | 175 return false; |
| 58 } | 176 } |
| 59 } else { | 177 } else { |
| 60 DVLOG(1) << "GLX_ARB_create_context not supported."; | 178 DVLOG(1) << "GLX_ARB_create_context not supported."; |
| 61 context_ = glXCreateNewContext( | 179 context_ = glXCreateNewContext( |
| 62 display_, | 180 display_, |
| 63 static_cast<GLXFBConfig>(compatible_surface->GetConfig()), | 181 static_cast<GLXFBConfig>(compatible_surface->GetConfig()), |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 | 310 |
| 193 bool GLContextGLX::WasAllocatedUsingRobustnessExtension() { | 311 bool GLContextGLX::WasAllocatedUsingRobustnessExtension() { |
| 194 return GLSurfaceGLX::IsCreateContextRobustnessSupported(); | 312 return GLSurfaceGLX::IsCreateContextRobustnessSupported(); |
| 195 } | 313 } |
| 196 | 314 |
| 197 GLContextGLX::~GLContextGLX() { | 315 GLContextGLX::~GLContextGLX() { |
| 198 Destroy(); | 316 Destroy(); |
| 199 } | 317 } |
| 200 | 318 |
| 201 } // namespace gl | 319 } // namespace gl |
| OLD | NEW |