summaryrefslogtreecommitdiffstats
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.cc400
1 files changed, 389 insertions, 11 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
index bd0e86e3f45..c2d1361555a 100644
--- a/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc
+++ b/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc
@@ -4,8 +4,11 @@
// Tests for the Command Buffer Helper.
+#include <list>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/memory/linked_ptr.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"
@@ -28,11 +31,54 @@ using testing::DoAll;
using testing::Invoke;
using testing::_;
-const int32 kTotalNumCommandEntries = 10;
+const int32 kTotalNumCommandEntries = 32;
const int32 kCommandBufferSizeBytes =
kTotalNumCommandEntries * sizeof(CommandBufferEntry);
const int32 kUnusedCommandId = 5; // we use 0 and 2 currently.
+// Override CommandBufferService::Flush() to lock flushing and simulate
+// the buffer becoming full in asynchronous mode.
+class CommandBufferServiceLocked : public CommandBufferService {
+ public:
+ explicit CommandBufferServiceLocked(
+ TransferBufferManagerInterface* transfer_buffer_manager)
+ : CommandBufferService(transfer_buffer_manager),
+ flush_locked_(false),
+ last_flush_(-1),
+ flush_count_(0) {}
+ virtual ~CommandBufferServiceLocked() {}
+
+ virtual void Flush(int32 put_offset) OVERRIDE {
+ flush_count_++;
+ if (!flush_locked_) {
+ last_flush_ = -1;
+ CommandBufferService::Flush(put_offset);
+ } else {
+ last_flush_ = put_offset;
+ }
+ }
+
+ void LockFlush() { flush_locked_ = true; }
+
+ void UnlockFlush() { flush_locked_ = false; }
+
+ int FlushCount() { return flush_count_; }
+
+ virtual void WaitForGetOffsetInRange(int32 start, int32 end) OVERRIDE {
+ if (last_flush_ != -1) {
+ CommandBufferService::Flush(last_flush_);
+ last_flush_ = -1;
+ }
+ CommandBufferService::WaitForGetOffsetInRange(start, end);
+ }
+
+ private:
+ bool flush_locked_;
+ int last_flush_;
+ int flush_count_;
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferServiceLocked);
+};
+
// 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).
@@ -51,7 +97,7 @@ class CommandBufferHelperTest : public testing::Test {
EXPECT_TRUE(manager->Initialize());
}
command_buffer_.reset(
- new CommandBufferService(transfer_buffer_manager_.get()));
+ new CommandBufferServiceLocked(transfer_buffer_manager_.get()));
EXPECT_TRUE(command_buffer_->Initialize());
gpu_scheduler_.reset(new GpuScheduler(
@@ -65,17 +111,22 @@ class CommandBufferHelperTest : public testing::Test {
helper_.reset(new CommandBufferHelper(command_buffer_.get()));
helper_->Initialize(kCommandBufferSizeBytes);
+
+ test_command_next_id_ = kUnusedCommandId;
}
virtual void TearDown() {
// If the GpuScheduler posts any tasks, this forces them to run.
base::MessageLoop::current()->RunUntilIdle();
+ test_command_args_.clear();
}
const CommandParser* GetParser() const {
return gpu_scheduler_->parser();
}
+ int32 ImmediateEntryCount() const { return helper_->immediate_entry_count_; }
+
// 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,
@@ -85,7 +136,8 @@ class CommandBufferHelperTest : public testing::Test {
CommandHeader header;
header.size = arg_count + 1;
header.command = command;
- CommandBufferEntry* cmds = helper_->GetSpace(arg_count + 1);
+ CommandBufferEntry* cmds =
+ static_cast<CommandBufferEntry*>(helper_->GetSpace(arg_count + 1));
CommandBufferOffset put = 0;
cmds[put++].value_header = header;
for (int ii = 0; ii < arg_count; ++ii) {
@@ -98,6 +150,68 @@ class CommandBufferHelperTest : public testing::Test {
.WillOnce(Return(_return));
}
+ void AddUniqueCommandWithExpect(error::Error _return, int cmd_size) {
+ EXPECT_GE(cmd_size, 1);
+ EXPECT_LT(cmd_size, kTotalNumCommandEntries);
+ int arg_count = cmd_size - 1;
+
+ // Allocate array for args.
+ linked_ptr<std::vector<CommandBufferEntry> > args_ptr(
+ new std::vector<CommandBufferEntry>(arg_count ? arg_count : 1));
+
+ for (int32 ii = 0; ii < arg_count; ++ii) {
+ (*args_ptr)[ii].value_uint32 = 0xF00DF00D + ii;
+ }
+
+ // Add command and save args in test_command_args_ until the test completes.
+ AddCommandWithExpect(
+ _return, test_command_next_id_++, arg_count, &(*args_ptr)[0]);
+ test_command_args_.insert(test_command_args_.end(), args_ptr);
+ }
+
+ void TestCommandWrappingFull(int32 cmd_size, int32 start_commands) {
+ const int32 num_args = cmd_size - 1;
+ EXPECT_EQ(kTotalNumCommandEntries % cmd_size, 0);
+
+ std::vector<CommandBufferEntry> args(num_args);
+ for (int32 ii = 0; ii < num_args; ++ii) {
+ args[ii].value_uint32 = ii + 1;
+ }
+
+ // Initially insert commands up to start_commands and Finish().
+ for (int32 ii = 0; ii < start_commands; ++ii) {
+ AddCommandWithExpect(
+ error::kNoError, ii + kUnusedCommandId, num_args, &args[0]);
+ }
+ helper_->Finish();
+
+ EXPECT_EQ(GetParser()->put(),
+ (start_commands * cmd_size) % kTotalNumCommandEntries);
+ EXPECT_EQ(GetParser()->get(),
+ (start_commands * cmd_size) % kTotalNumCommandEntries);
+
+ // Lock flushing to force the buffer to get full.
+ command_buffer_->LockFlush();
+
+ // Add enough commands to over fill the buffer.
+ for (int32 ii = 0; ii < kTotalNumCommandEntries / cmd_size + 2; ++ii) {
+ AddCommandWithExpect(error::kNoError,
+ start_commands + ii + kUnusedCommandId,
+ num_args,
+ &args[0]);
+ }
+
+ // Flush all commands.
+ command_buffer_->UnlockFlush();
+ 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 buffer from put to put+size is free in the parser.
void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
CommandBufferOffset parser_put = GetParser()->put();
@@ -122,15 +236,21 @@ class CommandBufferHelperTest : public testing::Test {
}
int32 GetGetOffset() {
- return command_buffer_->GetState().get_offset;
+ return command_buffer_->GetLastState().get_offset;
}
int32 GetPutOffset() {
- return command_buffer_->GetState().put_offset;
+ return command_buffer_->GetLastState().put_offset;
}
+ int32 GetHelperGetOffset() { return helper_->get_offset(); }
+
+ int32 GetHelperPutOffset() { return helper_->put_; }
+
+ uint32 GetHelperFlushGeneration() { return helper_->flush_generation(); }
+
error::Error GetError() {
- return command_buffer_->GetState().error;
+ return command_buffer_->GetLastState().error;
}
CommandBufferOffset get_helper_put() { return helper_->put_; }
@@ -141,12 +261,176 @@ class CommandBufferHelperTest : public testing::Test {
base::MessageLoop message_loop_;
scoped_ptr<AsyncAPIMock> api_mock_;
scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
- scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<CommandBufferServiceLocked> command_buffer_;
scoped_ptr<GpuScheduler> gpu_scheduler_;
scoped_ptr<CommandBufferHelper> helper_;
+ std::list<linked_ptr<std::vector<CommandBufferEntry> > > test_command_args_;
+ unsigned int test_command_next_id_;
Sequence sequence_;
};
+// Checks immediate_entry_count_ changes based on 'usable' state.
+TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesNotUsable) {
+ // Auto flushing mode is tested separately.
+ helper_->SetAutomaticFlushes(false);
+ EXPECT_EQ(helper_->usable(), true);
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
+ helper_->ClearUsable();
+ EXPECT_EQ(ImmediateEntryCount(), 0);
+}
+
+// Checks immediate_entry_count_ changes based on RingBuffer state.
+TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesNoRingBuffer) {
+ helper_->SetAutomaticFlushes(false);
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
+ helper_->FreeRingBuffer();
+ EXPECT_EQ(ImmediateEntryCount(), 0);
+}
+
+// Checks immediate_entry_count_ calc when Put >= Get and Get == 0.
+TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesGetAtZero) {
+ // No internal auto flushing.
+ helper_->SetAutomaticFlushes(false);
+ command_buffer_->LockFlush();
+
+ // Start at Get = Put = 0.
+ EXPECT_EQ(GetHelperPutOffset(), 0);
+ EXPECT_EQ(GetHelperGetOffset(), 0);
+
+ // Immediate count should be 1 less than the end of the buffer.
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
+ AddUniqueCommandWithExpect(error::kNoError, 2);
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 3);
+
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks immediate_entry_count_ calc when Put >= Get and Get > 0.
+TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesGetInMiddle) {
+ // No internal auto flushing.
+ helper_->SetAutomaticFlushes(false);
+ command_buffer_->LockFlush();
+
+ // Move to Get = Put = 2.
+ AddUniqueCommandWithExpect(error::kNoError, 2);
+ helper_->Finish();
+ EXPECT_EQ(GetHelperPutOffset(), 2);
+ EXPECT_EQ(GetHelperGetOffset(), 2);
+
+ // Immediate count should be up to the end of the buffer.
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 2);
+ AddUniqueCommandWithExpect(error::kNoError, 2);
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 4);
+
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks immediate_entry_count_ calc when Put < Get.
+TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesGetBeforePut) {
+ // Move to Get = kTotalNumCommandEntries / 4, Put = 0.
+ const int kInitGetOffset = kTotalNumCommandEntries / 4;
+ helper_->SetAutomaticFlushes(false);
+ command_buffer_->LockFlush();
+ AddUniqueCommandWithExpect(error::kNoError, kInitGetOffset);
+ helper_->Finish();
+ AddUniqueCommandWithExpect(error::kNoError,
+ kTotalNumCommandEntries - kInitGetOffset);
+
+ // Flush instead of Finish will let Put wrap without the command buffer
+ // immediately processing the data between Get and Put.
+ helper_->Flush();
+
+ EXPECT_EQ(GetHelperGetOffset(), kInitGetOffset);
+ EXPECT_EQ(GetHelperPutOffset(), 0);
+
+ // Immediate count should be up to Get - 1.
+ EXPECT_EQ(ImmediateEntryCount(), kInitGetOffset - 1);
+ AddUniqueCommandWithExpect(error::kNoError, 2);
+ EXPECT_EQ(ImmediateEntryCount(), kInitGetOffset - 3);
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks immediate_entry_count_ calc when automatic flushing is enabled.
+TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesAutoFlushing) {
+ command_buffer_->LockFlush();
+
+ // Start at Get = Put = 0.
+ EXPECT_EQ(GetHelperPutOffset(), 0);
+ EXPECT_EQ(GetHelperGetOffset(), 0);
+
+ // Without auto flushes, up to kTotalNumCommandEntries - 1 is available.
+ helper_->SetAutomaticFlushes(false);
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
+
+ // With auto flushes, and Get == Last Put,
+ // up to kTotalNumCommandEntries / kAutoFlushSmall is available.
+ helper_->SetAutomaticFlushes(true);
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries / kAutoFlushSmall);
+
+ // With auto flushes, and Get != Last Put,
+ // up to kTotalNumCommandEntries / kAutoFlushBig is available.
+ AddUniqueCommandWithExpect(error::kNoError, 2);
+ helper_->Flush();
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries / kAutoFlushBig);
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks immediate_entry_count_ calc when automatic flushing is enabled, and
+// we allocate commands over the immediate_entry_count_ size.
+TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesOverFlushLimit) {
+ // Lock internal flushing.
+ command_buffer_->LockFlush();
+
+ // Start at Get = Put = 0.
+ EXPECT_EQ(GetHelperPutOffset(), 0);
+ EXPECT_EQ(GetHelperGetOffset(), 0);
+
+ // Pre-check ImmediateEntryCount is limited with automatic flushing enabled.
+ helper_->SetAutomaticFlushes(true);
+ EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries / kAutoFlushSmall);
+
+ // Add a command larger than ImmediateEntryCount().
+ AddUniqueCommandWithExpect(error::kNoError, ImmediateEntryCount() + 1);
+
+ // ImmediateEntryCount() should now be 0, to force a flush check on the next
+ // command.
+ EXPECT_EQ(ImmediateEntryCount(), 0);
+
+ // Add a command when ImmediateEntryCount() == 0.
+ AddUniqueCommandWithExpect(error::kNoError, ImmediateEntryCount() + 1);
+
+ helper_->Finish();
+ // 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, and that the
// status/error stay valid.
TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
@@ -184,12 +468,16 @@ TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
// 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.
+ // Add num_commands * commands of size 3 through the helper to make sure we
+ // do wrap. kTotalNumCommandEntries must not be a multiple of 3.
+ COMPILE_ASSERT(kTotalNumCommandEntries % 3 != 0,
+ Is_multiple_of_num_command_entries);
+ const int kNumCommands = (kTotalNumCommandEntries / 3) * 2;
CommandBufferEntry args1[2];
args1[0].value_uint32 = 5;
args1[1].value_float = 4.f;
- for (unsigned int i = 0; i < 5; ++i) {
+ for (int i = 0; i < kNumCommands; ++i) {
AddCommandWithExpect(error::kNoError, kUnusedCommandId + i, 2, args1);
}
@@ -204,13 +492,13 @@ TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
// 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 int32 kCommandSize = kTotalNumCommandEntries / 2;
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;
+ args1[ii].value_uint32 = ii + 1;
}
for (unsigned int i = 0; i < 5; ++i) {
@@ -226,6 +514,22 @@ TEST_F(CommandBufferHelperTest, TestCommandWrappingExactMultiple) {
EXPECT_EQ(error::kNoError, GetError());
}
+// Checks exact wrapping condition with Get = 0.
+TEST_F(CommandBufferHelperTest, TestCommandWrappingFullAtStart) {
+ TestCommandWrappingFull(2, 0);
+}
+
+// Checks exact wrapping condition with 0 < Get < kTotalNumCommandEntries.
+TEST_F(CommandBufferHelperTest, TestCommandWrappingFullInMiddle) {
+ TestCommandWrappingFull(2, 1);
+}
+
+// Checks exact wrapping condition with Get = kTotalNumCommandEntries.
+// Get should wrap back to 0, but making sure.
+TEST_F(CommandBufferHelperTest, TestCommandWrappingFullAtEnd) {
+ TestCommandWrappingFull(2, kTotalNumCommandEntries / 2);
+}
+
// Checks that asking for available entries work, and that the parser
// effectively won't use that space.
TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
@@ -287,6 +591,46 @@ TEST_F(CommandBufferHelperTest, TestToken) {
EXPECT_EQ(error::kNoError, GetError());
}
+// Checks WaitForToken doesn't Flush if token is already read.
+TEST_F(CommandBufferHelperTest, TestWaitForTokenFlush) {
+ 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);
+ int32 token = helper_->InsertToken();
+
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(error::kNoError)));
+
+ int flush_count = command_buffer_->FlushCount();
+
+ // Test that waiting for pending token causes a Flush.
+ helper_->WaitForToken(token);
+ EXPECT_EQ(command_buffer_->FlushCount(), flush_count + 1);
+
+ // Test that we don't Flush repeatedly.
+ helper_->WaitForToken(token);
+ EXPECT_EQ(command_buffer_->FlushCount(), flush_count + 1);
+
+ // Add another command.
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
+
+ // Test that we don't Flush repeatedly even if commands are pending.
+ helper_->WaitForToken(token);
+ EXPECT_EQ(command_buffer_->FlushCount(), flush_count + 1);
+
+ 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());
@@ -330,4 +674,38 @@ TEST_F(CommandBufferHelperTest, IsContextLost) {
EXPECT_TRUE(helper_->IsContextLost());
}
+// Checks helper's 'flush generation' updates.
+TEST_F(CommandBufferHelperTest, TestFlushGeneration) {
+ // Explicit flushing only.
+ helper_->SetAutomaticFlushes(false);
+
+ // Generation should change after Flush() but not before.
+ uint32 gen1, gen2, gen3;
+
+ gen1 = GetHelperFlushGeneration();
+ AddUniqueCommandWithExpect(error::kNoError, 2);
+ gen2 = GetHelperFlushGeneration();
+ helper_->Flush();
+ gen3 = GetHelperFlushGeneration();
+ EXPECT_EQ(gen2, gen1);
+ EXPECT_NE(gen3, gen2);
+
+ // Generation should change after Finish() but not before.
+ gen1 = GetHelperFlushGeneration();
+ AddUniqueCommandWithExpect(error::kNoError, 2);
+ gen2 = GetHelperFlushGeneration();
+ helper_->Finish();
+ gen3 = GetHelperFlushGeneration();
+ EXPECT_EQ(gen2, gen1);
+ EXPECT_NE(gen3, gen2);
+
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
} // namespace gpu