Home | History | Annotate | Download | only in common
      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.
      4 
      5 // This file contains the common parts of command buffer formats.
      6 
      7 #ifndef GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
      8 #define GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
      9 
     10 #include <stddef.h>
     11 
     12 #include "base/logging.h"
     13 #include "gpu/command_buffer/common/bitfield_helpers.h"
     14 #include "gpu/command_buffer/common/types.h"
     15 #include "gpu/gpu_export.h"
     16 
     17 namespace gpu {
     18 
     19 namespace cmd {
     20   enum ArgFlags {
     21     kFixed = 0x0,
     22     kAtLeastN = 0x1
     23   };
     24 }  // namespace cmd
     25 
     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
     31 }
     32 
     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
     36 }
     37 
     38 // Struct that defines the command header in the command buffer.
     39 struct CommandHeader {
     40   Uint32 size:21;
     41   Uint32 command:11;
     42 
     43   GPU_EXPORT static const int32 kMaxSize = (1 << 21) - 1;
     44 
     45   void Init(uint32 _command, int32 _size) {
     46     DCHECK_LE(_size, kMaxSize);
     47     command = _command;
     48     size = _size;
     49   }
     50 
     51   // Sets the header based on the passed in command. Can not be used for
     52   // variable sized commands like immediate commands or Noop.
     53   template <typename T>
     54   void SetCmd() {
     55     COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
     56     Init(T::kCmdId, ComputeNumEntries(sizeof(T)));  // NOLINT
     57   }
     58 
     59   // Sets the header by a size in bytes of the immediate data after the command.
     60   template <typename T>
     61   void SetCmdBySize(uint32 size_of_data_in_bytes) {
     62     COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
     63     Init(T::kCmdId,
     64          ComputeNumEntries(sizeof(T) + size_of_data_in_bytes));  // NOLINT
     65   }
     66 
     67   // Sets the header by a size in bytes.
     68   template <typename T>
     69   void SetCmdByTotalSize(uint32 size_in_bytes) {
     70     COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
     71     DCHECK_GE(size_in_bytes, sizeof(T));  // NOLINT
     72     Init(T::kCmdId, ComputeNumEntries(size_in_bytes));
     73   }
     74 };
     75 
     76 COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4);
     77 
     78 // Union that defines possible command buffer entries.
     79 union CommandBufferEntry {
     80   CommandHeader value_header;
     81   Uint32 value_uint32;
     82   Int32 value_int32;
     83   float value_float;
     84 };
     85 
     86 const size_t kCommandBufferEntrySize = 4;
     87 
     88 COMPILE_ASSERT(sizeof(CommandBufferEntry) == kCommandBufferEntrySize,
     89                Sizeof_CommandBufferEntry_is_not_4);
     90 
     91 // Make sure the compiler does not add extra padding to any of the command
     92 // structures.
     93 #pragma pack(push, 1)
     94 
     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.
     98 // Parameters:
     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);
    104 }
    105 
    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>
    109 // Parameters:
    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);
    114 }
    115 
    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.
    118 // Parameters:
    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);
    126 }
    127 
    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_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   DCHECK_GE(total_size_in_bytes, sizeof(T));  // NOLINT
    137   return reinterpret_cast<char*>(cmd) +
    138       RoundSizeToMultipleOfEntries(total_size_in_bytes);
    139 }
    140 
    141 namespace cmd {
    142 
    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.
    148 //
    149 // NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
    150 #define COMMON_COMMAND_BUFFER_CMDS(OP) \
    151   OP(Noop)                          /*  0 */ \
    152   OP(SetToken)                      /*  1 */ \
    153   OP(SetBucketSize)                 /*  2 */ \
    154   OP(SetBucketData)                 /*  3 */ \
    155   OP(SetBucketDataImmediate)        /*  4 */ \
    156   OP(GetBucketStart)                /*  5 */ \
    157   OP(GetBucketData)                 /*  6 */ \
    158 
    159 // Common commands.
    160 enum CommandId {
    161   #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,
    162 
    163   COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
    164 
    165   #undef COMMON_COMMAND_BUFFER_CMD_OP
    166 
    167   kNumCommands,
    168   kLastCommonId = 255  // reserve 256 spaces for common commands.
    169 };
    170 
    171 COMPILE_ASSERT(kNumCommands - 1 <= kLastCommonId, Too_many_common_commands);
    172 
    173 const char* GetCommandName(CommandId id);
    174 
    175 // A Noop command.
    176 struct Noop {
    177   typedef Noop ValueType;
    178   static const CommandId kCmdId = kNoop;
    179   static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
    180 
    181   void SetHeader(uint32 skip_count) {
    182     DCHECK_GT(skip_count, 0u);
    183     header.Init(kCmdId, skip_count);
    184   }
    185 
    186   void Init(uint32 skip_count) {
    187     SetHeader(skip_count);
    188   }
    189 
    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
    194   }
    195 
    196   CommandHeader header;
    197 };
    198 
    199 COMPILE_ASSERT(sizeof(Noop) == 4, Sizeof_Noop_is_not_4);
    200 COMPILE_ASSERT(offsetof(Noop, header) == 0, Offsetof_Noop_header_not_0);
    201 
    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.
    204 struct SetToken {
    205   typedef SetToken ValueType;
    206   static const CommandId kCmdId = kSetToken;
    207   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
    208 
    209   void SetHeader() {
    210     header.SetCmd<ValueType>();
    211   }
    212 
    213   void Init(uint32 _token) {
    214     SetHeader();
    215     token = _token;
    216   }
    217   static void* Set(void* cmd, uint32 token) {
    218     static_cast<ValueType*>(cmd)->Init(token);
    219     return NextCmdAddress<ValueType>(cmd);
    220   }
    221 
    222   CommandHeader header;
    223   uint32 token;
    224 };
    225 
    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);
    231 
    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.
    241 //
    242 // You can clear a bucket on the service side and thereby free memory by sending
    243 // a size of 0.
    244 struct SetBucketSize {
    245   typedef SetBucketSize ValueType;
    246   static const CommandId kCmdId = kSetBucketSize;
    247   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
    248 
    249   void SetHeader() {
    250     header.SetCmd<ValueType>();
    251   }
    252 
    253   void Init(uint32 _bucket_id, uint32 _size) {
    254     SetHeader();
    255     bucket_id = _bucket_id;
    256     size = _size;
    257   }
    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);
    261   }
    262 
    263   CommandHeader header;
    264   uint32 bucket_id;
    265   uint32 size;
    266 };
    267 
    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);
    275 
    276 // Sets the contents of a portion of a bucket on the service side from data in
    277 // shared memory.
    278 // See SetBucketSize.
    279 struct SetBucketData {
    280   typedef SetBucketData ValueType;
    281   static const CommandId kCmdId = kSetBucketData;
    282   static const cmd::ArgFlags kArgFlags = cmd::kFixed;
    283 
    284   void SetHeader() {
    285     header.SetCmd<ValueType>();
    286   }
    287 
    288   void Init(uint32 _bucket_id,
    289             uint32 _offset,
    290             uint32 _size,
    291             uint32 _shared_memory_id,
    292             uint32 _shared_memory_offset) {
    293     SetHeader();
    294     bucket_id = _bucket_id;
    295     offset = _offset;
    296     size = _size;
    297     shared_memory_id = _shared_memory_id;
    298     shared_memory_offset = _shared_memory_offset;
    299   }
    300   static void* Set(void* cmd,
    301                    uint32 _bucket_id,
    302                    uint32 _offset,
    303                    uint32 _size,
    304                    uint32 _shared_memory_id,
    305                    uint32 _shared_memory_offset) {
    306     static_cast<ValueType*>(cmd)->Init(
    307         _bucket_id,
    308         _offset,
    309         _size,
    310         _shared_memory_id,
    311         _shared_memory_offset);
    312     return NextCmdAddress<ValueType>(cmd);
    313   }
    314 
    315   CommandHeader header;
    316   uint32 bucket_id;
    317   uint32 offset;
    318   uint32 size;
    319   uint32 shared_memory_id;
    320   uint32 shared_memory_offset;
    321 };
    322 
    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);
    336 
    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;
    344 
    345   void SetHeader(uint32 size) {
    346     header.SetCmdBySize<ValueType>(size);
    347   }
    348 
    349   void Init(uint32 _bucket_id,
    350             uint32 _offset,
    351             uint32 _size) {
    352     SetHeader(_size);
    353     bucket_id = _bucket_id;
    354     offset = _offset;
    355     size = _size;
    356   }
    357   static void* Set(void* cmd,
    358                    uint32 _bucket_id,
    359                    uint32 _offset,
    360                    uint32 _size) {
    361     static_cast<ValueType*>(cmd)->Init(
    362         _bucket_id,
    363         _offset,
    364         _size);
    365     return NextImmediateCmdAddress<ValueType>(cmd, _size);
    366   }
    367 
    368   CommandHeader header;
    369   uint32 bucket_id;
    370   uint32 offset;
    371   uint32 size;
    372 };
    373 
    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);
    384 
    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
    389 // GetBucketData.
    390 //
    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;
    399 
    400   typedef uint32 Result;
    401 
    402   void SetHeader() {
    403     header.SetCmd<ValueType>();
    404   }
    405 
    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) {
    412     SetHeader();
    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;
    419   }
    420   static void* Set(void* cmd,
    421                    uint32 _bucket_id,
    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(
    428         _bucket_id,
    429         _result_memory_id,
    430         _result_memory_offset,
    431         _data_memory_size,
    432         _data_memory_id,
    433         _data_memory_offset);
    434     return NextCmdAddress<ValueType>(cmd);
    435   }
    436 
    437   CommandHeader header;
    438   uint32 bucket_id;
    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;
    444 };
    445 
    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);
    461 
    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;
    468 
    469   void SetHeader() {
    470     header.SetCmd<ValueType>();
    471   }
    472 
    473   void Init(uint32 _bucket_id,
    474             uint32 _offset,
    475             uint32 _size,
    476             uint32 _shared_memory_id,
    477             uint32 _shared_memory_offset) {
    478     SetHeader();
    479     bucket_id = _bucket_id;
    480     offset = _offset;
    481     size = _size;
    482     shared_memory_id = _shared_memory_id;
    483     shared_memory_offset = _shared_memory_offset;
    484   }
    485   static void* Set(void* cmd,
    486                    uint32 _bucket_id,
    487                    uint32 _offset,
    488                    uint32 _size,
    489                    uint32 _shared_memory_id,
    490                    uint32 _shared_memory_offset) {
    491     static_cast<ValueType*>(cmd)->Init(
    492         _bucket_id,
    493         _offset,
    494         _size,
    495         _shared_memory_id,
    496         _shared_memory_offset);
    497     return NextCmdAddress<ValueType>(cmd);
    498   }
    499 
    500   CommandHeader header;
    501   uint32 bucket_id;
    502   uint32 offset;
    503   uint32 size;
    504   uint32 shared_memory_id;
    505   uint32 shared_memory_offset;
    506 };
    507 
    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);
    521 
    522 }  // namespace cmd
    523 
    524 #pragma pack(pop)
    525 
    526 }  // namespace gpu
    527 
    528 #endif  // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
    529 
    530