Use EXT_robustness where available on GLES2 platforms to detect and respond to resets of the graphics card.

BUG=138162
TEST=ran https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/conformance-suites/1.0.1/extra/slow-shader-example.html on Windows with ANGLE and verified that new code path was taken


Review URL: https://chromiumcodereview.appspot.com/10822029

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148721 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 12cda4b..e83be95 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -279,14 +279,15 @@
     delayed_echos_.pop_front();
   }
 
+  bool have_context = false;
   if (decoder_.get())
-    decoder_->MakeCurrent();
+    have_context = decoder_->MakeCurrent();
   FOR_EACH_OBSERVER(DestructionObserver,
                     destruction_observers_,
                     OnWillDestroyStub(this));
 
   if (decoder_.get()) {
-    decoder_->Destroy(true);
+    decoder_->Destroy(have_context);
     decoder_.reset();
   }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index ec799ea..12b02d1 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1542,7 +1542,7 @@
 
   int frame_number_;
 
-  bool has_arb_robustness_;
+  bool has_robustness_extension_;
   GLenum reset_status_;
 
   bool needs_mac_nvidia_driver_workaround_;
@@ -1963,7 +1963,7 @@
       feature_info_(group_->feature_info()),
       tex_image_2d_failed_(false),
       frame_number_(0),
-      has_arb_robustness_(false),
+      has_robustness_extension_(false),
       reset_status_(GL_NO_ERROR),
       needs_mac_nvidia_driver_workaround_(false),
       needs_glsl_built_in_function_emulation_(false),
@@ -2250,7 +2250,9 @@
     glEnable(GL_POINT_SPRITE);
   }
 
-  has_arb_robustness_ = context->HasExtension("GL_ARB_robustness");
+  has_robustness_extension_ =
+      context->HasExtension("GL_ARB_robustness") ||
+      context->HasExtension("GL_EXT_robustness");
 
   if (!feature_info_->feature_flags().disable_workarounds) {
 #if defined(OS_MACOSX)
@@ -8532,13 +8534,15 @@
 }
 
 bool GLES2DecoderImpl::WasContextLost() {
-  if (context_->WasAllocatedUsingARBRobustness() && has_arb_robustness_) {
-    GLenum status = glGetGraphicsResetStatusARB();
+  if (context_->WasAllocatedUsingRobustnessExtension()) {
+    GLenum status = GL_NO_ERROR;
+    if (has_robustness_extension_)
+      status = glGetGraphicsResetStatusARB();
     if (status != GL_NO_ERROR) {
       // The graphics card was reset. Signal a lost context to the application.
       reset_status_ = status;
       LOG(ERROR) << (surface_->IsOffscreen() ? "Offscreen" : "Onscreen")
-                 << " context lost via ARB_robustness. Reset status = 0x"
+                 << " context lost via ARB/EXT_robustness. Reset status = 0x"
                  << std::hex << status << std::dec;
       return true;
     }
diff --git a/third_party/khronos/EGL/eglext.h b/third_party/khronos/EGL/eglext.h
index 5e52a34..a91582b 100644
--- a/third_party/khronos/EGL/eglext.h
+++ b/third_party/khronos/EGL/eglext.h
@@ -328,6 +328,14 @@
 #endif
 #endif
 
+#ifndef EGL_EXT_create_context_robustness
+#define EGL_EXT_create_context_robustness 1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT	0x30BF
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+#define EGL_NO_RESET_NOTIFICATION_EXT		0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_EXT		0x31BF
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 11ccff2..e390be4 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -290,7 +290,8 @@
   'arguments': 'GLenum target, '
                'GLenum attachment, GLenum pname, GLint* params', },
 { 'return_type': 'GLenum',
-  'names': ['glGetGraphicsResetStatusARB'],
+  'names': ['glGetGraphicsResetStatusARB',
+            'glGetGraphicsResetStatusEXT'],
   'arguments': 'void', },
 { 'return_type': 'void',
   'names': ['glGetIntegerv'],
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc
index 48ef5fb..6ab53a1 100644
--- a/ui/gl/gl_context.cc
+++ b/ui/gl/gl_context.cc
@@ -81,7 +81,7 @@
   GLSurface::SetCurrent(surface);
 }
 
-bool GLContext::WasAllocatedUsingARBRobustness() {
+bool GLContext::WasAllocatedUsingRobustnessExtension() {
   return false;
 }
 
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h
index 6c25ca2..defeb25 100644
--- a/ui/gl/gl_context.h
+++ b/ui/gl/gl_context.h
@@ -70,7 +70,7 @@
 
   static GLContext* GetCurrent();
 
-  virtual bool WasAllocatedUsingARBRobustness();
+  virtual bool WasAllocatedUsingRobustnessExtension();
 
  protected:
   virtual ~GLContext();
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index a5c61e87..dc406f4 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -9,8 +9,9 @@
 #include "base/memory/scoped_ptr.h"
 #include "build/build_config.h"
 #include "third_party/angle/include/EGL/egl.h"
+#include "third_party/angle/include/EGL/eglext.h"
 #include "ui/gl/egl_util.h"
-#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_surface_egl.h"
 
 // This header must come after the above third-party include, as
 // it brings in #defines that cause conflicts.
@@ -40,15 +41,33 @@
     EGL_CONTEXT_CLIENT_VERSION, 2,
     EGL_NONE
   };
+  static const EGLint kContextRobustnessAttributes[] = {
+    EGL_CONTEXT_CLIENT_VERSION, 2,
+    EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
+    EGL_LOSE_CONTEXT_ON_RESET_EXT,
+    EGL_NONE
+  };
 
   display_ = compatible_surface->GetDisplay();
   config_ = compatible_surface->GetConfig();
 
+  const EGLint* context_attributes = NULL;
+  if (GLSurfaceEGL::IsCreateContextRobustnessSupported()) {
+    DVLOG(1) << "EGL_EXT_create_context_robustness supported.";
+    context_attributes = kContextRobustnessAttributes;
+  } else {
+    // At some point we should require the presence of the robustness
+    // extension and remove this code path.
+    DVLOG(1) << "EGL_EXT_create_context_robustness NOT supported.";
+    context_attributes = kContextAttributes;
+  }
+
   context_ = eglCreateContext(
       display_,
       config_,
       share_group() ? share_group()->GetHandle() : NULL,
-      kContextAttributes);
+      context_attributes);
+
   if (!context_) {
     LOG(ERROR) << "eglCreateContext failed with error "
                << GetLastEGLErrorString();
@@ -155,6 +174,10 @@
   return GLContext::GetExtensions() + " " + extensions;
 }
 
+bool GLContextEGL::WasAllocatedUsingRobustnessExtension() {
+  return GLSurfaceEGL::IsCreateContextRobustnessSupported();
+}
+
 GLContextEGL::~GLContextEGL() {
   Destroy();
 }
diff --git a/ui/gl/gl_context_egl.h b/ui/gl/gl_context_egl.h
index 21b8341..3090592 100644
--- a/ui/gl/gl_context_egl.h
+++ b/ui/gl/gl_context_egl.h
@@ -33,6 +33,7 @@
   virtual void* GetHandle() OVERRIDE;
   virtual void SetSwapInterval(int interval) OVERRIDE;
   virtual std::string GetExtensions() OVERRIDE;
+  virtual bool WasAllocatedUsingRobustnessExtension() OVERRIDE;
 
  protected:
   virtual ~GLContextEGL();
diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc
index db5534b..d052644 100644
--- a/ui/gl/gl_context_glx.cc
+++ b/ui/gl/gl_context_glx.cc
@@ -244,7 +244,7 @@
   return GLContext::GetExtensions();
 }
 
-bool GLContextGLX::WasAllocatedUsingARBRobustness() {
+bool GLContextGLX::WasAllocatedUsingRobustnessExtension() {
   return GLSurfaceGLX::IsCreateContextRobustnessSupported();
 }
 
diff --git a/ui/gl/gl_context_glx.h b/ui/gl/gl_context_glx.h
index 8fcd7a7..bba6b3d 100644
--- a/ui/gl/gl_context_glx.h
+++ b/ui/gl/gl_context_glx.h
@@ -33,7 +33,7 @@
   virtual void* GetHandle() OVERRIDE;
   virtual void SetSwapInterval(int interval) OVERRIDE;
   virtual std::string GetExtensions() OVERRIDE;
-  virtual bool WasAllocatedUsingARBRobustness() OVERRIDE;
+  virtual bool WasAllocatedUsingRobustnessExtension() OVERRIDE;
 
  protected:
   virtual ~GLContextGLX();
diff --git a/ui/gl/gl_fence.cc b/ui/gl/gl_fence.cc
index 82cdf30..0f7610c 100644
--- a/ui/gl/gl_fence.cc
+++ b/ui/gl/gl_fence.cc
@@ -93,12 +93,12 @@
 
 // static
 bool GLFence::IsContextLost() {
-  if (!gfx::g_GL_ARB_robustness)
+  if (!gfx::g_GL_ARB_robustness && !gfx::g_GL_EXT_robustness)
     return false;
 
   if (!gfx::GLContext::GetCurrent() ||
       !gfx::GLContext::GetCurrent()->
-          WasAllocatedUsingARBRobustness())
+          WasAllocatedUsingRobustnessExtension())
     return false;
 
   GLenum status = glGetGraphicsResetStatusARB();
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index b51d747..a05eae8 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -160,6 +160,19 @@
   current_surface_.Pointer()->Set(surface);
 }
 
+bool GLSurface::ExtensionsContain(const char* c_extensions, const char* name) {
+  DCHECK(name);
+  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;
+}
+
 GLSurfaceAdapter::GLSurfaceAdapter(GLSurface* surface) : surface_(surface) {}
 
 bool GLSurfaceAdapter::Initialize() {
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 979dc9f..4ecc472 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -119,6 +119,8 @@
   static bool InitializeOneOffInternal();
   static void SetCurrent(GLSurface* surface);
 
+  static bool ExtensionsContain(const char* extensions, const char* name);
+
  private:
   friend class base::RefCounted<GLSurface>;
   friend class GLContext;
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index a1214cf..c1d8af1 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -26,12 +26,17 @@
 namespace gfx {
 
 namespace {
+
 EGLConfig g_config;
 EGLDisplay g_display;
 EGLNativeDisplayType g_native_display;
 EGLConfig g_software_config;
 EGLDisplay g_software_display;
 EGLNativeDisplayType g_software_native_display;
+
+const char* g_egl_extensions = NULL;
+bool g_egl_create_context_robustness_supported = false;
+
 }
 
 GLSurfaceEGL::GLSurfaceEGL() : software_(false) {}
@@ -96,6 +101,10 @@
     return false;
   }
 
+  g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
+  g_egl_create_context_robustness_supported =
+      HasEGLExtension("EGL_EXT_create_context_robustness");
+
   initialized = true;
 
 #if defined(USE_X11) || defined(OS_ANDROID)
@@ -154,6 +163,18 @@
   return g_native_display;
 }
 
+const char* GLSurfaceEGL::GetEGLExtensions() {
+  return g_egl_extensions;
+}
+
+bool GLSurfaceEGL::HasEGLExtension(const char* name) {
+  return ExtensionsContain(GetEGLExtensions(), name);
+}
+
+bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
+  return g_egl_create_context_robustness_supported;
+}
+
 GLSurfaceEGL::~GLSurfaceEGL() {}
 
 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(bool software,
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index 399db43..85ca98c 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -41,6 +41,13 @@
   static EGLDisplay GetSoftwareDisplay();
   static EGLNativeDisplayType GetNativeDisplay();
 
+  // 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* GetEGLExtensions();
+  static bool HasEGLExtension(const char* name);
+  static bool IsCreateContextRobustnessSupported();
+
  protected:
   virtual ~GLSurfaceEGL();
 
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc
index efb0309..8428cfc 100644
--- a/ui/gl/gl_surface_glx.cc
+++ b/ui/gl/gl_surface_glx.cc
@@ -78,17 +78,7 @@
 
 // static
 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;
+  return ExtensionsContain(GetGLXExtensions(), name);
 }
 
 // static