Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / client / cmd_buffer_helper_test.cc
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.
4
5 // Tests for the Command Buffer Helper.
6
7 #include "base/bind.h"
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"
16
17 #if defined(OS_MACOSX)
18 #include "base/mac/scoped_nsautorelease_pool.h"
19 #endif
20
21 namespace gpu {
22
23 using testing::Return;
24 using testing::Mock;
25 using testing::Truly;
26 using testing::Sequence;
27 using testing::DoAll;
28 using testing::Invoke;
29 using testing::_;
30
31 const int32 kTotalNumCommandEntries = 10;
32 const int32 kCommandBufferSizeBytes =
33     kTotalNumCommandEntries * sizeof(CommandBufferEntry);
34 const int32 kUnusedCommandId = 5;  // we use 0 and 2 currently.
35
36 // Override CommandBufferService::Flush() to lock flushing and simulate
37 // the buffer becoming full in asynchronous mode.
38 class CommandBufferServiceLocked : public CommandBufferService {
39  public:
40   explicit CommandBufferServiceLocked(
41       TransferBufferManagerInterface* transfer_buffer_manager)
42       : CommandBufferService(transfer_buffer_manager),
43         flush_locked_(false) {}
44   virtual ~CommandBufferServiceLocked() {}
45
46   virtual void Flush(int32 put_offset) OVERRIDE {
47     if (!flush_locked_)
48       CommandBufferService::Flush(put_offset);
49   }
50
51   void LockFlush() { flush_locked_ = true; }
52
53   void UnlockFlush() { flush_locked_ = false; }
54
55  private:
56   bool flush_locked_;
57   DISALLOW_COPY_AND_ASSIGN(CommandBufferServiceLocked);
58 };
59
60 // Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
61 // using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
62 // (calling it directly, not through the RPC mechanism).
63 class CommandBufferHelperTest : public testing::Test {
64  protected:
65   virtual void SetUp() {
66     api_mock_.reset(new AsyncAPIMock);
67     // ignore noops in the mock - we don't want to inspect the internals of the
68     // helper.
69     EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, _, _))
70         .WillRepeatedly(Return(error::kNoError));
71
72     {
73       TransferBufferManager* manager = new TransferBufferManager();
74       transfer_buffer_manager_.reset(manager);
75       EXPECT_TRUE(manager->Initialize());
76     }
77     command_buffer_.reset(
78         new CommandBufferServiceLocked(transfer_buffer_manager_.get()));
79     EXPECT_TRUE(command_buffer_->Initialize());
80
81     gpu_scheduler_.reset(new GpuScheduler(
82         command_buffer_.get(), api_mock_.get(), NULL));
83     command_buffer_->SetPutOffsetChangeCallback(base::Bind(
84         &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
85     command_buffer_->SetGetBufferChangeCallback(base::Bind(
86         &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
87
88     api_mock_->set_engine(gpu_scheduler_.get());
89
90     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
91     helper_->Initialize(kCommandBufferSizeBytes);
92   }
93
94   virtual void TearDown() {
95     // If the GpuScheduler posts any tasks, this forces them to run.
96     base::MessageLoop::current()->RunUntilIdle();
97   }
98
99   const CommandParser* GetParser() const {
100     return gpu_scheduler_->parser();
101   }
102
103   // Adds a command to the buffer through the helper, while adding it as an
104   // expected call on the API mock.
105   void AddCommandWithExpect(error::Error _return,
106                             unsigned int command,
107                             int arg_count,
108                             CommandBufferEntry *args) {
109     CommandHeader header;
110     header.size = arg_count + 1;
111     header.command = command;
112     CommandBufferEntry* cmds = helper_->GetSpace(arg_count + 1);
113     CommandBufferOffset put = 0;
114     cmds[put++].value_header = header;
115     for (int ii = 0; ii < arg_count; ++ii) {
116       cmds[put++] = args[ii];
117     }
118
119     EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
120         Truly(AsyncAPIMock::IsArgs(arg_count, args))))
121         .InSequence(sequence_)
122         .WillOnce(Return(_return));
123   }
124
125   void TestCommandWrappingFull(int32 cmd_size, int32 start_commands) {
126     const int32 num_args = cmd_size - 1;
127     EXPECT_EQ(kTotalNumCommandEntries % cmd_size, 0);
128
129     std::vector<CommandBufferEntry> args(num_args);
130     for (int32 ii = 0; ii < num_args; ++ii) {
131       args[ii].value_uint32 = ii + 1;
132     }
133
134     // Initially insert commands up to start_commands and Finish()
135     for (int32 ii = 0; ii < start_commands; ++ii) {
136       AddCommandWithExpect(
137           error::kNoError, ii + kUnusedCommandId, num_args, &args[0]);
138     }
139     helper_->Finish();
140
141     EXPECT_EQ(GetParser()->put(),
142               (start_commands * cmd_size) % kTotalNumCommandEntries);
143     EXPECT_EQ(GetParser()->get(),
144               (start_commands * cmd_size) % kTotalNumCommandEntries);
145
146     // Lock flushing to force the buffer to get full
147     command_buffer_->LockFlush();
148
149     // Add enough commands to over fill the buffer
150     for (int32 ii = 0; ii < kTotalNumCommandEntries / cmd_size + 2; ++ii) {
151       AddCommandWithExpect(error::kNoError,
152                            start_commands + ii + kUnusedCommandId,
153                            num_args,
154                            &args[0]);
155     }
156
157     // Flush all commands
158     command_buffer_->UnlockFlush();
159     helper_->Finish();
160
161     // Check that the commands did happen.
162     Mock::VerifyAndClearExpectations(api_mock_.get());
163
164     // Check the error status.
165     EXPECT_EQ(error::kNoError, GetError());
166   }
167
168   // Checks that the buffer from put to put+size is free in the parser.
169   void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
170     CommandBufferOffset parser_put = GetParser()->put();
171     CommandBufferOffset parser_get = GetParser()->get();
172     CommandBufferOffset limit = put + size;
173     if (parser_get > parser_put) {
174       // "busy" buffer wraps, so "free" buffer is between put (inclusive) and
175       // get (exclusive).
176       EXPECT_LE(parser_put, put);
177       EXPECT_GT(parser_get, limit);
178     } else {
179       // "busy" buffer does not wrap, so the "free" buffer is the top side (from
180       // put to the limit) and the bottom side (from 0 to get).
181       if (put >= parser_put) {
182         // we're on the top side, check we are below the limit.
183         EXPECT_GE(kTotalNumCommandEntries, limit);
184       } else {
185         // we're on the bottom side, check we are below get.
186         EXPECT_GT(parser_get, limit);
187       }
188     }
189   }
190
191   int32 GetGetOffset() {
192     return command_buffer_->GetState().get_offset;
193   }
194
195   int32 GetPutOffset() {
196     return command_buffer_->GetState().put_offset;
197   }
198
199   error::Error GetError() {
200     return command_buffer_->GetState().error;
201   }
202
203   CommandBufferOffset get_helper_put() { return helper_->put_; }
204
205 #if defined(OS_MACOSX)
206   base::mac::ScopedNSAutoreleasePool autorelease_pool_;
207 #endif
208   base::MessageLoop message_loop_;
209   scoped_ptr<AsyncAPIMock> api_mock_;
210   scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
211   scoped_ptr<CommandBufferServiceLocked> command_buffer_;
212   scoped_ptr<GpuScheduler> gpu_scheduler_;
213   scoped_ptr<CommandBufferHelper> helper_;
214   Sequence sequence_;
215 };
216
217 // Checks that commands in the buffer are properly executed, and that the
218 // status/error stay valid.
219 TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
220   // Check initial state of the engine - it should have been configured by the
221   // helper.
222   EXPECT_TRUE(GetParser() != NULL);
223   EXPECT_EQ(error::kNoError, GetError());
224   EXPECT_EQ(0, GetGetOffset());
225
226   // Add 3 commands through the helper
227   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
228
229   CommandBufferEntry args1[2];
230   args1[0].value_uint32 = 3;
231   args1[1].value_float = 4.f;
232   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args1);
233
234   CommandBufferEntry args2[2];
235   args2[0].value_uint32 = 5;
236   args2[1].value_float = 6.f;
237   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args2);
238
239   // Wait until it's done.
240   helper_->Finish();
241   // Check that the engine has no more work to do.
242   EXPECT_TRUE(GetParser()->IsEmpty());
243
244   // Check that the commands did happen.
245   Mock::VerifyAndClearExpectations(api_mock_.get());
246
247   // Check the error status.
248   EXPECT_EQ(error::kNoError, GetError());
249 }
250
251 // Checks that commands in the buffer are properly executed when wrapping the
252 // buffer, and that the status/error stay valid.
253 TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
254   // Add 5 commands of size 3 through the helper to make sure we do wrap.
255   CommandBufferEntry args1[2];
256   args1[0].value_uint32 = 5;
257   args1[1].value_float = 4.f;
258
259   for (unsigned int i = 0; i < 5; ++i) {
260     AddCommandWithExpect(error::kNoError, kUnusedCommandId + i, 2, args1);
261   }
262
263   helper_->Finish();
264   // Check that the commands did happen.
265   Mock::VerifyAndClearExpectations(api_mock_.get());
266
267   // Check the error status.
268   EXPECT_EQ(error::kNoError, GetError());
269 }
270
271 // Checks the case where the command inserted exactly matches the space left in
272 // the command buffer.
273 TEST_F(CommandBufferHelperTest, TestCommandWrappingExactMultiple) {
274   const int32 kCommandSize = kTotalNumCommandEntries / 2;
275   const size_t kNumArgs = kCommandSize - 1;
276   COMPILE_ASSERT(kTotalNumCommandEntries % kCommandSize == 0,
277                  Not_multiple_of_num_command_entries);
278   CommandBufferEntry args1[kNumArgs];
279   for (size_t ii = 0; ii < kNumArgs; ++ii) {
280     args1[ii].value_uint32 = ii + 1;
281   }
282
283   for (unsigned int i = 0; i < 5; ++i) {
284     AddCommandWithExpect(
285         error::kNoError, i + kUnusedCommandId, kNumArgs, args1);
286   }
287
288   helper_->Finish();
289   // Check that the commands did happen.
290   Mock::VerifyAndClearExpectations(api_mock_.get());
291
292   // Check the error status.
293   EXPECT_EQ(error::kNoError, GetError());
294 }
295
296 TEST_F(CommandBufferHelperTest, TestCommandWrappingFullAtStart) {
297   TestCommandWrappingFull(2, 0);
298 }
299
300 TEST_F(CommandBufferHelperTest, TestCommandWrappingFullInMiddle) {
301   TestCommandWrappingFull(2, 1);
302 }
303
304 TEST_F(CommandBufferHelperTest, TestCommandWrappingFullAtEnd) {
305   TestCommandWrappingFull(2, kTotalNumCommandEntries / 2);
306 }
307
308 // Checks that asking for available entries work, and that the parser
309 // effectively won't use that space.
310 TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
311   CommandBufferEntry args[2];
312   args[0].value_uint32 = 3;
313   args[1].value_float = 4.f;
314
315   // Add 2 commands through the helper - 8 entries
316   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 1, 0, NULL);
317   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 2, 0, NULL);
318   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
319   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
320
321   // Ask for 5 entries.
322   helper_->WaitForAvailableEntries(5);
323
324   CommandBufferOffset put = get_helper_put();
325   CheckFreeSpace(put, 5);
326
327   // Add more commands.
328   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 5, 2, args);
329
330   // Wait until everything is done done.
331   helper_->Finish();
332
333   // Check that the commands did happen.
334   Mock::VerifyAndClearExpectations(api_mock_.get());
335
336   // Check the error status.
337   EXPECT_EQ(error::kNoError, GetError());
338 }
339
340 // Checks that the InsertToken/WaitForToken work.
341 TEST_F(CommandBufferHelperTest, TestToken) {
342   CommandBufferEntry args[2];
343   args[0].value_uint32 = 3;
344   args[1].value_float = 4.f;
345
346   // Add a first command.
347   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
348   // keep track of the buffer position.
349   CommandBufferOffset command1_put = get_helper_put();
350   int32 token = helper_->InsertToken();
351
352   EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
353       .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
354                       Return(error::kNoError)));
355   // Add another command.
356   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
357   helper_->WaitForToken(token);
358   // check that the get pointer is beyond the first command.
359   EXPECT_LE(command1_put, GetGetOffset());
360   helper_->Finish();
361
362   // Check that the commands did happen.
363   Mock::VerifyAndClearExpectations(api_mock_.get());
364
365   // Check the error status.
366   EXPECT_EQ(error::kNoError, GetError());
367 }
368
369 TEST_F(CommandBufferHelperTest, FreeRingBuffer) {
370   EXPECT_TRUE(helper_->HaveRingBuffer());
371
372   // Test freeing ring buffer.
373   helper_->FreeRingBuffer();
374   EXPECT_FALSE(helper_->HaveRingBuffer());
375
376   // Test that InsertToken allocates a new one
377   int32 token = helper_->InsertToken();
378   EXPECT_TRUE(helper_->HaveRingBuffer());
379   EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
380       .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
381                       Return(error::kNoError)));
382   helper_->WaitForToken(token);
383   helper_->FreeRingBuffer();
384   EXPECT_FALSE(helper_->HaveRingBuffer());
385
386   // Test that WaitForAvailableEntries allocates a new one
387   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
388   EXPECT_TRUE(helper_->HaveRingBuffer());
389   helper_->Finish();
390   helper_->FreeRingBuffer();
391   EXPECT_FALSE(helper_->HaveRingBuffer());
392
393   // Check that the commands did happen.
394   Mock::VerifyAndClearExpectations(api_mock_.get());
395 }
396
397 TEST_F(CommandBufferHelperTest, Noop) {
398   for (int ii = 1; ii < 4; ++ii) {
399     CommandBufferOffset put_before = get_helper_put();
400     helper_->Noop(ii);
401     CommandBufferOffset put_after = get_helper_put();
402     EXPECT_EQ(ii, put_after - put_before);
403   }
404 }
405
406 TEST_F(CommandBufferHelperTest, IsContextLost) {
407   EXPECT_FALSE(helper_->IsContextLost());
408   command_buffer_->SetParseError(error::kGenericError);
409   EXPECT_TRUE(helper_->IsContextLost());
410 }
411
412 }  // namespace gpu