Home | History | Annotate | Download | only in service
      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 #include "gpu/command_buffer/service/common_decoder.h"
      6 #include "gpu/command_buffer/service/cmd_buffer_engine.h"
      7 
      8 namespace gpu {
      9 
     10 CommonDecoder::Bucket::Bucket() : size_(0) {}
     11 
     12 CommonDecoder::Bucket::~Bucket() {}
     13 
     14 void* CommonDecoder::Bucket::GetData(size_t offset, size_t size) const {
     15   if (OffsetSizeValid(offset, size)) {
     16     return data_.get() + offset;
     17   }
     18   return NULL;
     19 }
     20 
     21 void CommonDecoder::Bucket::SetSize(size_t size) {
     22   if (size != size_) {
     23     data_.reset(size ? new int8[size] : NULL);
     24     size_ = size;
     25     memset(data_.get(), 0, size);
     26   }
     27 }
     28 
     29 bool CommonDecoder::Bucket::SetData(
     30     const void* src, size_t offset, size_t size) {
     31   if (OffsetSizeValid(offset, size)) {
     32     memcpy(data_.get() + offset, src, size);
     33     return true;
     34   }
     35   return false;
     36 }
     37 
     38 void CommonDecoder::Bucket::SetFromString(const char* str) {
     39   // Strings are passed NULL terminated to distinguish between empty string
     40   // and no string.
     41   if (!str) {
     42     SetSize(0);
     43   } else {
     44     size_t size = strlen(str) + 1;
     45     SetSize(size);
     46     SetData(str, 0, size);
     47   }
     48 }
     49 
     50 bool CommonDecoder::Bucket::GetAsString(std::string* str) {
     51   DCHECK(str);
     52   if (size_ == 0) {
     53     return false;
     54   }
     55   str->assign(GetDataAs<const char*>(0, size_ - 1), size_ - 1);
     56   return true;
     57 }
     58 
     59 CommonDecoder::CommonDecoder() : engine_(NULL) {}
     60 
     61 CommonDecoder::~CommonDecoder() {}
     62 
     63 void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
     64                                             unsigned int data_offset,
     65                                             unsigned int data_size) {
     66   CHECK(engine_);
     67   scoped_refptr<gpu::Buffer> buffer = engine_->GetSharedMemoryBuffer(shm_id);
     68   if (!buffer.get())
     69     return NULL;
     70   return buffer->GetDataAddress(data_offset, data_size);
     71 }
     72 
     73 scoped_refptr<gpu::Buffer> CommonDecoder::GetSharedMemoryBuffer(
     74     unsigned int shm_id) {
     75   return engine_->GetSharedMemoryBuffer(shm_id);
     76 }
     77 
     78 const char* CommonDecoder::GetCommonCommandName(
     79     cmd::CommandId command_id) const {
     80   return cmd::GetCommandName(command_id);
     81 }
     82 
     83 CommonDecoder::Bucket* CommonDecoder::GetBucket(uint32 bucket_id) const {
     84   BucketMap::const_iterator iter(buckets_.find(bucket_id));
     85   return iter != buckets_.end() ? &(*iter->second) : NULL;
     86 }
     87 
     88 CommonDecoder::Bucket* CommonDecoder::CreateBucket(uint32 bucket_id) {
     89   Bucket* bucket = GetBucket(bucket_id);
     90   if (!bucket) {
     91     bucket = new Bucket();
     92     buckets_[bucket_id] = linked_ptr<Bucket>(bucket);
     93   }
     94   return bucket;
     95 }
     96 
     97 namespace {
     98 
     99 // Returns the address of the first byte after a struct.
    100 template <typename T>
    101 const void* AddressAfterStruct(const T& pod) {
    102   return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
    103 }
    104 
    105 // Returns the address of the frst byte after the struct.
    106 template <typename RETURN_TYPE, typename COMMAND_TYPE>
    107 RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod) {
    108   return static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod)));
    109 }
    110 
    111 // TODO(vmiura): Looks like this g_command_info is duplicated in
    112 // common_decoder.cc
    113 // and gles2_cmd_decoder.cc.  Fix it!
    114 
    115 // A struct to hold info about each command.
    116 struct CommandInfo {
    117   uint8 arg_flags;   // How to handle the arguments for this command
    118   uint8 cmd_flags;   // How to handle this command
    119   uint16 arg_count;  // How many arguments are expected for this command.
    120 };
    121 
    122 // A table of CommandInfo for all the commands.
    123 const CommandInfo g_command_info[] = {
    124   #define COMMON_COMMAND_BUFFER_CMD_OP(name) {                           \
    125     cmd::name::kArgFlags,                                                \
    126     cmd::name::cmd_flags,                                                \
    127     sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, },  /* NOLINT */
    128 
    129   COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
    130 
    131   #undef COMMON_COMMAND_BUFFER_CMD_OP
    132 };
    133 
    134 }  // anonymous namespace.
    135 
    136 // Decode command with its arguments, and call the corresponding method.
    137 // Note: args is a pointer to the command buffer. As such, it could be changed
    138 // by a (malicious) client at any time, so if validation has to happen, it
    139 // should operate on a copy of them.
    140 error::Error CommonDecoder::DoCommonCommand(
    141     unsigned int command,
    142     unsigned int arg_count,
    143     const void* cmd_data) {
    144   if (command < arraysize(g_command_info)) {
    145     const CommandInfo& info = g_command_info[command];
    146     unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
    147     if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
    148         (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
    149       uint32 immediate_data_size =
    150           (arg_count - info_arg_count) * sizeof(CommandBufferEntry);  // NOLINT
    151       switch (command) {
    152         #define COMMON_COMMAND_BUFFER_CMD_OP(name)                      \
    153           case cmd::name::kCmdId:                                       \
    154             return Handle ## name(                                      \
    155                 immediate_data_size,                                    \
    156                 *static_cast<const cmd::name*>(cmd_data));              \
    157 
    158         COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
    159 
    160         #undef COMMON_COMMAND_BUFFER_CMD_OP
    161       }
    162     } else {
    163       return error::kInvalidArguments;
    164     }
    165   }
    166   return error::kUnknownCommand;
    167 }
    168 
    169 error::Error CommonDecoder::HandleNoop(
    170     uint32 immediate_data_size,
    171     const cmd::Noop& args) {
    172   return error::kNoError;
    173 }
    174 
    175 error::Error CommonDecoder::HandleSetToken(
    176     uint32 immediate_data_size,
    177     const cmd::SetToken& args) {
    178   engine_->set_token(args.token);
    179   return error::kNoError;
    180 }
    181 
    182 error::Error CommonDecoder::HandleSetBucketSize(
    183     uint32 immediate_data_size,
    184     const cmd::SetBucketSize& args) {
    185   uint32 bucket_id = args.bucket_id;
    186   uint32 size = args.size;
    187 
    188   Bucket* bucket = CreateBucket(bucket_id);
    189   bucket->SetSize(size);
    190   return error::kNoError;
    191 }
    192 
    193 error::Error CommonDecoder::HandleSetBucketData(
    194     uint32 immediate_data_size,
    195     const cmd::SetBucketData& args) {
    196   uint32 bucket_id = args.bucket_id;
    197   uint32 offset = args.offset;
    198   uint32 size = args.size;
    199   const void* data = GetSharedMemoryAs<const void*>(
    200       args.shared_memory_id, args.shared_memory_offset, size);
    201   if (!data) {
    202     return error::kInvalidArguments;
    203   }
    204   Bucket* bucket = GetBucket(bucket_id);
    205   if (!bucket) {
    206     return error::kInvalidArguments;
    207   }
    208   if (!bucket->SetData(data, offset, size)) {
    209     return error::kInvalidArguments;
    210   }
    211 
    212   return error::kNoError;
    213 }
    214 
    215 error::Error CommonDecoder::HandleSetBucketDataImmediate(
    216     uint32 immediate_data_size,
    217     const cmd::SetBucketDataImmediate& args) {
    218   const void* data = GetImmediateDataAs<const void*>(args);
    219   uint32 bucket_id = args.bucket_id;
    220   uint32 offset = args.offset;
    221   uint32 size = args.size;
    222   if (size > immediate_data_size) {
    223     return error::kInvalidArguments;
    224   }
    225   Bucket* bucket = GetBucket(bucket_id);
    226   if (!bucket) {
    227     return error::kInvalidArguments;
    228   }
    229   if (!bucket->SetData(data, offset, size)) {
    230     return error::kInvalidArguments;
    231   }
    232   return error::kNoError;
    233 }
    234 
    235 error::Error CommonDecoder::HandleGetBucketStart(
    236     uint32 immediate_data_size,
    237     const cmd::GetBucketStart& args) {
    238   uint32 bucket_id = args.bucket_id;
    239   uint32* result = GetSharedMemoryAs<uint32*>(
    240       args.result_memory_id, args.result_memory_offset, sizeof(*result));
    241   int32 data_memory_id = args.data_memory_id;
    242   uint32 data_memory_offset = args.data_memory_offset;
    243   uint32 data_memory_size = args.data_memory_size;
    244   uint8* data = NULL;
    245   if (data_memory_size != 0 || data_memory_id != 0 || data_memory_offset != 0) {
    246     data = GetSharedMemoryAs<uint8*>(
    247         args.data_memory_id, args.data_memory_offset, args.data_memory_size);
    248     if (!data) {
    249       return error::kInvalidArguments;
    250     }
    251   }
    252   if (!result) {
    253     return error::kInvalidArguments;
    254   }
    255   // Check that the client initialized the result.
    256   if (*result != 0) {
    257     return error::kInvalidArguments;
    258   }
    259   Bucket* bucket = GetBucket(bucket_id);
    260   if (!bucket) {
    261     return error::kInvalidArguments;
    262   }
    263   uint32 bucket_size = bucket->size();
    264   *result = bucket_size;
    265   if (data) {
    266     uint32 size = std::min(data_memory_size, bucket_size);
    267     memcpy(data, bucket->GetData(0, size), size);
    268   }
    269   return error::kNoError;
    270 }
    271 
    272 error::Error CommonDecoder::HandleGetBucketData(
    273     uint32 immediate_data_size,
    274     const cmd::GetBucketData& args) {
    275   uint32 bucket_id = args.bucket_id;
    276   uint32 offset = args.offset;
    277   uint32 size = args.size;
    278   void* data = GetSharedMemoryAs<void*>(
    279       args.shared_memory_id, args.shared_memory_offset, size);
    280   if (!data) {
    281     return error::kInvalidArguments;
    282   }
    283   Bucket* bucket = GetBucket(bucket_id);
    284   if (!bucket) {
    285     return error::kInvalidArguments;
    286   }
    287   const void* src = bucket->GetData(offset, size);
    288   if (!src) {
    289       return error::kInvalidArguments;
    290   }
    291   memcpy(data, src, size);
    292   return error::kNoError;
    293 }
    294 
    295 }  // namespace gpu
    296