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