// Copyright (c) 2011 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. #include "gpu/command_buffer/service/command_executor.h" #include #include #include "gpu/command_buffer/common/command_buffer_mock.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" #include "gpu/command_buffer/service/mocks.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using testing::_; using testing::DoAll; using testing::Invoke; using testing::NiceMock; using testing::Return; using testing::SetArgumentPointee; using testing::StrictMock; namespace gpu { const size_t kRingBufferSize = 1024; class CommandExecutorTest : public testing::Test { protected: static const int32_t kTransferBufferId = 123; void SetUp() override { scoped_ptr shared_memory(new ::base::SharedMemory); shared_memory->CreateAndMapAnonymous(kRingBufferSize); buffer_ = static_cast(shared_memory->memory()); shared_memory_buffer_ = MakeBufferFromSharedMemory(std::move(shared_memory), kRingBufferSize); memset(buffer_, 0, kRingBufferSize); command_buffer_.reset(new MockCommandBuffer); CommandBuffer::State default_state; ON_CALL(*command_buffer_.get(), GetLastState()) .WillByDefault(Return(default_state)); ON_CALL(*command_buffer_.get(), GetPutOffset()).WillByDefault(Return(0)); decoder_.reset(new gles2::MockGLES2Decoder()); // Install FakeDoCommands handler so we can use individual DoCommand() // expectations. EXPECT_CALL(*decoder_, DoCommands(_, _, _, _)) .WillRepeatedly( Invoke(decoder_.get(), &gles2::MockGLES2Decoder::FakeDoCommands)); executor_.reset(new gpu::CommandExecutor(command_buffer_.get(), decoder_.get(), decoder_.get())); EXPECT_CALL(*command_buffer_, GetTransferBuffer(kTransferBufferId)) .WillOnce(Return(shared_memory_buffer_)); EXPECT_CALL(*command_buffer_, SetGetOffset(0)); EXPECT_TRUE(executor_->SetGetBuffer(kTransferBufferId)); } void TearDown() override { // Ensure that any unexpected tasks posted by the GPU scheduler are executed // in order to fail the test. base::MessageLoop::current()->RunUntilIdle(); } error::Error GetError() { return command_buffer_->GetLastState().error; } scoped_ptr command_buffer_; scoped_refptr shared_memory_buffer_; int32_t* buffer_; scoped_ptr decoder_; scoped_ptr executor_; base::MessageLoop message_loop_; }; TEST_F(CommandExecutorTest, ExecutorDoesNothingIfRingBufferIsEmpty) { CommandBuffer::State state; EXPECT_CALL(*command_buffer_, GetLastState()).WillRepeatedly(Return(state)); EXPECT_CALL(*command_buffer_, SetParseError(_)).Times(0); executor_->PutChanged(); } TEST_F(CommandExecutorTest, GetSetBuffer) { CommandBuffer::State state; // Set the get offset to something not 0. EXPECT_CALL(*command_buffer_, SetGetOffset(2)); executor_->SetGetOffset(2); EXPECT_EQ(2, executor_->GetGetOffset()); // Set the buffer. EXPECT_CALL(*command_buffer_, GetTransferBuffer(kTransferBufferId)) .WillOnce(Return(shared_memory_buffer_)); EXPECT_CALL(*command_buffer_, SetGetOffset(0)); EXPECT_TRUE(executor_->SetGetBuffer(kTransferBufferId)); // Check the get offset was reset. EXPECT_EQ(0, executor_->GetGetOffset()); } TEST_F(CommandExecutorTest, ProcessesOneCommand) { CommandHeader* header = reinterpret_cast(&buffer_[0]); header[0].command = 7; header[0].size = 2; buffer_[1] = 123; CommandBuffer::State state; EXPECT_CALL(*command_buffer_, GetLastState()).WillRepeatedly(Return(state)); EXPECT_CALL(*command_buffer_, GetPutOffset()).WillRepeatedly(Return(2)); EXPECT_CALL(*command_buffer_, SetGetOffset(2)); EXPECT_CALL(*decoder_, DoCommand(7, 1, &buffer_[0])) .WillOnce(Return(error::kNoError)); EXPECT_CALL(*command_buffer_, SetParseError(_)).Times(0); executor_->PutChanged(); } TEST_F(CommandExecutorTest, ProcessesTwoCommands) { CommandHeader* header = reinterpret_cast(&buffer_[0]); header[0].command = 7; header[0].size = 2; buffer_[1] = 123; header[2].command = 8; header[2].size = 1; CommandBuffer::State state; EXPECT_CALL(*command_buffer_, GetLastState()).WillRepeatedly(Return(state)); EXPECT_CALL(*command_buffer_, GetPutOffset()).WillRepeatedly(Return(3)); EXPECT_CALL(*decoder_, DoCommand(7, 1, &buffer_[0])) .WillOnce(Return(error::kNoError)); EXPECT_CALL(*decoder_, DoCommand(8, 0, &buffer_[2])) .WillOnce(Return(error::kNoError)); EXPECT_CALL(*command_buffer_, SetGetOffset(3)); executor_->PutChanged(); } TEST_F(CommandExecutorTest, SetsErrorCodeOnCommandBuffer) { CommandHeader* header = reinterpret_cast(&buffer_[0]); header[0].command = 7; header[0].size = 1; CommandBuffer::State state; EXPECT_CALL(*command_buffer_, GetLastState()).WillRepeatedly(Return(state)); EXPECT_CALL(*command_buffer_, GetPutOffset()).WillRepeatedly(Return(1)); EXPECT_CALL(*decoder_, DoCommand(7, 0, &buffer_[0])) .WillOnce(Return(error::kUnknownCommand)); EXPECT_CALL(*command_buffer_, SetGetOffset(1)); EXPECT_CALL(*command_buffer_, SetContextLostReason(_)); EXPECT_CALL(*decoder_, GetContextLostReason()) .WillOnce(Return(error::kUnknown)); EXPECT_CALL(*command_buffer_, SetParseError(error::kUnknownCommand)); executor_->PutChanged(); } TEST_F(CommandExecutorTest, ProcessCommandsDoesNothingAfterError) { CommandBuffer::State state; state.error = error::kGenericError; EXPECT_CALL(*command_buffer_, GetLastState()).WillRepeatedly(Return(state)); executor_->PutChanged(); } TEST_F(CommandExecutorTest, CanGetAddressOfSharedMemory) { EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) .WillOnce(Return(shared_memory_buffer_)); EXPECT_EQ(&buffer_[0], executor_->GetSharedMemoryBuffer(7)->memory()); } ACTION_P2(SetPointee, address, value) { *address = value; } TEST_F(CommandExecutorTest, CanGetSizeOfSharedMemory) { EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) .WillOnce(Return(shared_memory_buffer_)); EXPECT_EQ(kRingBufferSize, executor_->GetSharedMemoryBuffer(7)->size()); } TEST_F(CommandExecutorTest, SetTokenForwardsToCommandBuffer) { EXPECT_CALL(*command_buffer_, SetToken(7)); executor_->set_token(7); } } // namespace gpu