- add sources.
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / common_decoder_unittest.cc
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.
4
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"
8
9 namespace gpu {
10
11 TEST(CommonDecoderBucket, Basic) {
12   CommonDecoder::Bucket bucket;
13   EXPECT_EQ(0u, bucket.size());
14   EXPECT_TRUE(NULL == bucket.GetData(0, 0));
15 }
16
17 TEST(CommonDecoderBucket, Size) {
18   CommonDecoder::Bucket bucket;
19   bucket.SetSize(24);
20   EXPECT_EQ(24u, bucket.size());
21   bucket.SetSize(12);
22   EXPECT_EQ(12u, bucket.size());
23 }
24
25 TEST(CommonDecoderBucket, GetData) {
26   CommonDecoder::Bucket bucket;
27
28   bucket.SetSize(24);
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));
34   bucket.SetSize(23);
35   EXPECT_TRUE(NULL == bucket.GetData(0, 24));
36 }
37
38 TEST(CommonDecoderBucket, SetData) {
39   CommonDecoder::Bucket bucket;
40   static const char data[] = "testing";
41
42   bucket.SetSize(10);
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)));
49 }
50
51 class TestCommonDecoder : public CommonDecoder {
52  public:
53   // Overridden from AsyncAPIInterface
54   virtual const char* GetCommandName(unsigned int command_id) const OVERRIDE {
55     return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
56   }
57
58   // Overridden from AsyncAPIInterface
59   virtual error::Error DoCommand(
60       unsigned int command,
61       unsigned int arg_count,
62       const void* cmd_data) OVERRIDE {
63     return DoCommonCommand(command, arg_count, cmd_data);
64   }
65
66   CommonDecoder::Bucket* GetBucket(uint32 id) const {
67     return CommonDecoder::GetBucket(id);
68   }
69 };
70
71 class MockCommandBufferEngine : public CommandBufferEngine {
72  public:
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;
79
80   MockCommandBufferEngine()
81       : CommandBufferEngine(),
82         token_(),
83         get_offset_(0) {
84   }
85
86   // Overridden from CommandBufferEngine.
87   virtual Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE {
88     Buffer buffer;
89     if (IsValidSharedMemoryId(shm_id)) {
90       buffer.ptr = buffer_;
91       buffer.size = kBufferSize;
92     }
93     return buffer;
94   }
95
96   template <typename T>
97   T GetSharedMemoryAs(uint32 offset) {
98     DCHECK_LT(offset, kBufferSize);
99     return reinterpret_cast<T>(&buffer_[offset]);
100   }
101
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);
107   }
108
109   // Overridden from CommandBufferEngine.
110   virtual void set_token(int32 token) OVERRIDE {
111     token_ = token;
112   }
113
114   int32 token() const {
115     return token_;
116   }
117
118   // Overridden from CommandBufferEngine.
119   virtual bool SetGetBuffer(int32 transfer_buffer_id) OVERRIDE {
120     NOTREACHED();
121     return false;
122   }
123
124   // Overridden from CommandBufferEngine.
125   virtual bool SetGetOffset(int32 offset) OVERRIDE {
126     if (static_cast<size_t>(offset) < kBufferSize) {
127       get_offset_ = offset;
128       return true;
129     }
130     return false;
131   }
132
133   // Overridden from CommandBufferEngine.
134   virtual int32 GetGetOffset() OVERRIDE {
135     return get_offset_;
136   }
137
138  private:
139   bool IsValidSharedMemoryId(int32 shm_id) {
140     return shm_id == kValidShmId || shm_id == kStartValidShmId;
141   }
142
143   int8 buffer_[kBufferSize];
144   int32 token_;
145   int32 get_offset_;
146 };
147
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;
154
155 class CommonDecoderTest : public testing::Test {
156  protected:
157   virtual void SetUp() {
158     decoder_.set_engine(&engine_);
159   }
160
161   virtual void TearDown() {
162   }
163
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,
169                               &cmd);
170   }
171
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,
177                               &cmd);
178   }
179
180   MockCommandBufferEngine engine_;
181   TestCommonDecoder decoder_;
182 };
183
184 TEST_F(CommonDecoderTest, Initialize) {
185   EXPECT_EQ(0, engine_.GetGetOffset());
186 }
187
188 TEST_F(CommonDecoderTest, DoCommonCommandInvalidCommand) {
189   EXPECT_EQ(error::kUnknownCommand, decoder_.DoCommand(999999, 0, NULL));
190 }
191
192 TEST_F(CommonDecoderTest, HandleNoop) {
193   cmd::Noop cmd;
194   const uint32 kSkipCount = 5;
195   cmd.Init(kSkipCount);
196   EXPECT_EQ(error::kNoError,
197             ExecuteImmediateCmd(
198                 cmd, kSkipCount * kCommandBufferEntrySize));
199   const uint32 kSkipCount2 = 1;
200   cmd.Init(kSkipCount2);
201   EXPECT_EQ(error::kNoError,
202             ExecuteImmediateCmd(
203                 cmd, kSkipCount2 * kCommandBufferEntrySize));
204 }
205
206 TEST_F(CommonDecoderTest, SetToken) {
207   cmd::SetToken cmd;
208   const int32 kTokenId = 123;
209   EXPECT_EQ(0, engine_.token());
210   cmd.Init(kTokenId);
211   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
212   EXPECT_EQ(kTokenId, engine_.token());
213 }
214
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());
240 }
241
242 TEST_F(CommonDecoderTest, SetBucketData) {
243   cmd::SetBucketSize size_cmd;
244   cmd::SetBucketData cmd;
245
246   static const char kData[] = "1234567890123456789";
247
248   const uint32 kBucketId = 123;
249   const uint32 kInvalidBucketId = 124;
250
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)));
256
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)));
265
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)]);
281
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));
286
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));
291
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));
296 }
297
298 TEST_F(CommonDecoderTest, SetBucketDataImmediate) {
299   cmd::SetBucketSize size_cmd;
300   int8 buffer[1024];
301   cmd::SetBucketDataImmediate& cmd =
302       *reinterpret_cast<cmd::SetBucketDataImmediate*>(&buffer);
303
304   static const char kData[] = "1234567890123456789";
305
306   const uint32 kBucketId = 123;
307   const uint32 kInvalidBucketId = 124;
308
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)));
314
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)));
322
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)]);
338
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)));
343
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)));
348
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)));
353 }
354
355 TEST_F(CommonDecoderTest, GetBucketStart) {
356   cmd::SetBucketSize size_cmd;
357   cmd::SetBucketData set_cmd;
358   cmd::GetBucketStart cmd;
359
360   static const char kData[] = "1234567890123456789";
361   static const char zero[sizeof(kData)] = { 0, };
362
363   const uint32 kBucketSize = sizeof(kData);
364   const uint32 kBucketId = 123;
365   const uint32 kInvalidBucketId = 124;
366
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));
376
377   // Check that the size is correct with no data buffer.
378   uint32* memory =
379       engine_.GetSharedMemoryAs<uint32*>(kSomeOffsetInSharedMemory);
380   *memory = 0x0;
381   cmd.Init(kBucketId,
382            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
383            0, 0, 0);
384   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
385   EXPECT_EQ(kBucketSize, *memory);
386
387   // Check that the data is copied with data buffer.
388   const uint32 kDataOffsetInSharedMemory = 54;
389   uint8* data = engine_.GetSharedMemoryAs<uint8*>(kDataOffsetInSharedMemory);
390   *memory = 0x0;
391   memset(data, 0, sizeof(kData));
392   cmd.Init(kBucketId,
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));
399
400   // Check that we can get a piece.
401   *memory = 0x0;
402   memset(data, 0, sizeof(kData));
403   const uint32 kPieceSize = kBucketSize / 2;
404   cmd.Init(kBucketId,
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));
412
413   // Check that it fails if the result_id is invalid
414   cmd.Init(kInvalidBucketId,
415            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
416            0, 0, 0);
417   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
418
419   // Check that it fails if the data_id is invalid
420   cmd.Init(kBucketId,
421            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
422            1, MockCommandBufferEngine::kInvalidShmId, 0);
423   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
424
425   // Check that it fails if the data_size is invalid
426   cmd.Init(kBucketId,
427            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
428            1, 0, 0);
429   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
430   cmd.Init(kBucketId,
431            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
432            MockCommandBufferEngine::kBufferSize + 1,
433            MockCommandBufferEngine::kValidShmId, 0);
434   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
435
436   // Check that it fails if the data_offset is invalid
437   cmd.Init(kBucketId,
438            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
439            0, 0, 1);
440   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
441   cmd.Init(kBucketId,
442            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
443            MockCommandBufferEngine::kBufferSize,
444            MockCommandBufferEngine::kValidShmId, 1);
445   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
446
447   // Check that it fails if the result size is not set to zero
448   *memory = 0x1;
449   cmd.Init(kBucketId,
450            MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
451            0, 0, 0);
452   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
453 }
454
455 TEST_F(CommonDecoderTest, GetBucketData) {
456   cmd::SetBucketSize size_cmd;
457   cmd::SetBucketData set_cmd;
458   cmd::GetBucketData cmd;
459
460   static const char kData[] = "1234567890123456789";
461   static const char zero[sizeof(kData)] = { 0, };
462
463   const uint32 kBucketId = 123;
464   const uint32 kInvalidBucketId = 124;
465
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));
474
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)));
481
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]);
495
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));
500
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));
505
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));
510 }
511
512 }  // namespace gpu