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 // This file contains the common parts of command buffer formats.
7 #ifndef GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
8 #define GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
12 #include "gpu/command_buffer/common/bitfield_helpers.h"
13 #include "gpu/command_buffer/common/logging.h"
14 #include "gpu/command_buffer/common/types.h"
15 #include "gpu/gpu_export.h"
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.
28 inline uint32
ComputeNumEntries(size_t size_in_bytes
) {
29 return static_cast<uint32
>(
30 (size_in_bytes
+ sizeof(uint32
) - 1) / sizeof(uint32
)); // NOLINT
33 // Rounds up to a multiple of entries in bytes.
34 inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes
) {
35 return ComputeNumEntries(size_in_bytes
) * sizeof(uint32
); // NOLINT
38 // Struct that defines the command header in the command buffer.
39 struct CommandHeader
{
43 GPU_EXPORT
static const int32 kMaxSize
= (1 << 21) - 1;
45 void Init(uint32 _command
, int32 _size
) {
46 GPU_DCHECK_LE(_size
, kMaxSize
);
51 // Sets the header based on the passed in command. Can not be used for
52 // variable sized commands like immediate commands or Noop.
55 COMPILE_ASSERT(T::kArgFlags
== cmd::kFixed
, Cmd_kArgFlags_not_kFixed
);
56 Init(T::kCmdId
, ComputeNumEntries(sizeof(T
))); // NOLINT
59 // Sets the header by a size in bytes of the immediate data after the command.
61 void SetCmdBySize(uint32 size_of_data_in_bytes
) {
62 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
64 ComputeNumEntries(sizeof(T
) + size_of_data_in_bytes
)); // NOLINT
67 // Sets the header by a size in bytes.
69 void SetCmdByTotalSize(uint32 size_in_bytes
) {
70 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
71 GPU_DCHECK_GE(size_in_bytes
, sizeof(T
)); // NOLINT
72 Init(T::kCmdId
, ComputeNumEntries(size_in_bytes
));
76 COMPILE_ASSERT(sizeof(CommandHeader
) == 4, Sizeof_CommandHeader_is_not_4
);
78 // Union that defines possible command buffer entries.
79 union CommandBufferEntry
{
80 CommandHeader value_header
;
86 const size_t kCommandBufferEntrySize
= 4;
88 COMPILE_ASSERT(sizeof(CommandBufferEntry
) == kCommandBufferEntrySize
,
89 Sizeof_CommandBufferEntry_is_not_4
);
91 // Make sure the compiler does not add extra padding to any of the command
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.
99 // cmd: Address of command.
100 template <typename T
>
101 void* ImmediateDataAddress(T
* cmd
) {
102 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
103 return reinterpret_cast<char*>(cmd
) + sizeof(*cmd
);
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
>
110 // cmd: Address of command.
111 void* NextCmdAddress(void* cmd
) {
112 COMPILE_ASSERT(T::kArgFlags
== cmd::kFixed
, Cmd_kArgFlags_not_kFixed
);
113 return reinterpret_cast<char*>(cmd
) + sizeof(T
);
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.
119 // cmd: Address of command.
120 // size_of_data_in_bytes: Size of the data for the command.
121 template <typename T
>
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
);
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.
131 // cmd: Address of command.
132 // size_of_cmd_in_bytes: Size of the cmd and data.
133 template <typename T
>
134 void* NextImmediateCmdAddressTotalSize(void* cmd
, uint32 total_size_in_bytes
) {
135 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
136 GPU_DCHECK_GE(total_size_in_bytes
, sizeof(T
)); // NOLINT
137 return reinterpret_cast<char*>(cmd
) +
138 RoundSizeToMultipleOfEntries(total_size_in_bytes
);
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.
149 // NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
150 #define COMMON_COMMAND_BUFFER_CMDS(OP) \
152 OP(SetToken) /* 1 */ \
153 OP(SetBucketSize) /* 2 */ \
154 OP(SetBucketData) /* 3 */ \
155 OP(SetBucketDataImmediate) /* 4 */ \
156 OP(GetBucketStart) /* 5 */ \
157 OP(GetBucketData) /* 6 */ \
161 #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,
163 COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP
)
165 #undef COMMON_COMMAND_BUFFER_CMD_OP
168 kLastCommonId
= 255 // reserve 256 spaces for common commands.
171 COMPILE_ASSERT(kNumCommands
- 1 <= kLastCommonId
, Too_many_common_commands
);
173 const char* GetCommandName(CommandId id
);
177 typedef Noop ValueType
;
178 static const CommandId kCmdId
= kNoop
;
179 static const cmd::ArgFlags kArgFlags
= cmd::kAtLeastN
;
181 void SetHeader(uint32 skip_count
) {
182 GPU_DCHECK_GT(skip_count
, 0u);
183 header
.Init(kCmdId
, skip_count
);
186 void Init(uint32 skip_count
) {
187 SetHeader(skip_count
);
190 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
196 CommandHeader header
;
199 COMPILE_ASSERT(sizeof(Noop
) == 4, Sizeof_Noop_is_not_4
);
200 COMPILE_ASSERT(offsetof(Noop
, header
) == 0, Offsetof_Noop_header_not_0
);
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.
205 typedef SetToken ValueType
;
206 static const CommandId kCmdId
= kSetToken
;
207 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
210 header
.SetCmd
<ValueType
>();
213 void Init(uint32 _token
) {
217 static void* Set(void* cmd
, uint32 token
) {
218 static_cast<ValueType
*>(cmd
)->Init(token
);
219 return NextCmdAddress
<ValueType
>(cmd
);
222 CommandHeader header
;
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
);
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.
242 // You can clear a bucket on the service side and thereby free memory by sending
244 struct SetBucketSize
{
245 typedef SetBucketSize ValueType
;
246 static const CommandId kCmdId
= kSetBucketSize
;
247 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
250 header
.SetCmd
<ValueType
>();
253 void Init(uint32 _bucket_id
, uint32 _size
) {
255 bucket_id
= _bucket_id
;
258 static void* Set(void* cmd
, uint32 _bucket_id
, uint32 _size
) {
259 static_cast<ValueType
*>(cmd
)->Init(_bucket_id
, _size
);
260 return NextCmdAddress
<ValueType
>(cmd
);
263 CommandHeader header
;
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
);
276 // Sets the contents of a portion of a bucket on the service side from data in
278 // See SetBucketSize.
279 struct SetBucketData
{
280 typedef SetBucketData ValueType
;
281 static const CommandId kCmdId
= kSetBucketData
;
282 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
285 header
.SetCmd
<ValueType
>();
288 void Init(uint32 _bucket_id
,
291 uint32 _shared_memory_id
,
292 uint32 _shared_memory_offset
) {
294 bucket_id
= _bucket_id
;
297 shared_memory_id
= _shared_memory_id
;
298 shared_memory_offset
= _shared_memory_offset
;
300 static void* Set(void* cmd
,
304 uint32 _shared_memory_id
,
305 uint32 _shared_memory_offset
) {
306 static_cast<ValueType
*>(cmd
)->Init(
311 _shared_memory_offset
);
312 return NextCmdAddress
<ValueType
>(cmd
);
315 CommandHeader header
;
319 uint32 shared_memory_id
;
320 uint32 shared_memory_offset
;
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
);
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
;
345 void SetHeader(uint32 size
) {
346 header
.SetCmdBySize
<ValueType
>(size
);
349 void Init(uint32 _bucket_id
,
353 bucket_id
= _bucket_id
;
357 static void* Set(void* cmd
,
361 static_cast<ValueType
*>(cmd
)->Init(
365 return NextImmediateCmdAddress
<ValueType
>(cmd
, _size
);
368 CommandHeader header
;
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
);
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
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
;
400 typedef uint32 Result
;
403 header
.SetCmd
<ValueType
>();
406 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
) {
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
;
420 static void* Set(void* cmd
,
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(
430 _result_memory_offset
,
433 _data_memory_offset
);
434 return NextCmdAddress
<ValueType
>(cmd
);
437 CommandHeader header
;
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
;
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
);
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
;
470 header
.SetCmd
<ValueType
>();
473 void Init(uint32 _bucket_id
,
476 uint32 _shared_memory_id
,
477 uint32 _shared_memory_offset
) {
479 bucket_id
= _bucket_id
;
482 shared_memory_id
= _shared_memory_id
;
483 shared_memory_offset
= _shared_memory_offset
;
485 static void* Set(void* cmd
,
489 uint32 _shared_memory_id
,
490 uint32 _shared_memory_offset
) {
491 static_cast<ValueType
*>(cmd
)->Init(
496 _shared_memory_offset
);
497 return NextCmdAddress
<ValueType
>(cmd
);
500 CommandHeader header
;
504 uint32 shared_memory_id
;
505 uint32 shared_memory_offset
;
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
);
528 #endif // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_