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_
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "gpu/command_buffer/common/bitfield_helpers.h"
16 #include "gpu/gpu_export.h"
27 // Pack & unpack Command cmd_flags
28 #define CMD_FLAG_SET_TRACE_LEVEL(level) ((level & 3) << 0)
29 #define CMD_FLAG_GET_TRACE_LEVEL(cmd_flags) ((cmd_flags >> 0) & 3)
31 // Computes the number of command buffer entries needed for a certain size. In
32 // other words it rounds up to a multiple of entries.
33 inline uint32_t ComputeNumEntries(size_t size_in_bytes
) {
34 return static_cast<uint32_t>(
35 (size_in_bytes
+ sizeof(uint32_t) - 1) / sizeof(uint32_t)); // NOLINT
38 // Rounds up to a multiple of entries in bytes.
39 inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes
) {
40 return ComputeNumEntries(size_in_bytes
) * sizeof(uint32_t); // NOLINT
43 // Struct that defines the command header in the command buffer.
44 struct CommandHeader
{
48 GPU_EXPORT
static const int32_t kMaxSize
= (1 << 21) - 1;
50 void Init(uint32_t _command
, int32_t _size
) {
51 DCHECK_LE(_size
, kMaxSize
);
56 // Sets the header based on the passed in command. Can not be used for
57 // variable sized commands like immediate commands or Noop.
60 COMPILE_ASSERT(T::kArgFlags
== cmd::kFixed
, Cmd_kArgFlags_not_kFixed
);
61 Init(T::kCmdId
, ComputeNumEntries(sizeof(T
))); // NOLINT
64 // Sets the header by a size in bytes of the immediate data after the command.
66 void SetCmdBySize(uint32_t size_of_data_in_bytes
) {
67 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
69 ComputeNumEntries(sizeof(T
) + size_of_data_in_bytes
)); // NOLINT
72 // Sets the header by a size in bytes.
74 void SetCmdByTotalSize(uint32_t size_in_bytes
) {
75 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
76 DCHECK_GE(size_in_bytes
, sizeof(T
)); // NOLINT
77 Init(T::kCmdId
, ComputeNumEntries(size_in_bytes
));
81 COMPILE_ASSERT(sizeof(CommandHeader
) == 4, Sizeof_CommandHeader_is_not_4
);
83 // Union that defines possible command buffer entries.
84 union CommandBufferEntry
{
85 CommandHeader value_header
;
86 uint32_t value_uint32
;
91 #define GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT 4
92 const size_t kCommandBufferEntrySize
= GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT
;
94 COMPILE_ASSERT(sizeof(CommandBufferEntry
) == kCommandBufferEntrySize
,
95 Sizeof_CommandBufferEntry_is_not_4
);
97 // Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned.
98 #pragma pack(push, GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT)
100 // Gets the address of memory just after a structure in a typesafe way. This is
101 // used for IMMEDIATE commands to get the address of the place to put the data.
102 // Immediate command put their data direclty in the command buffer.
104 // cmd: Address of command.
105 template <typename T
>
106 void* ImmediateDataAddress(T
* cmd
) {
107 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
108 return reinterpret_cast<char*>(cmd
) + sizeof(*cmd
);
111 // Gets the address of the place to put the next command in a typesafe way.
112 // This can only be used for fixed sized commands.
113 template <typename T
>
115 // cmd: Address of command.
116 void* NextCmdAddress(void* cmd
) {
117 COMPILE_ASSERT(T::kArgFlags
== cmd::kFixed
, Cmd_kArgFlags_not_kFixed
);
118 return reinterpret_cast<char*>(cmd
) + sizeof(T
);
121 // Gets the address of the place to put the next command in a typesafe way.
122 // This can only be used for variable sized command like IMMEDIATE commands.
124 // cmd: Address of command.
125 // size_of_data_in_bytes: Size of the data for the command.
126 template <typename T
>
127 void* NextImmediateCmdAddress(void* cmd
, uint32_t size_of_data_in_bytes
) {
128 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
129 return reinterpret_cast<char*>(cmd
) + sizeof(T
) + // NOLINT
130 RoundSizeToMultipleOfEntries(size_of_data_in_bytes
);
133 // Gets the address of the place to put the next command in a typesafe way.
134 // This can only be used for variable sized command like IMMEDIATE commands.
136 // cmd: Address of command.
137 // size_of_cmd_in_bytes: Size of the cmd and data.
138 template <typename T
>
139 void* NextImmediateCmdAddressTotalSize(void* cmd
,
140 uint32_t total_size_in_bytes
) {
141 COMPILE_ASSERT(T::kArgFlags
== cmd::kAtLeastN
, Cmd_kArgFlags_not_kAtLeastN
);
142 DCHECK_GE(total_size_in_bytes
, sizeof(T
)); // NOLINT
143 return reinterpret_cast<char*>(cmd
) +
144 RoundSizeToMultipleOfEntries(total_size_in_bytes
);
149 // This macro is used to safely and convienently expand the list of commnad
150 // buffer commands in to various lists and never have them get out of sync. To
151 // add a new command, add it this list, create the corresponding structure below
152 // and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where
153 // COMMAND_NAME is the name of your command structure.
155 // NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
156 #define COMMON_COMMAND_BUFFER_CMDS(OP) \
158 OP(SetToken) /* 1 */ \
159 OP(SetBucketSize) /* 2 */ \
160 OP(SetBucketData) /* 3 */ \
161 OP(SetBucketDataImmediate) /* 4 */ \
162 OP(GetBucketStart) /* 5 */ \
163 OP(GetBucketData) /* 6 */ \
167 #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,
169 COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP
)
171 #undef COMMON_COMMAND_BUFFER_CMD_OP
174 kLastCommonId
= 255 // reserve 256 spaces for common commands.
177 COMPILE_ASSERT(kNumCommands
- 1 <= kLastCommonId
, Too_many_common_commands
);
179 const char* GetCommandName(CommandId id
);
183 typedef Noop ValueType
;
184 static const CommandId kCmdId
= kNoop
;
185 static const cmd::ArgFlags kArgFlags
= cmd::kAtLeastN
;
186 static const uint8_t cmd_flags
= CMD_FLAG_SET_TRACE_LEVEL(3);
188 void SetHeader(uint32_t skip_count
) {
189 DCHECK_GT(skip_count
, 0u);
190 header
.Init(kCmdId
, skip_count
);
193 void Init(uint32_t skip_count
) {
194 SetHeader(skip_count
);
197 static void* Set(void* cmd
, uint32_t skip_count
) {
198 static_cast<ValueType
*>(cmd
)->Init(skip_count
);
199 return NextImmediateCmdAddress
<ValueType
>(
200 cmd
, skip_count
* sizeof(CommandBufferEntry
)); // NOLINT
203 CommandHeader header
;
206 COMPILE_ASSERT(sizeof(Noop
) == 4, Sizeof_Noop_is_not_4
);
207 COMPILE_ASSERT(offsetof(Noop
, header
) == 0, Offsetof_Noop_header_not_0
);
209 // The SetToken command puts a token in the command stream that you can
210 // use to check if that token has been passed in the command stream.
212 typedef SetToken ValueType
;
213 static const CommandId kCmdId
= kSetToken
;
214 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
215 static const uint8_t cmd_flags
= CMD_FLAG_SET_TRACE_LEVEL(3);
218 header
.SetCmd
<ValueType
>();
221 void Init(uint32_t _token
) {
225 static void* Set(void* cmd
, uint32_t token
) {
226 static_cast<ValueType
*>(cmd
)->Init(token
);
227 return NextCmdAddress
<ValueType
>(cmd
);
230 CommandHeader header
;
234 COMPILE_ASSERT(sizeof(SetToken
) == 8, Sizeof_SetToken_is_not_8
);
235 COMPILE_ASSERT(offsetof(SetToken
, header
) == 0,
236 Offsetof_SetToken_header_not_0
);
237 COMPILE_ASSERT(offsetof(SetToken
, token
) == 4,
238 Offsetof_SetToken_token_not_4
);
240 // Sets the size of a bucket for collecting data on the service side.
241 // This is a utility for gathering data on the service side so it can be used
242 // all at once when some service side API is called. It removes the need to add
243 // special commands just to support a particular API. For example, any API
244 // command that needs a string needs a way to send that string to the API over
245 // the command buffers. While you can require that the command buffer or
246 // transfer buffer be large enough to hold the largest string you can send,
247 // using this command removes that restriction by letting you send smaller
248 // pieces over and build up the data on the service side.
250 // You can clear a bucket on the service side and thereby free memory by sending
252 struct SetBucketSize
{
253 typedef SetBucketSize ValueType
;
254 static const CommandId kCmdId
= kSetBucketSize
;
255 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
256 static const uint8_t cmd_flags
= CMD_FLAG_SET_TRACE_LEVEL(3);
259 header
.SetCmd
<ValueType
>();
262 void Init(uint32_t _bucket_id
, uint32_t _size
) {
264 bucket_id
= _bucket_id
;
267 static void* Set(void* cmd
, uint32_t _bucket_id
, uint32_t _size
) {
268 static_cast<ValueType
*>(cmd
)->Init(_bucket_id
, _size
);
269 return NextCmdAddress
<ValueType
>(cmd
);
272 CommandHeader header
;
277 COMPILE_ASSERT(sizeof(SetBucketSize
) == 12, Sizeof_SetBucketSize_is_not_8
);
278 COMPILE_ASSERT(offsetof(SetBucketSize
, header
) == 0,
279 Offsetof_SetBucketSize_header_not_0
);
280 COMPILE_ASSERT(offsetof(SetBucketSize
, bucket_id
) == 4,
281 Offsetof_SetBucketSize_bucket_id_4
);
282 COMPILE_ASSERT(offsetof(SetBucketSize
, size
) == 8,
283 Offsetof_SetBucketSize_size_8
);
285 // Sets the contents of a portion of a bucket on the service side from data in
287 // See SetBucketSize.
288 struct SetBucketData
{
289 typedef SetBucketData ValueType
;
290 static const CommandId kCmdId
= kSetBucketData
;
291 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
292 static const uint8_t cmd_flags
= CMD_FLAG_SET_TRACE_LEVEL(3);
295 header
.SetCmd
<ValueType
>();
298 void Init(uint32_t _bucket_id
,
301 uint32_t _shared_memory_id
,
302 uint32_t _shared_memory_offset
) {
304 bucket_id
= _bucket_id
;
307 shared_memory_id
= _shared_memory_id
;
308 shared_memory_offset
= _shared_memory_offset
;
310 static void* Set(void* cmd
,
314 uint32_t _shared_memory_id
,
315 uint32_t _shared_memory_offset
) {
316 static_cast<ValueType
*>(cmd
)->Init(
321 _shared_memory_offset
);
322 return NextCmdAddress
<ValueType
>(cmd
);
325 CommandHeader header
;
329 uint32_t shared_memory_id
;
330 uint32_t shared_memory_offset
;
333 COMPILE_ASSERT(sizeof(SetBucketData
) == 24, Sizeof_SetBucketData_is_not_24
);
334 COMPILE_ASSERT(offsetof(SetBucketData
, header
) == 0,
335 Offsetof_SetBucketData_header_not_0
);
336 COMPILE_ASSERT(offsetof(SetBucketData
, bucket_id
) == 4,
337 Offsetof_SetBucketData_bucket_id_not_4
);
338 COMPILE_ASSERT(offsetof(SetBucketData
, offset
) == 8,
339 Offsetof_SetBucketData_offset_not_8
);
340 COMPILE_ASSERT(offsetof(SetBucketData
, size
) == 12,
341 Offsetof_SetBucketData_size_not_12
);
342 COMPILE_ASSERT(offsetof(SetBucketData
, shared_memory_id
) == 16,
343 Offsetof_SetBucketData_shared_memory_id_not_16
);
344 COMPILE_ASSERT(offsetof(SetBucketData
, shared_memory_offset
) == 20,
345 Offsetof_SetBucketData_shared_memory_offset_not_20
);
347 // Sets the contents of a portion of a bucket on the service side from data in
348 // the command buffer.
349 // See SetBucketSize.
350 struct SetBucketDataImmediate
{
351 typedef SetBucketDataImmediate ValueType
;
352 static const CommandId kCmdId
= kSetBucketDataImmediate
;
353 static const cmd::ArgFlags kArgFlags
= cmd::kAtLeastN
;
354 static const uint8_t cmd_flags
= CMD_FLAG_SET_TRACE_LEVEL(3);
356 void SetHeader(uint32_t size
) {
357 header
.SetCmdBySize
<ValueType
>(size
);
360 void Init(uint32_t _bucket_id
,
364 bucket_id
= _bucket_id
;
368 static void* Set(void* cmd
,
372 static_cast<ValueType
*>(cmd
)->Init(
376 return NextImmediateCmdAddress
<ValueType
>(cmd
, _size
);
379 CommandHeader header
;
385 COMPILE_ASSERT(sizeof(SetBucketDataImmediate
) == 16,
386 Sizeof_SetBucketDataImmediate_is_not_24
);
387 COMPILE_ASSERT(offsetof(SetBucketDataImmediate
, header
) == 0,
388 Offsetof_SetBucketDataImmediate_header_not_0
);
389 COMPILE_ASSERT(offsetof(SetBucketDataImmediate
, bucket_id
) == 4,
390 Offsetof_SetBucketDataImmediate_bucket_id_not_4
);
391 COMPILE_ASSERT(offsetof(SetBucketDataImmediate
, offset
) == 8,
392 Offsetof_SetBucketDataImmediate_offset_not_8
);
393 COMPILE_ASSERT(offsetof(SetBucketDataImmediate
, size
) == 12,
394 Offsetof_SetBucketDataImmediate_size_not_12
);
396 // Gets the start of a bucket the service has available. Sending a variable size
397 // result back to the client and the portion of that result that fits in the
398 // supplied shared memory. If the size of the result is larger than the supplied
399 // shared memory the rest of the bucket's contents can be retrieved with
402 // This is used for example for any API that returns a string. The problem is
403 // the largest thing you can send back in 1 command is the size of your shared
404 // memory. This command along with GetBucketData implements a way to get a
405 // result a piece at a time to help solve that problem in a generic way.
406 struct GetBucketStart
{
407 typedef GetBucketStart ValueType
;
408 static const CommandId kCmdId
= kGetBucketStart
;
409 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
410 static const uint8_t cmd_flags
= CMD_FLAG_SET_TRACE_LEVEL(3);
412 typedef uint32_t Result
;
415 header
.SetCmd
<ValueType
>();
418 void Init(uint32_t _bucket_id
,
419 uint32_t _result_memory_id
,
420 uint32_t _result_memory_offset
,
421 uint32_t _data_memory_size
,
422 uint32_t _data_memory_id
,
423 uint32_t _data_memory_offset
) {
425 bucket_id
= _bucket_id
;
426 result_memory_id
= _result_memory_id
;
427 result_memory_offset
= _result_memory_offset
;
428 data_memory_size
= _data_memory_size
;
429 data_memory_id
= _data_memory_id
;
430 data_memory_offset
= _data_memory_offset
;
432 static void* Set(void* cmd
,
434 uint32_t _result_memory_id
,
435 uint32_t _result_memory_offset
,
436 uint32_t _data_memory_size
,
437 uint32_t _data_memory_id
,
438 uint32_t _data_memory_offset
) {
439 static_cast<ValueType
*>(cmd
)->Init(
442 _result_memory_offset
,
445 _data_memory_offset
);
446 return NextCmdAddress
<ValueType
>(cmd
);
449 CommandHeader header
;
451 uint32_t result_memory_id
;
452 uint32_t result_memory_offset
;
453 uint32_t data_memory_size
;
454 uint32_t data_memory_id
;
455 uint32_t data_memory_offset
;
458 COMPILE_ASSERT(sizeof(GetBucketStart
) == 28, Sizeof_GetBucketStart_is_not_28
);
459 COMPILE_ASSERT(offsetof(GetBucketStart
, header
) == 0,
460 Offsetof_GetBucketStart_header_not_0
);
461 COMPILE_ASSERT(offsetof(GetBucketStart
, bucket_id
) == 4,
462 Offsetof_GetBucketStart_bucket_id_not_4
);
463 COMPILE_ASSERT(offsetof(GetBucketStart
, result_memory_id
) == 8,
464 Offsetof_GetBucketStart_result_memory_id_not_8
);
465 COMPILE_ASSERT(offsetof(GetBucketStart
, result_memory_offset
) == 12,
466 Offsetof_GetBucketStart_result_memory_offset_not_12
);
467 COMPILE_ASSERT(offsetof(GetBucketStart
, data_memory_size
) == 16,
468 Offsetof_GetBucketStart_data_memory_size_not_16
);
469 COMPILE_ASSERT(offsetof(GetBucketStart
, data_memory_id
) == 20,
470 Offsetof_GetBucketStart_data_memory_id_not_20
);
471 COMPILE_ASSERT(offsetof(GetBucketStart
, data_memory_offset
) == 24,
472 Offsetof_GetBucketStart_data_memory_offset_not_24
);
474 // Gets a piece of a result the service as available.
475 // See GetBucketSize.
476 struct GetBucketData
{
477 typedef GetBucketData ValueType
;
478 static const CommandId kCmdId
= kGetBucketData
;
479 static const cmd::ArgFlags kArgFlags
= cmd::kFixed
;
480 static const uint8_t cmd_flags
= CMD_FLAG_SET_TRACE_LEVEL(3);
483 header
.SetCmd
<ValueType
>();
486 void Init(uint32_t _bucket_id
,
489 uint32_t _shared_memory_id
,
490 uint32_t _shared_memory_offset
) {
492 bucket_id
= _bucket_id
;
495 shared_memory_id
= _shared_memory_id
;
496 shared_memory_offset
= _shared_memory_offset
;
498 static void* Set(void* cmd
,
502 uint32_t _shared_memory_id
,
503 uint32_t _shared_memory_offset
) {
504 static_cast<ValueType
*>(cmd
)->Init(
509 _shared_memory_offset
);
510 return NextCmdAddress
<ValueType
>(cmd
);
513 CommandHeader header
;
517 uint32_t shared_memory_id
;
518 uint32_t shared_memory_offset
;
521 COMPILE_ASSERT(sizeof(GetBucketData
) == 24, Sizeof_GetBucketData_is_not_20
);
522 COMPILE_ASSERT(offsetof(GetBucketData
, header
) == 0,
523 Offsetof_GetBucketData_header_not_0
);
524 COMPILE_ASSERT(offsetof(GetBucketData
, bucket_id
) == 4,
525 Offsetof_GetBucketData_bucket_id_not_4
);
526 COMPILE_ASSERT(offsetof(GetBucketData
, offset
) == 8,
527 Offsetof_GetBucketData_offset_not_8
);
528 COMPILE_ASSERT(offsetof(GetBucketData
, size
) == 12,
529 Offsetof_GetBucketData_size_not_12
);
530 COMPILE_ASSERT(offsetof(GetBucketData
, shared_memory_id
) == 16,
531 Offsetof_GetBucketData_shared_memory_id_not_16
);
532 COMPILE_ASSERT(offsetof(GetBucketData
, shared_memory_offset
) == 20,
533 Offsetof_GetBucketData_shared_memory_offset_not_20
);
541 #endif // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_