|  | // Copyright 2012 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifdef UNSAFE_BUFFERS_BUILD | 
|  | // TODO(crbug.com/351564777): Remove this and convert code to safer constructs. | 
|  | #pragma allow_unsafe_buffers | 
|  | #endif | 
|  |  | 
|  | // This file contains the common parts of command buffer formats. | 
|  |  | 
|  | #ifndef GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_ | 
|  | #define GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_ | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include "base/check_op.h" | 
|  | #include "gpu/command_buffer/common/gpu_command_buffer_common_export.h" | 
|  |  | 
|  | namespace gpu { | 
|  |  | 
|  | namespace cmd { | 
|  | enum ArgFlags { | 
|  | kFixed = 0x0, | 
|  | kAtLeastN = 0x1 | 
|  | }; | 
|  | }  // namespace cmd | 
|  |  | 
|  | // Pack & unpack Command cmd_flags | 
|  | #define CMD_FLAG_SET_TRACE_LEVEL(level)     (level & 3) | 
|  | #define CMD_FLAG_GET_TRACE_LEVEL(cmd_flags) (cmd_flags & 3) | 
|  |  | 
|  | // Computes the number of command buffer entries needed for a certain size. In | 
|  | // other words it rounds up to a multiple of entries. | 
|  | inline uint32_t ComputeNumEntries(size_t size_in_bytes) { | 
|  | return static_cast<uint32_t>( | 
|  | (size_in_bytes + sizeof(uint32_t) - 1) / sizeof(uint32_t));  // NOLINT | 
|  | } | 
|  |  | 
|  | // Rounds up to a multiple of entries in bytes. | 
|  | inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes) { | 
|  | return ComputeNumEntries(size_in_bytes) * sizeof(uint32_t);  // NOLINT | 
|  | } | 
|  |  | 
|  | // Struct that defines the command header in the command buffer. | 
|  | struct CommandHeader { | 
|  | uint32_t size:21; | 
|  | uint32_t command:11; | 
|  |  | 
|  | GPU_COMMAND_BUFFER_COMMON_EXPORT static const int32_t kMaxSize = | 
|  | (1 << 21) - 1; | 
|  |  | 
|  | void Init(uint32_t _command, int32_t _size) { | 
|  | DCHECK_LE(_size, kMaxSize); | 
|  | command = _command; | 
|  | size = _size; | 
|  | } | 
|  |  | 
|  | // Sets the header based on the passed in command. Can not be used for | 
|  | // variable sized commands like immediate commands or Noop. | 
|  | template <typename T> | 
|  | void SetCmd() { | 
|  | static_assert(T::kArgFlags == cmd::kFixed, | 
|  | "T::kArgFlags should equal cmd::kFixed"); | 
|  | Init(T::kCmdId, ComputeNumEntries(sizeof(T)));  // NOLINT | 
|  | } | 
|  |  | 
|  | // Sets the header by a size in bytes of the immediate data after the command. | 
|  | template <typename T> | 
|  | void SetCmdBySize(uint32_t size_of_data_in_bytes) { | 
|  | static_assert(T::kArgFlags == cmd::kAtLeastN, | 
|  | "T::kArgFlags should equal cmd::kAtLeastN"); | 
|  | Init(T::kCmdId, | 
|  | ComputeNumEntries(sizeof(T) + size_of_data_in_bytes));  // NOLINT | 
|  | } | 
|  |  | 
|  | // Sets the header by a size in bytes. | 
|  | template <typename T> | 
|  | void SetCmdByTotalSize(uint32_t size_in_bytes) { | 
|  | static_assert(T::kArgFlags == cmd::kAtLeastN, | 
|  | "T::kArgFlags should equal cmd::kAtLeastN"); | 
|  | DCHECK_GE(size_in_bytes, sizeof(T));  // NOLINT | 
|  | Init(T::kCmdId, ComputeNumEntries(size_in_bytes)); | 
|  | } | 
|  |  | 
|  | static CommandHeader FromVolatile(const volatile CommandHeader& other) { | 
|  | // const_cast is safe because the copy constructor is trivial. | 
|  | return const_cast<const CommandHeader&>(other); | 
|  | } | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(CommandHeader) == 4, | 
|  | "size of CommandHeader should equal 4"); | 
|  |  | 
|  | // Union that defines possible command buffer entries. | 
|  | union CommandBufferEntry { | 
|  | CommandHeader value_header; | 
|  | uint32_t value_uint32; | 
|  | int32_t value_int32; | 
|  | float value_float; | 
|  | }; | 
|  |  | 
|  | #define GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT 4 | 
|  | const size_t kCommandBufferEntrySize = GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT; | 
|  |  | 
|  | static_assert(sizeof(CommandBufferEntry) == kCommandBufferEntrySize, | 
|  | "size of CommandBufferEntry should equal " | 
|  | "kCommandBufferEntrySize"); | 
|  |  | 
|  | // Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned. | 
|  | #pragma pack(push, 4) | 
|  | static_assert(GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT == 4, | 
|  | "pragma pack alignment must be equal to " | 
|  | "GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT"); | 
|  |  | 
|  | // Gets the address of memory just after a structure in a typesafe way. This is | 
|  | // used for IMMEDIATE commands to get the address of the place to put the data. | 
|  | // Immediate command put their data direclty in the command buffer. | 
|  | // Parameters: | 
|  | //   cmd: Address of command. | 
|  | template <typename T> | 
|  | void* ImmediateDataAddress(T* cmd) { | 
|  | static_assert(T::kArgFlags == cmd::kAtLeastN, | 
|  | "T::kArgFlags should equal cmd::kAtLeastN"); | 
|  | return reinterpret_cast<char*>(cmd) + sizeof(*cmd); | 
|  | } | 
|  |  | 
|  | // Gets the address of the place to put the next command in a typesafe way. | 
|  | // This can only be used for fixed sized commands. | 
|  | template <typename T> | 
|  | // Parameters: | 
|  | //   cmd: Address of command. | 
|  | void* NextCmdAddress(void* cmd) { | 
|  | static_assert(T::kArgFlags == cmd::kFixed, | 
|  | "T::kArgFlags should equal cmd::kFixed"); | 
|  | return reinterpret_cast<char*>(cmd) + sizeof(T); | 
|  | } | 
|  |  | 
|  | // Gets the address of the place to put the next command in a typesafe way. | 
|  | // This can only be used for variable sized command like IMMEDIATE commands. | 
|  | // Parameters: | 
|  | //   cmd: Address of command. | 
|  | //   size_of_data_in_bytes: Size of the data for the command. | 
|  | template <typename T> | 
|  | void* NextImmediateCmdAddress(void* cmd, uint32_t size_of_data_in_bytes) { | 
|  | static_assert(T::kArgFlags == cmd::kAtLeastN, | 
|  | "T::kArgFlags should equal cmd::kAtLeastN"); | 
|  | return reinterpret_cast<char*>(cmd) + sizeof(T) +   // NOLINT | 
|  | RoundSizeToMultipleOfEntries(size_of_data_in_bytes); | 
|  | } | 
|  |  | 
|  | // Gets the address of the place to put the next command in a typesafe way. | 
|  | // This can only be used for variable sized command like IMMEDIATE commands. | 
|  | // Parameters: | 
|  | //   cmd: Address of command. | 
|  | //   size_of_cmd_in_bytes: Size of the cmd and data. | 
|  | template <typename T> | 
|  | void* NextImmediateCmdAddressTotalSize(void* cmd, | 
|  | uint32_t total_size_in_bytes) { | 
|  | static_assert(T::kArgFlags == cmd::kAtLeastN, | 
|  | "T::kArgFlags should equal cmd::kAtLeastN"); | 
|  | DCHECK_GE(total_size_in_bytes, sizeof(T));  // NOLINT | 
|  | return reinterpret_cast<char*>(cmd) + | 
|  | RoundSizeToMultipleOfEntries(total_size_in_bytes); | 
|  | } | 
|  |  | 
|  | namespace cmd { | 
|  |  | 
|  | // This macro is used to safely and convienently expand the list of commnad | 
|  | // buffer commands in to various lists and never have them get out of sync. To | 
|  | // add a new command, add it this list, create the corresponding structure below | 
|  | // and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where | 
|  | // COMMAND_NAME is the name of your command structure. | 
|  | // | 
|  | // NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order) | 
|  | #define COMMON_COMMAND_BUFFER_CMDS(OP) \ | 
|  | OP(Noop)                   /*  0 */  \ | 
|  | OP(SetToken)               /*  1 */  \ | 
|  | OP(SetBucketSize)          /*  2 */  \ | 
|  | OP(SetBucketData)          /*  3 */  \ | 
|  | OP(SetBucketDataImmediate) /*  4 */  \ | 
|  | OP(GetBucketStart)         /*  5 */  \ | 
|  | OP(GetBucketData)          /*  6 */  \ | 
|  | OP(InsertFenceSync)        /*  7 */ | 
|  |  | 
|  | // Common commands. | 
|  | enum CommandId { | 
|  | #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name, | 
|  |  | 
|  | COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP) | 
|  |  | 
|  | #undef COMMON_COMMAND_BUFFER_CMD_OP | 
|  |  | 
|  | kNumCommands, | 
|  | kLastCommonId = 255  // reserve 256 spaces for common commands. | 
|  | }; | 
|  |  | 
|  | static_assert(kNumCommands - 1 <= kLastCommonId, "too many commands"); | 
|  |  | 
|  | GPU_COMMAND_BUFFER_COMMON_EXPORT const char* GetCommandName(CommandId id); | 
|  |  | 
|  | // A Noop command. | 
|  | struct Noop { | 
|  | typedef Noop ValueType; | 
|  | static const CommandId kCmdId = kNoop; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); | 
|  |  | 
|  | void SetHeader(uint32_t skip_count) { | 
|  | DCHECK_GT(skip_count, 0u); | 
|  | header.Init(kCmdId, skip_count); | 
|  | } | 
|  |  | 
|  | void Init(uint32_t skip_count) { | 
|  | SetHeader(skip_count); | 
|  | } | 
|  |  | 
|  | static void* Set(void* cmd, uint32_t skip_count) { | 
|  | static_cast<ValueType*>(cmd)->Init(skip_count); | 
|  | return NextImmediateCmdAddress<ValueType>( | 
|  | cmd, skip_count * sizeof(CommandBufferEntry));  // NOLINT | 
|  | } | 
|  |  | 
|  | CommandHeader header; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(Noop) == 4, "size of Noop should equal 4"); | 
|  | static_assert(offsetof(Noop, header) == 0, | 
|  | "offset of Noop.header should equal 0"); | 
|  |  | 
|  | // The SetToken command puts a token in the command stream that you can | 
|  | // use to check if that token has been passed in the command stream. | 
|  | struct SetToken { | 
|  | typedef SetToken ValueType; | 
|  | static const CommandId kCmdId = kSetToken; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kFixed; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); | 
|  |  | 
|  | void SetHeader() { | 
|  | header.SetCmd<ValueType>(); | 
|  | } | 
|  |  | 
|  | void Init(uint32_t _token) { | 
|  | SetHeader(); | 
|  | token = _token; | 
|  | } | 
|  | static void* Set(void* cmd, uint32_t token) { | 
|  | static_cast<ValueType*>(cmd)->Init(token); | 
|  | return NextCmdAddress<ValueType>(cmd); | 
|  | } | 
|  |  | 
|  | CommandHeader header; | 
|  | uint32_t token; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(SetToken) == 8, "size of SetToken should equal 8"); | 
|  | static_assert(offsetof(SetToken, header) == 0, | 
|  | "offset of SetToken.header should equal 0"); | 
|  | static_assert(offsetof(SetToken, token) == 4, | 
|  | "offset of SetToken.token should equal 4"); | 
|  |  | 
|  | // Sets the size of a bucket for collecting data on the service side. | 
|  | // This is a utility for gathering data on the service side so it can be used | 
|  | // all at once when some service side API is called. It removes the need to add | 
|  | // special commands just to support a particular API. For example, any API | 
|  | // command that needs a string needs a way to send that string to the API over | 
|  | // the command buffers. While you can require that the command buffer or | 
|  | // transfer buffer be large enough to hold the largest string you can send, | 
|  | // using this command removes that restriction by letting you send smaller | 
|  | // pieces over and build up the data on the service side. | 
|  | // | 
|  | // You can clear a bucket on the service side and thereby free memory by sending | 
|  | // a size of 0. | 
|  | struct SetBucketSize { | 
|  | typedef SetBucketSize ValueType; | 
|  | static const CommandId kCmdId = kSetBucketSize; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kFixed; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); | 
|  |  | 
|  | void SetHeader() { | 
|  | header.SetCmd<ValueType>(); | 
|  | } | 
|  |  | 
|  | void Init(uint32_t _bucket_id, uint32_t _size) { | 
|  | SetHeader(); | 
|  | bucket_id = _bucket_id; | 
|  | size = _size; | 
|  | } | 
|  | static void* Set(void* cmd, uint32_t _bucket_id, uint32_t _size) { | 
|  | static_cast<ValueType*>(cmd)->Init(_bucket_id, _size); | 
|  | return NextCmdAddress<ValueType>(cmd); | 
|  | } | 
|  |  | 
|  | CommandHeader header; | 
|  | uint32_t bucket_id; | 
|  | uint32_t size; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(SetBucketSize) == 12, | 
|  | "size of SetBucketSize should equal 12"); | 
|  | static_assert(offsetof(SetBucketSize, header) == 0, | 
|  | "offset of SetBucketSize.header should equal 0"); | 
|  | static_assert(offsetof(SetBucketSize, bucket_id) == 4, | 
|  | "offset of SetBucketSize.bucket_id should equal 4"); | 
|  | static_assert(offsetof(SetBucketSize, size) == 8, | 
|  | "offset of SetBucketSize.size should equal 8"); | 
|  |  | 
|  | // Sets the contents of a portion of a bucket on the service side from data in | 
|  | // shared memory. | 
|  | // See SetBucketSize. | 
|  | struct SetBucketData { | 
|  | typedef SetBucketData ValueType; | 
|  | static const CommandId kCmdId = kSetBucketData; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kFixed; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); | 
|  |  | 
|  | void SetHeader() { | 
|  | header.SetCmd<ValueType>(); | 
|  | } | 
|  |  | 
|  | void Init(uint32_t _bucket_id, | 
|  | uint32_t _offset, | 
|  | uint32_t _size, | 
|  | uint32_t _shared_memory_id, | 
|  | uint32_t _shared_memory_offset) { | 
|  | SetHeader(); | 
|  | bucket_id = _bucket_id; | 
|  | offset = _offset; | 
|  | size = _size; | 
|  | shared_memory_id = _shared_memory_id; | 
|  | shared_memory_offset = _shared_memory_offset; | 
|  | } | 
|  | static void* Set(void* cmd, | 
|  | uint32_t _bucket_id, | 
|  | uint32_t _offset, | 
|  | uint32_t _size, | 
|  | uint32_t _shared_memory_id, | 
|  | uint32_t _shared_memory_offset) { | 
|  | static_cast<ValueType*>(cmd)->Init( | 
|  | _bucket_id, | 
|  | _offset, | 
|  | _size, | 
|  | _shared_memory_id, | 
|  | _shared_memory_offset); | 
|  | return NextCmdAddress<ValueType>(cmd); | 
|  | } | 
|  |  | 
|  | CommandHeader header; | 
|  | uint32_t bucket_id; | 
|  | uint32_t offset; | 
|  | uint32_t size; | 
|  | uint32_t shared_memory_id; | 
|  | uint32_t shared_memory_offset; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(SetBucketData) == 24, | 
|  | "size of SetBucketData should be 24"); | 
|  | static_assert(offsetof(SetBucketData, header) == 0, | 
|  | "offset of SetBucketData.header should be 0"); | 
|  | static_assert(offsetof(SetBucketData, bucket_id) == 4, | 
|  | "offset of SetBucketData.bucket_id should be 4"); | 
|  | static_assert(offsetof(SetBucketData, offset) == 8, | 
|  | "offset of SetBucketData.offset should be 8"); | 
|  | static_assert(offsetof(SetBucketData, size) == 12, | 
|  | "offset of SetBucketData.size should be 12"); | 
|  | static_assert(offsetof(SetBucketData, shared_memory_id) == 16, | 
|  | "offset of SetBucketData.shared_memory_id should be 16"); | 
|  | static_assert(offsetof(SetBucketData, shared_memory_offset) == 20, | 
|  | "offset of SetBucketData.shared_memory_offset should be 20"); | 
|  |  | 
|  | // Sets the contents of a portion of a bucket on the service side from data in | 
|  | // the command buffer. | 
|  | // See SetBucketSize. | 
|  | struct SetBucketDataImmediate { | 
|  | typedef SetBucketDataImmediate ValueType; | 
|  | static const CommandId kCmdId = kSetBucketDataImmediate; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); | 
|  |  | 
|  | void SetHeader(uint32_t _size) { header.SetCmdBySize<ValueType>(_size); } | 
|  |  | 
|  | void Init(uint32_t _bucket_id, | 
|  | uint32_t _offset, | 
|  | uint32_t _size) { | 
|  | SetHeader(_size); | 
|  | bucket_id = _bucket_id; | 
|  | offset = _offset; | 
|  | size = _size; | 
|  | } | 
|  | static void* Set(void* cmd, | 
|  | uint32_t _bucket_id, | 
|  | uint32_t _offset, | 
|  | uint32_t _size) { | 
|  | static_cast<ValueType*>(cmd)->Init( | 
|  | _bucket_id, | 
|  | _offset, | 
|  | _size); | 
|  | return NextImmediateCmdAddress<ValueType>(cmd, _size); | 
|  | } | 
|  |  | 
|  | CommandHeader header; | 
|  | uint32_t bucket_id; | 
|  | uint32_t offset; | 
|  | uint32_t size; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(SetBucketDataImmediate) == 16, | 
|  | "size of SetBucketDataImmediate should be 16"); | 
|  | static_assert(offsetof(SetBucketDataImmediate, header) == 0, | 
|  | "offset of SetBucketDataImmediate.header should be 0"); | 
|  | static_assert(offsetof(SetBucketDataImmediate, bucket_id) == 4, | 
|  | "offset of SetBucketDataImmediate.bucket_id should be 4"); | 
|  | static_assert(offsetof(SetBucketDataImmediate, offset) == 8, | 
|  | "offset of SetBucketDataImmediate.offset should be 8"); | 
|  | static_assert(offsetof(SetBucketDataImmediate, size) == 12, | 
|  | "offset of SetBucketDataImmediate.size should be 12"); | 
|  |  | 
|  | // Gets the start of a bucket the service has available. Sending a variable size | 
|  | // result back to the client and the portion of that result that fits in the | 
|  | // supplied shared memory. If the size of the result is larger than the supplied | 
|  | // shared memory the rest of the bucket's contents can be retrieved with | 
|  | // GetBucketData. | 
|  | // | 
|  | // This is used for example for any API that returns a string. The problem is | 
|  | // the largest thing you can send back in 1 command is the size of your shared | 
|  | // memory. This command along with GetBucketData implements a way to get a | 
|  | // result a piece at a time to help solve that problem in a generic way. | 
|  | struct GetBucketStart { | 
|  | typedef GetBucketStart ValueType; | 
|  | static const CommandId kCmdId = kGetBucketStart; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kFixed; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); | 
|  |  | 
|  | typedef uint32_t Result; | 
|  |  | 
|  | void SetHeader() { | 
|  | header.SetCmd<ValueType>(); | 
|  | } | 
|  |  | 
|  | void Init(uint32_t _bucket_id, | 
|  | uint32_t _result_memory_id, | 
|  | uint32_t _result_memory_offset, | 
|  | uint32_t _data_memory_size, | 
|  | uint32_t _data_memory_id, | 
|  | uint32_t _data_memory_offset) { | 
|  | SetHeader(); | 
|  | bucket_id = _bucket_id; | 
|  | result_memory_id = _result_memory_id; | 
|  | result_memory_offset = _result_memory_offset; | 
|  | data_memory_size = _data_memory_size; | 
|  | data_memory_id = _data_memory_id; | 
|  | data_memory_offset = _data_memory_offset; | 
|  | } | 
|  | static void* Set(void* cmd, | 
|  | uint32_t _bucket_id, | 
|  | uint32_t _result_memory_id, | 
|  | uint32_t _result_memory_offset, | 
|  | uint32_t _data_memory_size, | 
|  | uint32_t _data_memory_id, | 
|  | uint32_t _data_memory_offset) { | 
|  | static_cast<ValueType*>(cmd)->Init( | 
|  | _bucket_id, | 
|  | _result_memory_id, | 
|  | _result_memory_offset, | 
|  | _data_memory_size, | 
|  | _data_memory_id, | 
|  | _data_memory_offset); | 
|  | return NextCmdAddress<ValueType>(cmd); | 
|  | } | 
|  |  | 
|  | CommandHeader header; | 
|  | uint32_t bucket_id; | 
|  | uint32_t result_memory_id; | 
|  | uint32_t result_memory_offset; | 
|  | uint32_t data_memory_size; | 
|  | uint32_t data_memory_id; | 
|  | uint32_t data_memory_offset; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(GetBucketStart) == 28, | 
|  | "size of GetBucketStart should be 28"); | 
|  | static_assert(offsetof(GetBucketStart, header) == 0, | 
|  | "offset of GetBucketStart.header should be 0"); | 
|  | static_assert(offsetof(GetBucketStart, bucket_id) == 4, | 
|  | "offset of GetBucketStart.bucket_id should be 4"); | 
|  | static_assert(offsetof(GetBucketStart, result_memory_id) == 8, | 
|  | "offset of GetBucketStart.result_memory_id should be 8"); | 
|  | static_assert(offsetof(GetBucketStart, result_memory_offset) == 12, | 
|  | "offset of GetBucketStart.result_memory_offset should be 12"); | 
|  | static_assert(offsetof(GetBucketStart, data_memory_size) == 16, | 
|  | "offset of GetBucketStart.data_memory_size should be 16"); | 
|  | static_assert(offsetof(GetBucketStart, data_memory_id) == 20, | 
|  | "offset of GetBucketStart.data_memory_id should be 20"); | 
|  | static_assert(offsetof(GetBucketStart, data_memory_offset) == 24, | 
|  | "offset of GetBucketStart.data_memory_offset should be 24"); | 
|  |  | 
|  | // Gets a piece of a result the service as available. | 
|  | // See GetBucketSize. | 
|  | struct GetBucketData { | 
|  | typedef GetBucketData ValueType; | 
|  | static const CommandId kCmdId = kGetBucketData; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kFixed; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); | 
|  |  | 
|  | void SetHeader() { | 
|  | header.SetCmd<ValueType>(); | 
|  | } | 
|  |  | 
|  | void Init(uint32_t _bucket_id, | 
|  | uint32_t _offset, | 
|  | uint32_t _size, | 
|  | uint32_t _shared_memory_id, | 
|  | uint32_t _shared_memory_offset) { | 
|  | SetHeader(); | 
|  | bucket_id = _bucket_id; | 
|  | offset = _offset; | 
|  | size = _size; | 
|  | shared_memory_id = _shared_memory_id; | 
|  | shared_memory_offset = _shared_memory_offset; | 
|  | } | 
|  | static void* Set(void* cmd, | 
|  | uint32_t _bucket_id, | 
|  | uint32_t _offset, | 
|  | uint32_t _size, | 
|  | uint32_t _shared_memory_id, | 
|  | uint32_t _shared_memory_offset) { | 
|  | static_cast<ValueType*>(cmd)->Init( | 
|  | _bucket_id, | 
|  | _offset, | 
|  | _size, | 
|  | _shared_memory_id, | 
|  | _shared_memory_offset); | 
|  | return NextCmdAddress<ValueType>(cmd); | 
|  | } | 
|  |  | 
|  | CommandHeader header; | 
|  | uint32_t bucket_id; | 
|  | uint32_t offset; | 
|  | uint32_t size; | 
|  | uint32_t shared_memory_id; | 
|  | uint32_t shared_memory_offset; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(GetBucketData) == 24, | 
|  | "size of GetBucketData should be 24"); | 
|  | static_assert(offsetof(GetBucketData, header) == 0, | 
|  | "offset of GetBucketData.header should be 0"); | 
|  | static_assert(offsetof(GetBucketData, bucket_id) == 4, | 
|  | "offset of GetBucketData.bucket_id should be 4"); | 
|  | static_assert(offsetof(GetBucketData, offset) == 8, | 
|  | "offset of GetBucketData.offset should be 8"); | 
|  | static_assert(offsetof(GetBucketData, size) == 12, | 
|  | "offset of GetBucketData.size should be 12"); | 
|  | static_assert(offsetof(GetBucketData, shared_memory_id) == 16, | 
|  | "offset of GetBucketData.shared_memory_id should be 16"); | 
|  | static_assert(offsetof(GetBucketData, shared_memory_offset) == 20, | 
|  | "offset of GetBucketData.shared_memory_offset should be 20"); | 
|  |  | 
|  | struct InsertFenceSync { | 
|  | typedef InsertFenceSync ValueType; | 
|  | static const CommandId kCmdId = kInsertFenceSync; | 
|  | static const cmd::ArgFlags kArgFlags = cmd::kFixed; | 
|  | static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1); | 
|  |  | 
|  | void SetHeader() { header.SetCmd<ValueType>(); } | 
|  |  | 
|  | void Init(uint64_t _release_count) { | 
|  | SetHeader(); | 
|  | release_count_0 = static_cast<uint32_t>(_release_count & 0xFFFFFFFF); | 
|  | release_count_1 = | 
|  | static_cast<uint32_t>((_release_count >> 32) & 0xFFFFFFFF); | 
|  | } | 
|  |  | 
|  | void* Set(void* cmd, uint64_t _release_count) { | 
|  | static_cast<ValueType*>(cmd)->Init(_release_count); | 
|  | return NextCmdAddress<ValueType>(cmd); | 
|  | } | 
|  |  | 
|  | uint64_t release_count() const volatile { | 
|  | return (static_cast<uint64_t>(release_count_1) << 32) + | 
|  | static_cast<uint64_t>(release_count_0); | 
|  | } | 
|  |  | 
|  | gpu::CommandHeader header; | 
|  | uint32_t release_count_0; | 
|  | uint32_t release_count_1; | 
|  | }; | 
|  |  | 
|  | static_assert(sizeof(InsertFenceSync) == 12, | 
|  | "size of InsertFenceSync should be 12"); | 
|  | static_assert(offsetof(InsertFenceSync, header) == 0, | 
|  | "offset of InsertFenceSync header should be 0"); | 
|  | static_assert(offsetof(InsertFenceSync, release_count_0) == 4, | 
|  | "offset of InsertFenceSync release_count_0 should be 4"); | 
|  | static_assert(offsetof(InsertFenceSync, release_count_1) == 8, | 
|  | "offset of InsertFenceSync release_count_1 should be 8"); | 
|  |  | 
|  | }  // namespace cmd | 
|  |  | 
|  | #pragma pack(pop) | 
|  |  | 
|  | }  // namespace gpu | 
|  |  | 
|  | #endif  // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_ |