普通文本  |  296行  |  8.84 KB

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/common_decoder.h"
#include "gpu/command_buffer/service/cmd_buffer_engine.h"

namespace gpu {

CommonDecoder::Bucket::Bucket() : size_(0) {}

CommonDecoder::Bucket::~Bucket() {}

void* CommonDecoder::Bucket::GetData(size_t offset, size_t size) const {
  if (OffsetSizeValid(offset, size)) {
    return data_.get() + offset;
  }
  return NULL;
}

void CommonDecoder::Bucket::SetSize(size_t size) {
  if (size != size_) {
    data_.reset(size ? new int8[size] : NULL);
    size_ = size;
    memset(data_.get(), 0, size);
  }
}

bool CommonDecoder::Bucket::SetData(
    const void* src, size_t offset, size_t size) {
  if (OffsetSizeValid(offset, size)) {
    memcpy(data_.get() + offset, src, size);
    return true;
  }
  return false;
}

void CommonDecoder::Bucket::SetFromString(const char* str) {
  // Strings are passed NULL terminated to distinguish between empty string
  // and no string.
  if (!str) {
    SetSize(0);
  } else {
    size_t size = strlen(str) + 1;
    SetSize(size);
    SetData(str, 0, size);
  }
}

bool CommonDecoder::Bucket::GetAsString(std::string* str) {
  DCHECK(str);
  if (size_ == 0) {
    return false;
  }
  str->assign(GetDataAs<const char*>(0, size_ - 1), size_ - 1);
  return true;
}

CommonDecoder::CommonDecoder() : engine_(NULL) {}

CommonDecoder::~CommonDecoder() {}

void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
                                            unsigned int data_offset,
                                            unsigned int data_size) {
  CHECK(engine_);
  scoped_refptr<gpu::Buffer> buffer = engine_->GetSharedMemoryBuffer(shm_id);
  if (!buffer)
    return NULL;
  return buffer->GetDataAddress(data_offset, data_size);
}

scoped_refptr<gpu::Buffer> CommonDecoder::GetSharedMemoryBuffer(
    unsigned int shm_id) {
  return engine_->GetSharedMemoryBuffer(shm_id);
}

const char* CommonDecoder::GetCommonCommandName(
    cmd::CommandId command_id) const {
  return cmd::GetCommandName(command_id);
}

CommonDecoder::Bucket* CommonDecoder::GetBucket(uint32 bucket_id) const {
  BucketMap::const_iterator iter(buckets_.find(bucket_id));
  return iter != buckets_.end() ? &(*iter->second) : NULL;
}

CommonDecoder::Bucket* CommonDecoder::CreateBucket(uint32 bucket_id) {
  Bucket* bucket = GetBucket(bucket_id);
  if (!bucket) {
    bucket = new Bucket();
    buckets_[bucket_id] = linked_ptr<Bucket>(bucket);
  }
  return bucket;
}

namespace {

// Returns the address of the first byte after a struct.
template <typename T>
const void* AddressAfterStruct(const T& pod) {
  return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
}

// Returns the address of the frst byte after the struct.
template <typename RETURN_TYPE, typename COMMAND_TYPE>
RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod) {
  return static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod)));
}

// TODO(vmiura): Looks like this g_command_info is duplicated in
// common_decoder.cc
// and gles2_cmd_decoder.cc.  Fix it!

// A struct to hold info about each command.
struct CommandInfo {
  uint8 arg_flags;   // How to handle the arguments for this command
  uint8 cmd_flags;   // How to handle this command
  uint16 arg_count;  // How many arguments are expected for this command.
};

// A table of CommandInfo for all the commands.
const CommandInfo g_command_info[] = {
  #define COMMON_COMMAND_BUFFER_CMD_OP(name) {                           \
    cmd::name::kArgFlags,                                                \
    cmd::name::cmd_flags,                                                \
    sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, },  /* NOLINT */

  COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)

  #undef COMMON_COMMAND_BUFFER_CMD_OP
};

}  // anonymous namespace.

// Decode command with its arguments, and call the corresponding method.
// Note: args is a pointer to the command buffer. As such, it could be changed
// by a (malicious) client at any time, so if validation has to happen, it
// should operate on a copy of them.
error::Error CommonDecoder::DoCommonCommand(
    unsigned int command,
    unsigned int arg_count,
    const void* cmd_data) {
  if (command < arraysize(g_command_info)) {
    const CommandInfo& info = g_command_info[command];
    unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
    if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
        (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
      uint32 immediate_data_size =
          (arg_count - info_arg_count) * sizeof(CommandBufferEntry);  // NOLINT
      switch (command) {
        #define COMMON_COMMAND_BUFFER_CMD_OP(name)                      \
          case cmd::name::kCmdId:                                       \
            return Handle ## name(                                      \
                immediate_data_size,                                    \
                *static_cast<const cmd::name*>(cmd_data));              \

        COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)

        #undef COMMON_COMMAND_BUFFER_CMD_OP
      }
    } else {
      return error::kInvalidArguments;
    }
  }
  return error::kUnknownCommand;
}

error::Error CommonDecoder::HandleNoop(
    uint32 immediate_data_size,
    const cmd::Noop& args) {
  return error::kNoError;
}

error::Error CommonDecoder::HandleSetToken(
    uint32 immediate_data_size,
    const cmd::SetToken& args) {
  engine_->set_token(args.token);
  return error::kNoError;
}

error::Error CommonDecoder::HandleSetBucketSize(
    uint32 immediate_data_size,
    const cmd::SetBucketSize& args) {
  uint32 bucket_id = args.bucket_id;
  uint32 size = args.size;

  Bucket* bucket = CreateBucket(bucket_id);
  bucket->SetSize(size);
  return error::kNoError;
}

error::Error CommonDecoder::HandleSetBucketData(
    uint32 immediate_data_size,
    const cmd::SetBucketData& args) {
  uint32 bucket_id = args.bucket_id;
  uint32 offset = args.offset;
  uint32 size = args.size;
  const void* data = GetSharedMemoryAs<const void*>(
      args.shared_memory_id, args.shared_memory_offset, size);
  if (!data) {
    return error::kInvalidArguments;
  }
  Bucket* bucket = GetBucket(bucket_id);
  if (!bucket) {
    return error::kInvalidArguments;
  }
  if (!bucket->SetData(data, offset, size)) {
    return error::kInvalidArguments;
  }

  return error::kNoError;
}

error::Error CommonDecoder::HandleSetBucketDataImmediate(
    uint32 immediate_data_size,
    const cmd::SetBucketDataImmediate& args) {
  const void* data = GetImmediateDataAs<const void*>(args);
  uint32 bucket_id = args.bucket_id;
  uint32 offset = args.offset;
  uint32 size = args.size;
  if (size > immediate_data_size) {
    return error::kInvalidArguments;
  }
  Bucket* bucket = GetBucket(bucket_id);
  if (!bucket) {
    return error::kInvalidArguments;
  }
  if (!bucket->SetData(data, offset, size)) {
    return error::kInvalidArguments;
  }
  return error::kNoError;
}

error::Error CommonDecoder::HandleGetBucketStart(
    uint32 immediate_data_size,
    const cmd::GetBucketStart& args) {
  uint32 bucket_id = args.bucket_id;
  uint32* result = GetSharedMemoryAs<uint32*>(
      args.result_memory_id, args.result_memory_offset, sizeof(*result));
  int32 data_memory_id = args.data_memory_id;
  uint32 data_memory_offset = args.data_memory_offset;
  uint32 data_memory_size = args.data_memory_size;
  uint8* data = NULL;
  if (data_memory_size != 0 || data_memory_id != 0 || data_memory_offset != 0) {
    data = GetSharedMemoryAs<uint8*>(
        args.data_memory_id, args.data_memory_offset, args.data_memory_size);
    if (!data) {
      return error::kInvalidArguments;
    }
  }
  if (!result) {
    return error::kInvalidArguments;
  }
  // Check that the client initialized the result.
  if (*result != 0) {
    return error::kInvalidArguments;
  }
  Bucket* bucket = GetBucket(bucket_id);
  if (!bucket) {
    return error::kInvalidArguments;
  }
  uint32 bucket_size = bucket->size();
  *result = bucket_size;
  if (data) {
    uint32 size = std::min(data_memory_size, bucket_size);
    memcpy(data, bucket->GetData(0, size), size);
  }
  return error::kNoError;
}

error::Error CommonDecoder::HandleGetBucketData(
    uint32 immediate_data_size,
    const cmd::GetBucketData& args) {
  uint32 bucket_id = args.bucket_id;
  uint32 offset = args.offset;
  uint32 size = args.size;
  void* data = GetSharedMemoryAs<void*>(
      args.shared_memory_id, args.shared_memory_offset, size);
  if (!data) {
    return error::kInvalidArguments;
  }
  Bucket* bucket = GetBucket(bucket_id);
  if (!bucket) {
    return error::kInvalidArguments;
  }
  const void* src = bucket->GetData(offset, size);
  if (!src) {
      return error::kInvalidArguments;
  }
  memcpy(data, src, size);
  return error::kNoError;
}

}  // namespace gpu