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 const char* GetCommandName(unsigned int command_id
) const override
{
55 return GetCommonCommandName(static_cast<cmd::CommandId
>(command_id
));
58 // Overridden from AsyncAPIInterface
59 error::Error
DoCommand(unsigned int command
,
60 unsigned int arg_count
,
61 const void* cmd_data
) override
{
62 return DoCommonCommand(command
, arg_count
, cmd_data
);
65 CommonDecoder::Bucket
* GetBucket(uint32 id
) const {
66 return CommonDecoder::GetBucket(id
);
70 class MockCommandBufferEngine
: public CommandBufferEngine
{
72 static const int32 kStartValidShmId
= 1;
73 static const int32 kValidShmId
= 2;
74 static const int32 kInvalidShmId
= 3;
75 static const size_t kBufferSize
= 1024;
76 static const int32 kValidOffset
= kBufferSize
/ 2;
77 static const int32 kInvalidOffset
= kBufferSize
;
79 MockCommandBufferEngine()
80 : CommandBufferEngine(),
83 scoped_ptr
<base::SharedMemory
> shared_memory(new base::SharedMemory());
84 shared_memory
->CreateAndMapAnonymous(kBufferSize
);
85 buffer_
= MakeBufferFromSharedMemory(shared_memory
.Pass(), kBufferSize
);
88 // Overridden from CommandBufferEngine.
89 scoped_refptr
<gpu::Buffer
> GetSharedMemoryBuffer(int32 shm_id
) override
{
90 if (IsValidSharedMemoryId(shm_id
))
96 T
GetSharedMemoryAs(uint32 offset
) {
97 DCHECK_LT(offset
, kBufferSize
);
98 int8
* buffer_memory
= static_cast<int8
*>(buffer_
->memory());
99 return reinterpret_cast<T
>(&buffer_memory
[offset
]);
102 int32
GetSharedMemoryOffset(const void* memory
) {
103 int8
* buffer_memory
= static_cast<int8
*>(buffer_
->memory());
104 ptrdiff_t offset
= static_cast<const int8
*>(memory
) - &buffer_memory
[0];
105 DCHECK_GE(offset
, 0);
106 DCHECK_LT(static_cast<size_t>(offset
), kBufferSize
);
107 return static_cast<int32
>(offset
);
110 // Overridden from CommandBufferEngine.
111 void set_token(int32 token
) override
{ token_
= token
; }
113 int32
token() const {
117 // Overridden from CommandBufferEngine.
118 bool SetGetBuffer(int32 transfer_buffer_id
) override
{
123 // Overridden from CommandBufferEngine.
124 bool SetGetOffset(int32 offset
) override
{
125 if (static_cast<size_t>(offset
) < kBufferSize
) {
126 get_offset_
= offset
;
132 // Overridden from CommandBufferEngine.
133 int32
GetGetOffset() override
{ return get_offset_
; }
136 bool IsValidSharedMemoryId(int32 shm_id
) {
137 return shm_id
== kValidShmId
|| shm_id
== kStartValidShmId
;
140 scoped_refptr
<gpu::Buffer
> buffer_
;
145 const int32
MockCommandBufferEngine::kStartValidShmId
;
146 const int32
MockCommandBufferEngine::kValidShmId
;
147 const int32
MockCommandBufferEngine::kInvalidShmId
;
148 const size_t MockCommandBufferEngine::kBufferSize
;
149 const int32
MockCommandBufferEngine::kValidOffset
;
150 const int32
MockCommandBufferEngine::kInvalidOffset
;
152 class CommonDecoderTest
: public testing::Test
{
154 void SetUp() override
{ decoder_
.set_engine(&engine_
); }
156 void TearDown() override
{}
158 template <typename T
>
159 error::Error
ExecuteCmd(const T
& cmd
) {
160 static_assert(T::kArgFlags
== cmd::kFixed
,
161 "T::kArgFlags should equal cmd::kFixed");
162 return decoder_
.DoCommands(
163 1, (const void*)&cmd
, ComputeNumEntries(sizeof(cmd
)), 0);
166 template <typename T
>
167 error::Error
ExecuteImmediateCmd(const T
& cmd
, size_t data_size
) {
168 static_assert(T::kArgFlags
== cmd::kAtLeastN
,
169 "T::kArgFlags should equal cmd::kAtLeastN");
170 return decoder_
.DoCommands(
171 1, (const void*)&cmd
, ComputeNumEntries(sizeof(cmd
) + data_size
), 0);
174 MockCommandBufferEngine engine_
;
175 TestCommonDecoder decoder_
;
178 TEST_F(CommonDecoderTest
, Initialize
) {
179 EXPECT_EQ(0, engine_
.GetGetOffset());
182 TEST_F(CommonDecoderTest
, DoCommonCommandInvalidCommand
) {
183 EXPECT_EQ(error::kUnknownCommand
, decoder_
.DoCommand(999999, 0, NULL
));
186 TEST_F(CommonDecoderTest
, HandleNoop
) {
188 const uint32 kSkipCount
= 5;
189 cmd
.Init(kSkipCount
);
190 EXPECT_EQ(error::kNoError
,
192 cmd
, kSkipCount
* kCommandBufferEntrySize
));
193 const uint32 kSkipCount2
= 1;
194 cmd
.Init(kSkipCount2
);
195 EXPECT_EQ(error::kNoError
,
197 cmd
, kSkipCount2
* kCommandBufferEntrySize
));
200 TEST_F(CommonDecoderTest
, SetToken
) {
202 const int32 kTokenId
= 123;
203 EXPECT_EQ(0, engine_
.token());
205 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
206 EXPECT_EQ(kTokenId
, engine_
.token());
209 TEST_F(CommonDecoderTest
, SetBucketSize
) {
210 cmd::SetBucketSize cmd
;
211 const uint32 kBucketId
= 123;
212 const uint32 kBucketLength1
= 1234;
213 const uint32 kBucketLength2
= 78;
214 // Check the bucket does not exist.
215 EXPECT_TRUE(NULL
== decoder_
.GetBucket(kBucketId
));
216 // Check we can create one.
217 cmd
.Init(kBucketId
, kBucketLength1
);
218 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
219 CommonDecoder::Bucket
* bucket
;
220 bucket
= decoder_
.GetBucket(kBucketId
);
221 EXPECT_TRUE(NULL
!= bucket
);
222 EXPECT_EQ(kBucketLength1
, bucket
->size());
223 // Check we can change it.
224 cmd
.Init(kBucketId
, kBucketLength2
);
225 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
226 bucket
= decoder_
.GetBucket(kBucketId
);
227 EXPECT_TRUE(NULL
!= bucket
);
228 EXPECT_EQ(kBucketLength2
, bucket
->size());
229 // Check we can delete it.
230 cmd
.Init(kBucketId
, 0);
231 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
232 bucket
= decoder_
.GetBucket(kBucketId
);
233 EXPECT_EQ(0u, bucket
->size());
236 TEST_F(CommonDecoderTest
, SetBucketData
) {
237 cmd::SetBucketSize size_cmd
;
238 cmd::SetBucketData cmd
;
240 static const char kData
[] = "1234567890123456789";
242 const uint32 kBucketId
= 123;
243 const uint32 kInvalidBucketId
= 124;
245 size_cmd
.Init(kBucketId
, sizeof(kData
));
246 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
247 CommonDecoder::Bucket
* bucket
= decoder_
.GetBucket(kBucketId
);
248 // Check the data is not there.
249 EXPECT_NE(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
251 // Check we can set it.
252 const uint32 kSomeOffsetInSharedMemory
= 50;
253 void* memory
= engine_
.GetSharedMemoryAs
<void*>(kSomeOffsetInSharedMemory
);
254 memcpy(memory
, kData
, sizeof(kData
));
255 cmd
.Init(kBucketId
, 0, sizeof(kData
),
256 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
257 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
258 EXPECT_EQ(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
260 // Check we can set it partially.
261 static const char kData2
[] = "ABCEDFG";
262 const uint32 kSomeOffsetInBucket
= 5;
263 memcpy(memory
, kData2
, sizeof(kData2
));
264 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, sizeof(kData2
),
265 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
266 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
267 EXPECT_EQ(0, memcmp(bucket
->GetData(kSomeOffsetInBucket
, sizeof(kData2
)),
268 kData2
, sizeof(kData2
)));
269 const char* bucket_data
= bucket
->GetDataAs
<const char*>(0, sizeof(kData
));
270 // Check that nothing was affected outside of updated area.
271 EXPECT_EQ(kData
[kSomeOffsetInBucket
- 1],
272 bucket_data
[kSomeOffsetInBucket
- 1]);
273 EXPECT_EQ(kData
[kSomeOffsetInBucket
+ sizeof(kData2
)],
274 bucket_data
[kSomeOffsetInBucket
+ sizeof(kData2
)]);
276 // Check that it fails if the bucket_id is invalid
277 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData2
),
278 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
279 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
281 // Check that it fails if the offset is out of range.
282 cmd
.Init(kBucketId
, bucket
->size(), 1,
283 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
284 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
286 // Check that it fails if the size is out of range.
287 cmd
.Init(kBucketId
, 0, bucket
->size() + 1,
288 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
289 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
292 TEST_F(CommonDecoderTest
, SetBucketDataImmediate
) {
293 cmd::SetBucketSize size_cmd
;
295 cmd::SetBucketDataImmediate
& cmd
=
296 *reinterpret_cast<cmd::SetBucketDataImmediate
*>(&buffer
);
298 static const char kData
[] = "1234567890123456789";
300 const uint32 kBucketId
= 123;
301 const uint32 kInvalidBucketId
= 124;
303 size_cmd
.Init(kBucketId
, sizeof(kData
));
304 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
305 CommonDecoder::Bucket
* bucket
= decoder_
.GetBucket(kBucketId
);
306 // Check the data is not there.
307 EXPECT_NE(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
309 // Check we can set it.
310 void* memory
= &buffer
[0] + sizeof(cmd
);
311 memcpy(memory
, kData
, sizeof(kData
));
312 cmd
.Init(kBucketId
, 0, sizeof(kData
));
313 EXPECT_EQ(error::kNoError
,
314 ExecuteImmediateCmd(cmd
, sizeof(kData
)));
315 EXPECT_EQ(0, memcmp(bucket
->GetData(0, sizeof(kData
)), kData
, sizeof(kData
)));
317 // Check we can set it partially.
318 static const char kData2
[] = "ABCEDFG";
319 const uint32 kSomeOffsetInBucket
= 5;
320 memcpy(memory
, kData2
, sizeof(kData2
));
321 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, sizeof(kData2
));
322 EXPECT_EQ(error::kNoError
,
323 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
324 EXPECT_EQ(0, memcmp(bucket
->GetData(kSomeOffsetInBucket
, sizeof(kData2
)),
325 kData2
, sizeof(kData2
)));
326 const char* bucket_data
= bucket
->GetDataAs
<const char*>(0, sizeof(kData
));
327 // Check that nothing was affected outside of updated area.
328 EXPECT_EQ(kData
[kSomeOffsetInBucket
- 1],
329 bucket_data
[kSomeOffsetInBucket
- 1]);
330 EXPECT_EQ(kData
[kSomeOffsetInBucket
+ sizeof(kData2
)],
331 bucket_data
[kSomeOffsetInBucket
+ sizeof(kData2
)]);
333 // Check that it fails if the bucket_id is invalid
334 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData2
));
335 EXPECT_NE(error::kNoError
,
336 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
338 // Check that it fails if the offset is out of range.
339 cmd
.Init(kBucketId
, bucket
->size(), 1);
340 EXPECT_NE(error::kNoError
,
341 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
343 // Check that it fails if the size is out of range.
344 cmd
.Init(kBucketId
, 0, bucket
->size() + 1);
345 EXPECT_NE(error::kNoError
,
346 ExecuteImmediateCmd(cmd
, sizeof(kData2
)));
349 TEST_F(CommonDecoderTest
, GetBucketStart
) {
350 cmd::SetBucketSize size_cmd
;
351 cmd::SetBucketData set_cmd
;
352 cmd::GetBucketStart cmd
;
354 static const char kData
[] = "1234567890123456789";
355 static const char zero
[sizeof(kData
)] = { 0, };
357 const uint32 kBucketSize
= sizeof(kData
);
358 const uint32 kBucketId
= 123;
359 const uint32 kInvalidBucketId
= 124;
361 // Put data in the bucket.
362 size_cmd
.Init(kBucketId
, sizeof(kData
));
363 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
364 const uint32 kSomeOffsetInSharedMemory
= 50;
365 uint8
* start
= engine_
.GetSharedMemoryAs
<uint8
*>(kSomeOffsetInSharedMemory
);
366 memcpy(start
, kData
, sizeof(kData
));
367 set_cmd
.Init(kBucketId
, 0, sizeof(kData
),
368 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
369 EXPECT_EQ(error::kNoError
, ExecuteCmd(set_cmd
));
371 // Check that the size is correct with no data buffer.
373 engine_
.GetSharedMemoryAs
<uint32
*>(kSomeOffsetInSharedMemory
);
376 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
378 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
379 EXPECT_EQ(kBucketSize
, *memory
);
381 // Check that the data is copied with data buffer.
382 const uint32 kDataOffsetInSharedMemory
= 54;
383 uint8
* data
= engine_
.GetSharedMemoryAs
<uint8
*>(kDataOffsetInSharedMemory
);
385 memset(data
, 0, sizeof(kData
));
387 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
388 kBucketSize
, MockCommandBufferEngine::kValidShmId
,
389 kDataOffsetInSharedMemory
);
390 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
391 EXPECT_EQ(kBucketSize
, *memory
);
392 EXPECT_EQ(0, memcmp(data
, kData
, kBucketSize
));
394 // Check that we can get a piece.
396 memset(data
, 0, sizeof(kData
));
397 const uint32 kPieceSize
= kBucketSize
/ 2;
399 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
400 kPieceSize
, MockCommandBufferEngine::kValidShmId
,
401 kDataOffsetInSharedMemory
);
402 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
403 EXPECT_EQ(kBucketSize
, *memory
);
404 EXPECT_EQ(0, memcmp(data
, kData
, kPieceSize
));
405 EXPECT_EQ(0, memcmp(data
+ kPieceSize
, zero
, sizeof(kData
) - kPieceSize
));
407 // Check that it fails if the result_id is invalid
408 cmd
.Init(kInvalidBucketId
,
409 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
411 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
413 // Check that it fails if the data_id is invalid
415 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
416 1, MockCommandBufferEngine::kInvalidShmId
, 0);
417 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
419 // Check that it fails if the data_size is invalid
421 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
423 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
425 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
426 MockCommandBufferEngine::kBufferSize
+ 1,
427 MockCommandBufferEngine::kValidShmId
, 0);
428 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
430 // Check that it fails if the data_offset is invalid
432 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
434 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
436 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
437 MockCommandBufferEngine::kBufferSize
,
438 MockCommandBufferEngine::kValidShmId
, 1);
439 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
441 // Check that it fails if the result size is not set to zero
444 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
,
446 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
449 TEST_F(CommonDecoderTest
, GetBucketData
) {
450 cmd::SetBucketSize size_cmd
;
451 cmd::SetBucketData set_cmd
;
452 cmd::GetBucketData cmd
;
454 static const char kData
[] = "1234567890123456789";
455 static const char zero
[sizeof(kData
)] = { 0, };
457 const uint32 kBucketId
= 123;
458 const uint32 kInvalidBucketId
= 124;
460 size_cmd
.Init(kBucketId
, sizeof(kData
));
461 EXPECT_EQ(error::kNoError
, ExecuteCmd(size_cmd
));
462 const uint32 kSomeOffsetInSharedMemory
= 50;
463 uint8
* memory
= engine_
.GetSharedMemoryAs
<uint8
*>(kSomeOffsetInSharedMemory
);
464 memcpy(memory
, kData
, sizeof(kData
));
465 set_cmd
.Init(kBucketId
, 0, sizeof(kData
),
466 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
467 EXPECT_EQ(error::kNoError
, ExecuteCmd(set_cmd
));
469 // Check we can get the whole thing.
470 memset(memory
, 0, sizeof(kData
));
471 cmd
.Init(kBucketId
, 0, sizeof(kData
),
472 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
473 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
474 EXPECT_EQ(0, memcmp(memory
, kData
, sizeof(kData
)));
476 // Check we can get a piece.
477 const uint32 kSomeOffsetInBucket
= 5;
478 const uint32 kLengthOfPiece
= 6;
479 const uint8 kSentinel
= 0xff;
480 memset(memory
, 0, sizeof(kData
));
481 memory
[-1] = kSentinel
;
482 cmd
.Init(kBucketId
, kSomeOffsetInBucket
, kLengthOfPiece
,
483 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
484 EXPECT_EQ(error::kNoError
, ExecuteCmd(cmd
));
485 EXPECT_EQ(0, memcmp(memory
, kData
+ kSomeOffsetInBucket
, kLengthOfPiece
));
486 EXPECT_EQ(0, memcmp(memory
+ kLengthOfPiece
, zero
,
487 sizeof(kData
) - kLengthOfPiece
));
488 EXPECT_EQ(kSentinel
, memory
[-1]);
490 // Check that it fails if the bucket_id is invalid
491 cmd
.Init(kInvalidBucketId
, kSomeOffsetInBucket
, sizeof(kData
),
492 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
493 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
495 // Check that it fails if the offset is invalid
496 cmd
.Init(kBucketId
, sizeof(kData
) + 1, 1,
497 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
498 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));
500 // Check that it fails if the size is invalid
501 cmd
.Init(kBucketId
, 0, sizeof(kData
) + 1,
502 MockCommandBufferEngine::kValidShmId
, kSomeOffsetInSharedMemory
);
503 EXPECT_NE(error::kNoError
, ExecuteCmd(cmd
));