diff options
Diffstat (limited to 'gpu/command_buffer/service')
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)); |