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