910e62b5创建于 1月15日历史提交
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file contains the common parts of command buffer formats.

#ifndef GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
#define GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_

#include <stddef.h>
#include <stdint.h>

#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "gpu/command_buffer/common/gpu_command_buffer_common_export.h"

namespace gpu {

namespace cmd {
  enum ArgFlags {
    kFixed = 0x0,
    kAtLeastN = 0x1
  };
}  // namespace cmd

// Pack & unpack Command cmd_flags
#define CMD_FLAG_SET_TRACE_LEVEL(level)     (level & 3)
#define CMD_FLAG_GET_TRACE_LEVEL(cmd_flags) (cmd_flags & 3)

// Computes the number of command buffer entries needed for a certain size. In
// other words it rounds up to a multiple of entries.
inline uint32_t ComputeNumEntries(size_t size_in_bytes) {
  return static_cast<uint32_t>(
      (size_in_bytes + sizeof(uint32_t) - 1) / sizeof(uint32_t));  // NOLINT
}

// Rounds up to a multiple of entries in bytes.
inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes) {
  return ComputeNumEntries(size_in_bytes) * sizeof(uint32_t);  // NOLINT
}

// Struct that defines the command header in the command buffer.
struct CommandHeader {
  uint32_t size:21;
  uint32_t command:11;

  GPU_COMMAND_BUFFER_COMMON_EXPORT static const int32_t kMaxSize =
      (1 << 21) - 1;

  void Init(uint32_t _command, int32_t _size) {
    DCHECK_LE(_size, kMaxSize);
    command = _command;
    size = _size;
  }

  // Sets the header based on the passed in command. Can not be used for
  // variable sized commands like immediate commands or Noop.
  template <typename T>
  void SetCmd() {
    static_assert(T::kArgFlags == cmd::kFixed,
                  "T::kArgFlags should equal cmd::kFixed");
    Init(T::kCmdId, ComputeNumEntries(sizeof(T)));  // NOLINT
  }

  // Sets the header by a size in bytes of the immediate data after the command.
  template <typename T>
  void SetCmdBySize(uint32_t size_of_data_in_bytes) {
    static_assert(T::kArgFlags == cmd::kAtLeastN,
                  "T::kArgFlags should equal cmd::kAtLeastN");
    Init(T::kCmdId,
         ComputeNumEntries(sizeof(T) + size_of_data_in_bytes));  // NOLINT
  }

  // Sets the header by a size in bytes.
  template <typename T>
  void SetCmdByTotalSize(uint32_t size_in_bytes) {
    static_assert(T::kArgFlags == cmd::kAtLeastN,
                  "T::kArgFlags should equal cmd::kAtLeastN");
    DCHECK_GE(size_in_bytes, sizeof(T));  // NOLINT
    Init(T::kCmdId, ComputeNumEntries(size_in_bytes));
  }

  static CommandHeader FromVolatile(const volatile CommandHeader& other) {
    // const_cast is safe because the copy constructor is trivial.
    return const_cast<const CommandHeader&>(other);
  }
};

static_assert(sizeof(CommandHeader) == 4,
              "size of CommandHeader should equal 4");

// Union that defines possible command buffer entries.
union CommandBufferEntry {
  CommandHeader value_header;
  uint32_t value_uint32;
  int32_t value_int32;
  float value_float;
};

#define GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT 4
const size_t kCommandBufferEntrySize = GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT;

static_assert(sizeof(CommandBufferEntry) == kCommandBufferEntrySize,
              "size of CommandBufferEntry should equal "
              "kCommandBufferEntrySize");

// Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned.
#pragma pack(push, 4)
static_assert(GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT == 4,
              "pragma pack alignment must be equal to "
              "GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT");

// Gets the address of memory just after a structure in a typesafe way. This is
// used for IMMEDIATE commands to get the address of the place to put the data.
// Immediate command put their data direclty in the command buffer.
// Parameters:
//   cmd: Address of command.
template <typename T>
void* ImmediateDataAddress(T* cmd) {
  static_assert(T::kArgFlags == cmd::kAtLeastN,
                "T::kArgFlags should equal cmd::kAtLeastN");
  return UNSAFE_TODO(reinterpret_cast<char*>(cmd) + sizeof(*cmd));
}

// Gets the address of the place to put the next command in a typesafe way.
// This can only be used for fixed sized commands.
template <typename T>
// Parameters:
//   cmd: Address of command.
void* NextCmdAddress(void* cmd) {
  static_assert(T::kArgFlags == cmd::kFixed,
                "T::kArgFlags should equal cmd::kFixed");
  return UNSAFE_TODO(reinterpret_cast<char*>(cmd) + sizeof(T));
}

// Gets the address of the place to put the next command in a typesafe way.
// This can only be used for variable sized command like IMMEDIATE commands.
// Parameters:
//   cmd: Address of command.
//   size_of_data_in_bytes: Size of the data for the command.
template <typename T>
void* NextImmediateCmdAddress(void* cmd, uint32_t size_of_data_in_bytes) {
  static_assert(T::kArgFlags == cmd::kAtLeastN,
                "T::kArgFlags should equal cmd::kAtLeastN");
  return UNSAFE_TODO(reinterpret_cast<char*>(cmd) + sizeof(T) +  // NOLINT
                     RoundSizeToMultipleOfEntries(size_of_data_in_bytes));
}

// Gets the address of the place to put the next command in a typesafe way.
// This can only be used for variable sized command like IMMEDIATE commands.
// Parameters:
//   cmd: Address of command.
//   size_of_cmd_in_bytes: Size of the cmd and data.
template <typename T>
void* NextImmediateCmdAddressTotalSize(void* cmd,
                                       uint32_t total_size_in_bytes) {
  static_assert(T::kArgFlags == cmd::kAtLeastN,
                "T::kArgFlags should equal cmd::kAtLeastN");
  DCHECK_GE(total_size_in_bytes, sizeof(T));  // NOLINT
  return UNSAFE_TODO(reinterpret_cast<char*>(cmd) +
                     RoundSizeToMultipleOfEntries(total_size_in_bytes));
}

namespace cmd {

// This macro is used to safely and convienently expand the list of commnad
// buffer commands in to various lists and never have them get out of sync. To
// add a new command, add it this list, create the corresponding structure below
// and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where
// COMMAND_NAME is the name of your command structure.
//
// NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
#define COMMON_COMMAND_BUFFER_CMDS(OP) \
  OP(Noop)                   /*  0 */  \
  OP(SetToken)               /*  1 */  \
  OP(SetBucketSize)          /*  2 */  \
  OP(SetBucketData)          /*  3 */  \
  OP(SetBucketDataImmediate) /*  4 */  \
  OP(GetBucketStart)         /*  5 */  \
  OP(GetBucketData)          /*  6 */  \
  OP(InsertFenceSync)        /*  7 */

// Common commands.
enum CommandId {
  #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,

  COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)

  #undef COMMON_COMMAND_BUFFER_CMD_OP

  kNumCommands,
  kLastCommonId = 255  // reserve 256 spaces for common commands.
};

static_assert(kNumCommands - 1 <= kLastCommonId, "too many commands");

GPU_COMMAND_BUFFER_COMMON_EXPORT const char* GetCommandName(CommandId id);

// A Noop command.
struct Noop {
  typedef Noop ValueType;
  static const CommandId kCmdId = kNoop;
  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);

  void SetHeader(uint32_t skip_count) {
    DCHECK_GT(skip_count, 0u);
    header.Init(kCmdId, skip_count);
  }

  void Init(uint32_t skip_count) {
    SetHeader(skip_count);
  }

  static void* Set(void* cmd, uint32_t skip_count) {
    static_cast<ValueType*>(cmd)->Init(skip_count);
    return NextImmediateCmdAddress<ValueType>(
        cmd, skip_count * sizeof(CommandBufferEntry));  // NOLINT
  }

  CommandHeader header;
};

static_assert(sizeof(Noop) == 4, "size of Noop should equal 4");
static_assert(offsetof(Noop, header) == 0,
              "offset of Noop.header should equal 0");

// The SetToken command puts a token in the command stream that you can
// use to check if that token has been passed in the command stream.
struct SetToken {
  typedef SetToken ValueType;
  static const CommandId kCmdId = kSetToken;
  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);

  void SetHeader() {
    header.SetCmd<ValueType>();
  }

  void Init(uint32_t _token) {
    SetHeader();
    token = _token;
  }
  static void* Set(void* cmd, uint32_t token) {
    static_cast<ValueType*>(cmd)->Init(token);
    return NextCmdAddress<ValueType>(cmd);
  }

  CommandHeader header;
  uint32_t token;
};

static_assert(sizeof(SetToken) == 8, "size of SetToken should equal 8");
static_assert(offsetof(SetToken, header) == 0,
              "offset of SetToken.header should equal 0");
static_assert(offsetof(SetToken, token) == 4,
              "offset of SetToken.token should equal 4");

// Sets the size of a bucket for collecting data on the service side.
// This is a utility for gathering data on the service side so it can be used
// all at once when some service side API is called. It removes the need to add
// special commands just to support a particular API. For example, any API
// command that needs a string needs a way to send that string to the API over
// the command buffers. While you can require that the command buffer or
// transfer buffer be large enough to hold the largest string you can send,
// using this command removes that restriction by letting you send smaller
// pieces over and build up the data on the service side.
//
// You can clear a bucket on the service side and thereby free memory by sending
// a size of 0.
struct SetBucketSize {
  typedef SetBucketSize ValueType;
  static const CommandId kCmdId = kSetBucketSize;
  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);

  void SetHeader() {
    header.SetCmd<ValueType>();
  }

  void Init(uint32_t _bucket_id, uint32_t _size) {
    SetHeader();
    bucket_id = _bucket_id;
    size = _size;
  }
  static void* Set(void* cmd, uint32_t _bucket_id, uint32_t _size) {
    static_cast<ValueType*>(cmd)->Init(_bucket_id, _size);
    return NextCmdAddress<ValueType>(cmd);
  }

  CommandHeader header;
  uint32_t bucket_id;
  uint32_t size;
};

static_assert(sizeof(SetBucketSize) == 12,
              "size of SetBucketSize should equal 12");
static_assert(offsetof(SetBucketSize, header) == 0,
              "offset of SetBucketSize.header should equal 0");
static_assert(offsetof(SetBucketSize, bucket_id) == 4,
              "offset of SetBucketSize.bucket_id should equal 4");
static_assert(offsetof(SetBucketSize, size) == 8,
              "offset of SetBucketSize.size should equal 8");

// Sets the contents of a portion of a bucket on the service side from data in
// shared memory.
// See SetBucketSize.
struct SetBucketData {
  typedef SetBucketData ValueType;
  static const CommandId kCmdId = kSetBucketData;
  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);

  void SetHeader() {
    header.SetCmd<ValueType>();
  }

  void Init(uint32_t _bucket_id,
            uint32_t _offset,
            uint32_t _size,
            uint32_t _shared_memory_id,
            uint32_t _shared_memory_offset) {
    SetHeader();
    bucket_id = _bucket_id;
    offset = _offset;
    size = _size;
    shared_memory_id = _shared_memory_id;
    shared_memory_offset = _shared_memory_offset;
  }
  static void* Set(void* cmd,
                   uint32_t _bucket_id,
                   uint32_t _offset,
                   uint32_t _size,
                   uint32_t _shared_memory_id,
                   uint32_t _shared_memory_offset) {
    static_cast<ValueType*>(cmd)->Init(
        _bucket_id,
        _offset,
        _size,
        _shared_memory_id,
        _shared_memory_offset);
    return NextCmdAddress<ValueType>(cmd);
  }

  CommandHeader header;
  uint32_t bucket_id;
  uint32_t offset;
  uint32_t size;
  uint32_t shared_memory_id;
  uint32_t shared_memory_offset;
};

static_assert(sizeof(SetBucketData) == 24,
              "size of SetBucketData should be 24");
static_assert(offsetof(SetBucketData, header) == 0,
              "offset of SetBucketData.header should be 0");
static_assert(offsetof(SetBucketData, bucket_id) == 4,
              "offset of SetBucketData.bucket_id should be 4");
static_assert(offsetof(SetBucketData, offset) == 8,
              "offset of SetBucketData.offset should be 8");
static_assert(offsetof(SetBucketData, size) == 12,
              "offset of SetBucketData.size should be 12");
static_assert(offsetof(SetBucketData, shared_memory_id) == 16,
              "offset of SetBucketData.shared_memory_id should be 16");
static_assert(offsetof(SetBucketData, shared_memory_offset) == 20,
              "offset of SetBucketData.shared_memory_offset should be 20");

// Sets the contents of a portion of a bucket on the service side from data in
// the command buffer.
// See SetBucketSize.
struct SetBucketDataImmediate {
  typedef SetBucketDataImmediate ValueType;
  static const CommandId kCmdId = kSetBucketDataImmediate;
  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);

  void SetHeader(uint32_t _size) { header.SetCmdBySize<ValueType>(_size); }

  void Init(uint32_t _bucket_id,
            uint32_t _offset,
            uint32_t _size) {
    SetHeader(_size);
    bucket_id = _bucket_id;
    offset = _offset;
    size = _size;
  }
  static void* Set(void* cmd,
                   uint32_t _bucket_id,
                   uint32_t _offset,
                   uint32_t _size) {
    static_cast<ValueType*>(cmd)->Init(
        _bucket_id,
        _offset,
        _size);
    return NextImmediateCmdAddress<ValueType>(cmd, _size);
  }

  CommandHeader header;
  uint32_t bucket_id;
  uint32_t offset;
  uint32_t size;
};

static_assert(sizeof(SetBucketDataImmediate) == 16,
              "size of SetBucketDataImmediate should be 16");
static_assert(offsetof(SetBucketDataImmediate, header) == 0,
              "offset of SetBucketDataImmediate.header should be 0");
static_assert(offsetof(SetBucketDataImmediate, bucket_id) == 4,
              "offset of SetBucketDataImmediate.bucket_id should be 4");
static_assert(offsetof(SetBucketDataImmediate, offset) == 8,
              "offset of SetBucketDataImmediate.offset should be 8");
static_assert(offsetof(SetBucketDataImmediate, size) == 12,
              "offset of SetBucketDataImmediate.size should be 12");

// Gets the start of a bucket the service has available. Sending a variable size
// result back to the client and the portion of that result that fits in the
// supplied shared memory. If the size of the result is larger than the supplied
// shared memory the rest of the bucket's contents can be retrieved with
// GetBucketData.
//
// This is used for example for any API that returns a string. The problem is
// the largest thing you can send back in 1 command is the size of your shared
// memory. This command along with GetBucketData implements a way to get a
// result a piece at a time to help solve that problem in a generic way.
struct GetBucketStart {
  typedef GetBucketStart ValueType;
  static const CommandId kCmdId = kGetBucketStart;
  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);

  typedef uint32_t Result;

  void SetHeader() {
    header.SetCmd<ValueType>();
  }

  void Init(uint32_t _bucket_id,
            uint32_t _result_memory_id,
            uint32_t _result_memory_offset,
            uint32_t _data_memory_size,
            uint32_t _data_memory_id,
            uint32_t _data_memory_offset) {
    SetHeader();
    bucket_id = _bucket_id;
    result_memory_id = _result_memory_id;
    result_memory_offset = _result_memory_offset;
    data_memory_size = _data_memory_size;
    data_memory_id = _data_memory_id;
    data_memory_offset = _data_memory_offset;
  }
  static void* Set(void* cmd,
                   uint32_t _bucket_id,
                   uint32_t _result_memory_id,
                   uint32_t _result_memory_offset,
                   uint32_t _data_memory_size,
                   uint32_t _data_memory_id,
                   uint32_t _data_memory_offset) {
    static_cast<ValueType*>(cmd)->Init(
        _bucket_id,
        _result_memory_id,
        _result_memory_offset,
        _data_memory_size,
        _data_memory_id,
        _data_memory_offset);
    return NextCmdAddress<ValueType>(cmd);
  }

  CommandHeader header;
  uint32_t bucket_id;
  uint32_t result_memory_id;
  uint32_t result_memory_offset;
  uint32_t data_memory_size;
  uint32_t data_memory_id;
  uint32_t data_memory_offset;
};

static_assert(sizeof(GetBucketStart) == 28,
              "size of GetBucketStart should be 28");
static_assert(offsetof(GetBucketStart, header) == 0,
              "offset of GetBucketStart.header should be 0");
static_assert(offsetof(GetBucketStart, bucket_id) == 4,
              "offset of GetBucketStart.bucket_id should be 4");
static_assert(offsetof(GetBucketStart, result_memory_id) == 8,
              "offset of GetBucketStart.result_memory_id should be 8");
static_assert(offsetof(GetBucketStart, result_memory_offset) == 12,
              "offset of GetBucketStart.result_memory_offset should be 12");
static_assert(offsetof(GetBucketStart, data_memory_size) == 16,
              "offset of GetBucketStart.data_memory_size should be 16");
static_assert(offsetof(GetBucketStart, data_memory_id) == 20,
              "offset of GetBucketStart.data_memory_id should be 20");
static_assert(offsetof(GetBucketStart, data_memory_offset) == 24,
              "offset of GetBucketStart.data_memory_offset should be 24");

// Gets a piece of a result the service as available.
// See GetBucketSize.
struct GetBucketData {
  typedef GetBucketData ValueType;
  static const CommandId kCmdId = kGetBucketData;
  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);

  void SetHeader() {
    header.SetCmd<ValueType>();
  }

  void Init(uint32_t _bucket_id,
            uint32_t _offset,
            uint32_t _size,
            uint32_t _shared_memory_id,
            uint32_t _shared_memory_offset) {
    SetHeader();
    bucket_id = _bucket_id;
    offset = _offset;
    size = _size;
    shared_memory_id = _shared_memory_id;
    shared_memory_offset = _shared_memory_offset;
  }
  static void* Set(void* cmd,
                   uint32_t _bucket_id,
                   uint32_t _offset,
                   uint32_t _size,
                   uint32_t _shared_memory_id,
                   uint32_t _shared_memory_offset) {
    static_cast<ValueType*>(cmd)->Init(
        _bucket_id,
        _offset,
        _size,
        _shared_memory_id,
        _shared_memory_offset);
    return NextCmdAddress<ValueType>(cmd);
  }

  CommandHeader header;
  uint32_t bucket_id;
  uint32_t offset;
  uint32_t size;
  uint32_t shared_memory_id;
  uint32_t shared_memory_offset;
};

static_assert(sizeof(GetBucketData) == 24,
              "size of GetBucketData should be 24");
static_assert(offsetof(GetBucketData, header) == 0,
              "offset of GetBucketData.header should be 0");
static_assert(offsetof(GetBucketData, bucket_id) == 4,
              "offset of GetBucketData.bucket_id should be 4");
static_assert(offsetof(GetBucketData, offset) == 8,
              "offset of GetBucketData.offset should be 8");
static_assert(offsetof(GetBucketData, size) == 12,
              "offset of GetBucketData.size should be 12");
static_assert(offsetof(GetBucketData, shared_memory_id) == 16,
              "offset of GetBucketData.shared_memory_id should be 16");
static_assert(offsetof(GetBucketData, shared_memory_offset) == 20,
              "offset of GetBucketData.shared_memory_offset should be 20");

struct InsertFenceSync {
  typedef InsertFenceSync ValueType;
  static const CommandId kCmdId = kInsertFenceSync;
  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);

  void SetHeader() { header.SetCmd<ValueType>(); }

  void Init(uint64_t _release_count) {
    SetHeader();
    release_count_0 = static_cast<uint32_t>(_release_count & 0xFFFFFFFF);
    release_count_1 =
        static_cast<uint32_t>((_release_count >> 32) & 0xFFFFFFFF);
  }

  void* Set(void* cmd, uint64_t _release_count) {
    static_cast<ValueType*>(cmd)->Init(_release_count);
    return NextCmdAddress<ValueType>(cmd);
  }

  uint64_t release_count() const volatile {
    return (static_cast<uint64_t>(release_count_1) << 32) +
           static_cast<uint64_t>(release_count_0);
  }

  gpu::CommandHeader header;
  uint32_t release_count_0;
  uint32_t release_count_1;
};

static_assert(sizeof(InsertFenceSync) == 12,
              "size of InsertFenceSync should be 12");
static_assert(offsetof(InsertFenceSync, header) == 0,
              "offset of InsertFenceSync header should be 0");
static_assert(offsetof(InsertFenceSync, release_count_0) == 4,
              "offset of InsertFenceSync release_count_0 should be 4");
static_assert(offsetof(InsertFenceSync, release_count_1) == 8,
              "offset of InsertFenceSync release_count_1 should be 8");

}  // namespace cmd

#pragma pack(pop)

}  // namespace gpu

#endif  // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_