Elim cr-checkbox
[chromium-blink-merge.git] / gpu / command_buffer / common / cmd_buffer_common.h
bloba2b8c5a54788f4eb28f6671c053117ec53958236
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_
10 #include <stddef.h>
11 #include <stdint.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"
18 namespace gpu {
20 namespace cmd {
21 enum ArgFlags {
22 kFixed = 0x0,
23 kAtLeastN = 0x1
25 } // namespace cmd
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 {
45 uint32_t size:21;
46 uint32_t command:11;
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);
52 command = _command;
53 size = _size;
56 // Sets the header based on the passed in command. Can not be used for
57 // variable sized commands like immediate commands or Noop.
58 template <typename T>
59 void SetCmd() {
60 static_assert(T::kArgFlags == cmd::kFixed,
61 "T::kArgFlags should equal cmd::kFixed");
62 Init(T::kCmdId, ComputeNumEntries(sizeof(T))); // NOLINT
65 // Sets the header by a size in bytes of the immediate data after the command.
66 template <typename T>
67 void SetCmdBySize(uint32_t size_of_data_in_bytes) {
68 static_assert(T::kArgFlags == cmd::kAtLeastN,
69 "T::kArgFlags should equal cmd::kAtLeastN");
70 Init(T::kCmdId,
71 ComputeNumEntries(sizeof(T) + size_of_data_in_bytes)); // NOLINT
74 // Sets the header by a size in bytes.
75 template <typename T>
76 void SetCmdByTotalSize(uint32_t size_in_bytes) {
77 static_assert(T::kArgFlags == cmd::kAtLeastN,
78 "T::kArgFlags should equal cmd::kAtLeastN");
79 DCHECK_GE(size_in_bytes, sizeof(T)); // NOLINT
80 Init(T::kCmdId, ComputeNumEntries(size_in_bytes));
84 static_assert(sizeof(CommandHeader) == 4,
85 "size of CommandHeader should equal 4");
87 // Union that defines possible command buffer entries.
88 union CommandBufferEntry {
89 CommandHeader value_header;
90 uint32_t value_uint32;
91 int32_t value_int32;
92 float value_float;
95 #define GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT 4
96 const size_t kCommandBufferEntrySize = GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT;
98 static_assert(sizeof(CommandBufferEntry) == kCommandBufferEntrySize,
99 "size of CommandBufferEntry should equal "
100 "kCommandBufferEntrySize");
102 // Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned.
103 #pragma pack(push, GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT)
105 // Gets the address of memory just after a structure in a typesafe way. This is
106 // used for IMMEDIATE commands to get the address of the place to put the data.
107 // Immediate command put their data direclty in the command buffer.
108 // Parameters:
109 // cmd: Address of command.
110 template <typename T>
111 void* ImmediateDataAddress(T* cmd) {
112 static_assert(T::kArgFlags == cmd::kAtLeastN,
113 "T::kArgFlags should equal cmd::kAtLeastN");
114 return reinterpret_cast<char*>(cmd) + sizeof(*cmd);
117 // Gets the address of the place to put the next command in a typesafe way.
118 // This can only be used for fixed sized commands.
119 template <typename T>
120 // Parameters:
121 // cmd: Address of command.
122 void* NextCmdAddress(void* cmd) {
123 static_assert(T::kArgFlags == cmd::kFixed,
124 "T::kArgFlags should equal cmd::kFixed");
125 return reinterpret_cast<char*>(cmd) + sizeof(T);
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_data_in_bytes: Size of the data for the command.
133 template <typename T>
134 void* NextImmediateCmdAddress(void* cmd, uint32_t size_of_data_in_bytes) {
135 static_assert(T::kArgFlags == cmd::kAtLeastN,
136 "T::kArgFlags should equal cmd::kAtLeastN");
137 return reinterpret_cast<char*>(cmd) + sizeof(T) + // NOLINT
138 RoundSizeToMultipleOfEntries(size_of_data_in_bytes);
141 // Gets the address of the place to put the next command in a typesafe way.
142 // This can only be used for variable sized command like IMMEDIATE commands.
143 // Parameters:
144 // cmd: Address of command.
145 // size_of_cmd_in_bytes: Size of the cmd and data.
146 template <typename T>
147 void* NextImmediateCmdAddressTotalSize(void* cmd,
148 uint32_t total_size_in_bytes) {
149 static_assert(T::kArgFlags == cmd::kAtLeastN,
150 "T::kArgFlags should equal cmd::kAtLeastN");
151 DCHECK_GE(total_size_in_bytes, sizeof(T)); // NOLINT
152 return reinterpret_cast<char*>(cmd) +
153 RoundSizeToMultipleOfEntries(total_size_in_bytes);
156 namespace cmd {
158 // This macro is used to safely and convienently expand the list of commnad
159 // buffer commands in to various lists and never have them get out of sync. To
160 // add a new command, add it this list, create the corresponding structure below
161 // and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where
162 // COMMAND_NAME is the name of your command structure.
164 // NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
165 #define COMMON_COMMAND_BUFFER_CMDS(OP) \
166 OP(Noop) /* 0 */ \
167 OP(SetToken) /* 1 */ \
168 OP(SetBucketSize) /* 2 */ \
169 OP(SetBucketData) /* 3 */ \
170 OP(SetBucketDataImmediate) /* 4 */ \
171 OP(GetBucketStart) /* 5 */ \
172 OP(GetBucketData) /* 6 */ \
174 // Common commands.
175 enum CommandId {
176 #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,
178 COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
180 #undef COMMON_COMMAND_BUFFER_CMD_OP
182 kNumCommands,
183 kLastCommonId = 255 // reserve 256 spaces for common commands.
186 static_assert(kNumCommands - 1 <= kLastCommonId, "too many commands");
188 const char* GetCommandName(CommandId id);
190 // A Noop command.
191 struct Noop {
192 typedef Noop ValueType;
193 static const CommandId kCmdId = kNoop;
194 static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
195 static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
197 void SetHeader(uint32_t skip_count) {
198 DCHECK_GT(skip_count, 0u);
199 header.Init(kCmdId, skip_count);
202 void Init(uint32_t skip_count) {
203 SetHeader(skip_count);
206 static void* Set(void* cmd, uint32_t skip_count) {
207 static_cast<ValueType*>(cmd)->Init(skip_count);
208 return NextImmediateCmdAddress<ValueType>(
209 cmd, skip_count * sizeof(CommandBufferEntry)); // NOLINT
212 CommandHeader header;
215 static_assert(sizeof(Noop) == 4, "size of Noop should equal 4");
216 static_assert(offsetof(Noop, header) == 0,
217 "offset of Noop.header should equal 0");
219 // The SetToken command puts a token in the command stream that you can
220 // use to check if that token has been passed in the command stream.
221 struct SetToken {
222 typedef SetToken ValueType;
223 static const CommandId kCmdId = kSetToken;
224 static const cmd::ArgFlags kArgFlags = cmd::kFixed;
225 static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
227 void SetHeader() {
228 header.SetCmd<ValueType>();
231 void Init(uint32_t _token) {
232 SetHeader();
233 token = _token;
235 static void* Set(void* cmd, uint32_t token) {
236 static_cast<ValueType*>(cmd)->Init(token);
237 return NextCmdAddress<ValueType>(cmd);
240 CommandHeader header;
241 uint32_t token;
244 static_assert(sizeof(SetToken) == 8, "size of SetToken should equal 8");
245 static_assert(offsetof(SetToken, header) == 0,
246 "offset of SetToken.header should equal 0");
247 static_assert(offsetof(SetToken, token) == 4,
248 "offset of SetToken.token should equal 4");
250 // Sets the size of a bucket for collecting data on the service side.
251 // This is a utility for gathering data on the service side so it can be used
252 // all at once when some service side API is called. It removes the need to add
253 // special commands just to support a particular API. For example, any API
254 // command that needs a string needs a way to send that string to the API over
255 // the command buffers. While you can require that the command buffer or
256 // transfer buffer be large enough to hold the largest string you can send,
257 // using this command removes that restriction by letting you send smaller
258 // pieces over and build up the data on the service side.
260 // You can clear a bucket on the service side and thereby free memory by sending
261 // a size of 0.
262 struct SetBucketSize {
263 typedef SetBucketSize ValueType;
264 static const CommandId kCmdId = kSetBucketSize;
265 static const cmd::ArgFlags kArgFlags = cmd::kFixed;
266 static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
268 void SetHeader() {
269 header.SetCmd<ValueType>();
272 void Init(uint32_t _bucket_id, uint32_t _size) {
273 SetHeader();
274 bucket_id = _bucket_id;
275 size = _size;
277 static void* Set(void* cmd, uint32_t _bucket_id, uint32_t _size) {
278 static_cast<ValueType*>(cmd)->Init(_bucket_id, _size);
279 return NextCmdAddress<ValueType>(cmd);
282 CommandHeader header;
283 uint32_t bucket_id;
284 uint32_t size;
287 static_assert(sizeof(SetBucketSize) == 12,
288 "size of SetBucketSize should equal 12");
289 static_assert(offsetof(SetBucketSize, header) == 0,
290 "offset of SetBucketSize.header should equal 0");
291 static_assert(offsetof(SetBucketSize, bucket_id) == 4,
292 "offset of SetBucketSize.bucket_id should equal 4");
293 static_assert(offsetof(SetBucketSize, size) == 8,
294 "offset of SetBucketSize.size should equal 8");
296 // Sets the contents of a portion of a bucket on the service side from data in
297 // shared memory.
298 // See SetBucketSize.
299 struct SetBucketData {
300 typedef SetBucketData ValueType;
301 static const CommandId kCmdId = kSetBucketData;
302 static const cmd::ArgFlags kArgFlags = cmd::kFixed;
303 static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
305 void SetHeader() {
306 header.SetCmd<ValueType>();
309 void Init(uint32_t _bucket_id,
310 uint32_t _offset,
311 uint32_t _size,
312 uint32_t _shared_memory_id,
313 uint32_t _shared_memory_offset) {
314 SetHeader();
315 bucket_id = _bucket_id;
316 offset = _offset;
317 size = _size;
318 shared_memory_id = _shared_memory_id;
319 shared_memory_offset = _shared_memory_offset;
321 static void* Set(void* cmd,
322 uint32_t _bucket_id,
323 uint32_t _offset,
324 uint32_t _size,
325 uint32_t _shared_memory_id,
326 uint32_t _shared_memory_offset) {
327 static_cast<ValueType*>(cmd)->Init(
328 _bucket_id,
329 _offset,
330 _size,
331 _shared_memory_id,
332 _shared_memory_offset);
333 return NextCmdAddress<ValueType>(cmd);
336 CommandHeader header;
337 uint32_t bucket_id;
338 uint32_t offset;
339 uint32_t size;
340 uint32_t shared_memory_id;
341 uint32_t shared_memory_offset;
344 static_assert(sizeof(SetBucketData) == 24,
345 "size of SetBucketData should be 24");
346 static_assert(offsetof(SetBucketData, header) == 0,
347 "offset of SetBucketData.header should be 0");
348 static_assert(offsetof(SetBucketData, bucket_id) == 4,
349 "offset of SetBucketData.bucket_id should be 4");
350 static_assert(offsetof(SetBucketData, offset) == 8,
351 "offset of SetBucketData.offset should be 8");
352 static_assert(offsetof(SetBucketData, size) == 12,
353 "offset of SetBucketData.size should be 12");
354 static_assert(offsetof(SetBucketData, shared_memory_id) == 16,
355 "offset of SetBucketData.shared_memory_id should be 16");
356 static_assert(offsetof(SetBucketData, shared_memory_offset) == 20,
357 "offset of SetBucketData.shared_memory_offset should be 20");
359 // Sets the contents of a portion of a bucket on the service side from data in
360 // the command buffer.
361 // See SetBucketSize.
362 struct SetBucketDataImmediate {
363 typedef SetBucketDataImmediate ValueType;
364 static const CommandId kCmdId = kSetBucketDataImmediate;
365 static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
366 static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
368 void SetHeader(uint32_t size) {
369 header.SetCmdBySize<ValueType>(size);
372 void Init(uint32_t _bucket_id,
373 uint32_t _offset,
374 uint32_t _size) {
375 SetHeader(_size);
376 bucket_id = _bucket_id;
377 offset = _offset;
378 size = _size;
380 static void* Set(void* cmd,
381 uint32_t _bucket_id,
382 uint32_t _offset,
383 uint32_t _size) {
384 static_cast<ValueType*>(cmd)->Init(
385 _bucket_id,
386 _offset,
387 _size);
388 return NextImmediateCmdAddress<ValueType>(cmd, _size);
391 CommandHeader header;
392 uint32_t bucket_id;
393 uint32_t offset;
394 uint32_t size;
397 static_assert(sizeof(SetBucketDataImmediate) == 16,
398 "size of SetBucketDataImmediate should be 16");
399 static_assert(offsetof(SetBucketDataImmediate, header) == 0,
400 "offset of SetBucketDataImmediate.header should be 0");
401 static_assert(offsetof(SetBucketDataImmediate, bucket_id) == 4,
402 "offset of SetBucketDataImmediate.bucket_id should be 4");
403 static_assert(offsetof(SetBucketDataImmediate, offset) == 8,
404 "offset of SetBucketDataImmediate.offset should be 8");
405 static_assert(offsetof(SetBucketDataImmediate, size) == 12,
406 "offset of SetBucketDataImmediate.size should be 12");
408 // Gets the start of a bucket the service has available. Sending a variable size
409 // result back to the client and the portion of that result that fits in the
410 // supplied shared memory. If the size of the result is larger than the supplied
411 // shared memory the rest of the bucket's contents can be retrieved with
412 // GetBucketData.
414 // This is used for example for any API that returns a string. The problem is
415 // the largest thing you can send back in 1 command is the size of your shared
416 // memory. This command along with GetBucketData implements a way to get a
417 // result a piece at a time to help solve that problem in a generic way.
418 struct GetBucketStart {
419 typedef GetBucketStart ValueType;
420 static const CommandId kCmdId = kGetBucketStart;
421 static const cmd::ArgFlags kArgFlags = cmd::kFixed;
422 static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
424 typedef uint32_t Result;
426 void SetHeader() {
427 header.SetCmd<ValueType>();
430 void Init(uint32_t _bucket_id,
431 uint32_t _result_memory_id,
432 uint32_t _result_memory_offset,
433 uint32_t _data_memory_size,
434 uint32_t _data_memory_id,
435 uint32_t _data_memory_offset) {
436 SetHeader();
437 bucket_id = _bucket_id;
438 result_memory_id = _result_memory_id;
439 result_memory_offset = _result_memory_offset;
440 data_memory_size = _data_memory_size;
441 data_memory_id = _data_memory_id;
442 data_memory_offset = _data_memory_offset;
444 static void* Set(void* cmd,
445 uint32_t _bucket_id,
446 uint32_t _result_memory_id,
447 uint32_t _result_memory_offset,
448 uint32_t _data_memory_size,
449 uint32_t _data_memory_id,
450 uint32_t _data_memory_offset) {
451 static_cast<ValueType*>(cmd)->Init(
452 _bucket_id,
453 _result_memory_id,
454 _result_memory_offset,
455 _data_memory_size,
456 _data_memory_id,
457 _data_memory_offset);
458 return NextCmdAddress<ValueType>(cmd);
461 CommandHeader header;
462 uint32_t bucket_id;
463 uint32_t result_memory_id;
464 uint32_t result_memory_offset;
465 uint32_t data_memory_size;
466 uint32_t data_memory_id;
467 uint32_t data_memory_offset;
470 static_assert(sizeof(GetBucketStart) == 28,
471 "size of GetBucketStart should be 28");
472 static_assert(offsetof(GetBucketStart, header) == 0,
473 "offset of GetBucketStart.header should be 0");
474 static_assert(offsetof(GetBucketStart, bucket_id) == 4,
475 "offset of GetBucketStart.bucket_id should be 4");
476 static_assert(offsetof(GetBucketStart, result_memory_id) == 8,
477 "offset of GetBucketStart.result_memory_id should be 8");
478 static_assert(offsetof(GetBucketStart, result_memory_offset) == 12,
479 "offset of GetBucketStart.result_memory_offset should be 12");
480 static_assert(offsetof(GetBucketStart, data_memory_size) == 16,
481 "offset of GetBucketStart.data_memory_size should be 16");
482 static_assert(offsetof(GetBucketStart, data_memory_id) == 20,
483 "offset of GetBucketStart.data_memory_id should be 20");
484 static_assert(offsetof(GetBucketStart, data_memory_offset) == 24,
485 "offset of GetBucketStart.data_memory_offset should be 24");
487 // Gets a piece of a result the service as available.
488 // See GetBucketSize.
489 struct GetBucketData {
490 typedef GetBucketData ValueType;
491 static const CommandId kCmdId = kGetBucketData;
492 static const cmd::ArgFlags kArgFlags = cmd::kFixed;
493 static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
495 void SetHeader() {
496 header.SetCmd<ValueType>();
499 void Init(uint32_t _bucket_id,
500 uint32_t _offset,
501 uint32_t _size,
502 uint32_t _shared_memory_id,
503 uint32_t _shared_memory_offset) {
504 SetHeader();
505 bucket_id = _bucket_id;
506 offset = _offset;
507 size = _size;
508 shared_memory_id = _shared_memory_id;
509 shared_memory_offset = _shared_memory_offset;
511 static void* Set(void* cmd,
512 uint32_t _bucket_id,
513 uint32_t _offset,
514 uint32_t _size,
515 uint32_t _shared_memory_id,
516 uint32_t _shared_memory_offset) {
517 static_cast<ValueType*>(cmd)->Init(
518 _bucket_id,
519 _offset,
520 _size,
521 _shared_memory_id,
522 _shared_memory_offset);
523 return NextCmdAddress<ValueType>(cmd);
526 CommandHeader header;
527 uint32_t bucket_id;
528 uint32_t offset;
529 uint32_t size;
530 uint32_t shared_memory_id;
531 uint32_t shared_memory_offset;
534 static_assert(sizeof(GetBucketData) == 24,
535 "size of GetBucketData should be 24");
536 static_assert(offsetof(GetBucketData, header) == 0,
537 "offset of GetBucketData.header should be 0");
538 static_assert(offsetof(GetBucketData, bucket_id) == 4,
539 "offset of GetBucketData.bucket_id should be 4");
540 static_assert(offsetof(GetBucketData, offset) == 8,
541 "offset of GetBucketData.offset should be 8");
542 static_assert(offsetof(GetBucketData, size) == 12,
543 "offset of GetBucketData.size should be 12");
544 static_assert(offsetof(GetBucketData, shared_memory_id) == 16,
545 "offset of GetBucketData.shared_memory_id should be 16");
546 static_assert(offsetof(GetBucketData, shared_memory_offset) == 20,
547 "offset of GetBucketData.shared_memory_offset should be 20");
549 } // namespace cmd
551 #pragma pack(pop)
553 } // namespace gpu
555 #endif // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_