Infobar material design refresh: bg color
[chromium-blink-merge.git] / gpu / command_buffer / service / common_decoder.cc
blob99fdb765a0841876e01f45e85430a3bdf70d2a50
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.
5 #include "gpu/command_buffer/service/common_decoder.h"
7 #include "base/numerics/safe_math.h"
8 #include "gpu/command_buffer/service/cmd_buffer_engine.h"
10 namespace gpu {
12 const CommonDecoder::CommandInfo CommonDecoder::command_info[] = {
13 #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
14 { \
15 &CommonDecoder::Handle##name, cmd::name::kArgFlags, \
16 cmd::name::cmd_flags, \
17 sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, \
18 } \
19 , /* NOLINT */
20 COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
21 #undef COMMON_COMMAND_BUFFER_CMD_OP
25 CommonDecoder::Bucket::Bucket() : size_(0) {}
27 CommonDecoder::Bucket::~Bucket() {}
29 void* CommonDecoder::Bucket::GetData(size_t offset, size_t size) const {
30 if (OffsetSizeValid(offset, size)) {
31 return data_.get() + offset;
33 return NULL;
36 void CommonDecoder::Bucket::SetSize(size_t size) {
37 if (size != size_) {
38 data_.reset(size ? new int8[size] : NULL);
39 size_ = size;
40 memset(data_.get(), 0, size);
44 bool CommonDecoder::Bucket::SetData(
45 const void* src, size_t offset, size_t size) {
46 if (OffsetSizeValid(offset, size)) {
47 memcpy(data_.get() + offset, src, size);
48 return true;
50 return false;
53 void CommonDecoder::Bucket::SetFromString(const char* str) {
54 // Strings are passed NULL terminated to distinguish between empty string
55 // and no string.
56 if (!str) {
57 SetSize(0);
58 } else {
59 size_t size = strlen(str) + 1;
60 SetSize(size);
61 SetData(str, 0, size);
65 bool CommonDecoder::Bucket::GetAsString(std::string* str) {
66 DCHECK(str);
67 if (size_ == 0) {
68 return false;
70 str->assign(GetDataAs<const char*>(0, size_ - 1), size_ - 1);
71 return true;
74 bool CommonDecoder::Bucket::GetAsStrings(
75 GLsizei* _count, std::vector<char*>* _string, std::vector<GLint>* _length) {
76 const size_t kMinBucketSize = sizeof(GLint);
77 // Each string has at least |length| in the header and a NUL character.
78 const size_t kMinStringSize = sizeof(GLint) + 1;
79 const size_t bucket_size = this->size();
80 if (bucket_size < kMinBucketSize) {
81 return false;
83 char* bucket_data = this->GetDataAs<char*>(0, bucket_size);
84 GLint* header = reinterpret_cast<GLint*>(bucket_data);
85 GLsizei count = static_cast<GLsizei>(header[0]);
86 if (count < 0) {
87 return false;
89 const size_t max_count = (bucket_size - kMinBucketSize) / kMinStringSize;
90 if (max_count < static_cast<size_t>(count)) {
91 return false;
93 GLint* length = header + 1;
94 std::vector<char*> strs(count);
95 base::CheckedNumeric<size_t> total_size = sizeof(GLint);
96 total_size *= count + 1; // Header size.
97 if (!total_size.IsValid())
98 return false;
99 for (GLsizei ii = 0; ii < count; ++ii) {
100 strs[ii] = bucket_data + total_size.ValueOrDefault(0);
101 total_size += length[ii];
102 total_size += 1; // NUL char at the end of each char array.
103 if (!total_size.IsValid() || total_size.ValueOrDefault(0) > bucket_size ||
104 strs[ii][length[ii]] != 0) {
105 return false;
108 if (total_size.ValueOrDefault(0) != bucket_size) {
109 return false;
111 DCHECK(_count && _string && _length);
112 *_count = count;
113 *_string = strs;
114 _length->resize(count);
115 for (GLsizei ii = 0; ii < count; ++ii) {
116 (*_length)[ii] = length[ii];
118 return true;
121 CommonDecoder::CommonDecoder() : engine_(NULL) {}
123 CommonDecoder::~CommonDecoder() {}
125 void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
126 unsigned int data_offset,
127 unsigned int data_size) {
128 CHECK(engine_);
129 scoped_refptr<gpu::Buffer> buffer = engine_->GetSharedMemoryBuffer(shm_id);
130 if (!buffer.get())
131 return NULL;
132 return buffer->GetDataAddress(data_offset, data_size);
135 scoped_refptr<gpu::Buffer> CommonDecoder::GetSharedMemoryBuffer(
136 unsigned int shm_id) {
137 return engine_->GetSharedMemoryBuffer(shm_id);
140 const char* CommonDecoder::GetCommonCommandName(
141 cmd::CommandId command_id) const {
142 return cmd::GetCommandName(command_id);
145 CommonDecoder::Bucket* CommonDecoder::GetBucket(uint32 bucket_id) const {
146 BucketMap::const_iterator iter(buckets_.find(bucket_id));
147 return iter != buckets_.end() ? &(*iter->second) : NULL;
150 CommonDecoder::Bucket* CommonDecoder::CreateBucket(uint32 bucket_id) {
151 Bucket* bucket = GetBucket(bucket_id);
152 if (!bucket) {
153 bucket = new Bucket();
154 buckets_[bucket_id] = linked_ptr<Bucket>(bucket);
156 return bucket;
159 namespace {
161 // Returns the address of the first byte after a struct.
162 template <typename T>
163 const void* AddressAfterStruct(const T& pod) {
164 return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
167 // Returns the address of the frst byte after the struct.
168 template <typename RETURN_TYPE, typename COMMAND_TYPE>
169 RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod) {
170 return static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod)));
173 } // anonymous namespace.
175 // Decode command with its arguments, and call the corresponding method.
176 // Note: args is a pointer to the command buffer. As such, it could be changed
177 // by a (malicious) client at any time, so if validation has to happen, it
178 // should operate on a copy of them.
179 error::Error CommonDecoder::DoCommonCommand(
180 unsigned int command,
181 unsigned int arg_count,
182 const void* cmd_data) {
183 if (command < arraysize(command_info)) {
184 const CommandInfo& info = command_info[command];
185 unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
186 if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
187 (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
188 uint32 immediate_data_size =
189 (arg_count - info_arg_count) * sizeof(CommandBufferEntry); // NOLINT
190 return (this->*info.cmd_handler)(immediate_data_size, cmd_data);
191 } else {
192 return error::kInvalidArguments;
195 return error::kUnknownCommand;
198 error::Error CommonDecoder::HandleNoop(
199 uint32 immediate_data_size,
200 const void* cmd_data) {
201 return error::kNoError;
204 error::Error CommonDecoder::HandleSetToken(
205 uint32 immediate_data_size,
206 const void* cmd_data) {
207 const cmd::SetToken& args = *static_cast<const cmd::SetToken*>(cmd_data);
208 engine_->set_token(args.token);
209 return error::kNoError;
212 error::Error CommonDecoder::HandleSetBucketSize(
213 uint32 immediate_data_size,
214 const void* cmd_data) {
215 const cmd::SetBucketSize& args =
216 *static_cast<const cmd::SetBucketSize*>(cmd_data);
217 uint32 bucket_id = args.bucket_id;
218 uint32 size = args.size;
220 Bucket* bucket = CreateBucket(bucket_id);
221 bucket->SetSize(size);
222 return error::kNoError;
225 error::Error CommonDecoder::HandleSetBucketData(
226 uint32 immediate_data_size,
227 const void* cmd_data) {
228 const cmd::SetBucketData& args =
229 *static_cast<const cmd::SetBucketData*>(cmd_data);
230 uint32 bucket_id = args.bucket_id;
231 uint32 offset = args.offset;
232 uint32 size = args.size;
233 const void* data = GetSharedMemoryAs<const void*>(
234 args.shared_memory_id, args.shared_memory_offset, size);
235 if (!data) {
236 return error::kInvalidArguments;
238 Bucket* bucket = GetBucket(bucket_id);
239 if (!bucket) {
240 return error::kInvalidArguments;
242 if (!bucket->SetData(data, offset, size)) {
243 return error::kInvalidArguments;
246 return error::kNoError;
249 error::Error CommonDecoder::HandleSetBucketDataImmediate(
250 uint32 immediate_data_size,
251 const void* cmd_data) {
252 const cmd::SetBucketDataImmediate& args =
253 *static_cast<const cmd::SetBucketDataImmediate*>(cmd_data);
254 const void* data = GetImmediateDataAs<const void*>(args);
255 uint32 bucket_id = args.bucket_id;
256 uint32 offset = args.offset;
257 uint32 size = args.size;
258 if (size > immediate_data_size) {
259 return error::kInvalidArguments;
261 Bucket* bucket = GetBucket(bucket_id);
262 if (!bucket) {
263 return error::kInvalidArguments;
265 if (!bucket->SetData(data, offset, size)) {
266 return error::kInvalidArguments;
268 return error::kNoError;
271 error::Error CommonDecoder::HandleGetBucketStart(
272 uint32 immediate_data_size,
273 const void* cmd_data) {
274 const cmd::GetBucketStart& args =
275 *static_cast<const cmd::GetBucketStart*>(cmd_data);
276 uint32 bucket_id = args.bucket_id;
277 uint32* result = GetSharedMemoryAs<uint32*>(
278 args.result_memory_id, args.result_memory_offset, sizeof(*result));
279 int32 data_memory_id = args.data_memory_id;
280 uint32 data_memory_offset = args.data_memory_offset;
281 uint32 data_memory_size = args.data_memory_size;
282 uint8* data = NULL;
283 if (data_memory_size != 0 || data_memory_id != 0 || data_memory_offset != 0) {
284 data = GetSharedMemoryAs<uint8*>(
285 args.data_memory_id, args.data_memory_offset, args.data_memory_size);
286 if (!data) {
287 return error::kInvalidArguments;
290 if (!result) {
291 return error::kInvalidArguments;
293 // Check that the client initialized the result.
294 if (*result != 0) {
295 return error::kInvalidArguments;
297 Bucket* bucket = GetBucket(bucket_id);
298 if (!bucket) {
299 return error::kInvalidArguments;
301 uint32 bucket_size = bucket->size();
302 *result = bucket_size;
303 if (data) {
304 uint32 size = std::min(data_memory_size, bucket_size);
305 memcpy(data, bucket->GetData(0, size), size);
307 return error::kNoError;
310 error::Error CommonDecoder::HandleGetBucketData(
311 uint32 immediate_data_size,
312 const void* cmd_data) {
313 const cmd::GetBucketData& args =
314 *static_cast<const cmd::GetBucketData*>(cmd_data);
315 uint32 bucket_id = args.bucket_id;
316 uint32 offset = args.offset;
317 uint32 size = args.size;
318 void* data = GetSharedMemoryAs<void*>(
319 args.shared_memory_id, args.shared_memory_offset, size);
320 if (!data) {
321 return error::kInvalidArguments;
323 Bucket* bucket = GetBucket(bucket_id);
324 if (!bucket) {
325 return error::kInvalidArguments;
327 const void* src = bucket->GetData(offset, size);
328 if (!src) {
329 return error::kInvalidArguments;
331 memcpy(data, src, size);
332 return error::kNoError;
335 } // namespace gpu