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 #include <stdint.h> 12 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" 17 18 namespace gpu { 19 20 namespace cmd { 21 enum ArgFlags { 22 kFixed = 0x0, 23 kAtLeastN = 0x1 24 }; 25 } // namespace cmd 26 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) 30 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 36 } 37 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 41 } 42 43 // Struct that defines the command header in the command buffer. 44 struct CommandHeader { 45 uint32_t size:21; 46 uint32_t command:11; 47 48 GPU_EXPORT static const int32_t kMaxSize = (1 << 21) - 1; 49 50 void Init(uint32_t _command, int32_t _size) { 51 DCHECK_LE(_size, kMaxSize); 52 command = _command; 53 size = _size; 54 } 55 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 COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed); 61 Init(T::kCmdId, ComputeNumEntries(sizeof(T))); // NOLINT 62 } 63 64 // Sets the header by a size in bytes of the immediate data after the command. 65 template <typename T> 66 void SetCmdBySize(uint32_t size_of_data_in_bytes) { 67 COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN); 68 Init(T::kCmdId, 69 ComputeNumEntries(sizeof(T) + size_of_data_in_bytes)); // NOLINT 70 } 71 72 // Sets the header by a size in bytes. 73 template <typename T> 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)); 78 } 79 }; 80 81 COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4); 82 83 // Union that defines possible command buffer entries. 84 union CommandBufferEntry { 85 CommandHeader value_header; 86 uint32_t value_uint32; 87 int32_t value_int32; 88 float value_float; 89 }; 90 91 #define GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT 4 92 const size_t kCommandBufferEntrySize = GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT; 93 94 COMPILE_ASSERT(sizeof(CommandBufferEntry) == kCommandBufferEntrySize, 95 Sizeof_CommandBufferEntry_is_not_4); 96 97 // Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned. 98 #pragma pack(push, GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT) 99 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. 103 // Parameters: 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); 109 } 110 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> 114 // Parameters: 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); 119 } 120 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. 123 // Parameters: 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); 131 } 132 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. 135 // Parameters: 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); 145 } 146 147 namespace cmd { 148 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. 154 // 155 // NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order) 156 #define COMMON_COMMAND_BUFFER_CMDS(OP) \ 157 OP(Noop) /* 0 */ \ 158 OP(SetToken) /* 1 */ \ 159 OP(SetBucketSize) /* 2 */ \ 160 OP(SetBucketData) /* 3 */ \ 161 OP(SetBucketDataImmediate) /* 4 */ \ 162 OP(GetBucketStart) /* 5 */ \ 163 OP(GetBucketData) /* 6 */ \ 164 165 // Common commands. 166 enum CommandId { 167 #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name, 168 169 COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP) 170 171 #undef COMMON_COMMAND_BUFFER_CMD_OP 172 173 kNumCommands, 174 kLastCommonId = 255 // reserve 256 spaces for common commands. 175 }; 176 177 COMPILE_ASSERT(kNumCommands - 1 <= kLastCommonId, Too_many_common_commands); 178 179 const char* GetCommandName(CommandId id); 180 181 // A Noop command. 182 struct Noop { 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); 187 188 void SetHeader(uint32_t skip_count) { 189 DCHECK_GT(skip_count, 0u); 190 header.Init(kCmdId, skip_count); 191 } 192 193 void Init(uint32_t skip_count) { 194 SetHeader(skip_count); 195 } 196 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 201 } 202 203 CommandHeader header; 204 }; 205 206 COMPILE_ASSERT(sizeof(Noop) == 4, Sizeof_Noop_is_not_4); 207 COMPILE_ASSERT(offsetof(Noop, header) == 0, Offsetof_Noop_header_not_0); 208 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. 211 struct SetToken { 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); 216 217 void SetHeader() { 218 header.SetCmd<ValueType>(); 219 } 220 221 void Init(uint32_t _token) { 222 SetHeader(); 223 token = _token; 224 } 225 static void* Set(void* cmd, uint32_t token) { 226 static_cast<ValueType*>(cmd)->Init(token); 227 return NextCmdAddress<ValueType>(cmd); 228 } 229 230 CommandHeader header; 231 uint32_t token; 232 }; 233 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); 239 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. 249 // 250 // You can clear a bucket on the service side and thereby free memory by sending 251 // a size of 0. 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); 257 258 void SetHeader() { 259 header.SetCmd<ValueType>(); 260 } 261 262 void Init(uint32_t _bucket_id, uint32_t _size) { 263 SetHeader(); 264 bucket_id = _bucket_id; 265 size = _size; 266 } 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); 270 } 271 272 CommandHeader header; 273 uint32_t bucket_id; 274 uint32_t size; 275 }; 276 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); 284 285 // Sets the contents of a portion of a bucket on the service side from data in 286 // shared memory. 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); 293 294 void SetHeader() { 295 header.SetCmd<ValueType>(); 296 } 297 298 void Init(uint32_t _bucket_id, 299 uint32_t _offset, 300 uint32_t _size, 301 uint32_t _shared_memory_id, 302 uint32_t _shared_memory_offset) { 303 SetHeader(); 304 bucket_id = _bucket_id; 305 offset = _offset; 306 size = _size; 307 shared_memory_id = _shared_memory_id; 308 shared_memory_offset = _shared_memory_offset; 309 } 310 static void* Set(void* cmd, 311 uint32_t _bucket_id, 312 uint32_t _offset, 313 uint32_t _size, 314 uint32_t _shared_memory_id, 315 uint32_t _shared_memory_offset) { 316 static_cast<ValueType*>(cmd)->Init( 317 _bucket_id, 318 _offset, 319 _size, 320 _shared_memory_id, 321 _shared_memory_offset); 322 return NextCmdAddress<ValueType>(cmd); 323 } 324 325 CommandHeader header; 326 uint32_t bucket_id; 327 uint32_t offset; 328 uint32_t size; 329 uint32_t shared_memory_id; 330 uint32_t shared_memory_offset; 331 }; 332 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); 346 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); 355 356 void SetHeader(uint32_t size) { 357 header.SetCmdBySize<ValueType>(size); 358 } 359 360 void Init(uint32_t _bucket_id, 361 uint32_t _offset, 362 uint32_t _size) { 363 SetHeader(_size); 364 bucket_id = _bucket_id; 365 offset = _offset; 366 size = _size; 367 } 368 static void* Set(void* cmd, 369 uint32_t _bucket_id, 370 uint32_t _offset, 371 uint32_t _size) { 372 static_cast<ValueType*>(cmd)->Init( 373 _bucket_id, 374 _offset, 375 _size); 376 return NextImmediateCmdAddress<ValueType>(cmd, _size); 377 } 378 379 CommandHeader header; 380 uint32_t bucket_id; 381 uint32_t offset; 382 uint32_t size; 383 }; 384 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); 395 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 400 // GetBucketData. 401 // 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); 411 412 typedef uint32_t Result; 413 414 void SetHeader() { 415 header.SetCmd<ValueType>(); 416 } 417 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) { 424 SetHeader(); 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; 431 } 432 static void* Set(void* cmd, 433 uint32_t _bucket_id, 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( 440 _bucket_id, 441 _result_memory_id, 442 _result_memory_offset, 443 _data_memory_size, 444 _data_memory_id, 445 _data_memory_offset); 446 return NextCmdAddress<ValueType>(cmd); 447 } 448 449 CommandHeader header; 450 uint32_t bucket_id; 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; 456 }; 457 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); 473 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); 481 482 void SetHeader() { 483 header.SetCmd<ValueType>(); 484 } 485 486 void Init(uint32_t _bucket_id, 487 uint32_t _offset, 488 uint32_t _size, 489 uint32_t _shared_memory_id, 490 uint32_t _shared_memory_offset) { 491 SetHeader(); 492 bucket_id = _bucket_id; 493 offset = _offset; 494 size = _size; 495 shared_memory_id = _shared_memory_id; 496 shared_memory_offset = _shared_memory_offset; 497 } 498 static void* Set(void* cmd, 499 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 static_cast<ValueType*>(cmd)->Init( 505 _bucket_id, 506 _offset, 507 _size, 508 _shared_memory_id, 509 _shared_memory_offset); 510 return NextCmdAddress<ValueType>(cmd); 511 } 512 513 CommandHeader header; 514 uint32_t bucket_id; 515 uint32_t offset; 516 uint32_t size; 517 uint32_t shared_memory_id; 518 uint32_t shared_memory_offset; 519 }; 520 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); 534 535 } // namespace cmd 536 537 #pragma pack(pop) 538 539 } // namespace gpu 540 541 #endif // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_ 542 543