| // 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 <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" |
| #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 = 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) {} |
| ~CommandBufferServiceLocked() override {} |
| |
| 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_; } |
| |
| 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). |
| class CommandBufferHelperTest : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| api_mock_.reset(new AsyncAPIMock(true)); |
| |
| // 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 CommandBufferServiceLocked(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); |
| |
| 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, |
| unsigned int command, |
| int arg_count, |
| CommandBufferEntry *args) { |
| CommandHeader header; |
| header.size = arg_count + 1; |
| header.command = command; |
| 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) { |
| cmds[put++] = args[ii]; |
| } |
| |
| EXPECT_CALL(*api_mock_, DoCommand(command, arg_count, |
| Truly(AsyncAPIMock::IsArgs(arg_count, args)))) |
| .InSequence(sequence_) |
| .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(); |
| 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_->GetLastState().get_offset; |
| } |
| |
| int32 GetPutOffset() { |
| return command_buffer_->GetPutOffset(); |
| } |
| |
| int32 GetHelperGetOffset() { return helper_->get_offset(); } |
| |
| int32 GetHelperPutOffset() { return helper_->put_; } |
| |
| uint32 GetHelperFlushGeneration() { return helper_->flush_generation(); } |
| |
| error::Error GetError() { |
| return command_buffer_->GetLastState().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<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) { |
| // 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 num_commands * commands of size 3 through the helper to make sure we |
| // do wrap. kTotalNumCommandEntries must not be a multiple of 3. |
| static_assert(kTotalNumCommandEntries % 3 != 0, |
| "kTotalNumCommandEntries must not be a multiple of 3"); |
| const int kNumCommands = (kTotalNumCommandEntries / 3) * 2; |
| CommandBufferEntry args1[2]; |
| args1[0].value_uint32 = 5; |
| args1[1].value_float = 4.f; |
| |
| for (int i = 0; i < kNumCommands; ++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 = kTotalNumCommandEntries / 2; |
| const size_t kNumArgs = kCommandSize - 1; |
| static_assert(kTotalNumCommandEntries % kCommandSize == 0, |
| "kTotalNumCommandEntries should be a multiple of kCommandSize"); |
| CommandBufferEntry args1[kNumArgs]; |
| for (size_t ii = 0; ii < kNumArgs; ++ii) { |
| args1[ii].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 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) { |
| 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()); |
| } |
| |
| // 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()); |
| |
| // 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()); |
| } |
| |
| // 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()); |
| } |
| |
| TEST_F(CommandBufferHelperTest, TestOrderingBarrierFlushGeneration) { |
| // Explicit flushing only. |
| helper_->SetAutomaticFlushes(false); |
| |
| // Generation should change after OrderingBarrier() but not before. |
| uint32 gen1, gen2, gen3; |
| |
| gen1 = GetHelperFlushGeneration(); |
| AddUniqueCommandWithExpect(error::kNoError, 2); |
| gen2 = GetHelperFlushGeneration(); |
| helper_->OrderingBarrier(); |
| 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()); |
| } |
| |
| // Expect Flush() to always call CommandBuffer::Flush(). |
| TEST_F(CommandBufferHelperTest, TestFlushToCommandBuffer) { |
| // Explicit flushing only. |
| helper_->SetAutomaticFlushes(false); |
| |
| int flush_count1, flush_count2, flush_count3; |
| |
| flush_count1 = command_buffer_->FlushCount(); |
| AddUniqueCommandWithExpect(error::kNoError, 2); |
| helper_->Flush(); |
| flush_count2 = command_buffer_->FlushCount(); |
| helper_->Flush(); |
| flush_count3 = command_buffer_->FlushCount(); |
| |
| EXPECT_EQ(flush_count2, flush_count1 + 1); |
| EXPECT_EQ(flush_count3, flush_count2 + 1); |
| } |
| |
| // Expect OrderingBarrier() to always call CommandBuffer::OrderingBarrier(). |
| TEST_F(CommandBufferHelperTest, TestOrderingBarrierToCommandBuffer) { |
| // Explicit flushing only. |
| helper_->SetAutomaticFlushes(false); |
| |
| int flush_count1, flush_count2, flush_count3; |
| |
| flush_count1 = command_buffer_->FlushCount(); |
| AddUniqueCommandWithExpect(error::kNoError, 2); |
| helper_->OrderingBarrier(); |
| flush_count2 = command_buffer_->FlushCount(); |
| helper_->OrderingBarrier(); |
| flush_count3 = command_buffer_->FlushCount(); |
| |
| EXPECT_EQ(flush_count2, flush_count1 + 1); |
| EXPECT_EQ(flush_count3, flush_count2 + 1); |
| } |
| |
| } // namespace gpu |