// 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 "base/message_loop/message_loop.h" #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/gpu_scheduler.h" #include "gpu/command_buffer/service/mocks.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" #endif 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; const size_t kRingBufferEntries = kRingBufferSize / sizeof(CommandBufferEntry); class GpuSchedulerTest : public testing::Test { protected: static const int32 kTransferBufferId = 123; virtual void SetUp() { scoped_ptr shared_memory(new ::base::SharedMemory); shared_memory->CreateAndMapAnonymous(kRingBufferSize); buffer_ = static_cast(shared_memory->memory()); shared_memory_buffer_ = MakeBufferFromSharedMemory(shared_memory.Pass(), kRingBufferSize); memset(buffer_, 0, kRingBufferSize); command_buffer_.reset(new MockCommandBuffer); CommandBuffer::State default_state; default_state.num_entries = kRingBufferEntries; ON_CALL(*command_buffer_.get(), GetLastState()) .WillByDefault(Return(default_state)); decoder_.reset(new gles2::MockGLES2Decoder()); scheduler_.reset(new gpu::GpuScheduler(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(scheduler_->SetGetBuffer(kTransferBufferId)); } virtual void TearDown() { // 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; } #if defined(OS_MACOSX) base::mac::ScopedNSAutoreleasePool autorelease_pool_; #endif base::MessageLoop message_loop; scoped_ptr command_buffer_; scoped_refptr shared_memory_buffer_; int32* buffer_; scoped_ptr decoder_; scoped_ptr scheduler_; }; TEST_F(GpuSchedulerTest, SchedulerDoesNothingIfRingBufferIsEmpty) { CommandBuffer::State state; state.put_offset = 0; EXPECT_CALL(*command_buffer_, GetLastState()) .WillRepeatedly(Return(state)); EXPECT_CALL(*command_buffer_, SetParseError(_)) .Times(0); scheduler_->PutChanged(); } TEST_F(GpuSchedulerTest, GetSetBuffer) { CommandBuffer::State state; // Set the get offset to something not 0. EXPECT_CALL(*command_buffer_, SetGetOffset(2)); scheduler_->SetGetOffset(2); EXPECT_EQ(2, scheduler_->GetGetOffset()); // Set the buffer. EXPECT_CALL(*command_buffer_, GetTransferBuffer(kTransferBufferId)) .WillOnce(Return(shared_memory_buffer_)); EXPECT_CALL(*command_buffer_, SetGetOffset(0)); EXPECT_TRUE(scheduler_->SetGetBuffer(kTransferBufferId)); // Check the get offset was reset. EXPECT_EQ(0, scheduler_->GetGetOffset()); } TEST_F(GpuSchedulerTest, ProcessesOneCommand) { CommandHeader* header = reinterpret_cast(&buffer_[0]); header[0].command = 7; header[0].size = 2; buffer_[1] = 123; CommandBuffer::State state; state.put_offset = 2; EXPECT_CALL(*command_buffer_, GetLastState()) .WillRepeatedly(Return(state)); 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); scheduler_->PutChanged(); } TEST_F(GpuSchedulerTest, 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; state.put_offset = 3; EXPECT_CALL(*command_buffer_, GetLastState()) .WillRepeatedly(Return(state)); EXPECT_CALL(*decoder_, DoCommand(7, 1, &buffer_[0])) .WillOnce(Return(error::kNoError)); EXPECT_CALL(*command_buffer_, SetGetOffset(2)); EXPECT_CALL(*decoder_, DoCommand(8, 0, &buffer_[2])) .WillOnce(Return(error::kNoError)); EXPECT_CALL(*command_buffer_, SetGetOffset(3)); scheduler_->PutChanged(); } TEST_F(GpuSchedulerTest, SetsErrorCodeOnCommandBuffer) { CommandHeader* header = reinterpret_cast(&buffer_[0]); header[0].command = 7; header[0].size = 1; CommandBuffer::State state; state.put_offset = 1; EXPECT_CALL(*command_buffer_, GetLastState()) .WillRepeatedly(Return(state)); 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)); scheduler_->PutChanged(); } TEST_F(GpuSchedulerTest, ProcessCommandsDoesNothingAfterError) { CommandBuffer::State state; state.error = error::kGenericError; EXPECT_CALL(*command_buffer_, GetLastState()) .WillRepeatedly(Return(state)); scheduler_->PutChanged(); } TEST_F(GpuSchedulerTest, CanGetAddressOfSharedMemory) { EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) .WillOnce(Return(shared_memory_buffer_)); EXPECT_EQ(&buffer_[0], scheduler_->GetSharedMemoryBuffer(7)->memory()); } ACTION_P2(SetPointee, address, value) { *address = value; } TEST_F(GpuSchedulerTest, CanGetSizeOfSharedMemory) { EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) .WillOnce(Return(shared_memory_buffer_)); EXPECT_EQ(kRingBufferSize, scheduler_->GetSharedMemoryBuffer(7)->size()); } TEST_F(GpuSchedulerTest, SetTokenForwardsToCommandBuffer) { EXPECT_CALL(*command_buffer_, SetToken(7)); scheduler_->set_token(7); } } // namespace gpu