summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-14 00:38:43 +0000
committerkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-14 00:38:43 +0000
commit38d139d7410c8e42e731c5c58fab23d8d07b2721 (patch)
treefc3b1dba6528b6685354480990c4e11be03200e2
parent2c812ba0ee1bf617c72a8bcd1a26b3a8418b0b5f (diff)
downloadchromium_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
-rw-r--r--content/common/gpu/gpu_command_buffer_stub.cc4
-rw-r--r--content/common/gpu/gpu_messages.h5
-rw-r--r--content/renderer/gpu/command_buffer_proxy.cc11
-rw-r--r--content/renderer/gpu/command_buffer_proxy.h3
-rw-r--r--content/renderer/gpu/renderer_gl_context.cc31
-rw-r--r--content/renderer/gpu/renderer_gl_context.h16
-rw-r--r--content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc35
-rw-r--r--content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h4
-rw-r--r--content/renderer/render_widget_fullscreen_pepper.cc4
-rw-r--r--content/renderer/render_widget_fullscreen_pepper.h5
-rw-r--r--gpu/GLES2/gl2ext.h20
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py5
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h1
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h2
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc5
-rw-r--r--gpu/command_buffer/common/cmd_buffer_common.cc15
-rw-r--r--gpu/command_buffer/common/command_buffer.h15
-rw-r--r--gpu/command_buffer/common/command_buffer_mock.h2
-rw-r--r--gpu/command_buffer/common/constants.h12
-rw-r--r--gpu/command_buffer/common/gl_mock.h2
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h3
-rw-r--r--gpu/command_buffer/service/command_buffer_service.cc6
-rw-r--r--gpu/command_buffer/service/command_buffer_service.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc152
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h3
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_autogen.h17
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h1
-rw-r--r--gpu/command_buffer/service/gpu_scheduler.cc2
-rw-r--r--gpu/command_buffer/service/gpu_scheduler_unittest.cc2
-rw-r--r--ppapi/proxy/ppb_context_3d_proxy.cc6
-rw-r--r--ui/gfx/gl/generate_bindings.py4
-rw-r--r--ui/gfx/gl/gl_context.cc4
-rw-r--r--ui/gfx/gl/gl_context.h2
-rw-r--r--ui/gfx/gl/gl_context_glx.cc118
-rw-r--r--ui/gfx/gl/gl_context_glx.h1
-rw-r--r--ui/gfx/gl/gl_interface.h2
-rw-r--r--ui/gfx/gl/gl_surface_glx.cc85
-rw-r--r--ui/gfx/gl/gl_surface_glx.h8
-rw-r--r--webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc8
-rw-r--r--webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h2
-rw-r--r--webkit/gpu/webgraphicscontext3d_in_process_impl.cc5
-rw-r--r--webkit/gpu/webgraphicscontext3d_in_process_impl.h1
43 files changed, 509 insertions, 123 deletions
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 0b2d23b..8034372 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -242,7 +242,9 @@ void GpuCommandBufferStub::OnGetState(IPC::Message* reply_message) {
void GpuCommandBufferStub::OnParseError() {
TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnParseError");
- IPC::Message* msg = new GpuCommandBufferMsg_Destroyed(route_id_);
+ gpu::CommandBuffer::State state = command_buffer_->GetState();
+ IPC::Message* msg = new GpuCommandBufferMsg_Destroyed(
+ route_id_, state.context_lost_reason);
msg->set_unblock(true);
Send(msg);
// If an error occurs, the remaining commands will not be processed.
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index b30ab98..8f7c926 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -13,6 +13,7 @@
#include "content/common/gpu/gpu_info.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/constants.h"
#include "gpu/ipc/gpu_command_buffer_traits.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
@@ -105,6 +106,7 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::ReadWriteTokens)
IPC_STRUCT_TRAITS_END()
IPC_ENUM_TRAITS(content::CauseForGpuLaunch)
+IPC_ENUM_TRAITS(gpu::error::ContextLostReason)
//------------------------------------------------------------------------------
// GPU Messages
@@ -417,7 +419,8 @@ IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetWindowSize,
// Tells the proxy that there was an error and the command buffer had to be
// destroyed for some reason.
-IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_Destroyed)
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_Destroyed,
+ gpu::error::ContextLostReason /* reason */)
// --------------------------------------------------------------------------
// TransportTexture messages
diff --git a/content/renderer/gpu/command_buffer_proxy.cc b/content/renderer/gpu/command_buffer_proxy.cc
index ae81bf5..42949b6 100644
--- a/content/renderer/gpu/command_buffer_proxy.cc
+++ b/content/renderer/gpu/command_buffer_proxy.cc
@@ -59,16 +59,17 @@ bool CommandBufferProxy::OnMessageReceived(const IPC::Message& message) {
void CommandBufferProxy::OnChannelError() {
video_decoder_host_->OnChannelError();
- OnDestroyed();
+ OnDestroyed(gpu::error::kUnknown);
}
-void CommandBufferProxy::OnDestroyed() {
+void CommandBufferProxy::OnDestroyed(gpu::error::ContextLostReason reason) {
// Prevent any further messages from being sent.
channel_ = NULL;
// When the client sees that the context is lost, they should delete this
// CommandBufferProxy and create a new one.
last_state_.error = gpu::error::kLostContext;
+ last_state_.context_lost_reason = reason;
if (channel_error_callback_.get()) {
channel_error_callback_->Run();
@@ -332,6 +333,12 @@ void CommandBufferProxy::SetParseError(
NOTREACHED();
}
+void CommandBufferProxy::SetContextLostReason(
+ gpu::error::ContextLostReason reason) {
+ // Not implemented in proxy.
+ NOTREACHED();
+}
+
void CommandBufferProxy::OnSwapBuffers() {
if (swap_buffers_callback_.get())
swap_buffers_callback_->Run();
diff --git a/content/renderer/gpu/command_buffer_proxy.h b/content/renderer/gpu/command_buffer_proxy.h
index 2aabf9a..9879169 100644
--- a/content/renderer/gpu/command_buffer_proxy.h
+++ b/content/renderer/gpu/command_buffer_proxy.h
@@ -60,6 +60,7 @@ class CommandBufferProxy : public gpu::CommandBuffer,
virtual gpu::Buffer GetTransferBuffer(int32 handle);
virtual void SetToken(int32 token);
virtual void SetParseError(gpu::error::Error error);
+ virtual void SetContextLostReason(gpu::error::ContextLostReason reason);
virtual void OnSwapBuffers();
// Reparent a command buffer. TODO(apatrick): going forward, the notion of
@@ -113,7 +114,7 @@ class CommandBufferProxy : public gpu::CommandBuffer,
// Message handlers:
void OnUpdateState(const gpu::CommandBuffer::State& state);
void OnNotifyRepaint();
- void OnDestroyed();
+ void OnDestroyed(gpu::error::ContextLostReason reason);
// As with the service, the client takes ownership of the ring buffer.
int32 num_entries_;
diff --git a/content/renderer/gpu/renderer_gl_context.cc b/content/renderer/gpu/renderer_gl_context.cc
index 210fd1f..bf2d100 100644
--- a/content/renderer/gpu/renderer_gl_context.cc
+++ b/content/renderer/gpu/renderer_gl_context.cc
@@ -145,6 +145,24 @@ bool LatchAllocator::FreeLatch(uint32 latch_id) {
static base::LazyInstance<GLES2Initializer> g_gles2_initializer(
base::LINKER_INITIALIZED);
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(ENABLE_GPU)
+RendererGLContext::ContextLostReason ConvertReason(
+ gpu::error::ContextLostReason reason) {
+ switch (reason) {
+ case gpu::error::kGuilty:
+ return RendererGLContext::kGuilty;
+ case gpu::error::kInnocent:
+ return RendererGLContext::kInnocent;
+ case gpu::error::kUnknown:
+ return RendererGLContext::kUnknown;
+ }
+ NOTREACHED();
+ return RendererGLContext::kUnknown;
+}
+#endif
+
} // namespace anonymous
RendererGLContext::~RendererGLContext() {
@@ -308,7 +326,8 @@ void RendererGLContext::SetSwapBuffersCallback(Callback0::Type* callback) {
swap_buffers_callback_.reset(callback);
}
-void RendererGLContext::SetContextLostCallback(Callback0::Type* callback) {
+void RendererGLContext::SetContextLostCallback(
+ Callback1<ContextLostReason>::Type* callback) {
context_lost_callback_.reset(callback);
}
@@ -577,8 +596,14 @@ void RendererGLContext::OnSwapBuffers() {
}
void RendererGLContext::OnContextLost() {
- if (context_lost_callback_.get())
- context_lost_callback_->Run();
+ if (context_lost_callback_.get()) {
+ RendererGLContext::ContextLostReason reason = kUnknown;
+ if (command_buffer_) {
+ reason = ConvertReason(
+ command_buffer_->GetLastState().context_lost_reason);
+ }
+ context_lost_callback_->Run(reason);
+ }
}
bool RendererGLContext::CreateLatch(uint32* ret_latch) {
diff --git a/content/renderer/gpu/renderer_gl_context.h b/content/renderer/gpu/renderer_gl_context.h
index eb1096c..1c0280e 100644
--- a/content/renderer/gpu/renderer_gl_context.h
+++ b/content/renderer/gpu/renderer_gl_context.h
@@ -56,6 +56,18 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> {
NONE = 0x3038 // Attrib list = terminator
};
+ // Reasons that a lost context might have been provoked.
+ enum ContextLostReason {
+ // This context definitely provoked the loss of context.
+ kGuilty,
+
+ // This context definitely did not provoke the loss of context.
+ kInnocent,
+
+ // It is unknown whether this context provoked the loss of context.
+ kUnknown
+ };
+
// Initialize the library. This must have completed before any other
// functions are invoked.
static bool Initialize();
@@ -139,7 +151,7 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> {
// service side.
void SetSwapBuffersCallback(Callback0::Type* callback);
- void SetContextLostCallback(Callback0::Type* callback);
+ void SetContextLostCallback(Callback1<ContextLostReason>::Type* callback);
// Set the current RendererGLContext for the calling thread.
static bool MakeCurrent(RendererGLContext* context);
@@ -201,7 +213,7 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> {
scoped_refptr<GpuChannelHost> channel_;
base::WeakPtr<RendererGLContext> parent_;
scoped_ptr<Callback0::Type> swap_buffers_callback_;
- scoped_ptr<Callback0::Type> context_lost_callback_;
+ scoped_ptr<Callback1<ContextLostReason>::Type> context_lost_callback_;
uint32 parent_texture_id_;
uint32 child_to_parent_latch_;
uint32 parent_to_child_latch_;
diff --git a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc
index 73153bc..2d825b9 100644
--- a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc
@@ -38,6 +38,7 @@ WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl()
plugin_handle_(NULL),
#endif // defined(OS_MACOSX)
context_lost_callback_(0),
+ context_lost_reason_(GL_NO_ERROR),
cached_width_(0),
cached_height_(0),
bound_fbo_(0) {
@@ -685,7 +686,8 @@ WGC3Denum WebGraphicsContext3DCommandBufferImpl::getError() {
}
bool WebGraphicsContext3DCommandBufferImpl::isContextLost() {
- return context_->IsCommandBufferContextLost();
+ return context_->IsCommandBufferContextLost() ||
+ context_lost_reason_ != GL_NO_ERROR;
}
DELEGATE_TO_GL_2(getFloatv, GetFloatv, WGC3Denum, WGC3Dfloat*)
@@ -1031,7 +1033,36 @@ void WebGraphicsContext3DCommandBufferImpl::setContextLostCallback(
context_lost_callback_ = cb;
}
-void WebGraphicsContext3DCommandBufferImpl::OnContextLost() {
+WGC3Denum WebGraphicsContext3DCommandBufferImpl::getGraphicsResetStatusARB() {
+ if (context_->IsCommandBufferContextLost() &&
+ context_lost_reason_ == GL_NO_ERROR) {
+ return GL_UNKNOWN_CONTEXT_RESET_ARB;
+ }
+
+ return context_lost_reason_;
+}
+
+namespace {
+
+WGC3Denum convertReason(RendererGLContext::ContextLostReason reason) {
+ switch (reason) {
+ case RendererGLContext::kGuilty:
+ return GL_GUILTY_CONTEXT_RESET_ARB;
+ case RendererGLContext::kInnocent:
+ return GL_INNOCENT_CONTEXT_RESET_ARB;
+ case RendererGLContext::kUnknown:
+ return GL_UNKNOWN_CONTEXT_RESET_ARB;
+ }
+
+ NOTREACHED();
+ return GL_UNKNOWN_CONTEXT_RESET_ARB;
+}
+
+} // anonymous namespace
+
+void WebGraphicsContext3DCommandBufferImpl::OnContextLost(
+ RendererGLContext::ContextLostReason reason) {
+ context_lost_reason_ = convertReason(reason);
if (context_lost_callback_) {
context_lost_callback_->onContextLost();
}
diff --git a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h
index c9eabeb..5411502 100644
--- a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h
@@ -425,11 +425,12 @@ class WebGraphicsContext3DCommandBufferImpl
virtual void setContextLostCallback(
WebGraphicsContext3D::WebGraphicsContextLostCallback* callback);
+ virtual WGC3Denum getGraphicsResetStatusARB();
private:
// SwapBuffers callback.
void OnSwapBuffersComplete();
- virtual void OnContextLost();
+ virtual void OnContextLost(RendererGLContext::ContextLostReason reason);
// The context we use for OpenGL rendering.
RendererGLContext* context_;
@@ -443,6 +444,7 @@ class WebGraphicsContext3DCommandBufferImpl
gfx::PluginWindowHandle plugin_handle_;
#endif
WebGraphicsContext3D::WebGraphicsContextLostCallback* context_lost_callback_;
+ WGC3Denum context_lost_reason_;
WebKit::WebGraphicsContext3D::Attributes attributes_;
int cached_width_, cached_height_;
diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc
index ed4a5e8..e18a1c63 100644
--- a/content/renderer/render_widget_fullscreen_pepper.cc
+++ b/content/renderer/render_widget_fullscreen_pepper.cc
@@ -6,7 +6,6 @@
#include "base/message_loop.h"
#include "content/common/view_messages.h"
-#include "content/renderer/gpu/renderer_gl_context.h"
#include "content/renderer/gpu/gpu_channel_host.h"
#include "content/renderer/pepper_platform_context_3d_impl.h"
#include "content/renderer/render_thread.h"
@@ -471,7 +470,8 @@ void RenderWidgetFullscreenPepper::SwapBuffers() {
context_->SwapBuffers();
}
-void RenderWidgetFullscreenPepper::OnLostContext() {
+void RenderWidgetFullscreenPepper::OnLostContext(
+ RendererGLContext::ContextLostReason) {
if (!context_)
return;
// Destroy the context later, in case we got called from InitContext for
diff --git a/content/renderer/render_widget_fullscreen_pepper.h b/content/renderer/render_widget_fullscreen_pepper.h
index d22b418..1664034 100644
--- a/content/renderer/render_widget_fullscreen_pepper.h
+++ b/content/renderer/render_widget_fullscreen_pepper.h
@@ -6,6 +6,7 @@
#define CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_
#include "content/renderer/render_widget_fullscreen.h"
+#include "content/renderer/gpu/renderer_gl_context.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
#include "webkit/plugins/ppapi/fullscreen_container.h"
@@ -17,8 +18,6 @@ class PluginInstance;
} // namespace ppapi
} // namespace webkit
-class RendererGLContext;
-
// A RenderWidget that hosts a fullscreen pepper plugin. This provides a
// FullscreenContainer that the plugin instance can callback into to e.g.
// invalidate rects.
@@ -77,7 +76,7 @@ class RenderWidgetFullscreenPepper : public RenderWidgetFullscreen,
bool CheckCompositing();
// Called when the compositing context gets lost.
- void OnLostContext();
+ void OnLostContext(RendererGLContext::ContextLostReason);
// Binding of RendererGLContext swapbuffers callback to
// RenderWidget::OnSwapBuffersCompleted.
diff --git a/gpu/GLES2/gl2ext.h b/gpu/GLES2/gl2ext.h
index 7ad5ef1..1afb408 100644
--- a/gpu/GLES2/gl2ext.h
+++ b/gpu/GLES2/gl2ext.h
@@ -1010,6 +1010,26 @@ typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOCHROMIUM) ();
#endif
#endif
+/* GL_ARB_robustness */
+/* This extension is subsetted for the moment, incorporating only the
+ * enums necessary to describe the reasons that we might encounter for
+ * losing the context. The entry point querying the reset status is
+ * not yet incorporated; to do so, a spec will be needed of a GLES2
+ * subset of GL_ARB_robustness.
+ */
+#ifndef GL_ARB_robustness
+#define GL_ARB_robustness 1
+#ifndef GL_GUILTY_CONTEXT_RESET_ARB
+#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253
+#endif
+#ifndef GL_INNOCENT_CONTEXT_RESET_ARB
+#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254
+#endif
+#ifndef GL_UNKNOWN_CONTEXT_RESET_ARB
+#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index e2bf5aa..91df3e2 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1219,9 +1219,8 @@ _FUNCTION_INFO = {
'impl_decl': False,
},
'DrawArrays': {
- 'decoder_func': 'DoDrawArrays',
- 'unit_test': False,
- 'impl_decl': False,
+ 'type': 'Manual',
+ 'cmd_args': 'GLenum mode, GLint first, GLsizei count',
},
'DrawElements': {
'type': 'Manual',
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index cf555bd..d7b955e 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -171,7 +171,6 @@ class GLES2Implementation {
#include "../client/gles2_implementation_autogen.h"
void DisableVertexAttribArray(GLuint index);
- void DrawArrays(GLenum mode, GLint first, GLsizei count);
void EnableVertexAttribArray(GLuint index);
void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index edcb5da..270d303 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -324,6 +324,8 @@ void Disable(GLenum cap) {
helper_->Disable(cap);
}
+void DrawArrays(GLenum mode, GLint first, GLsizei count);
+
void DrawElements(
GLenum mode, GLsizei count, GLenum type, const void* indices);
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 9643b55..eb003a5 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -95,6 +95,11 @@ class GLES2MockCommandBufferHelper : public CommandBuffer {
state_.error = error;
}
+ virtual void SetContextLostReason(error::ContextLostReason reason) {
+ GPU_NOTREACHED();
+ state_.context_lost_reason = reason;
+ }
+
virtual void OnFlush(void* transfer_buffer) = 0;
private:
diff --git a/gpu/command_buffer/common/cmd_buffer_common.cc b/gpu/command_buffer/common/cmd_buffer_common.cc
index abfdc93..a9113b2 100644
--- a/gpu/command_buffer/common/cmd_buffer_common.cc
+++ b/gpu/command_buffer/common/cmd_buffer_common.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,8 @@
// command buffer commands.
#include "../common/cmd_buffer_common.h"
+#include "../common/command_buffer.h"
+#include "../common/logging.h"
namespace gpu {
#if !defined(_WIN32)
@@ -28,6 +30,17 @@ const char* GetCommandName(CommandId command_id) {
}
} // namespace cmd
+
+// TODO(kbr): this method body is here instead of command_buffer.cc
+// because NaCl currently compiles in this file but not the other.
+// Remove this method body and the includes of command_buffer.h and
+// logging.h above once NaCl defines SetContextLostReason() in its
+// CommandBuffer subclass and has been rolled forward. See
+// http://crbug.com/89127 .
+void CommandBuffer::SetContextLostReason(error::ContextLostReason) {
+ GPU_NOTREACHED();
+}
+
} // namespace gpu
diff --git a/gpu/command_buffer/common/command_buffer.h b/gpu/command_buffer/common/command_buffer.h
index d5fb24d..539098b 100644
--- a/gpu/command_buffer/common/command_buffer.h
+++ b/gpu/command_buffer/common/command_buffer.h
@@ -28,6 +28,7 @@ class CommandBuffer {
put_offset(0),
token(-1),
error(error::kNoError),
+ context_lost_reason(error::kUnknown),
generation(0) {
}
@@ -50,6 +51,9 @@ class CommandBuffer {
// Error status.
error::Error error;
+ // Lost context detail information.
+ error::ContextLostReason context_lost_reason;
+
// Generation index of this state. The generation index is incremented every
// time a new state is retrieved from the command processor, so that
// consistency can be kept even if IPC messages are processed out-of-order.
@@ -119,6 +123,17 @@ class CommandBuffer {
// Allows the reader to set the current parse error.
virtual void SetParseError(error::Error) = 0;
+ // Allows the reader to set the current context lost reason.
+ // NOTE: if calling this in conjunction with SetParseError,
+ // call this first.
+ //
+ // TODO(kbr): this temporarily has a definition (i.e., is not pure
+ // virtual) to work around a difficult interdependency with the NaCl
+ // build. Make this pure virtual and remove the body once this is
+ // defined in CommandBufferNaCl and NaCl has rolled forward. See
+ // http://crbug.com/89127 .
+ virtual void SetContextLostReason(error::ContextLostReason);
+
private:
DISALLOW_COPY_AND_ASSIGN(CommandBuffer);
};
diff --git a/gpu/command_buffer/common/command_buffer_mock.h b/gpu/command_buffer/common/command_buffer_mock.h
index 4da8e82..3243d17 100644
--- a/gpu/command_buffer/common/command_buffer_mock.h
+++ b/gpu/command_buffer/common/command_buffer_mock.h
@@ -36,6 +36,8 @@ class MockCommandBuffer : public CommandBuffer {
int32 id_request));
MOCK_METHOD1(SetToken, void(int32 token));
MOCK_METHOD1(SetParseError, void(error::Error error));
+ MOCK_METHOD1(SetContextLostReason,
+ void(error::ContextLostReason context_lost_reason));
private:
DISALLOW_COPY_AND_ASSIGN(MockCommandBuffer);
diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h
index 873dfa0..c204e87 100644
--- a/gpu/command_buffer/common/constants.h
+++ b/gpu/command_buffer/common/constants.h
@@ -44,6 +44,18 @@ namespace error {
return true;
}
}
+
+ // Provides finer grained information about why the context was lost.
+ enum ContextLostReason {
+ // This context definitely provoked the loss of context.
+ kGuilty,
+
+ // This context definitely did not provoke the loss of context.
+ kInnocent,
+
+ // It is unknown whether this context provoked the loss of context.
+ kUnknown
+ };
}
// Invalid shared memory Id, returned by RegisterSharedMemory in case of
diff --git a/gpu/command_buffer/common/gl_mock.h b/gpu/command_buffer/common/gl_mock.h
index 43e877b..ed39af4 100644
--- a/gpu/command_buffer/common/gl_mock.h
+++ b/gpu/command_buffer/common/gl_mock.h
@@ -431,6 +431,8 @@ class MockGLInterface : public GLInterface {
MOCK_METHOD3(GetFenceivNV, void(GLuint fence, GLenum pname, GLint *params));
MOCK_METHOD1(SetSurfaceCHROMIUM, void(GLuint));
+
+ MOCK_METHOD0(GetGraphicsResetStatusARB, GLenum());
};
} // namespace gfx
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index 37bf93e..1988472 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -341,6 +341,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x2600, "GL_NEAREST", },
{ 0x84C4, "GL_TEXTURE4", },
{ 0x85B5, "GL_VERTEX_ARRAY_BINDING_OES", },
+ { 0x8253, "GL_GUILTY_CONTEXT_RESET_ARB", },
{ 0x00200000, "GL_STENCIL_BUFFER_BIT5_QCOM", },
{ 0x8D61, "GL_HALF_FLOAT_OES", },
{ 0x8D62, "GL_RGB565", },
@@ -418,6 +419,8 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x8625, "GL_VERTEX_ATTRIB_ARRAY_TYPE", },
{ 0x8622, "GL_VERTEX_ATTRIB_ARRAY_ENABLED", },
{ 0x8623, "GL_VERTEX_ATTRIB_ARRAY_SIZE", },
+ { 0x8255, "GL_UNKNOWN_CONTEXT_RESET_ARB", },
+ { 0x8254, "GL_INNOCENT_CONTEXT_RESET_ARB", },
{ 0x1100, "GL_DONT_CARE", },
{ 0x1101, "GL_FASTEST", },
{ 0x1102, "GL_NICEST", },
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc
index b042a23..064341d 100644
--- a/gpu/command_buffer/service/command_buffer_service.cc
+++ b/gpu/command_buffer/service/command_buffer_service.cc
@@ -98,6 +98,7 @@ CommandBufferService::State CommandBufferService::GetState() {
state.put_offset = put_offset_;
state.token = token_;
state.error = error_;
+ state.context_lost_reason = context_lost_reason_;
state.generation = ++generation_;
return state;
@@ -254,6 +255,11 @@ void CommandBufferService::SetParseError(error::Error error) {
}
}
+void CommandBufferService::SetContextLostReason(
+ error::ContextLostReason reason) {
+ context_lost_reason_ = reason;
+}
+
void CommandBufferService::SetPutOffsetChangeCallback(
Callback1<bool>::Type* callback) {
put_offset_change_callback_.reset(callback);
diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h
index cffef5f..9c52531 100644
--- a/gpu/command_buffer/service/command_buffer_service.h
+++ b/gpu/command_buffer/service/command_buffer_service.h
@@ -40,6 +40,7 @@ class CommandBufferService : public CommandBuffer {
virtual Buffer GetTransferBuffer(int32 handle);
virtual void SetToken(int32 token);
virtual void SetParseError(error::Error error);
+ virtual void SetContextLostReason(error::ContextLostReason);
// Sets a callback that is called whenever the put offset is changed. When
// called with sync==true, the callback must not return until some progress
@@ -64,6 +65,7 @@ class CommandBufferService : public CommandBuffer {
int32 token_;
uint32 generation_;
error::Error error_;
+ error::ContextLostReason context_lost_reason_;
};
} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 045dfc3..e989af6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -496,6 +496,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
bool BoundFramebufferHasDepthAttachment();
bool BoundFramebufferHasStencilAttachment();
+ virtual error::ContextLostReason GetContextLostReason();
+
private:
friend class ScopedGLErrorSuppressor;
friend class ScopedResolvedFrameBufferBinder;
@@ -888,9 +890,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// Wrapper for glDetachShader
void DoDetachShader(GLuint client_program_id, GLint client_shader_id);
- // Wrapper for glDrawArrays.
- void DoDrawArrays(GLenum mode, GLint first, GLsizei count);
-
// Wrapper for glDisable
void DoDisable(GLenum cap);
@@ -1134,6 +1133,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
error::Error* error, GLuint* service_id, void** result,
GLenum* result_type);
+ // Returns true if the context was just lost due to e.g. GL_ARB_robustness.
+ bool WasContextLost();
+
// Generate a member function prototype for each command in an automated and
// typesafe way.
#define GLES2_CMD_OP(name) \
@@ -1301,6 +1303,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
int frame_number_;
+ bool has_arb_robustness_;
+ GLenum reset_status_;
+
DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
};
@@ -1637,7 +1642,9 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager,
validators_(group_->feature_info()->validators()),
feature_info_(group_->feature_info()),
tex_image_2d_failed_(false),
- frame_number_(0) {
+ frame_number_(0),
+ has_arb_robustness_(false),
+ reset_status_(GL_NO_ERROR) {
attrib_0_value_.v[0] = 0.0f;
attrib_0_value_.v[1] = 0.0f;
attrib_0_value_.v[2] = 0.0f;
@@ -1885,6 +1892,8 @@ bool GLES2DecoderImpl::Initialize(
glEnable(GL_POINT_SPRITE);
}
+ has_arb_robustness_ = context->HasExtension("GL_ARB_robustness");
+
if (!InitializeShaderTranslator()) {
return false;
}
@@ -2064,7 +2073,13 @@ void GLES2DecoderImpl::DeleteTexturesHelper(
// } // anonymous namespace
bool GLES2DecoderImpl::MakeCurrent() {
- return context_.get() ? context_->MakeCurrent(surface_.get()) : false;
+ bool result = context_.get() ? context_->MakeCurrent(surface_.get()) : false;
+ if (result && WasContextLost()) {
+ LOG(ERROR) << " GLES2DecoderImpl: Context lost during MakeCurrent.";
+ result = false;
+ }
+
+ return result;
}
void GLES2DecoderImpl::RestoreCurrentRenderbufferBindings() {
@@ -3361,43 +3376,6 @@ void GLES2DecoderImpl::DoClear(GLbitfield mask) {
}
}
-void GLES2DecoderImpl::DoDrawArrays(
- GLenum mode, GLint first, GLsizei count) {
- if (!CheckFramebufferComplete("glDrawArrays")) {
- return;
- }
- // We have to check this here because the prototype for glDrawArrays
- // is GLint not GLsizei.
- if (first < 0) {
- SetGLError(GL_INVALID_VALUE, "glDrawArrays: first < 0");
- return;
- }
-
- if (count == 0) {
- return;
- }
-
- GLuint max_vertex_accessed = first + count - 1;
- if (IsDrawValid(max_vertex_accessed)) {
- bool simulated_attrib_0 = SimulateAttrib0(max_vertex_accessed);
- bool simulated_fixed_attribs = false;
- if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) {
- bool textures_set = SetBlackTextureForNonRenderableTextures();
- ApplyDirtyState();
- glDrawArrays(mode, first, count);
- if (textures_set) {
- RestoreStateForNonRenderableTextures();
- }
- if (simulated_fixed_attribs) {
- RestoreStateForSimulatedFixedAttribs();
- }
- }
- if (simulated_attrib_0) {
- RestoreStateForSimulatedAttrib0();
- }
- }
-}
-
void GLES2DecoderImpl::DoFramebufferRenderbuffer(
GLenum target, GLenum attachment, GLenum renderbuffertarget,
GLuint client_renderbuffer_id) {
@@ -4371,6 +4349,59 @@ void GLES2DecoderImpl::RestoreStateForSimulatedFixedAttribs() {
bound_array_buffer_ ? bound_array_buffer_->service_id() : 0);
}
+error::Error GLES2DecoderImpl::HandleDrawArrays(
+ uint32 immediate_data_size, const gles2::DrawArrays& c) {
+ GLenum mode = static_cast<GLenum>(c.mode);
+ GLint first = static_cast<GLint>(c.first);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ if (!validators_->draw_mode.IsValid(mode)) {
+ SetGLError(GL_INVALID_ENUM, "glDrawArrays: mode GL_INVALID_ENUM");
+ return error::kNoError;
+ }
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDrawArrays: count < 0");
+ return error::kNoError;
+ }
+ if (!CheckFramebufferComplete("glDrawArrays")) {
+ return error::kNoError;
+ }
+ // We have to check this here because the prototype for glDrawArrays
+ // is GLint not GLsizei.
+ if (first < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDrawArrays: first < 0");
+ return error::kNoError;
+ }
+
+ if (count == 0) {
+ return error::kNoError;
+ }
+
+ GLuint max_vertex_accessed = first + count - 1;
+ if (IsDrawValid(max_vertex_accessed)) {
+ bool simulated_attrib_0 = SimulateAttrib0(max_vertex_accessed);
+ bool simulated_fixed_attribs = false;
+ if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) {
+ bool textures_set = SetBlackTextureForNonRenderableTextures();
+ ApplyDirtyState();
+ glDrawArrays(mode, first, count);
+ if (textures_set) {
+ RestoreStateForNonRenderableTextures();
+ }
+ if (simulated_fixed_attribs) {
+ RestoreStateForSimulatedFixedAttribs();
+ }
+ }
+ if (simulated_attrib_0) {
+ RestoreStateForSimulatedAttrib0();
+ }
+ if (WasContextLost()) {
+ LOG(ERROR) << " GLES2DecoderImpl: Context lost during DrawArrays.";
+ return error::kLostContext;
+ }
+ }
+ return error::kNoError;
+}
+
error::Error GLES2DecoderImpl::HandleDrawElements(
uint32 immediate_data_size, const gles2::DrawElements& c) {
if (!bound_element_array_buffer_ ||
@@ -4435,6 +4466,10 @@ error::Error GLES2DecoderImpl::HandleDrawElements(
if (simulated_attrib_0) {
RestoreStateForSimulatedAttrib0();
}
+ if (WasContextLost()) {
+ LOG(ERROR) << " GLES2DecoderImpl: Context lost during DrawElements.";
+ return error::kLostContext;
+ }
}
return error::kNoError;
}
@@ -6730,6 +6765,39 @@ error::Error GLES2DecoderImpl::HandleGetProgramInfoCHROMIUM(
return error::kNoError;
}
+error::ContextLostReason GLES2DecoderImpl::GetContextLostReason() {
+ switch (reset_status_) {
+ case GL_NO_ERROR:
+ // TODO(kbr): improve the precision of the error code in this case.
+ // Consider delegating to context for error code if MakeCurrent fails.
+ return error::kUnknown;
+ case GL_GUILTY_CONTEXT_RESET_ARB:
+ return error::kGuilty;
+ case GL_INNOCENT_CONTEXT_RESET_ARB:
+ return error::kInnocent;
+ case GL_UNKNOWN_CONTEXT_RESET_ARB:
+ return error::kUnknown;
+ }
+
+ NOTREACHED();
+ return error::kUnknown;
+}
+
+bool GLES2DecoderImpl::WasContextLost() {
+ if (context_->WasAllocatedUsingARBRobustness() && has_arb_robustness_) {
+ GLenum 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"
+ << std::hex << status << std::dec;
+ return true;
+ }
+ }
+ return false;
+}
+
// Include the auto-generated part of this file. We split this because it means
// we can easily edit the non-auto generated parts right here in this file
// instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 0551e5a..abd2b85 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -120,6 +120,9 @@ class GLES2Decoder : public CommonDecoder {
virtual bool GetServiceTextureId(uint32 client_texture_id,
uint32* service_texture_id);
+ // Provides detail about a lost context if one occurred.
+ virtual error::ContextLostReason GetContextLostReason() = 0;
+
protected:
GLES2Decoder();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 89cf621..44cba0b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -630,23 +630,6 @@ error::Error GLES2DecoderImpl::HandleDisableVertexAttribArray(
return error::kNoError;
}
-error::Error GLES2DecoderImpl::HandleDrawArrays(
- uint32 immediate_data_size, const gles2::DrawArrays& c) {
- GLenum mode = static_cast<GLenum>(c.mode);
- GLint first = static_cast<GLint>(c.first);
- GLsizei count = static_cast<GLsizei>(c.count);
- if (!validators_->draw_mode.IsValid(mode)) {
- SetGLError(GL_INVALID_ENUM, "glDrawArrays: mode GL_INVALID_ENUM");
- return error::kNoError;
- }
- if (count < 0) {
- SetGLError(GL_INVALID_VALUE, "glDrawArrays: count < 0");
- return error::kNoError;
- }
- DoDrawArrays(mode, first, count);
- return error::kNoError;
-}
-
error::Error GLES2DecoderImpl::HandleEnable(
uint32 immediate_data_size, const gles2::Enable& c) {
GLenum cap = static_cast<GLenum>(c.cap);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 0a44ecf..2f1275c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -54,6 +54,7 @@ class MockGLES2Decoder : public GLES2Decoder {
const void* cmd_data));
MOCK_METHOD2(GetServiceTextureId, bool(uint32 client_texture_id,
uint32* service_texture_id));
+ MOCK_METHOD0(GetContextLostReason, error::ContextLostReason());
MOCK_CONST_METHOD1(GetCommandName, const char*(unsigned int command_id));
DISALLOW_COPY_AND_ASSIGN(MockGLES2Decoder);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index fe90c47..209f259 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -704,6 +704,7 @@ TEST_F(GLES2DecoderTest1, DisableVertexAttribArrayValidArgs) {
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
// TODO(gman): DrawArrays
+
// TODO(gman): DrawElements
diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc
index 0a7d1dd..9365118 100644
--- a/gpu/command_buffer/service/gpu_scheduler.cc
+++ b/gpu/command_buffer/service/gpu_scheduler.cc
@@ -170,6 +170,7 @@ void GpuScheduler::ProcessCommands() {
if (decoder_.get()) {
if (!decoder_->MakeCurrent()) {
LOG(ERROR) << "Context lost because MakeCurrent failed.";
+ command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
command_buffer_->SetParseError(error::kLostContext);
return;
}
@@ -213,6 +214,7 @@ void GpuScheduler::ProcessCommands() {
is_break = true;
break;
} else if (error::IsError(error)) {
+ command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
command_buffer_->SetParseError(error);
return;
}
diff --git a/gpu/command_buffer/service/gpu_scheduler_unittest.cc b/gpu/command_buffer/service/gpu_scheduler_unittest.cc
index 8cdb361..3d21f90 100644
--- a/gpu/command_buffer/service/gpu_scheduler_unittest.cc
+++ b/gpu/command_buffer/service/gpu_scheduler_unittest.cc
@@ -217,6 +217,8 @@ TEST_F(GpuSchedulerTest, SetsErrorCodeOnCommandBuffer) {
error::kUnknownCommand));
EXPECT_CALL(*command_buffer_, SetGetOffset(1));
+ EXPECT_CALL(*decoder_, GetContextLostReason())
+ .WillOnce(Return(error::kUnknown));
EXPECT_CALL(*command_buffer_,
SetParseError(error::kUnknownCommand));
diff --git a/ppapi/proxy/ppb_context_3d_proxy.cc b/ppapi/proxy/ppb_context_3d_proxy.cc
index d31ad29..ff2fe93 100644
--- a/ppapi/proxy/ppb_context_3d_proxy.cc
+++ b/ppapi/proxy/ppb_context_3d_proxy.cc
@@ -98,6 +98,7 @@ class PepperCommandBuffer : public gpu::CommandBuffer {
virtual gpu::Buffer GetTransferBuffer(int32 handle);
virtual void SetToken(int32 token);
virtual void SetParseError(gpu::error::Error error);
+ virtual void SetContextLostReason(gpu::error::ContextLostReason reason);
private:
bool Send(IPC::Message* msg);
@@ -308,6 +309,11 @@ void PepperCommandBuffer::SetParseError(gpu::error::Error error) {
NOTREACHED();
}
+void PepperCommandBuffer::SetContextLostReason(
+ gpu::error::ContextLostReason reason) {
+ NOTREACHED();
+}
+
bool PepperCommandBuffer::Send(IPC::Message* msg) {
DCHECK(last_state_.error == gpu::error::kNoError);
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);
};
diff --git a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
index 9a6f472..0b623cc 100644
--- a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -752,6 +752,7 @@ WebGraphicsContext3DInProcessCommandBufferImpl::
plugin_handle_(NULL),
#endif // defined(OS_MACOSX)
context_lost_callback_(0),
+ context_lost_reason_(GL_NO_ERROR),
cached_width_(0),
cached_height_(0),
bound_fbo_(0) {
@@ -1788,7 +1789,14 @@ void WebGraphicsContext3DInProcessCommandBufferImpl::setContextLostCallback(
context_lost_callback_ = cb;
}
+WGC3Denum WebGraphicsContext3DInProcessCommandBufferImpl::
+ getGraphicsResetStatusARB() {
+ return context_lost_reason_;
+}
+
void WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost() {
+ // TODO(kbr): improve the precision here.
+ context_lost_reason_ = GL_UNKNOWN_CONTEXT_RESET_ARB;
if (context_lost_callback_) {
context_lost_callback_->onContextLost();
}
diff --git a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
index 3b6aaa8..5e2df99 100644
--- a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
+++ b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
@@ -429,6 +429,7 @@ class WebGraphicsContext3DInProcessCommandBufferImpl
virtual void setContextLostCallback(
WebGraphicsContext3D::WebGraphicsContextLostCallback* callback);
+ virtual WGC3Denum getGraphicsResetStatusARB();
private:
// SwapBuffers callback.
@@ -451,6 +452,7 @@ class WebGraphicsContext3DInProcessCommandBufferImpl
gfx::PluginWindowHandle plugin_handle_;
#endif
WebGraphicsContext3D::WebGraphicsContextLostCallback* context_lost_callback_;
+ WGC3Denum context_lost_reason_;
WebKit::WebGraphicsContext3D::Attributes attributes_;
int cached_width_, cached_height_;
diff --git a/webkit/gpu/webgraphicscontext3d_in_process_impl.cc b/webkit/gpu/webgraphicscontext3d_in_process_impl.cc
index 300bd27..e7d5757 100644
--- a/webkit/gpu/webgraphicscontext3d_in_process_impl.cc
+++ b/webkit/gpu/webgraphicscontext3d_in_process_impl.cc
@@ -1573,6 +1573,11 @@ void WebGraphicsContext3DInProcessImpl::deleteTexture(WebGLId texture) {
glDeleteTextures(1, &texture);
}
+WGC3Denum WebGraphicsContext3DInProcessImpl::getGraphicsResetStatusARB() {
+ // TODO(kbr): this implementation doesn't support lost contexts yet.
+ return GL_NO_ERROR;
+}
+
bool WebGraphicsContext3DInProcessImpl::AngleCreateCompilers() {
if (!ShInitialize())
return false;
diff --git a/webkit/gpu/webgraphicscontext3d_in_process_impl.h b/webkit/gpu/webgraphicscontext3d_in_process_impl.h
index 304f9fb..aafff28 100644
--- a/webkit/gpu/webgraphicscontext3d_in_process_impl.h
+++ b/webkit/gpu/webgraphicscontext3d_in_process_impl.h
@@ -407,6 +407,7 @@ class WebGraphicsContext3DInProcessImpl : public WebGraphicsContext3D {
virtual void setContextLostCallback(
WebGraphicsContext3D::WebGraphicsContextLostCallback* callback) {}
+ virtual WGC3Denum getGraphicsResetStatusARB();
private:
// ANGLE related.