summaryrefslogtreecommitdiff
path: root/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc')
-rw-r--r--chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc333
1 files changed, 333 insertions, 0 deletions
diff --git a/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc
new file mode 100644
index 00000000000..bd0e86e3f45
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc
@@ -0,0 +1,333 @@
+// 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.
+
+// Tests for the Command Buffer Helper.
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace gpu {
+
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::DoAll;
+using testing::Invoke;
+using testing::_;
+
+const int32 kTotalNumCommandEntries = 10;
+const int32 kCommandBufferSizeBytes =
+ kTotalNumCommandEntries * sizeof(CommandBufferEntry);
+const int32 kUnusedCommandId = 5; // we use 0 and 2 currently.
+
+// Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
+// using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
+// (calling it directly, not through the RPC mechanism).
+class CommandBufferHelperTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ // ignore noops in the mock - we don't want to inspect the internals of the
+ // helper.
+ EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, _, _))
+ .WillRepeatedly(Return(error::kNoError));
+
+ {
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ EXPECT_TRUE(manager->Initialize());
+ }
+ command_buffer_.reset(
+ new CommandBufferService(transfer_buffer_manager_.get()));
+ EXPECT_TRUE(command_buffer_->Initialize());
+
+ gpu_scheduler_.reset(new GpuScheduler(
+ command_buffer_.get(), api_mock_.get(), NULL));
+ command_buffer_->SetPutOffsetChangeCallback(base::Bind(
+ &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
+ command_buffer_->SetGetBufferChangeCallback(base::Bind(
+ &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
+
+ api_mock_->set_engine(gpu_scheduler_.get());
+
+ helper_.reset(new CommandBufferHelper(command_buffer_.get()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
+ const CommandParser* GetParser() const {
+ return gpu_scheduler_->parser();
+ }
+
+ // Adds a command to the buffer through the helper, while adding it as an
+ // expected call on the API mock.
+ void AddCommandWithExpect(error::Error _return,
+ unsigned int command,
+ int arg_count,
+ CommandBufferEntry *args) {
+ CommandHeader header;
+ header.size = arg_count + 1;
+ header.command = command;
+ CommandBufferEntry* cmds = helper_->GetSpace(arg_count + 1);
+ CommandBufferOffset put = 0;
+ cmds[put++].value_header = header;
+ for (int ii = 0; ii < arg_count; ++ii) {
+ cmds[put++] = args[ii];
+ }
+
+ EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
+ Truly(AsyncAPIMock::IsArgs(arg_count, args))))
+ .InSequence(sequence_)
+ .WillOnce(Return(_return));
+ }
+
+ // Checks that the buffer from put to put+size is free in the parser.
+ void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
+ CommandBufferOffset parser_put = GetParser()->put();
+ CommandBufferOffset parser_get = GetParser()->get();
+ CommandBufferOffset limit = put + size;
+ if (parser_get > parser_put) {
+ // "busy" buffer wraps, so "free" buffer is between put (inclusive) and
+ // get (exclusive).
+ EXPECT_LE(parser_put, put);
+ EXPECT_GT(parser_get, limit);
+ } else {
+ // "busy" buffer does not wrap, so the "free" buffer is the top side (from
+ // put to the limit) and the bottom side (from 0 to get).
+ if (put >= parser_put) {
+ // we're on the top side, check we are below the limit.
+ EXPECT_GE(kTotalNumCommandEntries, limit);
+ } else {
+ // we're on the bottom side, check we are below get.
+ EXPECT_GT(parser_get, limit);
+ }
+ }
+ }
+
+ int32 GetGetOffset() {
+ return command_buffer_->GetState().get_offset;
+ }
+
+ int32 GetPutOffset() {
+ return command_buffer_->GetState().put_offset;
+ }
+
+ error::Error GetError() {
+ return command_buffer_->GetState().error;
+ }
+
+ CommandBufferOffset get_helper_put() { return helper_->put_; }
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedNSAutoreleasePool autorelease_pool_;
+#endif
+ base::MessageLoop message_loop_;
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<GpuScheduler> gpu_scheduler_;
+ scoped_ptr<CommandBufferHelper> helper_;
+ Sequence sequence_;
+};
+
+// Checks that commands in the buffer are properly executed, and that the
+// status/error stay valid.
+TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
+ // Check initial state of the engine - it should have been configured by the
+ // helper.
+ EXPECT_TRUE(GetParser() != NULL);
+ EXPECT_EQ(error::kNoError, GetError());
+ EXPECT_EQ(0, GetGetOffset());
+
+ // Add 3 commands through the helper
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
+
+ CommandBufferEntry args1[2];
+ args1[0].value_uint32 = 3;
+ args1[1].value_float = 4.f;
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args1);
+
+ CommandBufferEntry args2[2];
+ args2[0].value_uint32 = 5;
+ args2[1].value_float = 6.f;
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args2);
+
+ // Wait until it's done.
+ helper_->Finish();
+ // Check that the engine has no more work to do.
+ EXPECT_TRUE(GetParser()->IsEmpty());
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks that commands in the buffer are properly executed when wrapping the
+// buffer, and that the status/error stay valid.
+TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
+ // Add 5 commands of size 3 through the helper to make sure we do wrap.
+ CommandBufferEntry args1[2];
+ args1[0].value_uint32 = 5;
+ args1[1].value_float = 4.f;
+
+ for (unsigned int i = 0; i < 5; ++i) {
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + i, 2, args1);
+ }
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks the case where the command inserted exactly matches the space left in
+// the command buffer.
+TEST_F(CommandBufferHelperTest, TestCommandWrappingExactMultiple) {
+ const int32 kCommandSize = 5;
+ const size_t kNumArgs = kCommandSize - 1;
+ COMPILE_ASSERT(kTotalNumCommandEntries % kCommandSize == 0,
+ Not_multiple_of_num_command_entries);
+ CommandBufferEntry args1[kNumArgs];
+ for (size_t ii = 0; ii < kNumArgs; ++ii) {
+ args1[0].value_uint32 = ii + 1;
+ }
+
+ for (unsigned int i = 0; i < 5; ++i) {
+ AddCommandWithExpect(
+ error::kNoError, i + kUnusedCommandId, kNumArgs, args1);
+ }
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks that asking for available entries work, and that the parser
+// effectively won't use that space.
+TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
+ CommandBufferEntry args[2];
+ args[0].value_uint32 = 3;
+ args[1].value_float = 4.f;
+
+ // Add 2 commands through the helper - 8 entries
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 1, 0, NULL);
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 2, 0, NULL);
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
+
+ // Ask for 5 entries.
+ helper_->WaitForAvailableEntries(5);
+
+ CommandBufferOffset put = get_helper_put();
+ CheckFreeSpace(put, 5);
+
+ // Add more commands.
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 5, 2, args);
+
+ // Wait until everything is done done.
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks that the InsertToken/WaitForToken work.
+TEST_F(CommandBufferHelperTest, TestToken) {
+ CommandBufferEntry args[2];
+ args[0].value_uint32 = 3;
+ args[1].value_float = 4.f;
+
+ // Add a first command.
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
+ // keep track of the buffer position.
+ CommandBufferOffset command1_put = get_helper_put();
+ int32 token = helper_->InsertToken();
+
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(error::kNoError)));
+ // Add another command.
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
+ helper_->WaitForToken(token);
+ // check that the get pointer is beyond the first command.
+ EXPECT_LE(command1_put, GetGetOffset());
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+TEST_F(CommandBufferHelperTest, FreeRingBuffer) {
+ EXPECT_TRUE(helper_->HaveRingBuffer());
+
+ // Test freeing ring buffer.
+ helper_->FreeRingBuffer();
+ EXPECT_FALSE(helper_->HaveRingBuffer());
+
+ // Test that InsertToken allocates a new one
+ int32 token = helper_->InsertToken();
+ EXPECT_TRUE(helper_->HaveRingBuffer());
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(error::kNoError)));
+ helper_->WaitForToken(token);
+ helper_->FreeRingBuffer();
+ EXPECT_FALSE(helper_->HaveRingBuffer());
+
+ // Test that WaitForAvailableEntries allocates a new one
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
+ EXPECT_TRUE(helper_->HaveRingBuffer());
+ helper_->Finish();
+ helper_->FreeRingBuffer();
+ EXPECT_FALSE(helper_->HaveRingBuffer());
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+}
+
+TEST_F(CommandBufferHelperTest, Noop) {
+ for (int ii = 1; ii < 4; ++ii) {
+ CommandBufferOffset put_before = get_helper_put();
+ helper_->Noop(ii);
+ CommandBufferOffset put_after = get_helper_put();
+ EXPECT_EQ(ii, put_after - put_before);
+ }
+}
+
+TEST_F(CommandBufferHelperTest, IsContextLost) {
+ EXPECT_FALSE(helper_->IsContextLost());
+ command_buffer_->SetParseError(error::kGenericError);
+ EXPECT_TRUE(helper_->IsContextLost());
+}
+
+} // namespace gpu