summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'gpu')
-rw-r--r--gpu/command_buffer/common/command_buffer_shared.h61
-rw-r--r--gpu/command_buffer/common/command_buffer_shared_test.cc97
-rw-r--r--gpu/command_buffer/service/command_buffer_service.cc18
-rw-r--r--gpu/command_buffer/service/command_buffer_service.h8
-rw-r--r--gpu/gpu.gyp1
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',