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