1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Tests for the Command Buffer Helper.
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
11 #include "gpu/command_buffer/service/command_buffer_service.h"
12 #include "gpu/command_buffer/service/gpu_scheduler.h"
13 #include "gpu/command_buffer/service/mocks.h"
14 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 #if defined(OS_MACOSX)
18 #include "base/mac/scoped_nsautorelease_pool.h"
23 using testing::Return
;
26 using testing::Sequence
;
28 using testing::Invoke
;
31 const int32 kTotalNumCommandEntries
= 10;
32 const int32 kCommandBufferSizeBytes
=
33 kTotalNumCommandEntries
* sizeof(CommandBufferEntry
);
34 const int32 kUnusedCommandId
= 5; // we use 0 and 2 currently.
36 // Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
37 // using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
38 // (calling it directly, not through the RPC mechanism).
39 class CommandBufferHelperTest
: public testing::Test
{
41 virtual void SetUp() {
42 api_mock_
.reset(new AsyncAPIMock
);
43 // ignore noops in the mock - we don't want to inspect the internals of the
45 EXPECT_CALL(*api_mock_
, DoCommand(cmd::kNoop
, _
, _
))
46 .WillRepeatedly(Return(error::kNoError
));
49 TransferBufferManager
* manager
= new TransferBufferManager();
50 transfer_buffer_manager_
.reset(manager
);
51 EXPECT_TRUE(manager
->Initialize());
53 command_buffer_
.reset(
54 new CommandBufferService(transfer_buffer_manager_
.get()));
55 EXPECT_TRUE(command_buffer_
->Initialize());
57 gpu_scheduler_
.reset(new GpuScheduler(
58 command_buffer_
.get(), api_mock_
.get(), NULL
));
59 command_buffer_
->SetPutOffsetChangeCallback(base::Bind(
60 &GpuScheduler::PutChanged
, base::Unretained(gpu_scheduler_
.get())));
61 command_buffer_
->SetGetBufferChangeCallback(base::Bind(
62 &GpuScheduler::SetGetBuffer
, base::Unretained(gpu_scheduler_
.get())));
64 api_mock_
->set_engine(gpu_scheduler_
.get());
66 helper_
.reset(new CommandBufferHelper(command_buffer_
.get()));
67 helper_
->Initialize(kCommandBufferSizeBytes
);
70 virtual void TearDown() {
71 // If the GpuScheduler posts any tasks, this forces them to run.
72 base::MessageLoop::current()->RunUntilIdle();
75 const CommandParser
* GetParser() const {
76 return gpu_scheduler_
->parser();
79 // Adds a command to the buffer through the helper, while adding it as an
80 // expected call on the API mock.
81 void AddCommandWithExpect(error::Error _return
,
84 CommandBufferEntry
*args
) {
86 header
.size
= arg_count
+ 1;
87 header
.command
= command
;
88 CommandBufferEntry
* cmds
= helper_
->GetSpace(arg_count
+ 1);
89 CommandBufferOffset put
= 0;
90 cmds
[put
++].value_header
= header
;
91 for (int ii
= 0; ii
< arg_count
; ++ii
) {
92 cmds
[put
++] = args
[ii
];
95 EXPECT_CALL(*api_mock_
, DoCommand(command
, arg_count
,
96 Truly(AsyncAPIMock::IsArgs(arg_count
, args
))))
97 .InSequence(sequence_
)
98 .WillOnce(Return(_return
));
101 // Checks that the buffer from put to put+size is free in the parser.
102 void CheckFreeSpace(CommandBufferOffset put
, unsigned int size
) {
103 CommandBufferOffset parser_put
= GetParser()->put();
104 CommandBufferOffset parser_get
= GetParser()->get();
105 CommandBufferOffset limit
= put
+ size
;
106 if (parser_get
> parser_put
) {
107 // "busy" buffer wraps, so "free" buffer is between put (inclusive) and
109 EXPECT_LE(parser_put
, put
);
110 EXPECT_GT(parser_get
, limit
);
112 // "busy" buffer does not wrap, so the "free" buffer is the top side (from
113 // put to the limit) and the bottom side (from 0 to get).
114 if (put
>= parser_put
) {
115 // we're on the top side, check we are below the limit.
116 EXPECT_GE(kTotalNumCommandEntries
, limit
);
118 // we're on the bottom side, check we are below get.
119 EXPECT_GT(parser_get
, limit
);
124 int32
GetGetOffset() {
125 return command_buffer_
->GetState().get_offset
;
128 int32
GetPutOffset() {
129 return command_buffer_
->GetState().put_offset
;
132 error::Error
GetError() {
133 return command_buffer_
->GetState().error
;
136 CommandBufferOffset
get_helper_put() { return helper_
->put_
; }
138 #if defined(OS_MACOSX)
139 base::mac::ScopedNSAutoreleasePool autorelease_pool_
;
141 base::MessageLoop message_loop_
;
142 scoped_ptr
<AsyncAPIMock
> api_mock_
;
143 scoped_ptr
<TransferBufferManagerInterface
> transfer_buffer_manager_
;
144 scoped_ptr
<CommandBufferService
> command_buffer_
;
145 scoped_ptr
<GpuScheduler
> gpu_scheduler_
;
146 scoped_ptr
<CommandBufferHelper
> helper_
;
150 // Checks that commands in the buffer are properly executed, and that the
151 // status/error stay valid.
152 TEST_F(CommandBufferHelperTest
, TestCommandProcessing
) {
153 // Check initial state of the engine - it should have been configured by the
155 EXPECT_TRUE(GetParser() != NULL
);
156 EXPECT_EQ(error::kNoError
, GetError());
157 EXPECT_EQ(0, GetGetOffset());
159 // Add 3 commands through the helper
160 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
, 0, NULL
);
162 CommandBufferEntry args1
[2];
163 args1
[0].value_uint32
= 3;
164 args1
[1].value_float
= 4.f
;
165 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
, 2, args1
);
167 CommandBufferEntry args2
[2];
168 args2
[0].value_uint32
= 5;
169 args2
[1].value_float
= 6.f
;
170 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
, 2, args2
);
172 // Wait until it's done.
174 // Check that the engine has no more work to do.
175 EXPECT_TRUE(GetParser()->IsEmpty());
177 // Check that the commands did happen.
178 Mock::VerifyAndClearExpectations(api_mock_
.get());
180 // Check the error status.
181 EXPECT_EQ(error::kNoError
, GetError());
184 // Checks that commands in the buffer are properly executed when wrapping the
185 // buffer, and that the status/error stay valid.
186 TEST_F(CommandBufferHelperTest
, TestCommandWrapping
) {
187 // Add 5 commands of size 3 through the helper to make sure we do wrap.
188 CommandBufferEntry args1
[2];
189 args1
[0].value_uint32
= 5;
190 args1
[1].value_float
= 4.f
;
192 for (unsigned int i
= 0; i
< 5; ++i
) {
193 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ i
, 2, args1
);
197 // Check that the commands did happen.
198 Mock::VerifyAndClearExpectations(api_mock_
.get());
200 // Check the error status.
201 EXPECT_EQ(error::kNoError
, GetError());
204 // Checks the case where the command inserted exactly matches the space left in
205 // the command buffer.
206 TEST_F(CommandBufferHelperTest
, TestCommandWrappingExactMultiple
) {
207 const int32 kCommandSize
= 5;
208 const size_t kNumArgs
= kCommandSize
- 1;
209 COMPILE_ASSERT(kTotalNumCommandEntries
% kCommandSize
== 0,
210 Not_multiple_of_num_command_entries
);
211 CommandBufferEntry args1
[kNumArgs
];
212 for (size_t ii
= 0; ii
< kNumArgs
; ++ii
) {
213 args1
[0].value_uint32
= ii
+ 1;
216 for (unsigned int i
= 0; i
< 5; ++i
) {
217 AddCommandWithExpect(
218 error::kNoError
, i
+ kUnusedCommandId
, kNumArgs
, args1
);
222 // Check that the commands did happen.
223 Mock::VerifyAndClearExpectations(api_mock_
.get());
225 // Check the error status.
226 EXPECT_EQ(error::kNoError
, GetError());
229 // Checks that asking for available entries work, and that the parser
230 // effectively won't use that space.
231 TEST_F(CommandBufferHelperTest
, TestAvailableEntries
) {
232 CommandBufferEntry args
[2];
233 args
[0].value_uint32
= 3;
234 args
[1].value_float
= 4.f
;
236 // Add 2 commands through the helper - 8 entries
237 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ 1, 0, NULL
);
238 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ 2, 0, NULL
);
239 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ 3, 2, args
);
240 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ 4, 2, args
);
242 // Ask for 5 entries.
243 helper_
->WaitForAvailableEntries(5);
245 CommandBufferOffset put
= get_helper_put();
246 CheckFreeSpace(put
, 5);
248 // Add more commands.
249 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ 5, 2, args
);
251 // Wait until everything is done done.
254 // Check that the commands did happen.
255 Mock::VerifyAndClearExpectations(api_mock_
.get());
257 // Check the error status.
258 EXPECT_EQ(error::kNoError
, GetError());
261 // Checks that the InsertToken/WaitForToken work.
262 TEST_F(CommandBufferHelperTest
, TestToken
) {
263 CommandBufferEntry args
[2];
264 args
[0].value_uint32
= 3;
265 args
[1].value_float
= 4.f
;
267 // Add a first command.
268 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ 3, 2, args
);
269 // keep track of the buffer position.
270 CommandBufferOffset command1_put
= get_helper_put();
271 int32 token
= helper_
->InsertToken();
273 EXPECT_CALL(*api_mock_
.get(), DoCommand(cmd::kSetToken
, 1, _
))
274 .WillOnce(DoAll(Invoke(api_mock_
.get(), &AsyncAPIMock::SetToken
),
275 Return(error::kNoError
)));
276 // Add another command.
277 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
+ 4, 2, args
);
278 helper_
->WaitForToken(token
);
279 // check that the get pointer is beyond the first command.
280 EXPECT_LE(command1_put
, GetGetOffset());
283 // Check that the commands did happen.
284 Mock::VerifyAndClearExpectations(api_mock_
.get());
286 // Check the error status.
287 EXPECT_EQ(error::kNoError
, GetError());
290 TEST_F(CommandBufferHelperTest
, FreeRingBuffer
) {
291 EXPECT_TRUE(helper_
->HaveRingBuffer());
293 // Test freeing ring buffer.
294 helper_
->FreeRingBuffer();
295 EXPECT_FALSE(helper_
->HaveRingBuffer());
297 // Test that InsertToken allocates a new one
298 int32 token
= helper_
->InsertToken();
299 EXPECT_TRUE(helper_
->HaveRingBuffer());
300 EXPECT_CALL(*api_mock_
.get(), DoCommand(cmd::kSetToken
, 1, _
))
301 .WillOnce(DoAll(Invoke(api_mock_
.get(), &AsyncAPIMock::SetToken
),
302 Return(error::kNoError
)));
303 helper_
->WaitForToken(token
);
304 helper_
->FreeRingBuffer();
305 EXPECT_FALSE(helper_
->HaveRingBuffer());
307 // Test that WaitForAvailableEntries allocates a new one
308 AddCommandWithExpect(error::kNoError
, kUnusedCommandId
, 0, NULL
);
309 EXPECT_TRUE(helper_
->HaveRingBuffer());
311 helper_
->FreeRingBuffer();
312 EXPECT_FALSE(helper_
->HaveRingBuffer());
314 // Check that the commands did happen.
315 Mock::VerifyAndClearExpectations(api_mock_
.get());
318 TEST_F(CommandBufferHelperTest
, Noop
) {
319 for (int ii
= 1; ii
< 4; ++ii
) {
320 CommandBufferOffset put_before
= get_helper_put();
322 CommandBufferOffset put_after
= get_helper_put();
323 EXPECT_EQ(ii
, put_after
- put_before
);
327 TEST_F(CommandBufferHelperTest
, IsContextLost
) {
328 EXPECT_FALSE(helper_
->IsContextLost());
329 command_buffer_
->SetParseError(error::kGenericError
);
330 EXPECT_TRUE(helper_
->IsContextLost());