• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Bucket()10 CommonDecoder::Bucket::Bucket() : size_(0) {}
11 
~Bucket()12 CommonDecoder::Bucket::~Bucket() {}
13 
GetData(size_t offset,size_t size) const14 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 
SetSize(size_t size)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 
SetData(const void * src,size_t offset,size_t size)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 
SetFromString(const char * str)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 
GetAsString(std::string * str)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 
CommonDecoder()59 CommonDecoder::CommonDecoder() : engine_(NULL) {}
60 
~CommonDecoder()61 CommonDecoder::~CommonDecoder() {}
62 
GetAddressAndCheckSize(unsigned int shm_id,unsigned int offset,unsigned int size)63 void* 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 
GetSharedMemoryBuffer(unsigned int shm_id)77 Buffer CommonDecoder::GetSharedMemoryBuffer(unsigned int shm_id) {
78   return engine_->GetSharedMemoryBuffer(shm_id);
79 }
80 
GetCommonCommandName(cmd::CommandId command_id) const81 const char* CommonDecoder::GetCommonCommandName(
82     cmd::CommandId command_id) const {
83   return cmd::GetCommandName(command_id);
84 }
85 
GetBucket(uint32 bucket_id) const86 CommonDecoder::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 
CreateBucket(uint32 bucket_id)91 CommonDecoder::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 
100 namespace {
101 
102 // Returns the address of the first byte after a struct.
103 template <typename T>
AddressAfterStruct(const T & pod)104 const 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.
109 template <typename RETURN_TYPE, typename COMMAND_TYPE>
GetImmediateDataAs(const COMMAND_TYPE & pod)110 RETURN_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.
115 struct 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.
121 const 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.
DoCommonCommand(unsigned int command,unsigned int arg_count,const void * cmd_data)137 error::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 
HandleNoop(uint32 immediate_data_size,const cmd::Noop & args)166 error::Error CommonDecoder::HandleNoop(
167     uint32 immediate_data_size,
168     const cmd::Noop& args) {
169   return error::kNoError;
170 }
171 
HandleSetToken(uint32 immediate_data_size,const cmd::SetToken & args)172 error::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 
HandleSetBucketSize(uint32 immediate_data_size,const cmd::SetBucketSize & args)179 error::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 
HandleSetBucketData(uint32 immediate_data_size,const cmd::SetBucketData & args)190 error::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 
HandleSetBucketDataImmediate(uint32 immediate_data_size,const cmd::SetBucketDataImmediate & args)212 error::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 
HandleGetBucketStart(uint32 immediate_data_size,const cmd::GetBucketStart & args)232 error::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 
HandleGetBucketData(uint32 immediate_data_size,const cmd::GetBucketData & args)269 error::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