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(),
84 scoped_ptr
<base::SharedMemory
> shared_memory(new base::SharedMemory());
85 shared_memory
->CreateAndMapAnonymous(kBufferSize
);
86 buffer_
= MakeBufferFromSharedMemory(shared_memory
.Pass(), kBufferSize
);
89 // Overridden from CommandBufferEngine.
90 virtual scoped_refptr
<gpu::Buffer
> GetSharedMemoryBuffer(int32 shm_id
)
92 if (IsValidSharedMemoryId(shm_id
))
98 T
GetSharedMemoryAs(uint32 offset
) {
99 DCHECK_LT(offset
, kBufferSize
);
100 int8
* buffer_memory
= static_cast<int8
*>(buffer_
->memory());
101 return reinterpret_cast<T
>(&buffer_memory
[offset
]);
104 int32
GetSharedMemoryOffset(const void* memory
) {
105 int8
* buffer_memory
= static_cast<int8
*>(buffer_
->memory());
106 ptrdiff_t offset
= static_cast<const int8
*>(memory
) - &buffer_memory
[0];
107 DCHECK_GE(offset
, 0);
108 DCHECK_LT(static_cast<size_t>(offset
), kBufferSize
);
109 return static_cast<int32
>(offset
);
112 // Overridden from CommandBufferEngine.
113 virtual void set_token(int32 token
) OVERRIDE
{
117 int32
token() const {
121 // Overridden from CommandBufferEngine.
122 virtual bool SetGetBuffer(int32 transfer_buffer_id
) OVERRIDE
{
127 // Overridden from CommandBufferEngine.
128 virtual bool SetGetOffset(int32 offset
) OVERRIDE
{
129 if (static_cast<size_t>(offset
) < kBufferSize
) {
130 get_offset_
= offset
;
136 // Overridden from CommandBufferEngine.
137 virtual int32
GetGetOffset() OVERRIDE
{
142 bool IsValidSharedMemoryId(int32 shm_id
) {
143 return shm_id
== kValidShmId
|| shm_id
== kStartValidShmId
;
146 scoped_refptr
<gpu::Buffer
> buffer_
;
151 const int32
MockCommandBufferEngine::kStartValidShmId
;
152 const int32
MockCommandBufferEngine::kValidShmId
;
153 const int32
MockCommandBufferEngine::kInvalidShmId
;
154 const size_t MockCommandBufferEngine::kBufferSize
;
155 const int32
MockCommandBufferEngine::kValidOffset
;
156 const int32
MockCommandBufferEngine::kInvalidOffset
;
158 class CommonDecoderTest
: public testing::Test
{
160 virtual void SetUp() {
161 decoder_
.set_engine(&engine_
);
164 virtual void TearDown() {
167 template <typename T
>
168 error::Error
ExecuteCmd(const T
& cmd
) {
169 COMPILE_ASSERT(T::kArgFlags
== cmd::kFixed
, Cmd_kArgFlags_not_kFixed
);
170 return decoder_
.DoCommand(cmd
.kCmdId
,
171 ComputeNumEntries(sizeof(cmd
)) - 1,
175 template <typename T
>
176 error::Error
ExecuteImmediateCmd(const T
& cmd
, size_t data_size
) {
177 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
178 return decoder_
.DoCommand(cmd
.kCmdId
,
179 ComputeNumEntries(sizeof(cmd
) + data_size
) - 1,
183 MockCommandBufferEngine engine_
;
184 TestCommonDecoder decoder_
;
187 TEST_F(CommonDecoderTest
, Initialize
) {
188 EXPECT_EQ(0, engine_
.GetGetOffset());
191 TEST_F(CommonDecoderTest
, DoCommonCommandInvalidCommand
) {
192 EXPECT_EQ(error::kUnknownCommand
, decoder_
.DoCommand(999999, 0, NULL
));
195 TEST_F(CommonDecoderTest
, HandleNoop
) {
197 const uint32 kSkipCount
= 5;
198 cmd
.Init(kSkipCount
);
199 EXPECT_EQ(error::kNoError
,
201 cmd
, kSkipCount
* kCommandBufferEntrySize
));
202 const uint32 kSkipCount2
= 1;
203 cmd
.Init(kSkipCount2
);
204 EXPECT_EQ(error::kNoError
,
206 cmd
, kSkipCount2
* kCommandBufferEntrySize
));
209 TEST_F(CommonDecoderTest
, SetToken
) {
211 const int32 kTokenId
= 123;
212 EXPECT_EQ(0, engine_
.token());
214 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
215 EXPECT_EQ(kTokenId
, engine_
.token());
218 TEST_F(CommonDecoderTest
, SetBucketSize
) {
219 cmd::SetBucketSize cmd
;
220 const uint32 kBucketId
= 123;
221 const uint32 kBucketLength1
= 1234;
222 const uint32 kBucketLength2
= 78;
223 // Check the bucket does not exist.
224 EXPECT_TRUE(NULL
== decoder_
.GetBucket(kBucketId
));
225 // Check we can create one.
226 cmd
.Init(kBucketId
, kBucketLength1
);
227 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
228 CommonDecoder::Bucket
* bucket
;
229 bucket
= decoder_
.GetBucket(kBucketId
);
230 EXPECT_TRUE(NULL
!= bucket
);
231 EXPECT_EQ(kBucketLength1
, bucket
->size());
232 // Check we can change it.
233 cmd
.Init(kBucketId
, kBucketLength2
);
234 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
235 bucket
= decoder_
.GetBucket(kBucketId
);
236 EXPECT_TRUE(NULL
!= bucket
);
237 EXPECT_EQ(kBucketLength2
, bucket
->size());
238 // Check we can delete it.
239 cmd
.Init(kBucketId
, 0);
240 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
241 bucket
= decoder_
.GetBucket(kBucketId
);
242 EXPECT_EQ(0u, bucket
->size());
245 TEST_F(CommonDecoderTest
, SetBucketData
) {
246 cmd::SetBucketSize size_cmd
;
247 cmd::SetBucketData cmd
;
249 static const char kData
[] = "1234567890123456789";
251 const uint32 kBucketId
= 123;
252 const uint32 kInvalidBucketId
= 124;
254 size_cmd
.Init(kBucketId
, sizeof(kData
));
255 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
256 CommonDecoder::Bucket
* bucket
= decoder_
.GetBucket(kBucketId
);
257 // Check the data is not there.
258 EXPECT_NE(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
260 // Check we can set it.
261 const uint32 kSomeOffsetInSharedMemory
= 50;
262 void* memory
= engine_
.GetSharedMemoryAs
<void*>(kSomeOffsetInSharedMemory
);
263 memcpy(memory
, kData
, sizeof(kData
));
264 cmd
.Init(kBucketId
, 0, sizeof(kData
),
265 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
266 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
267 EXPECT_EQ(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
269 // Check we can set it partially.
270 static const char kData2
[] = "ABCEDFG";
271 const uint32 kSomeOffsetInBucket
= 5;
272 memcpy(memory
, kData2
, sizeof(kData2
));
273 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, sizeof(kData2
),
274 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
275 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
276 EXPECT_EQ(0, memcmp(bucket
->GetData(kSomeOffsetInBucket
, sizeof(kData2
)),
277 kData2
, sizeof(kData2
)));
278 const char* bucket_data
= bucket
->GetDataAs
<const char*>(0, sizeof(kData
));
279 // Check that nothing was affected outside of updated area.
280 EXPECT_EQ(kData
[kSomeOffsetInBucket
- 1],
281 bucket_data
[kSomeOffsetInBucket
- 1]);
282 EXPECT_EQ(kData
[kSomeOffsetInBucket
+ sizeof(kData2
)],
283 bucket_data
[kSomeOffsetInBucket
+ sizeof(kData2
)]);
285 // Check that it fails if the bucket_id is invalid
286 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData2
),
287 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
288 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
290 // Check that it fails if the offset is out of range.
291 cmd
.Init(kBucketId
, bucket
->size(), 1,
292 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
293 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
295 // Check that it fails if the size is out of range.
296 cmd
.Init(kBucketId
, 0, bucket
->size() + 1,
297 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
298 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
301 TEST_F(CommonDecoderTest
, SetBucketDataImmediate
) {
302 cmd::SetBucketSize size_cmd
;
304 cmd::SetBucketDataImmediate
& cmd
=
305 *reinterpret_cast<cmd::SetBucketDataImmediate
*>(&buffer
);
307 static const char kData
[] = "1234567890123456789";
309 const uint32 kBucketId
= 123;
310 const uint32 kInvalidBucketId
= 124;
312 size_cmd
.Init(kBucketId
, sizeof(kData
));
313 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
314 CommonDecoder::Bucket
* bucket
= decoder_
.GetBucket(kBucketId
);
315 // Check the data is not there.
316 EXPECT_NE(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
318 // Check we can set it.
319 void* memory
= &buffer
[0] + sizeof(cmd
);
320 memcpy(memory
, kData
, sizeof(kData
));
321 cmd
.Init(kBucketId
, 0, sizeof(kData
));
322 EXPECT_EQ(error::kNoError
,
323 ExecuteImmediateCmd(cmd
, sizeof(kData
)));
324 EXPECT_EQ(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
326 // Check we can set it partially.
327 static const char kData2
[] = "ABCEDFG";
328 const uint32 kSomeOffsetInBucket
= 5;
329 memcpy(memory
, kData2
, sizeof(kData2
));
330 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, sizeof(kData2
));
331 EXPECT_EQ(error::kNoError
,
332 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
333 EXPECT_EQ(0, memcmp(bucket
->GetData(kSomeOffsetInBucket
, sizeof(kData2
)),
334 kData2
, sizeof(kData2
)));
335 const char* bucket_data
= bucket
->GetDataAs
<const char*>(0, sizeof(kData
));
336 // Check that nothing was affected outside of updated area.
337 EXPECT_EQ(kData
[kSomeOffsetInBucket
- 1],
338 bucket_data
[kSomeOffsetInBucket
- 1]);
339 EXPECT_EQ(kData
[kSomeOffsetInBucket
+ sizeof(kData2
)],
340 bucket_data
[kSomeOffsetInBucket
+ sizeof(kData2
)]);
342 // Check that it fails if the bucket_id is invalid
343 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData2
));
344 EXPECT_NE(error::kNoError
,
345 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
347 // Check that it fails if the offset is out of range.
348 cmd
.Init(kBucketId
, bucket
->size(), 1);
349 EXPECT_NE(error::kNoError
,
350 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
352 // Check that it fails if the size is out of range.
353 cmd
.Init(kBucketId
, 0, bucket
->size() + 1);
354 EXPECT_NE(error::kNoError
,
355 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
358 TEST_F(CommonDecoderTest
, GetBucketStart
) {
359 cmd::SetBucketSize size_cmd
;
360 cmd::SetBucketData set_cmd
;
361 cmd::GetBucketStart cmd
;
363 static const char kData
[] = "1234567890123456789";
364 static const char zero
[sizeof(kData
)] = { 0, };
366 const uint32 kBucketSize
= sizeof(kData
);
367 const uint32 kBucketId
= 123;
368 const uint32 kInvalidBucketId
= 124;
370 // Put data in the bucket.
371 size_cmd
.Init(kBucketId
, sizeof(kData
));
372 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
373 const uint32 kSomeOffsetInSharedMemory
= 50;
374 uint8
* start
= engine_
.GetSharedMemoryAs
<uint8
*>(kSomeOffsetInSharedMemory
);
375 memcpy(start
, kData
, sizeof(kData
));
376 set_cmd
.Init(kBucketId
, 0, sizeof(kData
),
377 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
378 EXPECT_EQ(error::kNoError
, ExecuteCmd(set_cmd
));
380 // Check that the size is correct with no data buffer.
382 engine_
.GetSharedMemoryAs
<uint32
*>(kSomeOffsetInSharedMemory
);
385 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
387 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
388 EXPECT_EQ(kBucketSize
, *memory
);
390 // Check that the data is copied with data buffer.
391 const uint32 kDataOffsetInSharedMemory
= 54;
392 uint8
* data
= engine_
.GetSharedMemoryAs
<uint8
*>(kDataOffsetInSharedMemory
);
394 memset(data
, 0, sizeof(kData
));
396 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
397 kBucketSize
, MockCommandBufferEngine::kValidShmId
,
398 kDataOffsetInSharedMemory
);
399 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
400 EXPECT_EQ(kBucketSize
, *memory
);
401 EXPECT_EQ(0, memcmp(data
, kData
, kBucketSize
));
403 // Check that we can get a piece.
405 memset(data
, 0, sizeof(kData
));
406 const uint32 kPieceSize
= kBucketSize
/ 2;
408 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
409 kPieceSize
, MockCommandBufferEngine::kValidShmId
,
410 kDataOffsetInSharedMemory
);
411 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
412 EXPECT_EQ(kBucketSize
, *memory
);
413 EXPECT_EQ(0, memcmp(data
, kData
, kPieceSize
));
414 EXPECT_EQ(0, memcmp(data
+ kPieceSize
, zero
, sizeof(kData
) - kPieceSize
));
416 // Check that it fails if the result_id is invalid
417 cmd
.Init(kInvalidBucketId
,
418 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
420 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
422 // Check that it fails if the data_id is invalid
424 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
425 1, MockCommandBufferEngine::kInvalidShmId
, 0);
426 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
428 // Check that it fails if the data_size is invalid
430 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
432 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
434 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
435 MockCommandBufferEngine::kBufferSize
+ 1,
436 MockCommandBufferEngine::kValidShmId
, 0);
437 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
439 // Check that it fails if the data_offset is invalid
441 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
443 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
445 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
446 MockCommandBufferEngine::kBufferSize
,
447 MockCommandBufferEngine::kValidShmId
, 1);
448 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
450 // Check that it fails if the result size is not set to zero
453 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
455 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
458 TEST_F(CommonDecoderTest
, GetBucketData
) {
459 cmd::SetBucketSize size_cmd
;
460 cmd::SetBucketData set_cmd
;
461 cmd::GetBucketData cmd
;
463 static const char kData
[] = "1234567890123456789";
464 static const char zero
[sizeof(kData
)] = { 0, };
466 const uint32 kBucketId
= 123;
467 const uint32 kInvalidBucketId
= 124;
469 size_cmd
.Init(kBucketId
, sizeof(kData
));
470 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
471 const uint32 kSomeOffsetInSharedMemory
= 50;
472 uint8
* memory
= engine_
.GetSharedMemoryAs
<uint8
*>(kSomeOffsetInSharedMemory
);
473 memcpy(memory
, kData
, sizeof(kData
));
474 set_cmd
.Init(kBucketId
, 0, sizeof(kData
),
475 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
476 EXPECT_EQ(error::kNoError
, ExecuteCmd(set_cmd
));
478 // Check we can get the whole thing.
479 memset(memory
, 0, sizeof(kData
));
480 cmd
.Init(kBucketId
, 0, sizeof(kData
),
481 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
482 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
483 EXPECT_EQ(0, memcmp(memory
, kData
, sizeof(kData
)));
485 // Check we can get a piece.
486 const uint32 kSomeOffsetInBucket
= 5;
487 const uint32 kLengthOfPiece
= 6;
488 const uint8 kSentinel
= 0xff;
489 memset(memory
, 0, sizeof(kData
));
490 memory
[-1] = kSentinel
;
491 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, kLengthOfPiece
,
492 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
493 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
494 EXPECT_EQ(0, memcmp(memory
, kData
+ kSomeOffsetInBucket
, kLengthOfPiece
));
495 EXPECT_EQ(0, memcmp(memory
+ kLengthOfPiece
, zero
,
496 sizeof(kData
) - kLengthOfPiece
));
497 EXPECT_EQ(kSentinel
, memory
[-1]);
499 // Check that it fails if the bucket_id is invalid
500 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData
),
501 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
502 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
504 // Check that it fails if the offset is invalid
505 cmd
.Init(kBucketId
, sizeof(kData
) + 1, 1,
506 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
507 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
509 // Check that it fails if the size is invalid
510 cmd
.Init(kBucketId
, 0, sizeof(kData
) + 1,
511 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
512 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));