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 "gpu/command_buffer/common/bitfield_helpers.h"
13#include "gpu/command_buffer/common/logging.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    GPU_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    GPU_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  GPU_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    GPU_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