summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service
diff options
context:
space:
mode:
Diffstat (limited to 'gpu/command_buffer/service')
-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
9 files changed, 127 insertions, 59 deletions
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 618829fb..9295279 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));