1// Copyright (c) 2011 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 parser.
6
7#include "base/logging.h"
8#include "base/memory/scoped_ptr.h"
9#include "gpu/command_buffer/service/cmd_parser.h"
10#include "gpu/command_buffer/service/mocks.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace gpu {
14
15using testing::_;
16using testing::Invoke;
17using testing::Mock;
18using testing::Return;
19using testing::Sequence;
20using testing::SetArgPointee;
21using testing::Truly;
22
23// Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and
24// a fixed size memory buffer. Also provides a simple API to create a
25// CommandParser.
26class CommandParserTest : public testing::Test {
27 protected:
28  virtual void SetUp() {
29    api_mock_.reset(new AsyncAPIMock(false));
30    buffer_entry_count_ = 20;
31    buffer_.reset(new CommandBufferEntry[buffer_entry_count_]);
32  }
33  virtual void TearDown() {}
34
35  void AddDoCommandsExpect(error::Error _return,
36                           unsigned int num_commands,
37                           int num_entries,
38                           int num_processed) {
39    EXPECT_CALL(*api_mock_, DoCommands(num_commands, _, num_entries, _))
40        .InSequence(sequence_)
41        .WillOnce(DoAll(SetArgPointee<3>(num_processed), Return(_return)));
42  }
43
44  // Creates a parser, with a buffer of the specified size (in entries).
45  CommandParser *MakeParser(unsigned int entry_count) {
46    size_t shm_size = buffer_entry_count_ *
47                      sizeof(CommandBufferEntry);  // NOLINT
48    size_t command_buffer_size = entry_count *
49                                 sizeof(CommandBufferEntry);  // NOLINT
50    DCHECK_LE(command_buffer_size, shm_size);
51    CommandParser* parser = new CommandParser(api_mock());
52
53    parser->SetBuffer(buffer(), shm_size, 0, command_buffer_size);
54    return parser;
55  }
56
57  unsigned int buffer_entry_count() { return 20; }
58  AsyncAPIMock *api_mock() { return api_mock_.get(); }
59  CommandBufferEntry *buffer() { return buffer_.get(); }
60 private:
61  unsigned int buffer_entry_count_;
62  scoped_ptr<AsyncAPIMock> api_mock_;
63  scoped_ptr<CommandBufferEntry[]> buffer_;
64  Sequence sequence_;
65};
66
67// Tests initialization conditions.
68TEST_F(CommandParserTest, TestInit) {
69  scoped_ptr<CommandParser> parser(MakeParser(10));
70  EXPECT_EQ(0, parser->get());
71  EXPECT_EQ(0, parser->put());
72  EXPECT_TRUE(parser->IsEmpty());
73}
74
75// Tests simple commands.
76TEST_F(CommandParserTest, TestSimple) {
77  scoped_ptr<CommandParser> parser(MakeParser(10));
78  CommandBufferOffset put = parser->put();
79  CommandHeader header;
80
81  // add a single command, no args
82  header.size = 1;
83  header.command = 123;
84  buffer()[put++].value_header = header;
85  parser->set_put(put);
86  EXPECT_EQ(put, parser->put());
87
88  AddDoCommandsExpect(error::kNoError, 1, 1, 1);
89  EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
90  EXPECT_EQ(put, parser->get());
91  Mock::VerifyAndClearExpectations(api_mock());
92
93  // add a single command, 2 args
94  header.size = 3;
95  header.command = 456;
96  buffer()[put++].value_header = header;
97  buffer()[put++].value_int32 = 2134;
98  buffer()[put++].value_float = 1.f;
99  parser->set_put(put);
100  EXPECT_EQ(put, parser->put());
101
102  AddDoCommandsExpect(error::kNoError, 1, 3, 3);
103  EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
104  EXPECT_EQ(put, parser->get());
105  Mock::VerifyAndClearExpectations(api_mock());
106}
107
108// Tests having multiple commands in the buffer.
109TEST_F(CommandParserTest, TestMultipleCommands) {
110  scoped_ptr<CommandParser> parser(MakeParser(10));
111  CommandBufferOffset put = parser->put();
112  CommandHeader header;
113
114  // add 2 commands, test with single ProcessCommands()
115  header.size = 2;
116  header.command = 789;
117  buffer()[put++].value_header = header;
118  buffer()[put++].value_int32 = 5151;
119
120  CommandBufferOffset put_cmd2 = put;
121  header.size = 2;
122  header.command = 876;
123  buffer()[put++].value_header = header;
124  buffer()[put++].value_int32 = 3434;
125  parser->set_put(put);
126  EXPECT_EQ(put, parser->put());
127
128  // Process up to 1 command.  4 entries remaining.
129  AddDoCommandsExpect(error::kNoError, 1, 4, 2);
130  EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
131  EXPECT_EQ(put_cmd2, parser->get());
132
133  // Process up to 1 command.  2 entries remaining.
134  AddDoCommandsExpect(error::kNoError, 1, 2, 2);
135  EXPECT_EQ(error::kNoError, parser->ProcessCommands(1));
136  EXPECT_EQ(put, parser->get());
137  Mock::VerifyAndClearExpectations(api_mock());
138
139  // add 2 commands again, test with ProcessAllCommands()
140  header.size = 2;
141  header.command = 123;
142  buffer()[put++].value_header = header;
143  buffer()[put++].value_int32 = 5656;
144
145  header.size = 2;
146  header.command = 321;
147  buffer()[put++].value_header = header;
148  buffer()[put++].value_int32 = 7878;
149  parser->set_put(put);
150  EXPECT_EQ(put, parser->put());
151
152  // 4 entries remaining.
153  AddDoCommandsExpect(
154      error::kNoError, CommandParser::kParseCommandsSlice, 4, 4);
155  EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
156  EXPECT_EQ(put, parser->get());
157  Mock::VerifyAndClearExpectations(api_mock());
158}
159
160// Tests that the parser will wrap correctly at the end of the buffer.
161TEST_F(CommandParserTest, TestWrap) {
162  scoped_ptr<CommandParser> parser(MakeParser(5));
163  CommandBufferOffset put = parser->put();
164  CommandHeader header;
165
166  // add 3 commands with no args (1 word each)
167  for (unsigned int i = 0; i < 3; ++i) {
168    header.size = 1;
169    header.command = i;
170    buffer()[put++].value_header = header;
171  }
172  parser->set_put(put);
173  EXPECT_EQ(put, parser->put());
174
175  // Process up to 10 commands.  3 entries remaining to put.
176  AddDoCommandsExpect(error::kNoError, 10, 3, 3);
177  EXPECT_EQ(error::kNoError, parser->ProcessCommands(10));
178  EXPECT_EQ(put, parser->get());
179  Mock::VerifyAndClearExpectations(api_mock());
180
181  // add 1 command with 1 arg (2 words). That should put us at the end of the
182  // buffer.
183  header.size = 2;
184  header.command = 3;
185  buffer()[put++].value_header = header;
186  buffer()[put++].value_int32 = 5;
187
188  DCHECK_EQ(5, put);
189  put = 0;
190
191  // add 1 command with 1 arg (2 words).
192  header.size = 2;
193  header.command = 4;
194  buffer()[put++].value_header = header;
195  buffer()[put++].value_int32 = 6;
196
197  // 2 entries remaining to end of buffer.
198  AddDoCommandsExpect(
199      error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
200  // 2 entries remaining to put.
201  AddDoCommandsExpect(
202      error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
203  parser->set_put(put);
204  EXPECT_EQ(put, parser->put());
205
206  EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
207  EXPECT_EQ(put, parser->get());
208  Mock::VerifyAndClearExpectations(api_mock());
209}
210
211// Tests error conditions.
212TEST_F(CommandParserTest, TestError) {
213  const unsigned int kNumEntries = 5;
214  scoped_ptr<CommandParser> parser(MakeParser(kNumEntries));
215  CommandBufferOffset put = parser->put();
216  CommandHeader header;
217
218  EXPECT_FALSE(parser->set_get(-1));
219  EXPECT_FALSE(parser->set_get(kNumEntries));
220
221  // Generate a command with size 0.
222  header.size = 0;
223  header.command = 3;
224  buffer()[put++].value_header = header;
225
226  parser->set_put(put);
227  EXPECT_EQ(put, parser->put());
228
229  AddDoCommandsExpect(
230      error::kInvalidSize, CommandParser::kParseCommandsSlice, 1, 0);
231  EXPECT_EQ(error::kInvalidSize,
232            parser->ProcessAllCommands());
233  // check that no DoCommand call was made.
234  Mock::VerifyAndClearExpectations(api_mock());
235
236  parser.reset(MakeParser(5));
237  put = parser->put();
238
239  // Generate a command with size 6, extends beyond the end of the buffer.
240  header.size = 6;
241  header.command = 3;
242  buffer()[put++].value_header = header;
243
244  parser->set_put(put);
245  EXPECT_EQ(put, parser->put());
246
247  AddDoCommandsExpect(
248      error::kOutOfBounds, CommandParser::kParseCommandsSlice, 1, 0);
249  EXPECT_EQ(error::kOutOfBounds,
250            parser->ProcessAllCommands());
251  // check that no DoCommand call was made.
252  Mock::VerifyAndClearExpectations(api_mock());
253
254  parser.reset(MakeParser(5));
255  put = parser->put();
256
257  // Generates 2 commands.
258  header.size = 1;
259  header.command = 3;
260  buffer()[put++].value_header = header;
261  CommandBufferOffset put_post_fail = put;
262  header.size = 1;
263  header.command = 4;
264  buffer()[put++].value_header = header;
265
266  parser->set_put(put);
267  EXPECT_EQ(put, parser->put());
268  // have the first command fail to parse.
269  AddDoCommandsExpect(
270      error::kUnknownCommand, CommandParser::kParseCommandsSlice, 2, 1);
271  EXPECT_EQ(error::kUnknownCommand,
272            parser->ProcessAllCommands());
273  // check that only one command was executed, and that get reflects that
274  // correctly.
275  EXPECT_EQ(put_post_fail, parser->get());
276  Mock::VerifyAndClearExpectations(api_mock());
277  // make the second one succeed, and check that the parser recovered fine.
278  AddDoCommandsExpect(
279      error::kNoError, CommandParser::kParseCommandsSlice, 1, 1);
280  EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
281  EXPECT_EQ(put, parser->get());
282  Mock::VerifyAndClearExpectations(api_mock());
283}
284
285TEST_F(CommandParserTest, SetBuffer) {
286  scoped_ptr<CommandParser> parser(MakeParser(3));
287  CommandBufferOffset put = parser->put();
288  CommandHeader header;
289
290  // add a single command, no args
291  header.size = 2;
292  header.command = 123;
293  buffer()[put++].value_header = header;
294  buffer()[put++].value_int32 = 456;
295  parser->set_put(put);
296
297  AddDoCommandsExpect(
298      error::kNoError, CommandParser::kParseCommandsSlice, 2, 2);
299  EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
300  // We should have advanced 2 entries
301  EXPECT_EQ(2, parser->get());
302  Mock::VerifyAndClearExpectations(api_mock());
303
304  scoped_ptr<CommandBufferEntry[]> buffer2(new CommandBufferEntry[2]);
305  parser->SetBuffer(
306      buffer2.get(), sizeof(CommandBufferEntry) * 2, 0,
307      sizeof(CommandBufferEntry) * 2);
308  // The put and get should have reset to 0.
309  EXPECT_EQ(0, parser->get());
310  EXPECT_EQ(0, parser->put());
311}
312
313}  // namespace gpu
314