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 17namespace gpu { 18 19namespace 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. 28inline 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. 34inline 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. 39struct 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 76COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4); 77 78// Union that defines possible command buffer entries. 79union CommandBufferEntry { 80 CommandHeader value_header; 81 Uint32 value_uint32; 82 Int32 value_int32; 83 float value_float; 84}; 85 86const size_t kCommandBufferEntrySize = 4; 87 88COMPILE_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. 100template <typename T> 101void* 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. 108template <typename T> 109// Parameters: 110// cmd: Address of command. 111void* 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. 121template <typename T> 122void* 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. 133template <typename T> 134void* 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 141namespace 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. 160enum 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 171COMPILE_ASSERT(kNumCommands - 1 <= kLastCommonId, Too_many_common_commands); 172 173const char* GetCommandName(CommandId id); 174 175// A Noop command. 176struct 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 199COMPILE_ASSERT(sizeof(Noop) == 4, Sizeof_Noop_is_not_4); 200COMPILE_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. 204struct 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 226COMPILE_ASSERT(sizeof(SetToken) == 8, Sizeof_SetToken_is_not_8); 227COMPILE_ASSERT(offsetof(SetToken, header) == 0, 228 Offsetof_SetToken_header_not_0); 229COMPILE_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. 244struct 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 268COMPILE_ASSERT(sizeof(SetBucketSize) == 12, Sizeof_SetBucketSize_is_not_8); 269COMPILE_ASSERT(offsetof(SetBucketSize, header) == 0, 270 Offsetof_SetBucketSize_header_not_0); 271COMPILE_ASSERT(offsetof(SetBucketSize, bucket_id) == 4, 272 Offsetof_SetBucketSize_bucket_id_4); 273COMPILE_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. 279struct 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 323COMPILE_ASSERT(sizeof(SetBucketData) == 24, Sizeof_SetBucketData_is_not_24); 324COMPILE_ASSERT(offsetof(SetBucketData, header) == 0, 325 Offsetof_SetBucketData_header_not_0); 326COMPILE_ASSERT(offsetof(SetBucketData, bucket_id) == 4, 327 Offsetof_SetBucketData_bucket_id_not_4); 328COMPILE_ASSERT(offsetof(SetBucketData, offset) == 8, 329 Offsetof_SetBucketData_offset_not_8); 330COMPILE_ASSERT(offsetof(SetBucketData, size) == 12, 331 Offsetof_SetBucketData_size_not_12); 332COMPILE_ASSERT(offsetof(SetBucketData, shared_memory_id) == 16, 333 Offsetof_SetBucketData_shared_memory_id_not_16); 334COMPILE_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. 340struct 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 374COMPILE_ASSERT(sizeof(SetBucketDataImmediate) == 16, 375 Sizeof_SetBucketDataImmediate_is_not_24); 376COMPILE_ASSERT(offsetof(SetBucketDataImmediate, header) == 0, 377 Offsetof_SetBucketDataImmediate_header_not_0); 378COMPILE_ASSERT(offsetof(SetBucketDataImmediate, bucket_id) == 4, 379 Offsetof_SetBucketDataImmediate_bucket_id_not_4); 380COMPILE_ASSERT(offsetof(SetBucketDataImmediate, offset) == 8, 381 Offsetof_SetBucketDataImmediate_offset_not_8); 382COMPILE_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. 395struct 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 446COMPILE_ASSERT(sizeof(GetBucketStart) == 28, Sizeof_GetBucketStart_is_not_28); 447COMPILE_ASSERT(offsetof(GetBucketStart, header) == 0, 448 Offsetof_GetBucketStart_header_not_0); 449COMPILE_ASSERT(offsetof(GetBucketStart, bucket_id) == 4, 450 Offsetof_GetBucketStart_bucket_id_not_4); 451COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_id) == 8, 452 Offsetof_GetBucketStart_result_memory_id_not_8); 453COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_offset) == 12, 454 Offsetof_GetBucketStart_result_memory_offset_not_12); 455COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_size) == 16, 456 Offsetof_GetBucketStart_data_memory_size_not_16); 457COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_id) == 20, 458 Offsetof_GetBucketStart_data_memory_id_not_20); 459COMPILE_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. 464struct 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 508COMPILE_ASSERT(sizeof(GetBucketData) == 24, Sizeof_GetBucketData_is_not_20); 509COMPILE_ASSERT(offsetof(GetBucketData, header) == 0, 510 Offsetof_GetBucketData_header_not_0); 511COMPILE_ASSERT(offsetof(GetBucketData, bucket_id) == 4, 512 Offsetof_GetBucketData_bucket_id_not_4); 513COMPILE_ASSERT(offsetof(GetBucketData, offset) == 8, 514 Offsetof_GetBucketData_offset_not_8); 515COMPILE_ASSERT(offsetof(GetBucketData, size) == 12, 516 Offsetof_GetBucketData_size_not_12); 517COMPILE_ASSERT(offsetof(GetBucketData, shared_memory_id) == 16, 518 Offsetof_GetBucketData_shared_memory_id_not_16); 519COMPILE_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