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 #include "gpu/command_buffer/service/common_decoder.h"
6 #include "gpu/command_buffer/service/cmd_buffer_engine.h"
7 #include "testing/gtest/include/gtest/gtest.h"
11 TEST(CommonDecoderBucket, Basic) {
12 CommonDecoder::Bucket bucket;
13 EXPECT_EQ(0u, bucket.size());
14 EXPECT_TRUE(NULL == bucket.GetData(0, 0));
17 TEST(CommonDecoderBucket, Size) {
18 CommonDecoder::Bucket bucket;
20 EXPECT_EQ(24u, bucket.size());
22 EXPECT_EQ(12u, bucket.size());
25 TEST(CommonDecoderBucket, GetData) {
26 CommonDecoder::Bucket bucket;
29 EXPECT_TRUE(NULL != bucket.GetData(0, 0));
30 EXPECT_TRUE(NULL != bucket.GetData(24, 0));
31 EXPECT_TRUE(NULL == bucket.GetData(25, 0));
32 EXPECT_TRUE(NULL != bucket.GetData(0, 24));
33 EXPECT_TRUE(NULL == bucket.GetData(0, 25));
35 EXPECT_TRUE(NULL == bucket.GetData(0, 24));
38 TEST(CommonDecoderBucket, SetData) {
39 CommonDecoder::Bucket bucket;
40 static const char data[] = "testing";
43 EXPECT_TRUE(bucket.SetData(data, 0, sizeof(data)));
44 EXPECT_EQ(0, memcmp(data, bucket.GetData(0, sizeof(data)), sizeof(data)));
45 EXPECT_TRUE(bucket.SetData(data, 2, sizeof(data)));
46 EXPECT_EQ(0, memcmp(data, bucket.GetData(2, sizeof(data)), sizeof(data)));
47 EXPECT_FALSE(bucket.SetData(data, 0, sizeof(data) * 2));
48 EXPECT_FALSE(bucket.SetData(data, 5, sizeof(data)));
51 class TestCommonDecoder : public CommonDecoder {
53 // Overridden from AsyncAPIInterface
54 virtual const char* GetCommandName(unsigned int command_id) const OVERRIDE {
55 return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
58 // Overridden from AsyncAPIInterface
59 virtual error::Error DoCommand(
61 unsigned int arg_count,
62 const void* cmd_data) OVERRIDE {
63 return DoCommonCommand(command, arg_count, cmd_data);
66 CommonDecoder::Bucket* GetBucket(uint32 id) const {
67 return CommonDecoder::GetBucket(id);
71 class MockCommandBufferEngine : public CommandBufferEngine {
73 static const int32 kStartValidShmId = 1;
74 static const int32 kValidShmId = 2;
75 static const int32 kInvalidShmId = 3;
76 static const size_t kBufferSize = 1024;
77 static const int32 kValidOffset = kBufferSize / 2;
78 static const int32 kInvalidOffset = kBufferSize;
80 MockCommandBufferEngine()
81 : CommandBufferEngine(),
86 // Overridden from CommandBufferEngine.
87 virtual Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE {
89 if (IsValidSharedMemoryId(shm_id)) {
91 buffer.size = kBufferSize;
97 T GetSharedMemoryAs(uint32 offset) {
98 DCHECK_LT(offset, kBufferSize);
99 return reinterpret_cast<T>(&buffer_[offset]);
102 int32 GetSharedMemoryOffset(const void* memory) {
103 ptrdiff_t offset = reinterpret_cast<const int8*>(memory) - &buffer_[0];
104 DCHECK_GE(offset, 0);
105 DCHECK_LT(static_cast<size_t>(offset), kBufferSize);
106 return static_cast<int32>(offset);
109 // Overridden from CommandBufferEngine.
110 virtual void set_token(int32 token) OVERRIDE {
114 int32 token() const {
118 // Overridden from CommandBufferEngine.
119 virtual bool SetGetBuffer(int32 transfer_buffer_id) OVERRIDE {
124 // Overridden from CommandBufferEngine.
125 virtual bool SetGetOffset(int32 offset) OVERRIDE {
126 if (static_cast<size_t>(offset) < kBufferSize) {
127 get_offset_ = offset;
133 // Overridden from CommandBufferEngine.
134 virtual int32 GetGetOffset() OVERRIDE {
139 bool IsValidSharedMemoryId(int32 shm_id) {
140 return shm_id == kValidShmId || shm_id == kStartValidShmId;
143 int8 buffer_[kBufferSize];
148 const int32 MockCommandBufferEngine::kStartValidShmId;
149 const int32 MockCommandBufferEngine::kValidShmId;
150 const int32 MockCommandBufferEngine::kInvalidShmId;
151 const size_t MockCommandBufferEngine::kBufferSize;
152 const int32 MockCommandBufferEngine::kValidOffset;
153 const int32 MockCommandBufferEngine::kInvalidOffset;
155 class CommonDecoderTest : public testing::Test {
157 virtual void SetUp() {
158 decoder_.set_engine(&engine_);
161 virtual void TearDown() {
164 template <typename T>
165 error::Error ExecuteCmd(const T& cmd) {
166 COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
167 return decoder_.DoCommand(cmd.kCmdId,
168 ComputeNumEntries(sizeof(cmd)) - 1,
172 template <typename T>
173 error::Error ExecuteImmediateCmd(const T& cmd, size_t data_size) {
174 COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
175 return decoder_.DoCommand(cmd.kCmdId,
176 ComputeNumEntries(sizeof(cmd) + data_size) - 1,
180 MockCommandBufferEngine engine_;
181 TestCommonDecoder decoder_;
184 TEST_F(CommonDecoderTest, Initialize) {
185 EXPECT_EQ(0, engine_.GetGetOffset());
188 TEST_F(CommonDecoderTest, DoCommonCommandInvalidCommand) {
189 EXPECT_EQ(error::kUnknownCommand, decoder_.DoCommand(999999, 0, NULL));
192 TEST_F(CommonDecoderTest, HandleNoop) {
194 const uint32 kSkipCount = 5;
195 cmd.Init(kSkipCount);
196 EXPECT_EQ(error::kNoError,
198 cmd, kSkipCount * kCommandBufferEntrySize));
199 const uint32 kSkipCount2 = 1;
200 cmd.Init(kSkipCount2);
201 EXPECT_EQ(error::kNoError,
203 cmd, kSkipCount2 * kCommandBufferEntrySize));
206 TEST_F(CommonDecoderTest, SetToken) {
208 const int32 kTokenId = 123;
209 EXPECT_EQ(0, engine_.token());
211 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
212 EXPECT_EQ(kTokenId, engine_.token());
215 TEST_F(CommonDecoderTest, SetBucketSize) {
216 cmd::SetBucketSize cmd;
217 const uint32 kBucketId = 123;
218 const uint32 kBucketLength1 = 1234;
219 const uint32 kBucketLength2 = 78;
220 // Check the bucket does not exist.
221 EXPECT_TRUE(NULL == decoder_.GetBucket(kBucketId));
222 // Check we can create one.
223 cmd.Init(kBucketId, kBucketLength1);
224 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
225 CommonDecoder::Bucket* bucket;
226 bucket = decoder_.GetBucket(kBucketId);
227 EXPECT_TRUE(NULL != bucket);
228 EXPECT_EQ(kBucketLength1, bucket->size());
229 // Check we can change it.
230 cmd.Init(kBucketId, kBucketLength2);
231 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
232 bucket = decoder_.GetBucket(kBucketId);
233 EXPECT_TRUE(NULL != bucket);
234 EXPECT_EQ(kBucketLength2, bucket->size());
235 // Check we can delete it.
236 cmd.Init(kBucketId, 0);
237 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
238 bucket = decoder_.GetBucket(kBucketId);
239 EXPECT_EQ(0u, bucket->size());
242 TEST_F(CommonDecoderTest, SetBucketData) {
243 cmd::SetBucketSize size_cmd;
244 cmd::SetBucketData cmd;
246 static const char kData[] = "1234567890123456789";
248 const uint32 kBucketId = 123;
249 const uint32 kInvalidBucketId = 124;
251 size_cmd.Init(kBucketId, sizeof(kData));
252 EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
253 CommonDecoder::Bucket* bucket = decoder_.GetBucket(kBucketId);
254 // Check the data is not there.
255 EXPECT_NE(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
257 // Check we can set it.
258 const uint32 kSomeOffsetInSharedMemory = 50;
259 void* memory = engine_.GetSharedMemoryAs<void*>(kSomeOffsetInSharedMemory);
260 memcpy(memory, kData, sizeof(kData));
261 cmd.Init(kBucketId, 0, sizeof(kData),
262 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
263 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
264 EXPECT_EQ(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
266 // Check we can set it partially.
267 static const char kData2[] = "ABCEDFG";
268 const uint32 kSomeOffsetInBucket = 5;
269 memcpy(memory, kData2, sizeof(kData2));
270 cmd.Init(kBucketId, kSomeOffsetInBucket, sizeof(kData2),
271 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
272 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
273 EXPECT_EQ(0, memcmp(bucket->GetData(kSomeOffsetInBucket, sizeof(kData2)),
274 kData2, sizeof(kData2)));
275 const char* bucket_data = bucket->GetDataAs<const char*>(0, sizeof(kData));
276 // Check that nothing was affected outside of updated area.
277 EXPECT_EQ(kData[kSomeOffsetInBucket - 1],
278 bucket_data[kSomeOffsetInBucket - 1]);
279 EXPECT_EQ(kData[kSomeOffsetInBucket + sizeof(kData2)],
280 bucket_data[kSomeOffsetInBucket + sizeof(kData2)]);
282 // Check that it fails if the bucket_id is invalid
283 cmd.Init(kInvalidBucketId, kSomeOffsetInBucket, sizeof(kData2),
284 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
285 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
287 // Check that it fails if the offset is out of range.
288 cmd.Init(kBucketId, bucket->size(), 1,
289 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
290 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
292 // Check that it fails if the size is out of range.
293 cmd.Init(kBucketId, 0, bucket->size() + 1,
294 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
295 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
298 TEST_F(CommonDecoderTest, SetBucketDataImmediate) {
299 cmd::SetBucketSize size_cmd;
301 cmd::SetBucketDataImmediate& cmd =
302 *reinterpret_cast<cmd::SetBucketDataImmediate*>(&buffer);
304 static const char kData[] = "1234567890123456789";
306 const uint32 kBucketId = 123;
307 const uint32 kInvalidBucketId = 124;
309 size_cmd.Init(kBucketId, sizeof(kData));
310 EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
311 CommonDecoder::Bucket* bucket = decoder_.GetBucket(kBucketId);
312 // Check the data is not there.
313 EXPECT_NE(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
315 // Check we can set it.
316 void* memory = &buffer[0] + sizeof(cmd);
317 memcpy(memory, kData, sizeof(kData));
318 cmd.Init(kBucketId, 0, sizeof(kData));
319 EXPECT_EQ(error::kNoError,
320 ExecuteImmediateCmd(cmd, sizeof(kData)));
321 EXPECT_EQ(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
323 // Check we can set it partially.
324 static const char kData2[] = "ABCEDFG";
325 const uint32 kSomeOffsetInBucket = 5;
326 memcpy(memory, kData2, sizeof(kData2));
327 cmd.Init(kBucketId, kSomeOffsetInBucket, sizeof(kData2));
328 EXPECT_EQ(error::kNoError,
329 ExecuteImmediateCmd(cmd, sizeof(kData2)));
330 EXPECT_EQ(0, memcmp(bucket->GetData(kSomeOffsetInBucket, sizeof(kData2)),
331 kData2, sizeof(kData2)));
332 const char* bucket_data = bucket->GetDataAs<const char*>(0, sizeof(kData));
333 // Check that nothing was affected outside of updated area.
334 EXPECT_EQ(kData[kSomeOffsetInBucket - 1],
335 bucket_data[kSomeOffsetInBucket - 1]);
336 EXPECT_EQ(kData[kSomeOffsetInBucket + sizeof(kData2)],
337 bucket_data[kSomeOffsetInBucket + sizeof(kData2)]);
339 // Check that it fails if the bucket_id is invalid
340 cmd.Init(kInvalidBucketId, kSomeOffsetInBucket, sizeof(kData2));
341 EXPECT_NE(error::kNoError,
342 ExecuteImmediateCmd(cmd, sizeof(kData2)));
344 // Check that it fails if the offset is out of range.
345 cmd.Init(kBucketId, bucket->size(), 1);
346 EXPECT_NE(error::kNoError,
347 ExecuteImmediateCmd(cmd, sizeof(kData2)));
349 // Check that it fails if the size is out of range.
350 cmd.Init(kBucketId, 0, bucket->size() + 1);
351 EXPECT_NE(error::kNoError,
352 ExecuteImmediateCmd(cmd, sizeof(kData2)));
355 TEST_F(CommonDecoderTest, GetBucketStart) {
356 cmd::SetBucketSize size_cmd;
357 cmd::SetBucketData set_cmd;
358 cmd::GetBucketStart cmd;
360 static const char kData[] = "1234567890123456789";
361 static const char zero[sizeof(kData)] = { 0, };
363 const uint32 kBucketSize = sizeof(kData);
364 const uint32 kBucketId = 123;
365 const uint32 kInvalidBucketId = 124;
367 // Put data in the bucket.
368 size_cmd.Init(kBucketId, sizeof(kData));
369 EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
370 const uint32 kSomeOffsetInSharedMemory = 50;
371 uint8* start = engine_.GetSharedMemoryAs<uint8*>(kSomeOffsetInSharedMemory);
372 memcpy(start, kData, sizeof(kData));
373 set_cmd.Init(kBucketId, 0, sizeof(kData),
374 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
375 EXPECT_EQ(error::kNoError, ExecuteCmd(set_cmd));
377 // Check that the size is correct with no data buffer.
379 engine_.GetSharedMemoryAs<uint32*>(kSomeOffsetInSharedMemory);
382 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
384 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
385 EXPECT_EQ(kBucketSize, *memory);
387 // Check that the data is copied with data buffer.
388 const uint32 kDataOffsetInSharedMemory = 54;
389 uint8* data = engine_.GetSharedMemoryAs<uint8*>(kDataOffsetInSharedMemory);
391 memset(data, 0, sizeof(kData));
393 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
394 kBucketSize, MockCommandBufferEngine::kValidShmId,
395 kDataOffsetInSharedMemory);
396 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
397 EXPECT_EQ(kBucketSize, *memory);
398 EXPECT_EQ(0, memcmp(data, kData, kBucketSize));
400 // Check that we can get a piece.
402 memset(data, 0, sizeof(kData));
403 const uint32 kPieceSize = kBucketSize / 2;
405 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
406 kPieceSize, MockCommandBufferEngine::kValidShmId,
407 kDataOffsetInSharedMemory);
408 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
409 EXPECT_EQ(kBucketSize, *memory);
410 EXPECT_EQ(0, memcmp(data, kData, kPieceSize));
411 EXPECT_EQ(0, memcmp(data + kPieceSize, zero, sizeof(kData) - kPieceSize));
413 // Check that it fails if the result_id is invalid
414 cmd.Init(kInvalidBucketId,
415 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
417 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
419 // Check that it fails if the data_id is invalid
421 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
422 1, MockCommandBufferEngine::kInvalidShmId, 0);
423 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
425 // Check that it fails if the data_size is invalid
427 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
429 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
431 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
432 MockCommandBufferEngine::kBufferSize + 1,
433 MockCommandBufferEngine::kValidShmId, 0);
434 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
436 // Check that it fails if the data_offset is invalid
438 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
440 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
442 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
443 MockCommandBufferEngine::kBufferSize,
444 MockCommandBufferEngine::kValidShmId, 1);
445 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
447 // Check that it fails if the result size is not set to zero
450 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
452 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
455 TEST_F(CommonDecoderTest, GetBucketData) {
456 cmd::SetBucketSize size_cmd;
457 cmd::SetBucketData set_cmd;
458 cmd::GetBucketData cmd;
460 static const char kData[] = "1234567890123456789";
461 static const char zero[sizeof(kData)] = { 0, };
463 const uint32 kBucketId = 123;
464 const uint32 kInvalidBucketId = 124;
466 size_cmd.Init(kBucketId, sizeof(kData));
467 EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
468 const uint32 kSomeOffsetInSharedMemory = 50;
469 uint8* memory = engine_.GetSharedMemoryAs<uint8*>(kSomeOffsetInSharedMemory);
470 memcpy(memory, kData, sizeof(kData));
471 set_cmd.Init(kBucketId, 0, sizeof(kData),
472 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
473 EXPECT_EQ(error::kNoError, ExecuteCmd(set_cmd));
475 // Check we can get the whole thing.
476 memset(memory, 0, sizeof(kData));
477 cmd.Init(kBucketId, 0, sizeof(kData),
478 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
479 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
480 EXPECT_EQ(0, memcmp(memory, kData, sizeof(kData)));
482 // Check we can get a piece.
483 const uint32 kSomeOffsetInBucket = 5;
484 const uint32 kLengthOfPiece = 6;
485 const uint8 kSentinel = 0xff;
486 memset(memory, 0, sizeof(kData));
487 memory[-1] = kSentinel;
488 cmd.Init(kBucketId, kSomeOffsetInBucket, kLengthOfPiece,
489 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
490 EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
491 EXPECT_EQ(0, memcmp(memory, kData + kSomeOffsetInBucket, kLengthOfPiece));
492 EXPECT_EQ(0, memcmp(memory + kLengthOfPiece, zero,
493 sizeof(kData) - kLengthOfPiece));
494 EXPECT_EQ(kSentinel, memory[-1]);
496 // Check that it fails if the bucket_id is invalid
497 cmd.Init(kInvalidBucketId, kSomeOffsetInBucket, sizeof(kData),
498 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
499 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
501 // Check that it fails if the offset is invalid
502 cmd.Init(kBucketId, sizeof(kData) + 1, 1,
503 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
504 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
506 // Check that it fails if the size is invalid
507 cmd.Init(kBucketId, 0, sizeof(kData) + 1,
508 MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
509 EXPECT_NE(error::kNoError, ExecuteCmd(cmd));