- add sources.
[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 // 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 {
40  protected:
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
44     // helper.
45     EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, _, _))
46         .WillRepeatedly(Return(error::kNoError));
47
48     {
49       TransferBufferManager* manager = new TransferBufferManager();
50       transfer_buffer_manager_.reset(manager);
51       EXPECT_TRUE(manager->Initialize());
52     }
53     command_buffer_.reset(
54         new CommandBufferService(transfer_buffer_manager_.get()));
55     EXPECT_TRUE(command_buffer_->Initialize());
56
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())));
63
64     api_mock_->set_engine(gpu_scheduler_.get());
65
66     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
67     helper_->Initialize(kCommandBufferSizeBytes);
68   }
69
70   virtual void TearDown() {
71     // If the GpuScheduler posts any tasks, this forces them to run.
72     base::MessageLoop::current()->RunUntilIdle();
73   }
74
75   const CommandParser* GetParser() const {
76     return gpu_scheduler_->parser();
77   }
78
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,
82                             unsigned int command,
83                             int arg_count,
84                             CommandBufferEntry *args) {
85     CommandHeader header;
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];
93     }
94
95     EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
96         Truly(AsyncAPIMock::IsArgs(arg_count, args))))
97         .InSequence(sequence_)
98         .WillOnce(Return(_return));
99   }
100
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
108       // get (exclusive).
109       EXPECT_LE(parser_put, put);
110       EXPECT_GT(parser_get, limit);
111     } else {
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);
117       } else {
118         // we're on the bottom side, check we are below get.
119         EXPECT_GT(parser_get, limit);
120       }
121     }
122   }
123
124   int32 GetGetOffset() {
125     return command_buffer_->GetState().get_offset;
126   }
127
128   int32 GetPutOffset() {
129     return command_buffer_->GetState().put_offset;
130   }
131
132   error::Error GetError() {
133     return command_buffer_->GetState().error;
134   }
135
136   CommandBufferOffset get_helper_put() { return helper_->put_; }
137
138 #if defined(OS_MACOSX)
139   base::mac::ScopedNSAutoreleasePool autorelease_pool_;
140 #endif
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_;
147   Sequence sequence_;
148 };
149
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
154   // helper.
155   EXPECT_TRUE(GetParser() != NULL);
156   EXPECT_EQ(error::kNoError, GetError());
157   EXPECT_EQ(0, GetGetOffset());
158
159   // Add 3 commands through the helper
160   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
161
162   CommandBufferEntry args1[2];
163   args1[0].value_uint32 = 3;
164   args1[1].value_float = 4.f;
165   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args1);
166
167   CommandBufferEntry args2[2];
168   args2[0].value_uint32 = 5;
169   args2[1].value_float = 6.f;
170   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args2);
171
172   // Wait until it's done.
173   helper_->Finish();
174   // Check that the engine has no more work to do.
175   EXPECT_TRUE(GetParser()->IsEmpty());
176
177   // Check that the commands did happen.
178   Mock::VerifyAndClearExpectations(api_mock_.get());
179
180   // Check the error status.
181   EXPECT_EQ(error::kNoError, GetError());
182 }
183
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;
191
192   for (unsigned int i = 0; i < 5; ++i) {
193     AddCommandWithExpect(error::kNoError, kUnusedCommandId + i, 2, args1);
194   }
195
196   helper_->Finish();
197   // Check that the commands did happen.
198   Mock::VerifyAndClearExpectations(api_mock_.get());
199
200   // Check the error status.
201   EXPECT_EQ(error::kNoError, GetError());
202 }
203
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;
214   }
215
216   for (unsigned int i = 0; i < 5; ++i) {
217     AddCommandWithExpect(
218         error::kNoError, i + kUnusedCommandId, kNumArgs, args1);
219   }
220
221   helper_->Finish();
222   // Check that the commands did happen.
223   Mock::VerifyAndClearExpectations(api_mock_.get());
224
225   // Check the error status.
226   EXPECT_EQ(error::kNoError, GetError());
227 }
228
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;
235
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);
241
242   // Ask for 5 entries.
243   helper_->WaitForAvailableEntries(5);
244
245   CommandBufferOffset put = get_helper_put();
246   CheckFreeSpace(put, 5);
247
248   // Add more commands.
249   AddCommandWithExpect(error::kNoError, kUnusedCommandId + 5, 2, args);
250
251   // Wait until everything is done done.
252   helper_->Finish();
253
254   // Check that the commands did happen.
255   Mock::VerifyAndClearExpectations(api_mock_.get());
256
257   // Check the error status.
258   EXPECT_EQ(error::kNoError, GetError());
259 }
260
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;
266
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();
272
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());
281   helper_->Finish();
282
283   // Check that the commands did happen.
284   Mock::VerifyAndClearExpectations(api_mock_.get());
285
286   // Check the error status.
287   EXPECT_EQ(error::kNoError, GetError());
288 }
289
290 TEST_F(CommandBufferHelperTest, FreeRingBuffer) {
291   EXPECT_TRUE(helper_->HaveRingBuffer());
292
293   // Test freeing ring buffer.
294   helper_->FreeRingBuffer();
295   EXPECT_FALSE(helper_->HaveRingBuffer());
296
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());
306
307   // Test that WaitForAvailableEntries allocates a new one
308   AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
309   EXPECT_TRUE(helper_->HaveRingBuffer());
310   helper_->Finish();
311   helper_->FreeRingBuffer();
312   EXPECT_FALSE(helper_->HaveRingBuffer());
313
314   // Check that the commands did happen.
315   Mock::VerifyAndClearExpectations(api_mock_.get());
316 }
317
318 TEST_F(CommandBufferHelperTest, Noop) {
319   for (int ii = 1; ii < 4; ++ii) {
320     CommandBufferOffset put_before = get_helper_put();
321     helper_->Noop(ii);
322     CommandBufferOffset put_after = get_helper_put();
323     EXPECT_EQ(ii, put_after - put_before);
324   }
325 }
326
327 TEST_F(CommandBufferHelperTest, IsContextLost) {
328   EXPECT_FALSE(helper_->IsContextLost());
329   command_buffer_->SetParseError(error::kGenericError);
330   EXPECT_TRUE(helper_->IsContextLost());
331 }
332
333 }  // namespace gpu