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_
.DoCommands(
171 1, (const void*)&cmd
, ComputeNumEntries(sizeof(cmd
)), 0);
174 template <typename T
>
175 error::Error
ExecuteImmediateCmd(const T
& cmd
, size_t data_size
) {
176 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
177 return decoder_
.DoCommands(
178 1, (const void*)&cmd
, ComputeNumEntries(sizeof(cmd
) + data_size
), 0);
181 MockCommandBufferEngine engine_
;
182 TestCommonDecoder decoder_
;
185 TEST_F(CommonDecoderTest
, Initialize
) {
186 EXPECT_EQ(0, engine_
.GetGetOffset());
189 TEST_F(CommonDecoderTest
, DoCommonCommandInvalidCommand
) {
190 EXPECT_EQ(error::kUnknownCommand
, decoder_
.DoCommand(999999, 0, NULL
));
193 TEST_F(CommonDecoderTest
, HandleNoop
) {
195 const uint32 kSkipCount
= 5;
196 cmd
.Init(kSkipCount
);
197 EXPECT_EQ(error::kNoError
,
199 cmd
, kSkipCount
* kCommandBufferEntrySize
));
200 const uint32 kSkipCount2
= 1;
201 cmd
.Init(kSkipCount2
);
202 EXPECT_EQ(error::kNoError
,
204 cmd
, kSkipCount2
* kCommandBufferEntrySize
));
207 TEST_F(CommonDecoderTest
, SetToken
) {
209 const int32 kTokenId
= 123;
210 EXPECT_EQ(0, engine_
.token());
212 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
213 EXPECT_EQ(kTokenId
, engine_
.token());
216 TEST_F(CommonDecoderTest
, SetBucketSize
) {
217 cmd::SetBucketSize cmd
;
218 const uint32 kBucketId
= 123;
219 const uint32 kBucketLength1
= 1234;
220 const uint32 kBucketLength2
= 78;
221 // Check the bucket does not exist.
222 EXPECT_TRUE(NULL
== decoder_
.GetBucket(kBucketId
));
223 // Check we can create one.
224 cmd
.Init(kBucketId
, kBucketLength1
);
225 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
226 CommonDecoder::Bucket
* bucket
;
227 bucket
= decoder_
.GetBucket(kBucketId
);
228 EXPECT_TRUE(NULL
!= bucket
);
229 EXPECT_EQ(kBucketLength1
, bucket
->size());
230 // Check we can change it.
231 cmd
.Init(kBucketId
, kBucketLength2
);
232 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
233 bucket
= decoder_
.GetBucket(kBucketId
);
234 EXPECT_TRUE(NULL
!= bucket
);
235 EXPECT_EQ(kBucketLength2
, bucket
->size());
236 // Check we can delete it.
237 cmd
.Init(kBucketId
, 0);
238 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
239 bucket
= decoder_
.GetBucket(kBucketId
);
240 EXPECT_EQ(0u, bucket
->size());
243 TEST_F(CommonDecoderTest
, SetBucketData
) {
244 cmd::SetBucketSize size_cmd
;
245 cmd::SetBucketData cmd
;
247 static const char kData
[] = "1234567890123456789";
249 const uint32 kBucketId
= 123;
250 const uint32 kInvalidBucketId
= 124;
252 size_cmd
.Init(kBucketId
, sizeof(kData
));
253 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
254 CommonDecoder::Bucket
* bucket
= decoder_
.GetBucket(kBucketId
);
255 // Check the data is not there.
256 EXPECT_NE(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
258 // Check we can set it.
259 const uint32 kSomeOffsetInSharedMemory
= 50;
260 void* memory
= engine_
.GetSharedMemoryAs
<void*>(kSomeOffsetInSharedMemory
);
261 memcpy(memory
, kData
, sizeof(kData
));
262 cmd
.Init(kBucketId
, 0, sizeof(kData
),
263 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
264 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
265 EXPECT_EQ(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
267 // Check we can set it partially.
268 static const char kData2
[] = "ABCEDFG";
269 const uint32 kSomeOffsetInBucket
= 5;
270 memcpy(memory
, kData2
, sizeof(kData2
));
271 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, sizeof(kData2
),
272 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
273 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
274 EXPECT_EQ(0, memcmp(bucket
->GetData(kSomeOffsetInBucket
, sizeof(kData2
)),
275 kData2
, sizeof(kData2
)));
276 const char* bucket_data
= bucket
->GetDataAs
<const char*>(0, sizeof(kData
));
277 // Check that nothing was affected outside of updated area.
278 EXPECT_EQ(kData
[kSomeOffsetInBucket
- 1],
279 bucket_data
[kSomeOffsetInBucket
- 1]);
280 EXPECT_EQ(kData
[kSomeOffsetInBucket
+ sizeof(kData2
)],
281 bucket_data
[kSomeOffsetInBucket
+ sizeof(kData2
)]);
283 // Check that it fails if the bucket_id is invalid
284 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData2
),
285 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
286 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
288 // Check that it fails if the offset is out of range.
289 cmd
.Init(kBucketId
, bucket
->size(), 1,
290 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
291 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
293 // Check that it fails if the size is out of range.
294 cmd
.Init(kBucketId
, 0, bucket
->size() + 1,
295 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
296 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
299 TEST_F(CommonDecoderTest
, SetBucketDataImmediate
) {
300 cmd::SetBucketSize size_cmd
;
302 cmd::SetBucketDataImmediate
& cmd
=
303 *reinterpret_cast<cmd::SetBucketDataImmediate
*>(&buffer
);
305 static const char kData
[] = "1234567890123456789";
307 const uint32 kBucketId
= 123;
308 const uint32 kInvalidBucketId
= 124;
310 size_cmd
.Init(kBucketId
, sizeof(kData
));
311 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
312 CommonDecoder::Bucket
* bucket
= decoder_
.GetBucket(kBucketId
);
313 // Check the data is not there.
314 EXPECT_NE(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
316 // Check we can set it.
317 void* memory
= &buffer
[0] + sizeof(cmd
);
318 memcpy(memory
, kData
, sizeof(kData
));
319 cmd
.Init(kBucketId
, 0, sizeof(kData
));
320 EXPECT_EQ(error::kNoError
,
321 ExecuteImmediateCmd(cmd
, sizeof(kData
)));
322 EXPECT_EQ(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
324 // Check we can set it partially.
325 static const char kData2
[] = "ABCEDFG";
326 const uint32 kSomeOffsetInBucket
= 5;
327 memcpy(memory
, kData2
, sizeof(kData2
));
328 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, sizeof(kData2
));
329 EXPECT_EQ(error::kNoError
,
330 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
331 EXPECT_EQ(0, memcmp(bucket
->GetData(kSomeOffsetInBucket
, sizeof(kData2
)),
332 kData2
, sizeof(kData2
)));
333 const char* bucket_data
= bucket
->GetDataAs
<const char*>(0, sizeof(kData
));
334 // Check that nothing was affected outside of updated area.
335 EXPECT_EQ(kData
[kSomeOffsetInBucket
- 1],
336 bucket_data
[kSomeOffsetInBucket
- 1]);
337 EXPECT_EQ(kData
[kSomeOffsetInBucket
+ sizeof(kData2
)],
338 bucket_data
[kSomeOffsetInBucket
+ sizeof(kData2
)]);
340 // Check that it fails if the bucket_id is invalid
341 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData2
));
342 EXPECT_NE(error::kNoError
,
343 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
345 // Check that it fails if the offset is out of range.
346 cmd
.Init(kBucketId
, bucket
->size(), 1);
347 EXPECT_NE(error::kNoError
,
348 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
350 // Check that it fails if the size is out of range.
351 cmd
.Init(kBucketId
, 0, bucket
->size() + 1);
352 EXPECT_NE(error::kNoError
,
353 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
356 TEST_F(CommonDecoderTest
, GetBucketStart
) {
357 cmd::SetBucketSize size_cmd
;
358 cmd::SetBucketData set_cmd
;
359 cmd::GetBucketStart cmd
;
361 static const char kData
[] = "1234567890123456789";
362 static const char zero
[sizeof(kData
)] = { 0, };
364 const uint32 kBucketSize
= sizeof(kData
);
365 const uint32 kBucketId
= 123;
366 const uint32 kInvalidBucketId
= 124;
368 // Put data in the bucket.
369 size_cmd
.Init(kBucketId
, sizeof(kData
));
370 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
371 const uint32 kSomeOffsetInSharedMemory
= 50;
372 uint8
* start
= engine_
.GetSharedMemoryAs
<uint8
*>(kSomeOffsetInSharedMemory
);
373 memcpy(start
, kData
, sizeof(kData
));
374 set_cmd
.Init(kBucketId
, 0, sizeof(kData
),
375 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
376 EXPECT_EQ(error::kNoError
, ExecuteCmd(set_cmd
));
378 // Check that the size is correct with no data buffer.
380 engine_
.GetSharedMemoryAs
<uint32
*>(kSomeOffsetInSharedMemory
);
383 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
385 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
386 EXPECT_EQ(kBucketSize
, *memory
);
388 // Check that the data is copied with data buffer.
389 const uint32 kDataOffsetInSharedMemory
= 54;
390 uint8
* data
= engine_
.GetSharedMemoryAs
<uint8
*>(kDataOffsetInSharedMemory
);
392 memset(data
, 0, sizeof(kData
));
394 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
395 kBucketSize
, MockCommandBufferEngine::kValidShmId
,
396 kDataOffsetInSharedMemory
);
397 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
398 EXPECT_EQ(kBucketSize
, *memory
);
399 EXPECT_EQ(0, memcmp(data
, kData
, kBucketSize
));
401 // Check that we can get a piece.
403 memset(data
, 0, sizeof(kData
));
404 const uint32 kPieceSize
= kBucketSize
/ 2;
406 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
407 kPieceSize
, MockCommandBufferEngine::kValidShmId
,
408 kDataOffsetInSharedMemory
);
409 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
410 EXPECT_EQ(kBucketSize
, *memory
);
411 EXPECT_EQ(0, memcmp(data
, kData
, kPieceSize
));
412 EXPECT_EQ(0, memcmp(data
+ kPieceSize
, zero
, sizeof(kData
) - kPieceSize
));
414 // Check that it fails if the result_id is invalid
415 cmd
.Init(kInvalidBucketId
,
416 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
418 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
420 // Check that it fails if the data_id is invalid
422 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
423 1, MockCommandBufferEngine::kInvalidShmId
, 0);
424 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
426 // Check that it fails if the data_size is invalid
428 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
430 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
432 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
433 MockCommandBufferEngine::kBufferSize
+ 1,
434 MockCommandBufferEngine::kValidShmId
, 0);
435 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
437 // Check that it fails if the data_offset is invalid
439 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
441 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
443 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
444 MockCommandBufferEngine::kBufferSize
,
445 MockCommandBufferEngine::kValidShmId
, 1);
446 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
448 // Check that it fails if the result size is not set to zero
451 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
453 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
456 TEST_F(CommonDecoderTest
, GetBucketData
) {
457 cmd::SetBucketSize size_cmd
;
458 cmd::SetBucketData set_cmd
;
459 cmd::GetBucketData cmd
;
461 static const char kData
[] = "1234567890123456789";
462 static const char zero
[sizeof(kData
)] = { 0, };
464 const uint32 kBucketId
= 123;
465 const uint32 kInvalidBucketId
= 124;
467 size_cmd
.Init(kBucketId
, sizeof(kData
));
468 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
469 const uint32 kSomeOffsetInSharedMemory
= 50;
470 uint8
* memory
= engine_
.GetSharedMemoryAs
<uint8
*>(kSomeOffsetInSharedMemory
);
471 memcpy(memory
, kData
, sizeof(kData
));
472 set_cmd
.Init(kBucketId
, 0, sizeof(kData
),
473 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
474 EXPECT_EQ(error::kNoError
, ExecuteCmd(set_cmd
));
476 // Check we can get the whole thing.
477 memset(memory
, 0, sizeof(kData
));
478 cmd
.Init(kBucketId
, 0, sizeof(kData
),
479 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
480 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
481 EXPECT_EQ(0, memcmp(memory
, kData
, sizeof(kData
)));
483 // Check we can get a piece.
484 const uint32 kSomeOffsetInBucket
= 5;
485 const uint32 kLengthOfPiece
= 6;
486 const uint8 kSentinel
= 0xff;
487 memset(memory
, 0, sizeof(kData
));
488 memory
[-1] = kSentinel
;
489 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, kLengthOfPiece
,
490 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
491 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
492 EXPECT_EQ(0, memcmp(memory
, kData
+ kSomeOffsetInBucket
, kLengthOfPiece
));
493 EXPECT_EQ(0, memcmp(memory
+ kLengthOfPiece
, zero
,
494 sizeof(kData
) - kLengthOfPiece
));
495 EXPECT_EQ(kSentinel
, memory
[-1]);
497 // Check that it fails if the bucket_id is invalid
498 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData
),
499 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
500 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
502 // Check that it fails if the offset is invalid
503 cmd
.Init(kBucketId
, sizeof(kData
) + 1, 1,
504 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
505 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
507 // Check that it fails if the size is invalid
508 cmd
.Init(kBucketId
, 0, sizeof(kData
) + 1,
509 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
510 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));