diff options
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/common/command_buffer_shared.h | 61 | ||||
-rw-r--r-- | gpu/command_buffer/common/command_buffer_shared_test.cc | 97 | ||||
-rw-r--r-- | gpu/command_buffer/service/command_buffer_service.cc | 18 | ||||
-rw-r--r-- | gpu/command_buffer/service/command_buffer_service.h | 8 | ||||
-rw-r--r-- | gpu/gpu.gyp | 1 |
5 files changed, 185 insertions, 0 deletions
diff --git a/gpu/command_buffer/common/command_buffer_shared.h b/gpu/command_buffer/common/command_buffer_shared.h new file mode 100644 index 0000000..017a644 --- /dev/null +++ b/gpu/command_buffer/common/command_buffer_shared.h @@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_SHARED_H_ +#define GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_SHARED_H_ + +#include "command_buffer.h" +#include "base/atomicops.h" + +namespace gpu { + +// This is a standard 4-slot asynchronous communication mechanism, used to +// ensure that the reader gets a consistent copy of what the writer wrote. +template<typename T> +class SharedState { + T states_[2][2]; + base::subtle::Atomic32 reading_; + base::subtle::Atomic32 latest_; + base::subtle::Atomic32 slots_[2]; + +public: + + void Initialize() { + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + states_[i][j] = T(); + } + } + base::subtle::NoBarrier_Store(&reading_, 0); + base::subtle::NoBarrier_Store(&latest_, 0); + base::subtle::NoBarrier_Store(&slots_[0], 0); + base::subtle::Acquire_Store(&slots_[1], 0); + } + + void Write(const T& state) { + int towrite = !base::subtle::Acquire_Load(&reading_); + int index = !base::subtle::Acquire_Load(&slots_[towrite]); + states_[towrite][index] = state; + base::subtle::MemoryBarrier(); + base::subtle::Acquire_Store(&slots_[towrite], index); + base::subtle::Acquire_Store(&latest_, towrite); + } + + // Attempt to update the state, updating only if the generation counter is + // newer. + void Read(T* state) { + base::subtle::MemoryBarrier(); + int toread = !!base::subtle::Acquire_Load(&latest_); + base::subtle::Acquire_Store(&reading_, toread); + int index = !!base::subtle::Acquire_Load(&slots_[toread]); + if (states_[toread][index].generation - state->generation < 0x80000000U) + *state = states_[toread][index]; + } +}; + +typedef SharedState<CommandBuffer::State> CommandBufferSharedState; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_SHARED_H_ diff --git a/gpu/command_buffer/common/command_buffer_shared_test.cc b/gpu/command_buffer/common/command_buffer_shared_test.cc new file mode 100644 index 0000000..f7ff2f0 --- /dev/null +++ b/gpu/command_buffer/common/command_buffer_shared_test.cc @@ -0,0 +1,97 @@ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains the tests for the CommandBufferSharedState class. + +#include "gpu/command_buffer/common/command_buffer_shared.h" +#include "base/bind.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gpu { + +class CommandBufferSharedTest : public testing::Test { + protected: + + virtual void SetUp() { + shared_state_.reset(new CommandBufferSharedState()); + shared_state_->Initialize(); + } + + scoped_ptr<CommandBufferSharedState> shared_state_; +}; + +TEST_F(CommandBufferSharedTest, TestBasic) { + CommandBuffer::State state; + + shared_state_->Read(&state); + + EXPECT_LT(state.generation, 0x80000000); + EXPECT_EQ(state.get_offset, 0); + EXPECT_EQ(state.put_offset, 0); + EXPECT_EQ(state.token, -1); + EXPECT_EQ(state.error, gpu::error::kNoError); + EXPECT_EQ(state.context_lost_reason, gpu::error::kUnknown); +} + +static const int kSize = 100000; + +void WriteToState(int32 *buffer, + CommandBufferSharedState* shared_state) { + CommandBuffer::State state; + for (int i = 0; i < kSize; i++) { + state.token = i - 1; + state.get_offset = i + 1; + state.generation = i + 2; + state.error = static_cast<gpu::error::Error>(i + 3); + // Ensure that the producer doesn't update the buffer until after the + // consumer reads from it. + EXPECT_EQ(buffer[i], 0); + + shared_state->Write(state); + } +} + +TEST_F(CommandBufferSharedTest, TestConsistency) { + scoped_array<int32> buffer; + buffer.reset(new int32[kSize]); + base::Thread consumer("Reader Thread"); + + memset(buffer.get(), 0, kSize * sizeof(int32)); + + consumer.Start(); + consumer.message_loop()->PostTask( + FROM_HERE, base::Bind(&WriteToState, buffer.get(), + shared_state_.get())); + + CommandBuffer::State last_state; + while (1) { + CommandBuffer::State state = last_state; + + shared_state_->Read(&state); + + if (state.generation < last_state.generation) + continue; + + if (state.get_offset >= 1) { + buffer[state.get_offset - 1] = 1; + // Check that the state is consistent + EXPECT_LE(last_state.token, state.token); + EXPECT_LE(last_state.generation, state.generation); + last_state = state; + EXPECT_EQ(state.token, state.get_offset - 2); + EXPECT_EQ(state.generation, + static_cast<unsigned int>(state.get_offset) + 1); + EXPECT_EQ(state.error, state.get_offset + 2); + + if (state.get_offset == kSize) + break; + } + } +} + +} // namespace gpu + diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc index c5a1162..13d3098 100644 --- a/gpu/command_buffer/service/command_buffer_service.cc +++ b/gpu/command_buffer/service/command_buffer_service.cc @@ -9,6 +9,7 @@ #include "base/process_util.h" #include "base/debug/trace_event.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" +#include "gpu/command_buffer/common/command_buffer_shared.h" using ::base::SharedMemory; @@ -16,6 +17,7 @@ namespace gpu { CommandBufferService::CommandBufferService() : ring_buffer_id_(-1), + shared_state_(NULL), num_entries_(0), get_offset_(0), put_offset_(0), @@ -59,6 +61,13 @@ CommandBufferService::State CommandBufferService::GetLastState() { return GetState(); } +void CommandBufferService::UpdateState() { + if (shared_state_) { + CommandBufferService::State state = GetState(); + shared_state_->Write(state); + } +} + CommandBufferService::State CommandBufferService::FlushSync( int32 put_offset, int32 last_known_get) { if (put_offset < 0 || put_offset > num_entries_) { @@ -98,6 +107,15 @@ void CommandBufferService::SetGetBuffer(int32 transfer_buffer_id) { if (!get_buffer_change_callback_.is_null()) { get_buffer_change_callback_.Run(ring_buffer_id_); } + + UpdateState(); +} + +void CommandBufferService::SetSharedStateBuffer(int32 transfer_buffer_id) { + gpu::Buffer buffer = GetTransferBuffer(transfer_buffer_id); + shared_state_ = reinterpret_cast<CommandBufferSharedState*>(buffer.ptr); + + UpdateState(); } void CommandBufferService::SetGetOffset(int32 get_offset) { diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h index 7704636..2c59678 100644 --- a/gpu/command_buffer/service/command_buffer_service.h +++ b/gpu/command_buffer/service/command_buffer_service.h @@ -13,6 +13,7 @@ #include "base/memory/scoped_ptr.h" #include "base/shared_memory.h" #include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/common/command_buffer_shared.h" namespace gpu { @@ -56,9 +57,16 @@ class CommandBufferService : public CommandBuffer { const GetBufferChangedCallback& callback); virtual void SetParseErrorCallback(const base::Closure& callback); + // Setup the transfer buffer that shared state should be copied into. + void SetSharedStateBuffer(int32 transfer_buffer_id); + + // Copy the current state into the shared state transfer buffer. + void UpdateState(); + private: int32 ring_buffer_id_; Buffer ring_buffer_; + CommandBufferSharedState* shared_state_; int32 num_entries_; int32 get_offset_; int32 put_offset_; diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index c24c4d1..7af8343 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -317,6 +317,7 @@ 'command_buffer/common/bitfield_helpers_test.cc', 'command_buffer/common/command_buffer_mock.cc', 'command_buffer/common/command_buffer_mock.h', + 'command_buffer/common/command_buffer_shared_test.cc', 'command_buffer/common/gles2_cmd_format_test.cc', 'command_buffer/common/gles2_cmd_format_test_autogen.h', 'command_buffer/common/gles2_cmd_utils_unittest.cc', |