Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / common_decoder.cc
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