diff options
author | kbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-14 00:38:43 +0000 |
---|---|---|
committer | kbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-14 00:38:43 +0000 |
commit | 38d139d7410c8e42e731c5c58fab23d8d07b2721 (patch) | |
tree | fc3b1dba6528b6685354480990c4e11be03200e2 /ui/gfx | |
parent | 2c812ba0ee1bf617c72a8bcd1a26b3a8418b0b5f (diff) | |
download | chromium_src-38d139d7410c8e42e731c5c58fab23d8d07b2721.zip chromium_src-38d139d7410c8e42e731c5c58fab23d8d07b2721.tar.gz chromium_src-38d139d7410c8e42e731c5c58fab23d8d07b2721.tar.bz2 |
Detect and expose loss of OpenGL context using GL_ARB_robustness.
(This CL was originally reviewed under
http://codereview.chromium.org/7331020/ . The only difference is the
removal of an #include from command_buffer.h that was accidentally
left in and which caused a significant increase in the number of files
containing static initializers, presumably because of the dependent
#include of <iostream>.)
This initial patch changes the Linux port to use
GLX_ARB_create_context_robustness when available, and tests
periodically whether the context has been lost after each draw call
and when making the context current. The detection of context loss
also works with EGL and ANGLE, although it always reports an unknown
reset status.
WebKit changes will follow which test the reset status and determine
what to do in response; for example, the policy might be to never
restore a WebGL context which was lost (due to a GPU reset) and which
was determined to be the guilty context.
Tested manually with WebGL stress tests and verified on Linux and
Windows that in at least some situations it is possible to detect
guilty contexts and shut down the associated WebGL application. Some
precision of this detection was recently lost and will need to be
fixed in following CLs. Also updated and ran GPU unit tests.
BUG=88106
TEST=none (tested manually; try servers)
R=gman,apatrick,piman
Review URL: http://codereview.chromium.org/7362005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92453 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx')
-rw-r--r-- | ui/gfx/gl/generate_bindings.py | 4 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context.cc | 4 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context.h | 2 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_glx.cc | 118 | ||||
-rw-r--r-- | ui/gfx/gl/gl_context_glx.h | 1 | ||||
-rw-r--r-- | ui/gfx/gl/gl_interface.h | 2 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_glx.cc | 85 | ||||
-rw-r--r-- | ui/gfx/gl/gl_surface_glx.h | 8 |
8 files changed, 183 insertions, 41 deletions
diff --git a/ui/gfx/gl/generate_bindings.py b/ui/gfx/gl/generate_bindings.py index b083229..e0475c2 100644 --- a/ui/gfx/gl/generate_bindings.py +++ b/ui/gfx/gl/generate_bindings.py @@ -121,6 +121,7 @@ GL_FUNCTIONS = [ ['void', ['glGetFramebufferAttachmentParameterivEXT', 'glGetFramebufferAttachmentParameteriv'], 'GLenum target, ' 'GLenum attachment, GLenum pname, GLint* params'], +['GLenum', ['glGetGraphicsResetStatusARB'], 'void'], ['void', ['glGetIntegerv'], 'GLenum pname, GLint* params'], ['void', ['glGetProgramiv'], 'GLuint program, GLenum pname, GLint* params'], ['void', ['glGetProgramInfoLog'], @@ -432,6 +433,9 @@ GLX_FUNCTIONS = [ 'Display* dpy, GLXDrawable drawable, int interval'], ['GLXFBConfig', ['glXGetFBConfigFromVisualSGIX'], 'Display* dpy, XVisualInfo* visualInfo'], +['GLXContext', ['glXCreateContextAttribsARB'], + 'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, ' + 'const int* attrib_list'], ] FUNCTION_SETS = [ diff --git a/ui/gfx/gl/gl_context.cc b/ui/gfx/gl/gl_context.cc index c19741f..87379bf 100644 --- a/ui/gfx/gl/gl_context.cc +++ b/ui/gfx/gl/gl_context.cc @@ -61,4 +61,8 @@ bool GLContext::LosesAllContextsOnContextLost() } } +bool GLContext::WasAllocatedUsingARBRobustness() { + return false; +} + } // namespace gfx diff --git a/ui/gfx/gl/gl_context.h b/ui/gfx/gl/gl_context.h index 2159423..ff88e0c 100644 --- a/ui/gfx/gl/gl_context.h +++ b/ui/gfx/gl/gl_context.h @@ -64,6 +64,8 @@ class GLContext : public base::RefCounted<GLContext> { static bool LosesAllContextsOnContextLost(); + virtual bool WasAllocatedUsingARBRobustness(); + protected: virtual ~GLContext(); diff --git a/ui/gfx/gl/gl_context_glx.cc b/ui/gfx/gl/gl_context_glx.cc index ba8d7ab..aa863cc 100644 --- a/ui/gfx/gl/gl_context_glx.cc +++ b/ui/gfx/gl/gl_context_glx.cc @@ -56,50 +56,81 @@ GLContextGLX::~GLContextGLX() { bool GLContextGLX::Initialize(GLSurface* compatible_surface) { GLSurfaceGLX* surface_glx = static_cast<GLSurfaceGLX*>(compatible_surface); - GLXFBConfig config = static_cast<GLXFBConfig>(surface_glx->GetConfig()); GLXContext share_handle = static_cast<GLXContext>( share_group() ? share_group()->GetHandle() : NULL); - // The means by which the context is created depends on whether the drawable - // type works reliably with GLX 1.3. If it does not then fall back to GLX 1.2. - if (config) { - context_ = glXCreateNewContext( + if (GLSurfaceGLX::IsCreateContextRobustnessSupported()) { + DLOG(INFO) << "GLX_ARB_create_context_robustness supported."; + + std::vector<int> attribs; + attribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + attribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB); + attribs.push_back(0); + context_ = glXCreateContextAttribsARB( GLSurfaceGLX::GetDisplay(), static_cast<GLXFBConfig>(surface_glx->GetConfig()), - GLX_RGBA_TYPE, share_handle, - True); - } else { - Display* display = GLSurfaceGLX::GetDisplay(); - - // Get the visuals for the X drawable. - XWindowAttributes attributes; - XGetWindowAttributes( - display, - reinterpret_cast<GLXDrawable>(surface_glx->GetHandle()), - &attributes); - - XVisualInfo visual_info_template; - visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); - - int visual_info_count = 0; - scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( - XGetVisualInfo(display, VisualIDMask, - &visual_info_template, - &visual_info_count)); - - DCHECK(visual_info_list.get()); - if (visual_info_count == 0) { - LOG(ERROR) << "No visual info for visual ID."; - return false; + True, + &attribs.front()); + if (context_) { + DLOG(INFO) << " Successfully allocated " + << (surface_glx->IsOffscreen() ? "offscreen" : "onscreen") + << " GL context with LOSE_CONTEXT_ON_RESET_ARB"; + } else { + // TODO(kbr): it is not expected that things will work properly + // in this case, since we will likely allocate our offscreen + // contexts with this bit set and the onscreen contexts without, + // and won't be able to put them in the same share group. + // Consider what to do here; force loss of all contexts and + // reallocation without ARB_robustness? + LOG(ERROR) << + " FAILED to allocate GL context with LOSE_CONTEXT_ON_RESET_ARB"; } + } - // Attempt to create a context with each visual in turn until one works. - context_ = glXCreateContext( - display, - visual_info_list.get(), - share_handle, - True); + if (!context_) { + // The means by which the context is created depends on whether + // the drawable type works reliably with GLX 1.3. If it does not + // then fall back to GLX 1.2. + if (surface_glx->IsOffscreen()) { + context_ = glXCreateNewContext( + GLSurfaceGLX::GetDisplay(), + static_cast<GLXFBConfig>(surface_glx->GetConfig()), + GLX_RGBA_TYPE, + share_handle, + True); + } else { + Display* display = GLSurfaceGLX::GetDisplay(); + + // Get the visuals for the X drawable. + XWindowAttributes attributes; + XGetWindowAttributes( + display, + reinterpret_cast<GLXDrawable>(surface_glx->GetHandle()), + &attributes); + + XVisualInfo visual_info_template; + visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); + + int visual_info_count = 0; + scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( + XGetVisualInfo(display, VisualIDMask, + &visual_info_template, + &visual_info_count)); + + DCHECK(visual_info_list.get()); + if (visual_info_count == 0) { + LOG(ERROR) << "No visual info for visual ID."; + return false; + } + + // Attempt to create a context with each visual in turn until one works. + context_ = glXCreateContext( + display, + visual_info_list.get(), + share_handle, + True); + } } if (!context_) { @@ -108,6 +139,13 @@ bool GLContextGLX::Initialize(GLSurface* compatible_surface) { return false; } + DLOG(INFO) << (surface_glx->IsOffscreen() ? "Offscreen" : "Onscreen") + << " context was " + << (glXIsDirect(GLSurfaceGLX::GetDisplay(), + static_cast<GLXContext>(context_)) + ? "direct" : "indirect") + << "."; + return true; } @@ -188,9 +226,7 @@ void GLContextGLX::SetSwapInterval(int interval) { std::string GLContextGLX::GetExtensions() { DCHECK(IsCurrent(NULL)); - const char* extensions = glXQueryExtensionsString( - GLSurfaceGLX::GetDisplay(), - 0); + const char* extensions = GLSurfaceGLX::GetGLXExtensions(); if (extensions) { return GLContext::GetExtensions() + " " + extensions; } @@ -198,4 +234,8 @@ std::string GLContextGLX::GetExtensions() { return GLContext::GetExtensions(); } +bool GLContextGLX::WasAllocatedUsingARBRobustness() { + return GLSurfaceGLX::IsCreateContextRobustnessSupported(); +} + } // namespace gfx diff --git a/ui/gfx/gl/gl_context_glx.h b/ui/gfx/gl/gl_context_glx.h index e89bcb2..5432df7 100644 --- a/ui/gfx/gl/gl_context_glx.h +++ b/ui/gfx/gl/gl_context_glx.h @@ -25,6 +25,7 @@ class GLContextGLX : public GLContext { virtual void* GetHandle(); virtual void SetSwapInterval(int interval); virtual std::string GetExtensions(); + virtual bool WasAllocatedUsingARBRobustness(); private: void* context_; diff --git a/ui/gfx/gl/gl_interface.h b/ui/gfx/gl/gl_interface.h index 55ea9d1..3c3b3fa 100644 --- a/ui/gfx/gl/gl_interface.h +++ b/ui/gfx/gl/gl_interface.h @@ -540,6 +540,8 @@ class GLInterface { virtual void SetSurfaceCHROMIUM(GLuint id) = 0; + virtual GLenum GetGraphicsResetStatusARB() = 0; + private: static GLInterface* interface_; }; diff --git a/ui/gfx/gl/gl_surface_glx.cc b/ui/gfx/gl/gl_surface_glx.cc index 5a051de..b584080 100644 --- a/ui/gfx/gl/gl_surface_glx.cc +++ b/ui/gfx/gl/gl_surface_glx.cc @@ -32,6 +32,8 @@ class ScopedPtrXFree { }; Display* g_display; +const char* g_glx_extensions = NULL; +bool g_glx_create_context_robustness_supported = false; } // namespace anonymous @@ -63,6 +65,10 @@ bool GLSurfaceGLX::InitializeOneOff() { return false; } + g_glx_extensions = glXQueryExtensionsString(g_display, 0); + g_glx_create_context_robustness_supported = + HasGLXExtension("GLX_ARB_create_context_robustness"); + initialized = true; return true; } @@ -71,8 +77,31 @@ Display* GLSurfaceGLX::GetDisplay() { return g_display; } +const char* GLSurfaceGLX::GetGLXExtensions() { + return g_glx_extensions; +} + +bool GLSurfaceGLX::HasGLXExtension(const char* name) { + DCHECK(name); + const char* c_extensions = GetGLXExtensions(); + if (!c_extensions) + return false; + std::string extensions(c_extensions); + extensions += " "; + + std::string delimited_name(name); + delimited_name += " "; + + return extensions.find(delimited_name) != std::string::npos; +} + +bool GLSurfaceGLX::IsCreateContextRobustnessSupported() { + return g_glx_create_context_robustness_supported; +} + NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::PluginWindowHandle window) - : window_(window) { + : window_(window), + config_(NULL) { } NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() { @@ -106,7 +135,59 @@ void* NativeViewGLSurfaceGLX::GetHandle() { } void* NativeViewGLSurfaceGLX::GetConfig() { - return NULL; + if (!config_) { + // This code path is expensive, but we only take it when + // attempting to use GLX_ARB_create_context_robustness, in which + // case we need a GLXFBConfig for the window in order to create a + // context for it. + // + // TODO(kbr): this is not a reliable code path. On platforms which + // support it, we should use glXChooseFBConfig in the browser + // process to choose the FBConfig and from there the X Visual to + // use when creating the window in the first place. Then we can + // pass that FBConfig down rather than attempting to reconstitute + // it. + + XWindowAttributes attributes; + XGetWindowAttributes( + g_display, + reinterpret_cast<GLXDrawable>(GetHandle()), + &attributes); + int visual_id = XVisualIDFromVisual(attributes.visual); + + int num_elements = 0; + scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs( + glXGetFBConfigs(g_display, + DefaultScreen(g_display), + &num_elements)); + if (!configs.get()) { + LOG(ERROR) << "glXGetFBConfigs failed."; + return NULL; + } + if (!num_elements) { + LOG(ERROR) << "glXGetFBConfigs returned 0 elements."; + return NULL; + } + bool found = false; + int i; + for (i = 0; i < num_elements; ++i) { + int value; + if (glXGetFBConfigAttrib( + g_display, configs.get()[i], GLX_VISUAL_ID, &value)) { + LOG(ERROR) << "glXGetFBConfigAttrib failed."; + return NULL; + } + if (value == visual_id) { + found = true; + break; + } + } + if (found) { + config_ = configs.get()[i]; + } + } + + return config_; } PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size) diff --git a/ui/gfx/gl/gl_surface_glx.h b/ui/gfx/gl/gl_surface_glx.h index 343137c..54a52e0 100644 --- a/ui/gfx/gl/gl_surface_glx.h +++ b/ui/gfx/gl/gl_surface_glx.h @@ -22,6 +22,13 @@ class GLSurfaceGLX : public GLSurface { static bool InitializeOneOff(); static Display* GetDisplay(); + // These aren't particularly tied to surfaces, but since we already + // have the static InitializeOneOff here, it's easiest to reuse its + // initialization guards. + static const char* GetGLXExtensions(); + static bool HasGLXExtension(const char* name); + static bool IsCreateContextRobustnessSupported(); + // Get the FB config that the surface was created with or NULL if it is not // a GLX drawable. virtual void* GetConfig() = 0; @@ -47,6 +54,7 @@ class NativeViewGLSurfaceGLX : public GLSurfaceGLX { private: gfx::PluginWindowHandle window_; + void* config_; DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceGLX); }; |