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.
ComputeNumEntries(size_t size_in_bytes)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.
RoundSizeToMultipleOfEntries(size_t size_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
InitCommandHeader45 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>
SetCmdCommandHeader54 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>
SetCmdBySizeCommandHeader61 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>
SetCmdByTotalSizeCommandHeader69 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>
ImmediateDataAddress(T * cmd)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.
NextCmdAddress(void * cmd)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>
NextImmediateCmdAddress(void * cmd,uint32 size_of_data_in_bytes)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>
NextImmediateCmdAddressTotalSize(void * cmd,uint32 total_size_in_bytes)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
SetHeaderNoop181 void SetHeader(uint32 skip_count) {
182 DCHECK_GT(skip_count, 0u);
183 header.Init(kCmdId, skip_count);
184 }
185
InitNoop186 void Init(uint32 skip_count) {
187 SetHeader(skip_count);
188 }
189
SetNoop190 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
SetHeaderSetToken209 void SetHeader() {
210 header.SetCmd<ValueType>();
211 }
212
InitSetToken213 void Init(uint32 _token) {
214 SetHeader();
215 token = _token;
216 }
SetSetToken217 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
SetHeaderSetBucketSize249 void SetHeader() {
250 header.SetCmd<ValueType>();
251 }
252
InitSetBucketSize253 void Init(uint32 _bucket_id, uint32 _size) {
254 SetHeader();
255 bucket_id = _bucket_id;
256 size = _size;
257 }
SetSetBucketSize258 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
SetHeaderSetBucketData284 void SetHeader() {
285 header.SetCmd<ValueType>();
286 }
287
InitSetBucketData288 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 }
SetSetBucketData300 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
SetHeaderSetBucketDataImmediate345 void SetHeader(uint32 size) {
346 header.SetCmdBySize<ValueType>(size);
347 }
348
InitSetBucketDataImmediate349 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 }
SetSetBucketDataImmediate357 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
SetHeaderGetBucketStart402 void SetHeader() {
403 header.SetCmd<ValueType>();
404 }
405
InitGetBucketStart406 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 }
SetGetBucketStart420 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
SetHeaderGetBucketData469 void SetHeader() {
470 header.SetCmd<ValueType>();
471 }
472
InitGetBucketData473 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 }
SetGetBucketData485 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