#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 "base/compiler_specific.h"
#include "gpu/command_buffer/common/gpu_command_buffer_common_export.h"
namespace gpu {
namespace cmd {
enum ArgFlags {
kFixed = 0x0,
kAtLeastN = 0x1
};
}
#define CMD_FLAG_SET_TRACE_LEVEL(level) (level & 3)
#define CMD_FLAG_GET_TRACE_LEVEL(cmd_flags) (cmd_flags & 3)
inline uint32_t ComputeNumEntries(size_t size_in_bytes) {
return static_cast<uint32_t>(
(size_in_bytes + sizeof(uint32_t) - 1) / sizeof(uint32_t));
}
inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes) {
return ComputeNumEntries(size_in_bytes) * sizeof(uint32_t);
}
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;
}
template <typename T>
void SetCmd() {
static_assert(T::kArgFlags == cmd::kFixed,
"T::kArgFlags should equal cmd::kFixed");
Init(T::kCmdId, ComputeNumEntries(sizeof(T)));
}
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));
}
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));
Init(T::kCmdId, ComputeNumEntries(size_in_bytes));
}
static CommandHeader FromVolatile(const volatile CommandHeader& other) {
return const_cast<const CommandHeader&>(other);
}
};
static_assert(sizeof(CommandHeader) == 4,
"size of CommandHeader should equal 4");
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");
#pragma pack(push, 4)
static_assert(GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT == 4,
"pragma pack alignment must be equal to "
"GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT");
template <typename T>
void* ImmediateDataAddress(T* cmd) {
static_assert(T::kArgFlags == cmd::kAtLeastN,
"T::kArgFlags should equal cmd::kAtLeastN");
return UNSAFE_TODO(reinterpret_cast<char*>(cmd) + sizeof(*cmd));
}
template <typename T>
void* NextCmdAddress(void* cmd) {
static_assert(T::kArgFlags == cmd::kFixed,
"T::kArgFlags should equal cmd::kFixed");
return UNSAFE_TODO(reinterpret_cast<char*>(cmd) + sizeof(T));
}
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 UNSAFE_TODO(reinterpret_cast<char*>(cmd) + sizeof(T) +
RoundSizeToMultipleOfEntries(size_of_data_in_bytes));
}
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));
return UNSAFE_TODO(reinterpret_cast<char*>(cmd) +
RoundSizeToMultipleOfEntries(total_size_in_bytes));
}
namespace cmd {
#define COMMON_COMMAND_BUFFER_CMDS(OP) \
OP(Noop) \
OP(SetToken) \
OP(SetBucketSize) \
OP(SetBucketData) \
OP(SetBucketDataImmediate) \
OP(GetBucketStart) \
OP(GetBucketData) \
OP(InsertFenceSync)
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
};
static_assert(kNumCommands - 1 <= kLastCommonId, "too many commands");
GPU_COMMAND_BUFFER_COMMON_EXPORT const char* GetCommandName(CommandId id);
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));
}
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");
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");
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");
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");
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");
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");
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");
}
#pragma pack(pop)
}
#endif