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
18namespace gpu {
19
20namespace 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.
33inline 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.
39inline 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.
44struct 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
81COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4);
82
83// Union that defines possible command buffer entries.
84union 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
92const size_t kCommandBufferEntrySize = GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT;
93
94COMPILE_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.
105template <typename T>
106void* 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.
113template <typename T>
114// Parameters:
115//   cmd: Address of command.
116void* 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.
126template <typename T>
127void* 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.
138template <typename T>
139void* 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
147namespace 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.
166enum 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
177COMPILE_ASSERT(kNumCommands - 1 <= kLastCommonId, Too_many_common_commands);
178
179const char* GetCommandName(CommandId id);
180
181// A Noop command.
182struct 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
206COMPILE_ASSERT(sizeof(Noop) == 4, Sizeof_Noop_is_not_4);
207COMPILE_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.
211struct 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
234COMPILE_ASSERT(sizeof(SetToken) == 8, Sizeof_SetToken_is_not_8);
235COMPILE_ASSERT(offsetof(SetToken, header) == 0,
236               Offsetof_SetToken_header_not_0);
237COMPILE_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.
252struct 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
277COMPILE_ASSERT(sizeof(SetBucketSize) == 12, Sizeof_SetBucketSize_is_not_8);
278COMPILE_ASSERT(offsetof(SetBucketSize, header) == 0,
279               Offsetof_SetBucketSize_header_not_0);
280COMPILE_ASSERT(offsetof(SetBucketSize, bucket_id) == 4,
281               Offsetof_SetBucketSize_bucket_id_4);
282COMPILE_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.
288struct 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
333COMPILE_ASSERT(sizeof(SetBucketData) == 24, Sizeof_SetBucketData_is_not_24);
334COMPILE_ASSERT(offsetof(SetBucketData, header) == 0,
335               Offsetof_SetBucketData_header_not_0);
336COMPILE_ASSERT(offsetof(SetBucketData, bucket_id) == 4,
337               Offsetof_SetBucketData_bucket_id_not_4);
338COMPILE_ASSERT(offsetof(SetBucketData, offset) == 8,
339               Offsetof_SetBucketData_offset_not_8);
340COMPILE_ASSERT(offsetof(SetBucketData, size) == 12,
341               Offsetof_SetBucketData_size_not_12);
342COMPILE_ASSERT(offsetof(SetBucketData, shared_memory_id) == 16,
343               Offsetof_SetBucketData_shared_memory_id_not_16);
344COMPILE_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.
350struct 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
385COMPILE_ASSERT(sizeof(SetBucketDataImmediate) == 16,
386               Sizeof_SetBucketDataImmediate_is_not_24);
387COMPILE_ASSERT(offsetof(SetBucketDataImmediate, header) == 0,
388               Offsetof_SetBucketDataImmediate_header_not_0);
389COMPILE_ASSERT(offsetof(SetBucketDataImmediate, bucket_id) == 4,
390               Offsetof_SetBucketDataImmediate_bucket_id_not_4);
391COMPILE_ASSERT(offsetof(SetBucketDataImmediate, offset) == 8,
392               Offsetof_SetBucketDataImmediate_offset_not_8);
393COMPILE_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.
406struct 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
458COMPILE_ASSERT(sizeof(GetBucketStart) == 28, Sizeof_GetBucketStart_is_not_28);
459COMPILE_ASSERT(offsetof(GetBucketStart, header) == 0,
460               Offsetof_GetBucketStart_header_not_0);
461COMPILE_ASSERT(offsetof(GetBucketStart, bucket_id) == 4,
462               Offsetof_GetBucketStart_bucket_id_not_4);
463COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_id) == 8,
464               Offsetof_GetBucketStart_result_memory_id_not_8);
465COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_offset) == 12,
466               Offsetof_GetBucketStart_result_memory_offset_not_12);
467COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_size) == 16,
468               Offsetof_GetBucketStart_data_memory_size_not_16);
469COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_id) == 20,
470               Offsetof_GetBucketStart_data_memory_id_not_20);
471COMPILE_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.
476struct 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
521COMPILE_ASSERT(sizeof(GetBucketData) == 24, Sizeof_GetBucketData_is_not_20);
522COMPILE_ASSERT(offsetof(GetBucketData, header) == 0,
523               Offsetof_GetBucketData_header_not_0);
524COMPILE_ASSERT(offsetof(GetBucketData, bucket_id) == 4,
525               Offsetof_GetBucketData_bucket_id_not_4);
526COMPILE_ASSERT(offsetof(GetBucketData, offset) == 8,
527               Offsetof_GetBucketData_offset_not_8);
528COMPILE_ASSERT(offsetof(GetBucketData, size) == 12,
529               Offsetof_GetBucketData_size_not_12);
530COMPILE_ASSERT(offsetof(GetBucketData, shared_memory_id) == 16,
531               Offsetof_GetBucketData_shared_memory_id_not_16);
532COMPILE_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