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"
12 const CommonDecoder::CommandInfo
CommonDecoder::command_info
[] = {
13 #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
15 &CommonDecoder::Handle##name, cmd::name::kArgFlags, \
16 cmd::name::cmd_flags, \
17 sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, \
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
;
36 void CommonDecoder::Bucket::SetSize(size_t size
) {
38 data_
.reset(size
? new int8
[size
] : NULL
);
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
);
53 void CommonDecoder::Bucket::SetFromString(const char* str
) {
54 // Strings are passed NULL terminated to distinguish between empty string
59 size_t size
= strlen(str
) + 1;
61 SetData(str
, 0, size
);
65 bool CommonDecoder::Bucket::GetAsString(std::string
* str
) {
70 str
->assign(GetDataAs
<const char*>(0, size_
- 1), size_
- 1);
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
) {
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]);
89 const size_t max_count
= (bucket_size
- kMinBucketSize
) / kMinStringSize
;
90 if (max_count
< static_cast<size_t>(count
)) {
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())
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) {
108 if (total_size
.ValueOrDefault(0) != bucket_size
) {
111 DCHECK(_count
&& _string
&& _length
);
114 _length
->resize(count
);
115 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
116 (*_length
)[ii
] = length
[ii
];
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
) {
129 scoped_refptr
<gpu::Buffer
> buffer
= engine_
->GetSharedMemoryBuffer(shm_id
);
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
);
153 bucket
= new Bucket();
154 buckets_
[bucket_id
] = linked_ptr
<Bucket
>(bucket
);
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
);
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
);
236 return error::kInvalidArguments
;
238 Bucket
* bucket
= GetBucket(bucket_id
);
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
);
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
;
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
);
287 return error::kInvalidArguments
;
291 return error::kInvalidArguments
;
293 // Check that the client initialized the result.
295 return error::kInvalidArguments
;
297 Bucket
* bucket
= GetBucket(bucket_id
);
299 return error::kInvalidArguments
;
301 uint32 bucket_size
= bucket
->size();
302 *result
= bucket_size
;
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
);
321 return error::kInvalidArguments
;
323 Bucket
* bucket
= GetBucket(bucket_id
);
325 return error::kInvalidArguments
;
327 const void* src
= bucket
->GetData(offset
, size
);
329 return error::kInvalidArguments
;
331 memcpy(data
, src
, size
);
332 return error::kNoError
;