• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // This file contains the common parts of command buffer formats.
6 
7 #ifndef GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
8 #define GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
9 
10 #include <stddef.h>
11 
12 #include "base/logging.h"
13 #include "gpu/command_buffer/common/bitfield_helpers.h"
14 #include "gpu/command_buffer/common/types.h"
15 #include "gpu/gpu_export.h"
16 
17 namespace gpu {
18 
19 namespace cmd {
20   enum ArgFlags {
21     kFixed = 0x0,
22     kAtLeastN = 0x1
23   };
24 }  // namespace cmd
25 
26 // Computes the number of command buffer entries needed for a certain size. In
27 // other words it rounds up to a multiple of entries.
ComputeNumEntries(size_t size_in_bytes)28 inline uint32 ComputeNumEntries(size_t size_in_bytes) {
29   return static_cast<uint32>(
30       (size_in_bytes + sizeof(uint32) - 1) / sizeof(uint32));  // NOLINT
31 }
32 
33 // Rounds up to a multiple of entries in bytes.
RoundSizeToMultipleOfEntries(size_t size_in_bytes)34 inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes) {
35   return ComputeNumEntries(size_in_bytes) * sizeof(uint32);  // NOLINT
36 }
37 
38 // Struct that defines the command header in the command buffer.
39 struct CommandHeader {
40   Uint32 size:21;
41   Uint32 command:11;
42 
43   GPU_EXPORT static const int32 kMaxSize = (1 << 21) - 1;
44 
InitCommandHeader45   void Init(uint32 _command, int32 _size) {
46     DCHECK_LE(_size, kMaxSize);
47     command = _command;
48     size = _size;
49   }
50 
51   // Sets the header based on the passed in command. Can not be used for
52   // variable sized commands like immediate commands or Noop.
53   template <typename T>
SetCmdCommandHeader54   void SetCmd() {
55     COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
56     Init(T::kCmdId, ComputeNumEntries(sizeof(T)));  // NOLINT
57   }
58 
59   // Sets the header by a size in bytes of the immediate data after the command.
60   template <typename T>
SetCmdBySizeCommandHeader61   void SetCmdBySize(uint32 size_of_data_in_bytes) {
62     COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
63     Init(T::kCmdId,
64          ComputeNumEntries(sizeof(T) + size_of_data_in_bytes));  // NOLINT
65   }
66 
67   // Sets the header by a size in bytes.
68   template <typename T>
SetCmdByTotalSizeCommandHeader69   void SetCmdByTotalSize(uint32 size_in_bytes) {
70     COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
71     DCHECK_GE(size_in_bytes, sizeof(T));  // NOLINT
72     Init(T::kCmdId, ComputeNumEntries(size_in_bytes));
73   }
74 };
75 
76 COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4);
77 
78 // Union that defines possible command buffer entries.
79 union CommandBufferEntry {
80   CommandHeader value_header;
81   Uint32 value_uint32;
82   Int32 value_int32;
83   float value_float;
84 };
85 
86 const size_t kCommandBufferEntrySize = 4;
87 
88 COMPILE_ASSERT(sizeof(CommandBufferEntry) == kCommandBufferEntrySize,
89                Sizeof_CommandBufferEntry_is_not_4);
90 
91 // Make sure the compiler does not add extra padding to any of the command
92 // structures.
93 #pragma pack(push, 1)
94 
95 // Gets the address of memory just after a structure in a typesafe way. This is
96 // used for IMMEDIATE commands to get the address of the place to put the data.
97 // Immediate command put their data direclty in the command buffer.
98 // Parameters:
99 //   cmd: Address of command.
100 template <typename T>
ImmediateDataAddress(T * cmd)101 void* ImmediateDataAddress(T* cmd) {
102   COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
103   return reinterpret_cast<char*>(cmd) + sizeof(*cmd);
104 }
105 
106 // Gets the address of the place to put the next command in a typesafe way.
107 // This can only be used for fixed sized commands.
108 template <typename T>
109 // Parameters:
110 //   cmd: Address of command.
NextCmdAddress(void * cmd)111 void* NextCmdAddress(void* cmd) {
112   COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
113   return reinterpret_cast<char*>(cmd) + sizeof(T);
114 }
115 
116 // Gets the address of the place to put the next command in a typesafe way.
117 // This can only be used for variable sized command like IMMEDIATE commands.
118 // Parameters:
119 //   cmd: Address of command.
120 //   size_of_data_in_bytes: Size of the data for the command.
121 template <typename T>
NextImmediateCmdAddress(void * cmd,uint32 size_of_data_in_bytes)122 void* NextImmediateCmdAddress(void* cmd, uint32 size_of_data_in_bytes) {
123   COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
124   return reinterpret_cast<char*>(cmd) + sizeof(T) +   // NOLINT
125       RoundSizeToMultipleOfEntries(size_of_data_in_bytes);
126 }
127 
128 // Gets the address of the place to put the next command in a typesafe way.
129 // This can only be used for variable sized command like IMMEDIATE commands.
130 // Parameters:
131 //   cmd: Address of command.
132 //   size_of_cmd_in_bytes: Size of the cmd and data.
133 template <typename T>
NextImmediateCmdAddressTotalSize(void * cmd,uint32 total_size_in_bytes)134 void* NextImmediateCmdAddressTotalSize(void* cmd, uint32 total_size_in_bytes) {
135   COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
136   DCHECK_GE(total_size_in_bytes, sizeof(T));  // NOLINT
137   return reinterpret_cast<char*>(cmd) +
138       RoundSizeToMultipleOfEntries(total_size_in_bytes);
139 }
140 
141 namespace cmd {
142 
143 // This macro is used to safely and convienently expand the list of commnad
144 // buffer commands in to various lists and never have them get out of sync. To
145 // add a new command, add it this list, create the corresponding structure below
146 // and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where
147 // COMMAND_NAME is the name of your command structure.
148 //
149 // NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
150 #define COMMON_COMMAND_BUFFER_CMDS(OP) \
151   OP(Noop)                          /*  0 */ \
152   OP(SetToken)                      /*  1 */ \
153   OP(SetBucketSize)                 /*  2 */ \
154   OP(SetBucketData)                 /*  3 */ \
155   OP(SetBucketDataImmediate)        /*  4 */ \
156   OP(GetBucketStart)                /*  5 */ \
157   OP(GetBucketData)                 /*  6 */ \
158 
159 // Common commands.
160 enum CommandId {
161   #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,
162 
163   COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
164 
165   #undef COMMON_COMMAND_BUFFER_CMD_OP
166 
167   kNumCommands,
168   kLastCommonId = 255  // reserve 256 spaces for common commands.
169 };
170 
171 COMPILE_ASSERT(kNumCommands - 1 <= kLastCommonId, Too_many_common_commands);
172 
173 const char* GetCommandName(CommandId id);
174 
175 // A Noop command.
176 struct Noop {
177   typedef Noop ValueType;
178   static const CommandId kCmdId = kNoop;
179   static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
180 
SetHeaderNoop181   void SetHeader(uint32 skip_count) {
182     DCHECK_GT(skip_count, 0u);
183     header.Init(kCmdId, skip_count);
184   }
185 
InitNoop186   void Init(uint32 skip_count) {
187     SetHeader(skip_count);
188   }
189 
SetNoop190   static void* Set(void* cmd, uint32 skip_count) {
191     static_cast<ValueType*>(cmd)->Init(skip_count);
192     return NextImmediateCmdAddress<ValueType>(
193         cmd, skip_count * sizeof(CommandBufferEntry));  // NOLINT
194   }
195 
196   CommandHeader header;
197 };
198 
199 COMPILE_ASSERT(sizeof(Noop) == 4, Sizeof_Noop_is_not_4);
200 COMPILE_ASSERT(offsetof(Noop, header) == 0, Offsetof_Noop_header_not_0);
201 
202 // The SetToken command puts a token in the command stream that you can
203 // use to check if that token has been passed in the command stream.
204 struct SetToken {
205   typedef SetToken ValueType;
206   static const CommandId kCmdId = kSetToken;
207   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
208 
SetHeaderSetToken209   void SetHeader() {
210     header.SetCmd<ValueType>();
211   }
212 
InitSetToken213   void Init(uint32 _token) {
214     SetHeader();
215     token = _token;
216   }
SetSetToken217   static void* Set(void* cmd, uint32 token) {
218     static_cast<ValueType*>(cmd)->Init(token);
219     return NextCmdAddress<ValueType>(cmd);
220   }
221 
222   CommandHeader header;
223   uint32 token;
224 };
225 
226 COMPILE_ASSERT(sizeof(SetToken) == 8, Sizeof_SetToken_is_not_8);
227 COMPILE_ASSERT(offsetof(SetToken, header) == 0,
228                Offsetof_SetToken_header_not_0);
229 COMPILE_ASSERT(offsetof(SetToken, token) == 4,
230                Offsetof_SetToken_token_not_4);
231 
232 // Sets the size of a bucket for collecting data on the service side.
233 // This is a utility for gathering data on the service side so it can be used
234 // all at once when some service side API is called. It removes the need to add
235 // special commands just to support a particular API. For example, any API
236 // command that needs a string needs a way to send that string to the API over
237 // the command buffers. While you can require that the command buffer or
238 // transfer buffer be large enough to hold the largest string you can send,
239 // using this command removes that restriction by letting you send smaller
240 // pieces over and build up the data on the service side.
241 //
242 // You can clear a bucket on the service side and thereby free memory by sending
243 // a size of 0.
244 struct SetBucketSize {
245   typedef SetBucketSize ValueType;
246   static const CommandId kCmdId = kSetBucketSize;
247   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
248 
SetHeaderSetBucketSize249   void SetHeader() {
250     header.SetCmd<ValueType>();
251   }
252 
InitSetBucketSize253   void Init(uint32 _bucket_id, uint32 _size) {
254     SetHeader();
255     bucket_id = _bucket_id;
256     size = _size;
257   }
SetSetBucketSize258   static void* Set(void* cmd, uint32 _bucket_id, uint32 _size) {
259     static_cast<ValueType*>(cmd)->Init(_bucket_id, _size);
260     return NextCmdAddress<ValueType>(cmd);
261   }
262 
263   CommandHeader header;
264   uint32 bucket_id;
265   uint32 size;
266 };
267 
268 COMPILE_ASSERT(sizeof(SetBucketSize) == 12, Sizeof_SetBucketSize_is_not_8);
269 COMPILE_ASSERT(offsetof(SetBucketSize, header) == 0,
270                Offsetof_SetBucketSize_header_not_0);
271 COMPILE_ASSERT(offsetof(SetBucketSize, bucket_id) == 4,
272                Offsetof_SetBucketSize_bucket_id_4);
273 COMPILE_ASSERT(offsetof(SetBucketSize, size) == 8,
274                Offsetof_SetBucketSize_size_8);
275 
276 // Sets the contents of a portion of a bucket on the service side from data in
277 // shared memory.
278 // See SetBucketSize.
279 struct SetBucketData {
280   typedef SetBucketData ValueType;
281   static const CommandId kCmdId = kSetBucketData;
282   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
283 
SetHeaderSetBucketData284   void SetHeader() {
285     header.SetCmd<ValueType>();
286   }
287 
InitSetBucketData288   void Init(uint32 _bucket_id,
289             uint32 _offset,
290             uint32 _size,
291             uint32 _shared_memory_id,
292             uint32 _shared_memory_offset) {
293     SetHeader();
294     bucket_id = _bucket_id;
295     offset = _offset;
296     size = _size;
297     shared_memory_id = _shared_memory_id;
298     shared_memory_offset = _shared_memory_offset;
299   }
SetSetBucketData300   static void* Set(void* cmd,
301                    uint32 _bucket_id,
302                    uint32 _offset,
303                    uint32 _size,
304                    uint32 _shared_memory_id,
305                    uint32 _shared_memory_offset) {
306     static_cast<ValueType*>(cmd)->Init(
307         _bucket_id,
308         _offset,
309         _size,
310         _shared_memory_id,
311         _shared_memory_offset);
312     return NextCmdAddress<ValueType>(cmd);
313   }
314 
315   CommandHeader header;
316   uint32 bucket_id;
317   uint32 offset;
318   uint32 size;
319   uint32 shared_memory_id;
320   uint32 shared_memory_offset;
321 };
322 
323 COMPILE_ASSERT(sizeof(SetBucketData) == 24, Sizeof_SetBucketData_is_not_24);
324 COMPILE_ASSERT(offsetof(SetBucketData, header) == 0,
325                Offsetof_SetBucketData_header_not_0);
326 COMPILE_ASSERT(offsetof(SetBucketData, bucket_id) == 4,
327                Offsetof_SetBucketData_bucket_id_not_4);
328 COMPILE_ASSERT(offsetof(SetBucketData, offset) == 8,
329                Offsetof_SetBucketData_offset_not_8);
330 COMPILE_ASSERT(offsetof(SetBucketData, size) == 12,
331                Offsetof_SetBucketData_size_not_12);
332 COMPILE_ASSERT(offsetof(SetBucketData, shared_memory_id) == 16,
333                Offsetof_SetBucketData_shared_memory_id_not_16);
334 COMPILE_ASSERT(offsetof(SetBucketData, shared_memory_offset) == 20,
335                Offsetof_SetBucketData_shared_memory_offset_not_20);
336 
337 // Sets the contents of a portion of a bucket on the service side from data in
338 // the command buffer.
339 // See SetBucketSize.
340 struct SetBucketDataImmediate {
341   typedef SetBucketDataImmediate ValueType;
342   static const CommandId kCmdId = kSetBucketDataImmediate;
343   static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
344 
SetHeaderSetBucketDataImmediate345   void SetHeader(uint32 size) {
346     header.SetCmdBySize<ValueType>(size);
347   }
348 
InitSetBucketDataImmediate349   void Init(uint32 _bucket_id,
350             uint32 _offset,
351             uint32 _size) {
352     SetHeader(_size);
353     bucket_id = _bucket_id;
354     offset = _offset;
355     size = _size;
356   }
SetSetBucketDataImmediate357   static void* Set(void* cmd,
358                    uint32 _bucket_id,
359                    uint32 _offset,
360                    uint32 _size) {
361     static_cast<ValueType*>(cmd)->Init(
362         _bucket_id,
363         _offset,
364         _size);
365     return NextImmediateCmdAddress<ValueType>(cmd, _size);
366   }
367 
368   CommandHeader header;
369   uint32 bucket_id;
370   uint32 offset;
371   uint32 size;
372 };
373 
374 COMPILE_ASSERT(sizeof(SetBucketDataImmediate) == 16,
375                Sizeof_SetBucketDataImmediate_is_not_24);
376 COMPILE_ASSERT(offsetof(SetBucketDataImmediate, header) == 0,
377                Offsetof_SetBucketDataImmediate_header_not_0);
378 COMPILE_ASSERT(offsetof(SetBucketDataImmediate, bucket_id) == 4,
379                Offsetof_SetBucketDataImmediate_bucket_id_not_4);
380 COMPILE_ASSERT(offsetof(SetBucketDataImmediate, offset) == 8,
381                Offsetof_SetBucketDataImmediate_offset_not_8);
382 COMPILE_ASSERT(offsetof(SetBucketDataImmediate, size) == 12,
383                Offsetof_SetBucketDataImmediate_size_not_12);
384 
385 // Gets the start of a bucket the service has available. Sending a variable size
386 // result back to the client and the portion of that result that fits in the
387 // supplied shared memory. If the size of the result is larger than the supplied
388 // shared memory the rest of the bucket's contents can be retrieved with
389 // GetBucketData.
390 //
391 // This is used for example for any API that returns a string. The problem is
392 // the largest thing you can send back in 1 command is the size of your shared
393 // memory. This command along with GetBucketData implements a way to get a
394 // result a piece at a time to help solve that problem in a generic way.
395 struct GetBucketStart {
396   typedef GetBucketStart ValueType;
397   static const CommandId kCmdId = kGetBucketStart;
398   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
399 
400   typedef uint32 Result;
401 
SetHeaderGetBucketStart402   void SetHeader() {
403     header.SetCmd<ValueType>();
404   }
405 
InitGetBucketStart406   void Init(uint32 _bucket_id,
407             uint32 _result_memory_id,
408             uint32 _result_memory_offset,
409             uint32 _data_memory_size,
410             uint32 _data_memory_id,
411             uint32 _data_memory_offset) {
412     SetHeader();
413     bucket_id = _bucket_id;
414     result_memory_id = _result_memory_id;
415     result_memory_offset = _result_memory_offset;
416     data_memory_size = _data_memory_size;
417     data_memory_id = _data_memory_id;
418     data_memory_offset = _data_memory_offset;
419   }
SetGetBucketStart420   static void* Set(void* cmd,
421                    uint32 _bucket_id,
422                    uint32 _result_memory_id,
423                    uint32 _result_memory_offset,
424                    uint32 _data_memory_size,
425                    uint32 _data_memory_id,
426                    uint32 _data_memory_offset) {
427     static_cast<ValueType*>(cmd)->Init(
428         _bucket_id,
429         _result_memory_id,
430         _result_memory_offset,
431         _data_memory_size,
432         _data_memory_id,
433         _data_memory_offset);
434     return NextCmdAddress<ValueType>(cmd);
435   }
436 
437   CommandHeader header;
438   uint32 bucket_id;
439   uint32 result_memory_id;
440   uint32 result_memory_offset;
441   uint32 data_memory_size;
442   uint32 data_memory_id;
443   uint32 data_memory_offset;
444 };
445 
446 COMPILE_ASSERT(sizeof(GetBucketStart) == 28, Sizeof_GetBucketStart_is_not_28);
447 COMPILE_ASSERT(offsetof(GetBucketStart, header) == 0,
448                Offsetof_GetBucketStart_header_not_0);
449 COMPILE_ASSERT(offsetof(GetBucketStart, bucket_id) == 4,
450                Offsetof_GetBucketStart_bucket_id_not_4);
451 COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_id) == 8,
452                Offsetof_GetBucketStart_result_memory_id_not_8);
453 COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_offset) == 12,
454                Offsetof_GetBucketStart_result_memory_offset_not_12);
455 COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_size) == 16,
456                Offsetof_GetBucketStart_data_memory_size_not_16);
457 COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_id) == 20,
458                Offsetof_GetBucketStart_data_memory_id_not_20);
459 COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_offset) == 24,
460                Offsetof_GetBucketStart_data_memory_offset_not_24);
461 
462 // Gets a piece of a result the service as available.
463 // See GetBucketSize.
464 struct GetBucketData {
465   typedef GetBucketData ValueType;
466   static const CommandId kCmdId = kGetBucketData;
467   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
468 
SetHeaderGetBucketData469   void SetHeader() {
470     header.SetCmd<ValueType>();
471   }
472 
InitGetBucketData473   void Init(uint32 _bucket_id,
474             uint32 _offset,
475             uint32 _size,
476             uint32 _shared_memory_id,
477             uint32 _shared_memory_offset) {
478     SetHeader();
479     bucket_id = _bucket_id;
480     offset = _offset;
481     size = _size;
482     shared_memory_id = _shared_memory_id;
483     shared_memory_offset = _shared_memory_offset;
484   }
SetGetBucketData485   static void* Set(void* cmd,
486                    uint32 _bucket_id,
487                    uint32 _offset,
488                    uint32 _size,
489                    uint32 _shared_memory_id,
490                    uint32 _shared_memory_offset) {
491     static_cast<ValueType*>(cmd)->Init(
492         _bucket_id,
493         _offset,
494         _size,
495         _shared_memory_id,
496         _shared_memory_offset);
497     return NextCmdAddress<ValueType>(cmd);
498   }
499 
500   CommandHeader header;
501   uint32 bucket_id;
502   uint32 offset;
503   uint32 size;
504   uint32 shared_memory_id;
505   uint32 shared_memory_offset;
506 };
507 
508 COMPILE_ASSERT(sizeof(GetBucketData) == 24, Sizeof_GetBucketData_is_not_20);
509 COMPILE_ASSERT(offsetof(GetBucketData, header) == 0,
510                Offsetof_GetBucketData_header_not_0);
511 COMPILE_ASSERT(offsetof(GetBucketData, bucket_id) == 4,
512                Offsetof_GetBucketData_bucket_id_not_4);
513 COMPILE_ASSERT(offsetof(GetBucketData, offset) == 8,
514                Offsetof_GetBucketData_offset_not_8);
515 COMPILE_ASSERT(offsetof(GetBucketData, size) == 12,
516                Offsetof_GetBucketData_size_not_12);
517 COMPILE_ASSERT(offsetof(GetBucketData, shared_memory_id) == 16,
518                Offsetof_GetBucketData_shared_memory_id_not_16);
519 COMPILE_ASSERT(offsetof(GetBucketData, shared_memory_offset) == 20,
520                Offsetof_GetBucketData_shared_memory_offset_not_20);
521 
522 }  // namespace cmd
523 
524 #pragma pack(pop)
525 
526 }  // namespace gpu
527 
528 #endif  // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
529 
530