From 1285660590d371fedced6253c43be569c2d054ee Mon Sep 17 00:00:00 2001 From: sunnyps Date: Fri, 9 Dec 2016 13:06:43 -0800 Subject: [PATCH] gpu: Thread-safe command buffer state lookup. This makes client side (in-process / proxy) command buffer state thread- safe and adds release count to the client-server shared state. This allows the compositor thread to monitor worker context sync token in the service. Client side command buffer state is synchronized using a lock. Extra caching of the state is added to command buffer helper so that it doesn't acquire the lock for every command. Also fixes command buffer memory tracing so that it happens on the same thread which the context provider is bound to. R=piman@chromium.org,jbauman@chromium.org BUG=514813,638862 CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel Review-Url: https://codereview.chromium.org/2550583002 Cr-Commit-Position: refs/heads/master@{#437651} --- cc/test/test_context_support.cc | 4 + cc/test/test_context_support.h | 1 + .../client/context_provider_command_buffer.cc | 7 +- .../renderer/pepper/ppb_graphics_3d_impl.cc | 6 +- .../client/client_test_helper.cc | 46 +++-- .../client/client_test_helper.h | 7 +- .../client/cmd_buffer_helper.cc | 78 +++++---- gpu/command_buffer/client/cmd_buffer_helper.h | 54 ++---- .../client/cmd_buffer_helper_test.cc | 6 +- gpu/command_buffer/client/context_support.h | 4 + .../client/gles2_implementation.cc | 17 +- .../client/gles2_implementation.h | 3 +- gpu/command_buffer/client/gpu_control.h | 25 ++- gpu/command_buffer/client/ring_buffer.cc | 3 +- .../common/cmd_buffer_common.cc | 11 -- gpu/command_buffer/common/command_buffer.h | 27 +-- .../common/command_buffer_mock.h | 5 +- .../service/command_buffer_service.cc | 30 ++-- .../service/command_buffer_service.h | 10 +- gpu/command_buffer/tests/gl_manager.cc | 9 + gpu/command_buffer/tests/gl_manager.h | 3 + .../tests/gl_readback_unittest.cc | 7 +- gpu/gles2_conform_support/egl/context.cc | 5 + gpu/gles2_conform_support/egl/context.h | 1 + gpu/ipc/client/command_buffer_proxy_impl.cc | 157 +++++++++++++----- gpu/ipc/client/command_buffer_proxy_impl.h | 31 ++-- gpu/ipc/in_process_command_buffer.cc | 76 ++++----- gpu/ipc/in_process_command_buffer.h | 12 +- gpu/ipc/service/gpu_command_buffer_stub.cc | 1 + ppapi/proxy/ppapi_command_buffer_proxy.cc | 48 +++--- ppapi/proxy/ppapi_command_buffer_proxy.h | 6 +- 31 files changed, 390 insertions(+), 310 deletions(-) diff --git a/cc/test/test_context_support.cc b/cc/test/test_context_support.cc index e1b94a5d278b63..74d9983efbd8c5 100644 --- a/cc/test/test_context_support.cc +++ b/cc/test/test_context_support.cc @@ -27,6 +27,10 @@ void TestContextSupport::SignalSyncToken(const gpu::SyncToken& sync_token, weak_ptr_factory_.GetWeakPtr())); } +bool TestContextSupport::IsFenceSyncReleased(uint64_t release) { + return true; +} + void TestContextSupport::SignalQuery(uint32_t query, const base::Closure& callback) { sync_point_callbacks_.push_back(callback); diff --git a/cc/test/test_context_support.h b/cc/test/test_context_support.h index cbab29656f5a7d..2f1cc997910224 100644 --- a/cc/test/test_context_support.h +++ b/cc/test/test_context_support.h @@ -29,6 +29,7 @@ class TestContextSupport : public gpu::ContextSupport { // gpu::ContextSupport implementation. void SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) override; + bool IsFenceSyncReleased(uint64_t release) override; void SignalQuery(uint32_t query, const base::Closure& callback) override; void SetAggressivelyFreeResources(bool aggressively_free_resources) override; void Swap() override; diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc index 74bbf375caece9..5aa148499e8542 100644 --- a/content/common/gpu/client/context_provider_command_buffer.cc +++ b/content/common/gpu/client/context_provider_command_buffer.cc @@ -292,9 +292,9 @@ bool ContextProviderCommandBuffer::BindToCurrentThread() { return false; } - if (command_buffer_->GetLastError() != gpu::error::kNoError) { + if (command_buffer_->GetLastState().error != gpu::error::kNoError) { DLOG(ERROR) << "Context dead on arrival. Last error: " - << command_buffer_->GetLastError(); + << command_buffer_->GetLastState().error; return false; } @@ -454,6 +454,9 @@ bool ContextProviderCommandBuffer::OnMemoryDump( if (support_locking_) hold.emplace(context_lock_); + gles2_impl_->OnMemoryDump(args, pmd); + gles2_helper_->OnMemoryDump(args, pmd); + context_thread_checker_.DetachFromThread(); SkiaGpuTraceMemoryDump trace_memory_dump( pmd, gles2_impl_->ShareGroupTracingGUID()); diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc index 6db7f7b3b65253..3cd4671be0e791 100644 --- a/content/renderer/pepper/ppb_graphics_3d_impl.cc +++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc @@ -117,15 +117,13 @@ PP_Bool PPB_Graphics3D_Impl::Flush(int32_t put_offset) { gpu::CommandBuffer::State PPB_Graphics3D_Impl::WaitForTokenInRange( int32_t start, int32_t end) { - GetCommandBuffer()->WaitForTokenInRange(start, end); - return GetCommandBuffer()->GetLastState(); + return GetCommandBuffer()->WaitForTokenInRange(start, end); } gpu::CommandBuffer::State PPB_Graphics3D_Impl::WaitForGetOffsetInRange( int32_t start, int32_t end) { - GetCommandBuffer()->WaitForGetOffsetInRange(start, end); - return GetCommandBuffer()->GetLastState(); + return GetCommandBuffer()->WaitForGetOffsetInRange(start, end); } void PPB_Graphics3D_Impl::EnsureWorkVisible() { diff --git a/gpu/command_buffer/client/client_test_helper.cc b/gpu/command_buffer/client/client_test_helper.cc index ff7e06944875ac..12c889c6424816 100644 --- a/gpu/command_buffer/client/client_test_helper.cc +++ b/gpu/command_buffer/client/client_test_helper.cc @@ -20,30 +20,33 @@ using ::testing::Invoke; namespace gpu { -MockCommandBufferBase::MockCommandBufferBase() : put_offset_(0) { -} +MockCommandBufferBase::MockCommandBufferBase() : put_offset_(0) {} -MockCommandBufferBase::~MockCommandBufferBase() { -} +MockCommandBufferBase::~MockCommandBufferBase() {} CommandBuffer::State MockCommandBufferBase::GetLastState() { return state_; } -int32_t MockCommandBufferBase::GetLastToken() { - return state_.token; -} - void MockCommandBufferBase::SetGetOffset(int32_t get_offset) { state_.get_offset = get_offset; } -void MockCommandBufferBase::WaitForTokenInRange(int32_t start, int32_t end) {} +void MockCommandBufferBase::SetReleaseCount(uint64_t release_count) { + state_.release_count = release_count; +} + +CommandBuffer::State MockCommandBufferBase::WaitForTokenInRange(int32_t start, + int32_t end) { + return state_; +} -void MockCommandBufferBase::WaitForGetOffsetInRange(int32_t start, - int32_t end) { +CommandBuffer::State MockCommandBufferBase::WaitForGetOffsetInRange( + int32_t start, + int32_t end) { state_.get_offset = put_offset_; OnFlush(); + return state_; } void MockCommandBufferBase::SetGetBuffer(int transfer_buffer_id) { @@ -125,8 +128,7 @@ MockClientCommandBuffer::MockClientCommandBuffer() { DelegateToFake(); } -MockClientCommandBuffer::~MockClientCommandBuffer() { -} +MockClientCommandBuffer::~MockClientCommandBuffer() {} void MockClientCommandBuffer::Flush(int32_t put_offset) { FlushHelper(put_offset); @@ -138,30 +140,24 @@ void MockClientCommandBuffer::OrderingBarrier(int32_t put_offset) { void MockClientCommandBuffer::DelegateToFake() { ON_CALL(*this, DestroyTransferBuffer(_)) - .WillByDefault(Invoke( - this, &MockCommandBufferBase::DestroyTransferBufferHelper)); + .WillByDefault( + Invoke(this, &MockCommandBufferBase::DestroyTransferBufferHelper)); } MockClientCommandBufferMockFlush::MockClientCommandBufferMockFlush() { DelegateToFake(); } -MockClientCommandBufferMockFlush::~MockClientCommandBufferMockFlush() { -} +MockClientCommandBufferMockFlush::~MockClientCommandBufferMockFlush() {} void MockClientCommandBufferMockFlush::DelegateToFake() { MockClientCommandBuffer::DelegateToFake(); ON_CALL(*this, Flush(_)) - .WillByDefault(Invoke( - this, &MockCommandBufferBase::FlushHelper)); + .WillByDefault(Invoke(this, &MockCommandBufferBase::FlushHelper)); } -MockClientGpuControl::MockClientGpuControl() { -} +MockClientGpuControl::MockClientGpuControl() {} -MockClientGpuControl::~MockClientGpuControl() { -} +MockClientGpuControl::~MockClientGpuControl() {} } // namespace gpu - - diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h index e34f7d427d92b9..9df3e6bac71f0b 100644 --- a/gpu/command_buffer/client/client_test_helper.h +++ b/gpu/command_buffer/client/client_test_helper.h @@ -33,11 +33,11 @@ class MockCommandBufferBase : public CommandBufferServiceBase { ~MockCommandBufferBase() override; State GetLastState() override; - int32_t GetLastToken() override; - void WaitForTokenInRange(int32_t start, int32_t end) override; - void WaitForGetOffsetInRange(int32_t start, int32_t end) override; + State WaitForTokenInRange(int32_t start, int32_t end) override; + State WaitForGetOffsetInRange(int32_t start, int32_t end) override; void SetGetBuffer(int transfer_buffer_id) override; void SetGetOffset(int32_t get_offset) override; + void SetReleaseCount(uint64_t release_count) override; scoped_refptr CreateTransferBuffer(size_t size, int32_t* id) override; scoped_refptr GetTransferBuffer(int32_t id) override; @@ -119,6 +119,7 @@ class MockClientGpuControl : public GpuControl { MOCK_METHOD1(IsFenceSyncRelease, bool(uint64_t release)); MOCK_METHOD1(IsFenceSyncFlushed, bool(uint64_t release)); MOCK_METHOD1(IsFenceSyncFlushReceived, bool(uint64_t release)); + MOCK_METHOD1(IsFenceSyncReleased, bool(uint64_t release)); MOCK_METHOD2(SignalSyncToken, void(const SyncToken& sync_token, const base::Closure& callback)); MOCK_METHOD1(CanWaitUnverifiedSyncToken, bool(const SyncToken*)); diff --git a/gpu/command_buffer/client/cmd_buffer_helper.cc b/gpu/command_buffer/client/cmd_buffer_helper.cc index 0304b8f7e5d1ae..7021fa399f4ccf 100644 --- a/gpu/command_buffer/client/cmd_buffer_helper.cc +++ b/gpu/command_buffer/client/cmd_buffer_helper.cc @@ -27,12 +27,14 @@ CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer) : command_buffer_(command_buffer), ring_buffer_id_(-1), ring_buffer_size_(0), - entries_(NULL), + entries_(nullptr), total_entry_count_(0), immediate_entry_count_(0), token_(0), put_(0), last_put_sent_(0), + cached_last_token_read_(0), + cached_get_offset_(0), #if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK) commands_issued_(0), #endif @@ -40,13 +42,6 @@ CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer) context_lost_(false), flush_automatically_(true), flush_generation_(0) { - // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). - // Don't register a dump provider in these cases. - // TODO(ericrk): Get this working in Android Webview. crbug.com/517156 - if (base::ThreadTaskRunnerHandle::IsSet()) { - base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( - this, "gpu::CommandBufferHelper", base::ThreadTaskRunnerHandle::Get()); - } } void CommandBufferHelper::SetAutomaticFlushes(bool enabled) { @@ -55,9 +50,8 @@ void CommandBufferHelper::SetAutomaticFlushes(bool enabled) { } bool CommandBufferHelper::IsContextLost() { - if (!context_lost_) { - context_lost_ = error::IsError(command_buffer()->GetLastError()); - } + if (!context_lost_) + context_lost_ = error::IsError(command_buffer()->GetLastState().error); return context_lost_; } @@ -71,7 +65,7 @@ void CommandBufferHelper::CalcImmediateEntries(int waiting_count) { } // Get maximum safe contiguous entries. - const int32_t curr_get = get_offset(); + const int32_t curr_get = cached_get_offset_; if (curr_get > put_) { immediate_entry_count_ = curr_get - put_ - 1; } else { @@ -116,7 +110,7 @@ bool CommandBufferHelper::AllocateRingBuffer() { command_buffer_->CreateTransferBuffer(ring_buffer_size_, &id); if (id < 0) { ClearUsable(); - DCHECK(error::IsError(command_buffer()->GetLastError())); + DCHECK(context_lost_); return false; } @@ -128,6 +122,7 @@ bool CommandBufferHelper::AllocateRingBuffer() { // Call to SetGetBuffer(id) above resets get and put offsets to 0. // No need to query it through IPC. put_ = 0; + cached_get_offset_ = 0; CalcImmediateEntries(0); return true; } @@ -143,8 +138,8 @@ void CommandBufferHelper::FreeResources() { } void CommandBufferHelper::FreeRingBuffer() { - CHECK((put_ == get_offset()) || - error::IsError(command_buffer_->GetLastState().error)); + CHECK((put_ == cached_get_offset_) || + error::IsError(command_buffer_->GetLastState().error)); FreeResources(); } @@ -154,19 +149,25 @@ bool CommandBufferHelper::Initialize(int32_t ring_buffer_size) { } CommandBufferHelper::~CommandBufferHelper() { - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - this); FreeResources(); } +void CommandBufferHelper::UpdateCachedState(const CommandBuffer::State& state) { + cached_get_offset_ = state.get_offset; + cached_last_token_read_ = state.token; + context_lost_ = error::IsError(state.error); +} + bool CommandBufferHelper::WaitForGetOffsetInRange(int32_t start, int32_t end) { DCHECK(start >= 0 && start <= total_entry_count_); DCHECK(end >= 0 && end <= total_entry_count_); if (!usable()) { return false; } - command_buffer_->WaitForGetOffsetInRange(start, end); - return command_buffer_->GetLastError() == gpu::error::kNoError; + CommandBuffer::State last_state = + command_buffer_->WaitForGetOffsetInRange(start, end); + UpdateCachedState(last_state); + return !context_lost_; } void CommandBufferHelper::Flush() { @@ -213,7 +214,7 @@ bool CommandBufferHelper::Finish() { return false; } // If there is no work just exit. - if (put_ == get_offset()) { + if (put_ == cached_get_offset_) { return true; } DCHECK(HaveRingBuffer() || @@ -221,7 +222,7 @@ bool CommandBufferHelper::Finish() { Flush(); if (!WaitForGetOffsetInRange(put_, put_)) return false; - DCHECK_EQ(get_offset(), put_); + DCHECK_EQ(cached_get_offset_, put_); CalcImmediateEntries(0); @@ -246,14 +247,25 @@ int32_t CommandBufferHelper::InsertToken() { cmd->Init(token_); if (token_ == 0) { TRACE_EVENT0("gpu", "CommandBufferHelper::InsertToken(wrapped)"); - // we wrapped - Finish(); - DCHECK_EQ(token_, last_token_read()); + bool finished = Finish(); // we wrapped + DCHECK(!finished || (cached_last_token_read_ == 0)); } } return token_; } +bool CommandBufferHelper::HasTokenPassed(int32_t token) { + // If token_ wrapped around we Finish'd. + if (token > token_) + return true; + // Don't update state if we don't have to. + if (token <= cached_last_token_read_) + return true; + CommandBuffer::State last_state = command_buffer_->GetLastState(); + UpdateCachedState(last_state); + return token <= cached_last_token_read_; +} + // Waits until the current token value is greater or equal to the value passed // in argument. void CommandBufferHelper::WaitForToken(int32_t token) { @@ -263,11 +275,17 @@ void CommandBufferHelper::WaitForToken(int32_t token) { // Return immediately if corresponding InsertToken failed. if (token < 0) return; - if (token > token_) return; // we wrapped - if (last_token_read() >= token) + if (token > token_) + return; // we wrapped + if (cached_last_token_read_ >= token) + return; + UpdateCachedState(command_buffer_->GetLastState()); + if (cached_last_token_read_ >= token) return; Flush(); - command_buffer_->WaitForTokenInRange(token, token_); + CommandBuffer::State last_state = + command_buffer_->WaitForTokenInRange(token, token_); + UpdateCachedState(last_state); } // Waits for available entries, basically waiting until get >= put + count + 1. @@ -288,13 +306,13 @@ void CommandBufferHelper::WaitForAvailableEntries(int32_t count) { // but we need to make sure get wraps first, actually that get is 1 or // more (since put will wrap to 0 after we add the noops). DCHECK_LE(1, put_); - int32_t curr_get = get_offset(); + int32_t curr_get = cached_get_offset_; if (curr_get > put_ || curr_get == 0) { TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries"); Flush(); if (!WaitForGetOffsetInRange(1, put_)) return; - curr_get = get_offset(); + curr_get = cached_get_offset_; DCHECK_LE(curr_get, put_); DCHECK_NE(0, curr_get); } @@ -328,7 +346,7 @@ void CommandBufferHelper::WaitForAvailableEntries(int32_t count) { } int32_t CommandBufferHelper::GetTotalFreeEntriesNoWaiting() const { - int32_t current_get_offset = get_offset(); + int32_t current_get_offset = cached_get_offset_; if (current_get_offset > put_) { return current_get_offset - put_ - 1; } else { diff --git a/gpu/command_buffer/client/cmd_buffer_helper.h b/gpu/command_buffer/client/cmd_buffer_helper.h index 0c0edddfd7bab7..3ea507f897547e 100644 --- a/gpu/command_buffer/client/cmd_buffer_helper.h +++ b/gpu/command_buffer/client/cmd_buffer_helper.h @@ -102,11 +102,7 @@ class GPU_EXPORT CommandBufferHelper // Returns true if the token has passed. // Parameters: // the value of the token to check whether it has passed - bool HasTokenPassed(int32_t token) const { - if (token > token_) - return true; // we wrapped - return last_token_read() >= token; - } + bool HasTokenPassed(int32_t token); // Waits until the token of a particular value has passed through the command // stream (i.e. commands inserted before that token have been executed). @@ -179,12 +175,6 @@ class GPU_EXPORT CommandBufferHelper return data; } - int32_t last_token_read() const { return command_buffer_->GetLastToken(); } - - int32_t get_offset() const { - return command_buffer_->GetLastState().get_offset; - } - // Common Commands void Noop(uint32_t skip_count) { cmd::Noop* cmd = GetImmediateCmdSpace( @@ -215,10 +205,7 @@ class GPU_EXPORT CommandBufferHelper uint32_t shared_memory_offset) { cmd::SetBucketData* cmd = GetCmdSpace(); if (cmd) { - cmd->Init(bucket_id, - offset, - size, - shared_memory_id, + cmd->Init(bucket_id, offset, size, shared_memory_id, shared_memory_offset); } } @@ -243,12 +230,8 @@ class GPU_EXPORT CommandBufferHelper uint32_t data_memory_offset) { cmd::GetBucketStart* cmd = GetCmdSpace(); if (cmd) { - cmd->Init(bucket_id, - result_memory_id, - result_memory_offset, - data_memory_size, - data_memory_id, - data_memory_offset); + cmd->Init(bucket_id, result_memory_id, result_memory_offset, + data_memory_size, data_memory_id, data_memory_offset); } } @@ -259,17 +242,12 @@ class GPU_EXPORT CommandBufferHelper uint32_t shared_memory_offset) { cmd::GetBucketData* cmd = GetCmdSpace(); if (cmd) { - cmd->Init(bucket_id, - offset, - size, - shared_memory_id, + cmd->Init(bucket_id, offset, size, shared_memory_id, shared_memory_offset); } } - CommandBuffer* command_buffer() const { - return command_buffer_; - } + CommandBuffer* command_buffer() const { return command_buffer_; } scoped_refptr get_ring_buffer() const { return ring_buffer_; } @@ -277,13 +255,9 @@ class GPU_EXPORT CommandBufferHelper void FreeRingBuffer(); - bool HaveRingBuffer() const { - return ring_buffer_id_ != -1; - } + bool HaveRingBuffer() const { return ring_buffer_id_ != -1; } - bool usable () const { - return usable_; - } + bool usable() const { return usable_; } void ClearUsable() { usable_ = false; @@ -296,11 +270,6 @@ class GPU_EXPORT CommandBufferHelper base::trace_event::ProcessMemoryDump* pmd) override; private: - // Returns the number of available entries (they may not be contiguous). - int32_t AvailableEntries() { - return (get_offset() - put_ - 1 + total_entry_count_) % total_entry_count_; - } - void CalcImmediateEntries(int waiting_count); bool AllocateRingBuffer(); void FreeResources(); @@ -316,6 +285,10 @@ class GPU_EXPORT CommandBufferHelper int32_t GetTotalFreeEntriesNoWaiting() const; + // Updates |cached_get_offset_|, |cached_last_token_read_| and |context_lost_| + // from given command buffer state. + void UpdateCachedState(const CommandBuffer::State& state); + CommandBuffer* command_buffer_; int32_t ring_buffer_id_; int32_t ring_buffer_size_; @@ -326,7 +299,8 @@ class GPU_EXPORT CommandBufferHelper int32_t token_; int32_t put_; int32_t last_put_sent_; - int32_t last_barrier_put_sent_; + int32_t cached_last_token_read_; + int32_t cached_get_offset_; #if defined(CMD_HELPER_PERIODIC_FLUSH_CHECK) int commands_issued_; diff --git a/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/gpu/command_buffer/client/cmd_buffer_helper_test.cc index 40ae25e700f904..3489ea8b8dea51 100644 --- a/gpu/command_buffer/client/cmd_buffer_helper_test.cc +++ b/gpu/command_buffer/client/cmd_buffer_helper_test.cc @@ -68,7 +68,7 @@ class CommandBufferServiceLocked : public CommandBufferService { int FlushCount() { return flush_count_; } - void WaitForGetOffsetInRange(int32_t start, int32_t end) override { + State WaitForGetOffsetInRange(int32_t start, int32_t end) override { // Flush only if it's required to unblock this Wait. if (last_flush_ != -1 && !CommandBuffer::InRange(start, end, previous_put_offset_)) { @@ -76,7 +76,7 @@ class CommandBufferServiceLocked : public CommandBufferService { CommandBufferService::Flush(last_flush_); last_flush_ = -1; } - CommandBufferService::WaitForGetOffsetInRange(start, end); + return CommandBufferService::WaitForGetOffsetInRange(start, end); } private: @@ -247,7 +247,7 @@ class CommandBufferHelperTest : public testing::Test { int32_t GetPutOffset() { return command_buffer_->GetPutOffset(); } - int32_t GetHelperGetOffset() { return helper_->get_offset(); } + int32_t GetHelperGetOffset() { return helper_->cached_get_offset_; } int32_t GetHelperPutOffset() { return helper_->put_; } diff --git a/gpu/command_buffer/client/context_support.h b/gpu/command_buffer/client/context_support.h index c2d71734144a74..f15da14cc8e8af 100644 --- a/gpu/command_buffer/client/context_support.h +++ b/gpu/command_buffer/client/context_support.h @@ -25,6 +25,10 @@ class ContextSupport { virtual void SignalSyncToken(const SyncToken& sync_token, const base::Closure& callback) = 0; + // Returns true if the given fence sync has been released (executed) by the + // command buffer. This may be called from any thread. + virtual bool IsFenceSyncReleased(uint64_t release_count) = 0; + // Runs |callback| when a query created via glCreateQueryEXT() has cleared // passed the glEndQueryEXT() point. virtual void SignalQuery(uint32_t query, const base::Closure& callback) = 0; diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 0f12cd4c93d2c8..155d1efd218b59 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -262,21 +262,10 @@ bool GLES2Implementation::Initialize( return false; } - // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). - // Don't register a dump provider in these cases. - // TODO(ericrk): Get this working in Android Webview. crbug.com/517156 - if (base::ThreadTaskRunnerHandle::IsSet()) { - base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( - this, "GLES2Implementation", base::ThreadTaskRunnerHandle::Get()); - } - return true; } GLES2Implementation::~GLES2Implementation() { - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - this); - // Make sure the queries are finished otherwise we'll delete the // shared memory (mapped_memory_) which will free the memory used // by the queries. The GPU process when validating that memory is still @@ -405,6 +394,12 @@ void GLES2Implementation::SignalSyncToken(const gpu::SyncToken& sync_token, } } +// For some command buffer implementations this can be called from any thread. +// It's safe to access gpu_control_ without the lock because it is const. +bool GLES2Implementation::IsFenceSyncReleased(uint64_t release_count) { + return gpu_control_->IsFenceSyncReleased(release_count); +} + void GLES2Implementation::SignalQuery(uint32_t query, const base::Closure& callback) { // Flush previously entered commands to ensure ordering with any diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index d26378a4387674..3d29d312ebab19 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -251,6 +251,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation // ContextSupport implementation. void SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) override; + bool IsFenceSyncReleased(uint64_t release_count) override; void SignalQuery(uint32_t query, const base::Closure& callback) override; void SetAggressivelyFreeResources(bool aggressively_free_resources) override; @@ -816,7 +817,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation int current_trace_stack_; - GpuControl* gpu_control_; + GpuControl* const gpu_control_; Capabilities capabilities_; diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h index afdb93adee484d..62429898c882dc 100644 --- a/gpu/command_buffer/client/gpu_control.h +++ b/gpu/command_buffer/client/gpu_control.h @@ -82,18 +82,29 @@ class GPU_EXPORT GpuControl { virtual CommandBufferId GetCommandBufferID() const = 0; virtual int32_t GetExtraCommandBufferData() const = 0; - // Fence Syncs use release counters at a context level, these fence syncs - // need to be flushed before they can be shared with other contexts across - // channels. Subclasses should implement these functions and take care of - // figuring out when a fence sync has been flushed. The difference between - // IsFenceSyncFlushed and IsFenceSyncFlushReceived, one is testing is the - // client has issued the flush, and the other is testing if the service - // has received the flush. + // Generates a fence sync which should be inserted into the GL command stream. + // When the service executes the fence sync it is released. Fence syncs are + // shared with other contexts as sync tokens which encapsulate the fence sync + // and the command buffer on which it was generated. Fence syncs need to be + // flushed before they can be used by other contexts. Furthermore, the flush + // must be verified before sending a sync token across channel boundaries. virtual uint64_t GenerateFenceSyncRelease() = 0; + + // Returns true if the fence sync is valid. virtual bool IsFenceSyncRelease(uint64_t release) = 0; + + // Returns true if the client has flushed the fence sync. virtual bool IsFenceSyncFlushed(uint64_t release) = 0; + + // Returns true if the service has received the fence sync. Used for verifying + // sync tokens. virtual bool IsFenceSyncFlushReceived(uint64_t release) = 0; + // Returns true if the service has released (executed) the fence sync. Some + // implementations may support calling this from any thread without holding + // the lock provided by the client. + virtual bool IsFenceSyncReleased(uint64_t release) = 0; + // Runs |callback| when sync token is signalled. virtual void SignalSyncToken(const SyncToken& sync_token, const base::Closure& callback) = 0; diff --git a/gpu/command_buffer/client/ring_buffer.cc b/gpu/command_buffer/client/ring_buffer.cc index ebbb1182aed5f1..118dc57276e5d7 100644 --- a/gpu/command_buffer/client/ring_buffer.cc +++ b/gpu/command_buffer/client/ring_buffer.cc @@ -146,10 +146,9 @@ void RingBuffer::DiscardBlock(void* pointer) { } unsigned int RingBuffer::GetLargestFreeSizeNoWaiting() { - unsigned int last_token_read = helper_->last_token_read(); while (!blocks_.empty()) { Block& block = blocks_.front(); - if (block.token > last_token_read || block.state == IN_USE) break; + if (!helper_->HasTokenPassed(block.token) || block.state == IN_USE) break; FreeOldestBlock(); } if (free_offset_ == in_use_offset_) { diff --git a/gpu/command_buffer/common/cmd_buffer_common.cc b/gpu/command_buffer/common/cmd_buffer_common.cc index c9f4b164eeec9d..bdb08f32cb968d 100644 --- a/gpu/command_buffer/common/cmd_buffer_common.cc +++ b/gpu/command_buffer/common/cmd_buffer_common.cc @@ -32,17 +32,6 @@ const char* GetCommandName(CommandId command_id) { } } // namespace cmd - -#if !defined(NACL_WIN64) -// TODO(apatrick): this is a temporary optimization while skia is calling -// RendererGLContext::MakeCurrent prior to every GL call. It saves returning 6 -// ints redundantly when only the error is needed for the CommandBufferProxy -// implementation. -error::Error CommandBuffer::GetLastError() { - return GetLastState().error; -} -#endif - } // namespace gpu diff --git a/gpu/command_buffer/common/command_buffer.h b/gpu/command_buffer/common/command_buffer.h index 355c6670217546..789c6f8965a1a9 100644 --- a/gpu/command_buffer/common/command_buffer.h +++ b/gpu/command_buffer/common/command_buffer.h @@ -22,6 +22,7 @@ class GPU_EXPORT CommandBuffer { State() : get_offset(0), token(-1), + release_count(0), error(error::kNoError), context_lost_reason(error::kUnknown), generation(0) { @@ -37,6 +38,10 @@ class GPU_EXPORT CommandBuffer { // embedded in the command buffer. The default token value is zero. int32_t token; + // The fence sync release count. Incremented by InsertFenceSync commands. + // Used by the client to monitor sync token progress. + uint64_t release_count; + // Error status. error::Error error; @@ -74,13 +79,6 @@ class GPU_EXPORT CommandBuffer { // Returns the last state without synchronizing with the service. virtual State GetLastState() = 0; - // Returns the last token without synchronizing with the service. Note that - // while you could just call GetLastState().token, GetLastState needs to be - // fast as it is called for every command where GetLastToken is only called - // by code that needs to know the last token so it can be slower but more up - // to date than GetLastState. - virtual int32_t GetLastToken() = 0; - // The writer calls this to update its put offset. This ensures the reader // sees the latest added commands, and will eventually process them. On the // service side, commands are processed up to the given put_offset before @@ -94,11 +92,11 @@ class GPU_EXPORT CommandBuffer { // The writer calls this to wait until the current token is within a // specific range, inclusive. Can return early if an error is generated. - virtual void WaitForTokenInRange(int32_t start, int32_t end) = 0; + virtual State WaitForTokenInRange(int32_t start, int32_t end) = 0; // The writer calls this to wait until the current get offset is within a // specific range, inclusive. Can return early if an error is generated. - virtual void WaitForGetOffsetInRange(int32_t start, int32_t end) = 0; + virtual State WaitForGetOffsetInRange(int32_t start, int32_t end) = 0; // Sets the buffer commands are read from. // Also resets the get and put offsets to 0. @@ -112,17 +110,6 @@ class GPU_EXPORT CommandBuffer { // Destroy a transfer buffer. The ID must be positive. virtual void DestroyTransferBuffer(int32_t id) = 0; -// The NaCl Win64 build only really needs the struct definitions above; having -// GetLastError declared would mean we'd have to also define it, and pull more -// of gpu in to the NaCl Win64 build. -#if !defined(NACL_WIN64) - // TODO(apatrick): this is a temporary optimization while skia is calling - // RendererGLContext::MakeCurrent prior to every GL call. It saves returning 6 - // ints redundantly when only the error is needed for the CommandBufferProxy - // implementation. - virtual error::Error GetLastError(); -#endif - 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 4bdd782b0c11da..ff17e50f462549 100644 --- a/gpu/command_buffer/common/command_buffer_mock.h +++ b/gpu/command_buffer/common/command_buffer_mock.h @@ -25,10 +25,11 @@ class MockCommandBuffer : public CommandBufferServiceBase { MOCK_METHOD0(GetLastToken, int32_t()); MOCK_METHOD1(Flush, void(int32_t put_offset)); MOCK_METHOD1(OrderingBarrier, void(int32_t put_offset)); - MOCK_METHOD2(WaitForTokenInRange, void(int32_t start, int32_t end)); - MOCK_METHOD2(WaitForGetOffsetInRange, void(int32_t start, int32_t end)); + MOCK_METHOD2(WaitForTokenInRange, State(int32_t start, int32_t end)); + MOCK_METHOD2(WaitForGetOffsetInRange, State(int32_t start, int32_t end)); MOCK_METHOD1(SetGetBuffer, void(int32_t transfer_buffer_id)); MOCK_METHOD1(SetGetOffset, void(int32_t get_offset)); + MOCK_METHOD1(SetReleaseCount, void(uint64_t release_count)); MOCK_METHOD2(CreateTransferBuffer, scoped_refptr(size_t size, int32_t* id)); MOCK_METHOD1(DestroyTransferBuffer, void(int32_t id)); diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc index ec9facb23331dd..3e6a92c320b62c 100644 --- a/gpu/command_buffer/service/command_buffer_service.cc +++ b/gpu/command_buffer/service/command_buffer_service.cc @@ -42,24 +42,24 @@ class MemoryBufferBacking : public BufferBacking { CommandBufferService::CommandBufferService( TransferBufferManagerInterface* transfer_buffer_manager) : ring_buffer_id_(-1), - shared_state_(NULL), + shared_state_(nullptr), num_entries_(0), get_offset_(0), put_offset_(0), transfer_buffer_manager_(transfer_buffer_manager), token_(0), + release_count_(0), generation_(0), error_(error::kNoError), - context_lost_reason_(error::kUnknown) { -} + context_lost_reason_(error::kUnknown) {} -CommandBufferService::~CommandBufferService() { -} +CommandBufferService::~CommandBufferService() {} CommandBufferService::State CommandBufferService::GetLastState() { State state; state.get_offset = get_offset_; state.token = token_; + state.release_count = release_count_; state.error = error_; state.context_lost_reason = context_lost_reason_; state.generation = ++generation_; @@ -67,10 +67,6 @@ CommandBufferService::State CommandBufferService::GetLastState() { return state; } -int32_t CommandBufferService::GetLastToken() { - return GetLastState().token; -} - void CommandBufferService::UpdateState() { if (shared_state_) { CommandBufferService::State state = GetLastState(); @@ -78,12 +74,17 @@ void CommandBufferService::UpdateState() { } } -void CommandBufferService::WaitForTokenInRange(int32_t start, int32_t end) { +CommandBuffer::State CommandBufferService::WaitForTokenInRange(int32_t start, + int32_t end) { DCHECK(error_ != error::kNoError || InRange(start, end, token_)); + return GetLastState(); } -void CommandBufferService::WaitForGetOffsetInRange(int32_t start, int32_t end) { +CommandBuffer::State CommandBufferService::WaitForGetOffsetInRange( + int32_t start, + int32_t end) { DCHECK(error_ != error::kNoError || InRange(start, end, get_offset_)); + return GetLastState(); } void CommandBufferService::Flush(int32_t put_offset) { @@ -136,6 +137,12 @@ void CommandBufferService::SetGetOffset(int32_t get_offset) { get_offset_ = get_offset; } +void CommandBufferService::SetReleaseCount(uint64_t release_count) { + DCHECK(release_count >= release_count_); + release_count_ = release_count; + UpdateState(); +} + scoped_refptr CommandBufferService::CreateTransferBuffer(size_t size, int32_t* id) { static int32_t next_id = 1; @@ -181,7 +188,6 @@ scoped_refptr CommandBufferService::CreateTransferBufferWithId( return GetTransferBuffer(id); } - void CommandBufferService::SetToken(int32_t token) { token_ = token; UpdateState(); diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h index 0d305bf2582e29..9e030db0456707 100644 --- a/gpu/command_buffer/service/command_buffer_service.h +++ b/gpu/command_buffer/service/command_buffer_service.h @@ -24,6 +24,9 @@ class GPU_EXPORT CommandBufferServiceBase : public CommandBuffer { // Sets the current get offset. This can be called from any thread. virtual void SetGetOffset(int32_t get_offset) = 0; + // Set the release count for the last fence sync seen in the command stream. + virtual void SetReleaseCount(uint64_t release_count) = 0; + // Get the transfer buffer associated with an ID. Returns a null buffer for // ID 0. virtual scoped_refptr GetTransferBuffer(int32_t id) = 0; @@ -54,17 +57,17 @@ class GPU_EXPORT CommandBufferService : public CommandBufferServiceBase { // CommandBuffer implementation: State GetLastState() override; - int32_t GetLastToken() override; void Flush(int32_t put_offset) override; void OrderingBarrier(int32_t put_offset) override; - void WaitForTokenInRange(int32_t start, int32_t end) override; - void WaitForGetOffsetInRange(int32_t start, int32_t end) override; + State WaitForTokenInRange(int32_t start, int32_t end) override; + State WaitForGetOffsetInRange(int32_t start, int32_t end) override; void SetGetBuffer(int32_t transfer_buffer_id) override; scoped_refptr CreateTransferBuffer(size_t size, int32_t* id) override; void DestroyTransferBuffer(int32_t id) override; // CommandBufferServiceBase implementation: void SetGetOffset(int32_t get_offset) override; + void SetReleaseCount(uint64_t release_count) override; scoped_refptr GetTransferBuffer(int32_t id) override; void SetToken(int32_t token) override; void SetParseError(error::Error error) override; @@ -110,6 +113,7 @@ class GPU_EXPORT CommandBufferService : public CommandBufferServiceBase { base::Closure parse_error_callback_; scoped_refptr transfer_buffer_manager_; int32_t token_; + uint64_t release_count_; uint32_t generation_; error::Error error_; error::ContextLostReason context_lost_reason_; diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index a9e0a305de7aa4..49db8c83d4a913 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc @@ -428,6 +428,7 @@ void GLManager::SetupBaseContext() { void GLManager::OnFenceSyncRelease(uint64_t release) { DCHECK(sync_point_client_); DCHECK(!sync_point_client_->client_state()->IsFenceSyncReleased(release)); + command_buffer_->SetReleaseCount(release); sync_point_client_->ReleaseFenceSync(release); } @@ -455,6 +456,10 @@ void GLManager::SetSurface(gl::GLSurface* surface) { decoder_->SetSurface(surface); } +void GLManager::PerformIdleWork() { + executor_->PerformIdleWork(); +} + void GLManager::Destroy() { if (gles2_implementation_.get()) { MakeCurrent(); @@ -633,6 +638,10 @@ bool GLManager::IsFenceSyncFlushReceived(uint64_t release) { return IsFenceSyncRelease(release); } +bool GLManager::IsFenceSyncReleased(uint64_t release) { + return release <= command_buffer_->GetLastState().release_count; +} + void GLManager::SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) { if (sync_point_manager_) { diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h index e0ca4749bdf84b..7e7425c255305e 100644 --- a/gpu/command_buffer/tests/gl_manager.h +++ b/gpu/command_buffer/tests/gl_manager.h @@ -100,6 +100,8 @@ class GLManager : private GpuControl { void SetSurface(gl::GLSurface* surface); + void PerformIdleWork(); + void set_use_iosurface_memory_buffers(bool use_iosurface_memory_buffers) { use_iosurface_memory_buffers_ = use_iosurface_memory_buffers; } @@ -146,6 +148,7 @@ class GLManager : private GpuControl { bool IsFenceSyncRelease(uint64_t release) override; bool IsFenceSyncFlushed(uint64_t release) override; bool IsFenceSyncFlushReceived(uint64_t release) override; + bool IsFenceSyncReleased(uint64_t release) override; void SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) override; bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override; diff --git a/gpu/command_buffer/tests/gl_readback_unittest.cc b/gpu/command_buffer/tests/gl_readback_unittest.cc index 0d9e48260f9803..6b7222ee2d68b6 100644 --- a/gpu/command_buffer/tests/gl_readback_unittest.cc +++ b/gpu/command_buffer/tests/gl_readback_unittest.cc @@ -30,14 +30,16 @@ class GLReadbackTest : public testing::Test { void TearDown() override { gl_.Destroy(); } - static void WaitForQueryCallback(int q, base::Closure cb) { + void WaitForQueryCallback(int q, base::Closure cb) { unsigned int done = 0; + gl_.PerformIdleWork(); glGetQueryObjectuivEXT(q, GL_QUERY_RESULT_AVAILABLE_EXT, &done); if (done) { cb.Run(); } else { base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&WaitForQueryCallback, q, cb), + FROM_HERE, base::Bind(&GLReadbackTest::WaitForQueryCallback, + base::Unretained(this), q, cb), base::TimeDelta::FromMilliseconds(3)); } } @@ -51,7 +53,6 @@ class GLReadbackTest : public testing::Test { GLManager gl_; }; - TEST_F(GLReadbackTest, ReadPixelsWithPBOAndQuery) { const GLint kBytesPerPixel = 4; const GLint kWidth = 2; diff --git a/gpu/gles2_conform_support/egl/context.cc b/gpu/gles2_conform_support/egl/context.cc index 2d870e7dc2dca6..041eac6f7f0cb8 100644 --- a/gpu/gles2_conform_support/egl/context.cc +++ b/gpu/gles2_conform_support/egl/context.cc @@ -221,6 +221,11 @@ bool Context::IsFenceSyncFlushReceived(uint64_t release) { return display_->IsFenceSyncFlushReceived(release); } +bool Context::IsFenceSyncReleased(uint64_t release) { + NOTIMPLEMENTED(); + return false; +} + void Context::SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) { NOTIMPLEMENTED(); diff --git a/gpu/gles2_conform_support/egl/context.h b/gpu/gles2_conform_support/egl/context.h index 22da23b1648eaa..7d45ea70515a63 100644 --- a/gpu/gles2_conform_support/egl/context.h +++ b/gpu/gles2_conform_support/egl/context.h @@ -77,6 +77,7 @@ class Context : public base::RefCountedThreadSafe, bool IsFenceSyncRelease(uint64_t release) override; bool IsFenceSyncFlushed(uint64_t release) override; bool IsFenceSyncFlushReceived(uint64_t release) override; + bool IsFenceSyncReleased(uint64_t release) override; void SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) override; bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override; diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc index 4564553ed21f9c..552f23b92d4c52 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.cc +++ b/gpu/ipc/client/command_buffer_proxy_impl.cc @@ -106,9 +106,9 @@ CommandBufferProxyImpl::~CommandBufferProxyImpl() { } bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) { - std::unique_ptr lock; + base::Optional lock; if (lock_) - lock.reset(new base::AutoLock(*lock_)); + lock.emplace(*lock_); bool handled = true; IPC_BEGIN_MESSAGE_MAP(CommandBufferProxyImpl, message) IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Destroyed, OnDestroyed); @@ -123,6 +123,7 @@ bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) { if (!handled) { LOG(ERROR) << "Gpu process sent invalid message."; + base::AutoLock last_state_lock(last_state_lock_); OnGpuAsyncMessageError(gpu::error::kInvalidGpuMessage, gpu::error::kLostContext); } @@ -130,9 +131,10 @@ bool CommandBufferProxyImpl::OnMessageReceived(const IPC::Message& message) { } void CommandBufferProxyImpl::OnChannelError() { - std::unique_ptr lock; + base::Optional lock; if (lock_) - lock.reset(new base::AutoLock(*lock_)); + lock.emplace(*lock_); + base::AutoLock last_state_lock(last_state_lock_); gpu::error::ContextLostReason context_lost_reason = gpu::error::kGpuChannelLost; @@ -148,6 +150,7 @@ void CommandBufferProxyImpl::OnChannelError() { void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason, gpu::error::Error error) { + base::AutoLock lock(last_state_lock_); OnGpuAsyncMessageError(reason, error); } @@ -177,6 +180,7 @@ void CommandBufferProxyImpl::OnSignalAck(uint32_t id) { SignalTaskMap::iterator it = signal_tasks_.find(id); if (it == signal_tasks_.end()) { LOG(ERROR) << "Gpu process sent invalid SignalAck."; + base::AutoLock lock(last_state_lock_); OnGpuAsyncMessageError(gpu::error::kInvalidGpuMessage, gpu::error::kLostContext); return; @@ -210,7 +214,6 @@ bool CommandBufferProxyImpl::Initialize( if (!base::SharedMemory::IsHandleValid(handle)) return false; - // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed. tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION( @@ -239,17 +242,15 @@ bool CommandBufferProxyImpl::Initialize( return true; } -gpu::CommandBuffer::State CommandBufferProxyImpl::GetLastState() { - return last_state_; -} - -int32_t CommandBufferProxyImpl::GetLastToken() { +CommandBuffer::State CommandBufferProxyImpl::GetLastState() { + base::AutoLock lock(last_state_lock_); TryUpdateState(); - return last_state_.token; + return last_state_; } void CommandBufferProxyImpl::Flush(int32_t put_offset) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -283,6 +284,7 @@ void CommandBufferProxyImpl::Flush(int32_t put_offset) { void CommandBufferProxyImpl::OrderingBarrier(int32_t put_offset) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -333,30 +335,53 @@ void CommandBufferProxyImpl::SetUpdateVSyncParametersCallback( update_vsync_parameters_completion_callback_ = callback; } -void CommandBufferProxyImpl::WaitForTokenInRange(int32_t start, int32_t end) { +gpu::CommandBuffer::State CommandBufferProxyImpl::WaitForTokenInRange( + int32_t start, + int32_t end) { CheckLock(); + base::AutoLock lock(last_state_lock_); TRACE_EVENT2("gpu", "CommandBufferProxyImpl::WaitForToken", "start", start, "end", end); + // Error needs to be checked in case the state was updated on another thread. + // We need to make sure that the reentrant context loss callback is called so + // that the share group is also lost before we return any error up the stack. + if (last_state_.error != gpu::error::kNoError) { + if (gpu_control_client_) + gpu_control_client_->OnGpuControlLostContextMaybeReentrant(); + return last_state_; + } TryUpdateState(); if (!InRange(start, end, last_state_.token) && last_state_.error == gpu::error::kNoError) { gpu::CommandBuffer::State state; if (Send(new GpuCommandBufferMsg_WaitForTokenInRange(route_id_, start, end, - &state))) + &state))) { SetStateFromSyncReply(state); + } } if (!InRange(start, end, last_state_.token) && last_state_.error == gpu::error::kNoError) { LOG(ERROR) << "GPU state invalid after WaitForTokenInRange."; OnGpuSyncReplyError(); } + return last_state_; } -void CommandBufferProxyImpl::WaitForGetOffsetInRange(int32_t start, - int32_t end) { +gpu::CommandBuffer::State CommandBufferProxyImpl::WaitForGetOffsetInRange( + int32_t start, + int32_t end) { CheckLock(); + base::AutoLock lock(last_state_lock_); TRACE_EVENT2("gpu", "CommandBufferProxyImpl::WaitForGetOffset", "start", start, "end", end); + // Error needs to be checked in case the state was updated on another thread. + // We need to make sure that the reentrant context loss callback is called so + // that the share group is also lost before we return any error up the stack. + if (last_state_.error != gpu::error::kNoError) { + if (gpu_control_client_) + gpu_control_client_->OnGpuControlLostContextMaybeReentrant(); + return last_state_; + } TryUpdateState(); if (!InRange(start, end, last_state_.get_offset) && last_state_.error == gpu::error::kNoError) { @@ -370,10 +395,12 @@ void CommandBufferProxyImpl::WaitForGetOffsetInRange(int32_t start, LOG(ERROR) << "GPU state invalid after WaitForGetOffsetInRange."; OnGpuSyncReplyError(); } + return last_state_; } void CommandBufferProxyImpl::SetGetBuffer(int32_t shm_id) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -385,6 +412,7 @@ scoped_refptr CommandBufferProxyImpl::CreateTransferBuffer( size_t size, int32_t* id) { CheckLock(); + base::AutoLock lock(last_state_lock_); *id = -1; if (last_state_.error != gpu::error::kNoError) @@ -428,6 +456,7 @@ scoped_refptr CommandBufferProxyImpl::CreateTransferBuffer( void CommandBufferProxyImpl::DestroyTransferBuffer(int32_t id) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -448,6 +477,7 @@ int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer, size_t height, unsigned internal_format) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return -1; @@ -508,6 +538,7 @@ int32_t CommandBufferProxyImpl::CreateImage(ClientBuffer buffer, void CommandBufferProxyImpl::DestroyImage(int32_t id) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -535,6 +566,7 @@ int32_t CommandBufferProxyImpl::CreateGpuMemoryBufferImage( uint32_t CommandBufferProxyImpl::CreateStreamTexture(uint32_t texture_id) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return 0; @@ -587,6 +619,7 @@ bool CommandBufferProxyImpl::IsFenceSyncFlushed(uint64_t release) { bool CommandBufferProxyImpl::IsFenceSyncFlushReceived(uint64_t release) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return false; @@ -610,9 +643,18 @@ bool CommandBufferProxyImpl::IsFenceSyncFlushReceived(uint64_t release) { return false; } +// This can be called from any thread without holding |lock_|. Use a thread-safe +// non-error throwing variant of TryUpdateState for this. +bool CommandBufferProxyImpl::IsFenceSyncReleased(uint64_t release) { + base::AutoLock lock(last_state_lock_); + TryUpdateStateThreadSafe(); + return release <= last_state_.release_count; +} + void CommandBufferProxyImpl::SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -647,6 +689,7 @@ bool CommandBufferProxyImpl::CanWaitUnverifiedSyncToken( void CommandBufferProxyImpl::SignalQuery(uint32_t query, const base::Closure& callback) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -665,6 +708,7 @@ void CommandBufferProxyImpl::SignalQuery(uint32_t query, void CommandBufferProxyImpl::TakeFrontBuffer(const gpu::Mailbox& mailbox) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -675,6 +719,7 @@ void CommandBufferProxyImpl::ReturnFrontBuffer(const gpu::Mailbox& mailbox, const gpu::SyncToken& sync_token, bool is_lost) { CheckLock(); + base::AutoLock lock(last_state_lock_); if (last_state_.error != gpu::error::kNoError) return; @@ -682,36 +727,47 @@ void CommandBufferProxyImpl::ReturnFrontBuffer(const gpu::Mailbox& mailbox, Send(new GpuCommandBufferMsg_ReturnFrontBuffer(route_id_, mailbox, is_lost)); } -gpu::error::Error CommandBufferProxyImpl::GetLastError() { - return last_state_.error; -} - bool CommandBufferProxyImpl::Send(IPC::Message* msg) { - // Caller should not intentionally send a message if the context is lost. - DCHECK(last_state_.error == gpu::error::kNoError); DCHECK(channel_); - - if (!msg->is_sync()) { - bool result = channel_->Send(msg); - // Send() should always return true for async messages. - DCHECK(result); - return true; + last_state_lock_.AssertAcquired(); + DCHECK_EQ(gpu::error::kNoError, last_state_.error); + + last_state_lock_.Release(); + + // Call is_sync() before sending message. + bool is_sync = msg->is_sync(); + bool result = channel_->Send(msg); + // Send() should always return true for async messages. + DCHECK(is_sync || result); + + last_state_lock_.Acquire(); + + if (last_state_.error != gpu::error::kNoError) { + // Error needs to be checked in case the state was updated on another thread + // while we were waiting on Send. We need to make sure that the reentrant + // context loss callback is called so that the share group is also lost + // before we return any error up the stack. + if (gpu_control_client_) + gpu_control_client_->OnGpuControlLostContextMaybeReentrant(); + return false; } - if (channel_->Send(msg)) - return true; + if (!result) { + // Flag the command buffer as lost. Defer deleting the channel until + // OnChannelError is called after returning to the message loop in case it + // is referenced elsewhere. + DVLOG(1) << "CommandBufferProxyImpl::Send failed. Losing context."; + OnClientError(gpu::error::kLostContext); + return false; + } - // Flag the command buffer as lost. Defer deleting the channel until - // OnChannelError is called after returning to the message loop in case - // it is referenced elsewhere. - DVLOG(1) << "CommandBufferProxyImpl::Send failed. Losing context."; - OnClientError(gpu::error::kLostContext); - return false; + return true; } void CommandBufferProxyImpl::SetStateFromSyncReply( const gpu::CommandBuffer::State& state) { - DCHECK(last_state_.error == gpu::error::kNoError); + CheckLock(); + last_state_lock_.AssertAcquired(); // Handle wraparound. It works as long as we don't have more than 2B state // updates in flight across which reordering occurs. if (state.generation - last_state_.generation < 0x80000000U) @@ -721,6 +777,8 @@ void CommandBufferProxyImpl::SetStateFromSyncReply( } void CommandBufferProxyImpl::TryUpdateState() { + CheckLock(); + last_state_lock_.AssertAcquired(); if (last_state_.error == gpu::error::kNoError) { shared_state()->Read(&last_state_); if (last_state_.error != gpu::error::kNoError) @@ -728,7 +786,21 @@ void CommandBufferProxyImpl::TryUpdateState() { } } +void CommandBufferProxyImpl::TryUpdateStateThreadSafe() { + last_state_lock_.AssertAcquired(); + if (last_state_.error == gpu::error::kNoError) { + shared_state()->Read(&last_state_); + if (last_state_.error != gpu::error::kNoError) { + callback_thread_->PostTask( + FROM_HERE, + base::Bind(&CommandBufferProxyImpl::LockAndDisconnectChannel, + weak_this_)); + } + } +} + void CommandBufferProxyImpl::TryUpdateStateDontReportError() { + last_state_lock_.AssertAcquired(); if (last_state_.error == gpu::error::kNoError) shared_state()->Read(&last_state_); } @@ -799,6 +871,8 @@ void CommandBufferProxyImpl::OnUpdateVSyncParameters(base::TimeTicks timebase, } void CommandBufferProxyImpl::OnGpuSyncReplyError() { + CheckLock(); + last_state_lock_.AssertAcquired(); last_state_.error = gpu::error::kLostContext; last_state_.context_lost_reason = gpu::error::kInvalidGpuMessage; // This method may be inside a callstack from the GpuControlClient (we got a @@ -811,15 +885,20 @@ void CommandBufferProxyImpl::OnGpuAsyncMessageError( gpu::error::ContextLostReason reason, gpu::error::Error error) { CheckLock(); + last_state_lock_.AssertAcquired(); last_state_.error = error; last_state_.context_lost_reason = reason; // This method only occurs when receiving IPC messages, so we know it's not in - // a callstack from the GpuControlClient. + // a callstack from the GpuControlClient. Unlock the state lock to prevent + // a deadlock when calling the context loss callback. + base::AutoUnlock unlock(last_state_lock_); DisconnectChannel(); } void CommandBufferProxyImpl::OnGpuStateError() { - DCHECK(last_state_.error != gpu::error::kNoError); + CheckLock(); + last_state_lock_.AssertAcquired(); + DCHECK_NE(gpu::error::kNoError, last_state_.error); // This method may be inside a callstack from the GpuControlClient (we // encountered an error while trying to perform some action). So avoid // re-entering the GpuControlClient here. @@ -828,6 +907,7 @@ void CommandBufferProxyImpl::OnGpuStateError() { void CommandBufferProxyImpl::OnClientError(gpu::error::Error error) { CheckLock(); + last_state_lock_.AssertAcquired(); last_state_.error = error; last_state_.context_lost_reason = gpu::error::kUnknown; // This method may be inside a callstack from the GpuControlClient (we @@ -838,6 +918,7 @@ void CommandBufferProxyImpl::OnClientError(gpu::error::Error error) { void CommandBufferProxyImpl::DisconnectChannelInFreshCallStack() { CheckLock(); + last_state_lock_.AssertAcquired(); // Inform the GpuControlClient of the lost state immediately, though this may // be a re-entrant call to the client so we use the MaybeReentrant variant. if (gpu_control_client_) diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h index 89300514ca5aec..00f844a8d2c74a 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.h +++ b/gpu/ipc/client/command_buffer_proxy_impl.h @@ -96,11 +96,10 @@ class GPU_EXPORT CommandBufferProxyImpl // CommandBuffer implementation: State GetLastState() override; - int32_t GetLastToken() override; void Flush(int32_t put_offset) override; void OrderingBarrier(int32_t put_offset) override; - void WaitForTokenInRange(int32_t start, int32_t end) override; - void WaitForGetOffsetInRange(int32_t start, int32_t end) override; + State WaitForTokenInRange(int32_t start, int32_t end) override; + State WaitForGetOffsetInRange(int32_t start, int32_t end) override; void SetGetBuffer(int32_t shm_id) override; scoped_refptr CreateTransferBuffer(size_t size, int32_t* id) override; @@ -128,6 +127,7 @@ class GPU_EXPORT CommandBufferProxyImpl bool IsFenceSyncRelease(uint64_t release) override; bool IsFenceSyncFlushed(uint64_t release) override; bool IsFenceSyncFlushReceived(uint64_t release) override; + bool IsFenceSyncReleased(uint64_t release) override; void SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) override; bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override; @@ -157,12 +157,6 @@ class GPU_EXPORT CommandBufferProxyImpl void SetUpdateVSyncParametersCallback( const UpdateVSyncParametersCallback& callback); - // TODO(apatrick): this is a temporary optimization while skia is calling - // ContentGLContext::MakeCurrent prior to every GL call. It saves returning 6 - // ints redundantly when only the error is needed for the - // CommandBufferProxyImpl implementation. - gpu::error::Error GetLastError() override; - int32_t route_id() const { return route_id_; } const scoped_refptr& channel() const { return channel_; } @@ -211,6 +205,9 @@ class GPU_EXPORT CommandBufferProxyImpl // Try to read an updated copy of the state from shared memory, and calls // OnGpuStateError() if the new state has an error. void TryUpdateState(); + // Like above but calls the error handler and disconnects channel by posting + // a task. + void TryUpdateStateThreadSafe(); // Like the above but does not call the error event handler if the new state // has an error. void TryUpdateStateDontReportError(); @@ -240,6 +237,16 @@ class GPU_EXPORT CommandBufferProxyImpl // The shared memory area used to update state. gpu::CommandBufferSharedState* shared_state() const; + // The shared memory area used to update state. + std::unique_ptr shared_state_shm_; + + // The last cached state received from the service. + State last_state_; + + // Lock to access shared state e.g. sync token release count across multiple + // threads. This allows tracking command buffer progress from another thread. + base::Lock last_state_lock_; + // There should be a lock_ if this is going to be used across multiple // threads, or we guarantee it is used by a single thread by using a thread // checker if no lock_ is set. @@ -252,12 +259,6 @@ class GPU_EXPORT CommandBufferProxyImpl // Unowned list of DeletionObservers. base::ObserverList deletion_observers_; - // The last cached state received from the service. - State last_state_; - - // The shared memory area used to update state. - std::unique_ptr shared_state_shm_; - scoped_refptr channel_; const gpu::CommandBufferId command_buffer_id_; const int32_t route_id_; diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc index a30b1e17e7ba1a..bc3c0eda69d6c2 100644 --- a/gpu/ipc/in_process_command_buffer.cc +++ b/gpu/ipc/in_process_command_buffer.cc @@ -497,14 +497,6 @@ void InProcessCommandBuffer::OnContextLost() { gpu_control_client_->OnGpuControlLostContext(); } -CommandBuffer::State InProcessCommandBuffer::GetStateFast() { - CheckSequencedThread(); - base::AutoLock lock(state_after_last_flush_lock_); - if (state_after_last_flush_.generation - last_state_.generation < 0x80000000U) - last_state_ = state_after_last_flush_; - return last_state_; -} - void InProcessCommandBuffer::QueueTask(bool out_of_order, const base::Closure& task) { if (out_of_order) { @@ -543,13 +535,17 @@ void InProcessCommandBuffer::ProcessTasksOnGpuThread() { CommandBuffer::State InProcessCommandBuffer::GetLastState() { CheckSequencedThread(); + base::AutoLock lock(last_state_lock_); return last_state_; } -int32_t InProcessCommandBuffer::GetLastToken() { +void InProcessCommandBuffer::UpdateLastStateOnGpuThread() { CheckSequencedThread(); - GetStateFast(); - return last_state_.token; + command_buffer_lock_.AssertAcquired(); + base::AutoLock lock(last_state_lock_); + State state = command_buffer_->GetLastState(); + if (state.generation - last_state_.generation < 0x80000000U) + last_state_ = state; } void InProcessCommandBuffer::FlushOnGpuThread(int32_t put_offset) { @@ -557,18 +553,13 @@ void InProcessCommandBuffer::FlushOnGpuThread(int32_t put_offset) { ScopedEvent handle_flush(&flush_event_); base::AutoLock lock(command_buffer_lock_); - { - command_buffer_->Flush(put_offset); - { - // Update state before signaling the flush event. - base::AutoLock lock(state_after_last_flush_lock_); - state_after_last_flush_ = command_buffer_->GetLastState(); - } - } + command_buffer_->Flush(put_offset); + // Update state before signaling the flush event. + UpdateLastStateOnGpuThread(); // If we've processed all pending commands but still have pending queries, // pump idle work until the query is passed. - if (put_offset == state_after_last_flush_.get_offset && + if (put_offset == command_buffer_->GetLastState().get_offset && (executor_->HasMoreIdleWork() || executor_->HasPendingQueries())) { ScheduleDelayedWorkOnGpuThread(); } @@ -599,7 +590,7 @@ void InProcessCommandBuffer::ScheduleDelayedWorkOnGpuThread() { void InProcessCommandBuffer::Flush(int32_t put_offset) { CheckSequencedThread(); - if (last_state_.error != gpu::error::kNoError) + if (GetLastState().error != gpu::error::kNoError) return; if (last_put_offset_ == put_offset) @@ -617,29 +608,34 @@ void InProcessCommandBuffer::OrderingBarrier(int32_t put_offset) { Flush(put_offset); } -void InProcessCommandBuffer::WaitForTokenInRange(int32_t start, int32_t end) { +CommandBuffer::State InProcessCommandBuffer::WaitForTokenInRange(int32_t start, + int32_t end) { CheckSequencedThread(); - while (!InRange(start, end, GetLastToken()) && - last_state_.error == gpu::error::kNoError) { + State last_state = GetLastState(); + while (!InRange(start, end, last_state.token) && + last_state.error == gpu::error::kNoError) { flush_event_.Wait(); + last_state = GetLastState(); } + return last_state; } -void InProcessCommandBuffer::WaitForGetOffsetInRange(int32_t start, - int32_t end) { +CommandBuffer::State InProcessCommandBuffer::WaitForGetOffsetInRange( + int32_t start, + int32_t end) { CheckSequencedThread(); - - GetStateFast(); - while (!InRange(start, end, last_state_.get_offset) && - last_state_.error == gpu::error::kNoError) { + State last_state = GetLastState(); + while (!InRange(start, end, last_state.get_offset) && + last_state.error == gpu::error::kNoError) { flush_event_.Wait(); - GetStateFast(); + last_state = GetLastState(); } + return last_state; } void InProcessCommandBuffer::SetGetBuffer(int32_t shm_id) { CheckSequencedThread(); - if (last_state_.error != gpu::error::kNoError) + if (GetLastState().error != gpu::error::kNoError) return; base::WaitableEvent completion( @@ -651,10 +647,7 @@ void InProcessCommandBuffer::SetGetBuffer(int32_t shm_id) { QueueTask(false, task); completion.Wait(); - { - base::AutoLock lock(state_after_last_flush_lock_); - state_after_last_flush_ = command_buffer_->GetLastState(); - } + last_put_offset_ = 0; } void InProcessCommandBuffer::SetGetBufferOnGpuThread( @@ -662,7 +655,7 @@ void InProcessCommandBuffer::SetGetBufferOnGpuThread( base::WaitableEvent* completion) { base::AutoLock lock(command_buffer_lock_); command_buffer_->SetGetBuffer(shm_id); - last_put_offset_ = 0; + UpdateLastStateOnGpuThread(); completion->Signal(); } @@ -1030,6 +1023,10 @@ bool InProcessCommandBuffer::IsFenceSyncFlushReceived(uint64_t release) { return IsFenceSyncFlushed(release); } +bool InProcessCommandBuffer::IsFenceSyncReleased(uint64_t release) { + return release <= GetLastState().release_count; +} + void InProcessCommandBuffer::SignalSyncToken(const SyncToken& sync_token, const base::Closure& callback) { CheckSequencedThread(); @@ -1132,11 +1129,6 @@ void InProcessCommandBuffer::SetUpdateVSyncParametersCallback( update_vsync_parameters_completion_callback_ = callback; } -gpu::error::Error InProcessCommandBuffer::GetLastError() { - CheckSequencedThread(); - return last_state_.error; -} - namespace { void PostCallback( diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h index ae2aed2a59e24d..113f0869620201 100644 --- a/gpu/ipc/in_process_command_buffer.h +++ b/gpu/ipc/in_process_command_buffer.h @@ -98,16 +98,14 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer, // CommandBuffer implementation: State GetLastState() override; - int32_t GetLastToken() override; void Flush(int32_t put_offset) override; void OrderingBarrier(int32_t put_offset) override; - void WaitForTokenInRange(int32_t start, int32_t end) override; - void WaitForGetOffsetInRange(int32_t start, int32_t end) override; + State WaitForTokenInRange(int32_t start, int32_t end) override; + State WaitForGetOffsetInRange(int32_t start, int32_t end) override; void SetGetBuffer(int32_t shm_id) override; scoped_refptr CreateTransferBuffer(size_t size, int32_t* id) override; void DestroyTransferBuffer(int32_t id) override; - gpu::error::Error GetLastError() override; // GpuControl implementation: // NOTE: The GpuControlClient will be called on the client thread. @@ -132,6 +130,7 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer, bool IsFenceSyncRelease(uint64_t release) override; bool IsFenceSyncFlushed(uint64_t release) override; bool IsFenceSyncFlushReceived(uint64_t release) override; + bool IsFenceSyncReleased(uint64_t release) override; void SignalSyncToken(const SyncToken& sync_token, const base::Closure& callback) override; bool CanWaitUnverifiedSyncToken(const SyncToken* sync_token) override; @@ -233,10 +232,10 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer, void Destroy(); bool DestroyOnGpuThread(); void FlushOnGpuThread(int32_t put_offset); + void UpdateLastStateOnGpuThread(); void ScheduleDelayedWorkOnGpuThread(); bool MakeCurrent(); base::Closure WrapCallback(const base::Closure& callback); - State GetStateFast(); void QueueTask(bool out_of_order, const base::Closure& task); void ProcessTasksOnGpuThread(); void CheckSequencedThread(); @@ -295,6 +294,7 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer, bool context_lost_; #endif State last_state_; + base::Lock last_state_lock_; int32_t last_put_offset_; gpu::Capabilities capabilities_; GpuMemoryBufferManager* gpu_memory_buffer_manager_; @@ -307,8 +307,6 @@ class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer, base::Lock command_buffer_lock_; base::WaitableEvent flush_event_; scoped_refptr service_; - State state_after_last_flush_; - base::Lock state_after_last_flush_lock_; // The group of contexts that share namespaces with this context. scoped_refptr context_group_; diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc index b6396195afabdc..13bc2617b5a23b 100644 --- a/gpu/ipc/service/gpu_command_buffer_stub.cc +++ b/gpu/ipc/service/gpu_command_buffer_stub.cc @@ -947,6 +947,7 @@ void GpuCommandBufferStub::OnFenceSyncRelease(uint64_t release) { mailbox_manager->PushTextureUpdates(sync_token); } + command_buffer_->SetReleaseCount(release); sync_point_client_->ReleaseFenceSync(release); } diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc index 77ef28217f98a9..40e9d70dcf9865 100644 --- a/ppapi/proxy/ppapi_command_buffer_proxy.cc +++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc @@ -29,8 +29,7 @@ PpapiCommandBufferProxy::PpapiCommandBufferProxy( pending_fence_sync_release_(0), flushed_fence_sync_release_(0), validated_fence_sync_release_(0) { - shared_state_shm_.reset( - new base::SharedMemory(shared_state.shmem(), false)); + shared_state_shm_.reset(new base::SharedMemory(shared_state.shmem(), false)); shared_state_shm_->Map(shared_state.size()); InstanceData* data = dispatcher->GetInstanceData(resource.instance()); flush_info_ = &data->flush_info_; @@ -42,14 +41,9 @@ PpapiCommandBufferProxy::~PpapiCommandBufferProxy() { } gpu::CommandBuffer::State PpapiCommandBufferProxy::GetLastState() { - ppapi::ProxyLock::AssertAcquiredDebugOnly(); - return last_state_; -} - -int32_t PpapiCommandBufferProxy::GetLastToken() { ppapi::ProxyLock::AssertAcquiredDebugOnly(); TryUpdateState(); - return last_state_.token; + return last_state_; } void PpapiCommandBufferProxy::Flush(int32_t put_offset) { @@ -74,49 +68,46 @@ void PpapiCommandBufferProxy::OrderingBarrier(int32_t put_offset) { pending_fence_sync_release_ = next_fence_sync_release_ - 1; } -void PpapiCommandBufferProxy::WaitForTokenInRange(int32_t start, int32_t end) { +gpu::CommandBuffer::State PpapiCommandBufferProxy::WaitForTokenInRange( + int32_t start, + int32_t end) { TryUpdateState(); if (!InRange(start, end, last_state_.token) && last_state_.error == gpu::error::kNoError) { bool success = false; gpu::CommandBuffer::State state; if (Send(new PpapiHostMsg_PPBGraphics3D_WaitForTokenInRange( - ppapi::API_ID_PPB_GRAPHICS_3D, - resource_, - start, - end, - &state, - &success))) + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, start, end, &state, + &success))) UpdateState(state, success); } DCHECK(InRange(start, end, last_state_.token) || last_state_.error != gpu::error::kNoError); + return last_state_; } -void PpapiCommandBufferProxy::WaitForGetOffsetInRange(int32_t start, - int32_t end) { +gpu::CommandBuffer::State PpapiCommandBufferProxy::WaitForGetOffsetInRange( + int32_t start, + int32_t end) { TryUpdateState(); if (!InRange(start, end, last_state_.get_offset) && last_state_.error == gpu::error::kNoError) { bool success = false; gpu::CommandBuffer::State state; if (Send(new PpapiHostMsg_PPBGraphics3D_WaitForGetOffsetInRange( - ppapi::API_ID_PPB_GRAPHICS_3D, - resource_, - start, - end, - &state, - &success))) + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, start, end, &state, + &success))) UpdateState(state, success); } DCHECK(InRange(start, end, last_state_.get_offset) || last_state_.error != gpu::error::kNoError); + return last_state_; } void PpapiCommandBufferProxy::SetGetBuffer(int32_t transfer_buffer_id) { if (last_state_.error == gpu::error::kNoError) { Send(new PpapiHostMsg_PPBGraphics3D_SetGetBuffer( - ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id)); + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, transfer_buffer_id)); } } @@ -133,8 +124,8 @@ scoped_refptr PpapiCommandBufferProxy::CreateTransferBuffer( ppapi::proxy::SerializedHandle handle( ppapi::proxy::SerializedHandle::SHARED_MEMORY); if (!Send(new PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer( - ppapi::API_ID_PPB_GRAPHICS_3D, resource_, - base::checked_cast(size), id, &handle))) { + ppapi::API_ID_PPB_GRAPHICS_3D, resource_, + base::checked_cast(size), id, &handle))) { if (last_state_.error == gpu::error::kNoError) last_state_.error = gpu::error::kLostContext; return NULL; @@ -213,6 +204,11 @@ bool PpapiCommandBufferProxy::IsFenceSyncFlushReceived(uint64_t release) { return release <= validated_fence_sync_release_; } +bool PpapiCommandBufferProxy::IsFenceSyncReleased(uint64_t release) { + NOTIMPLEMENTED(); + return false; +} + void PpapiCommandBufferProxy::SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) { NOTIMPLEMENTED(); diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h index 3cb7f42325061d..24427f60bc1e48 100644 --- a/ppapi/proxy/ppapi_command_buffer_proxy.h +++ b/ppapi/proxy/ppapi_command_buffer_proxy.h @@ -42,11 +42,10 @@ class PPAPI_PROXY_EXPORT PpapiCommandBufferProxy : public gpu::CommandBuffer, // gpu::CommandBuffer implementation: State GetLastState() override; - int32_t GetLastToken() override; void Flush(int32_t put_offset) override; void OrderingBarrier(int32_t put_offset) override; - void WaitForTokenInRange(int32_t start, int32_t end) override; - void WaitForGetOffsetInRange(int32_t start, int32_t end) override; + State WaitForTokenInRange(int32_t start, int32_t end) override; + State WaitForGetOffsetInRange(int32_t start, int32_t end) override; void SetGetBuffer(int32_t transfer_buffer_id) override; scoped_refptr CreateTransferBuffer(size_t size, int32_t* id) override; @@ -73,6 +72,7 @@ class PPAPI_PROXY_EXPORT PpapiCommandBufferProxy : public gpu::CommandBuffer, bool IsFenceSyncRelease(uint64_t release) override; bool IsFenceSyncFlushed(uint64_t release) override; bool IsFenceSyncFlushReceived(uint64_t release) override; + bool IsFenceSyncReleased(uint64_t release) override; void SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) override; bool CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) override;