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"
6 #include "gpu/command_buffer/service/cmd_buffer_engine.h"
10 const CommonDecoder::CommandInfo
CommonDecoder::command_info
[] = {
11 #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
13 &CommonDecoder::Handle##name, cmd::name::kArgFlags, \
14 cmd::name::cmd_flags, \
15 sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, \
18 COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP
)
19 #undef COMMON_COMMAND_BUFFER_CMD_OP
23 CommonDecoder::Bucket::Bucket() : size_(0) {}
25 CommonDecoder::Bucket::~Bucket() {}
27 void* CommonDecoder::Bucket::GetData(size_t offset
, size_t size
) const {
28 if (OffsetSizeValid(offset
, size
)) {
29 return data_
.get() + offset
;
34 void CommonDecoder::Bucket::SetSize(size_t size
) {
36 data_
.reset(size
? new int8
[size
] : NULL
);
38 memset(data_
.get(), 0, size
);
42 bool CommonDecoder::Bucket::SetData(
43 const void* src
, size_t offset
, size_t size
) {
44 if (OffsetSizeValid(offset
, size
)) {
45 memcpy(data_
.get() + offset
, src
, size
);
51 void CommonDecoder::Bucket::SetFromString(const char* str
) {
52 // Strings are passed NULL terminated to distinguish between empty string
57 size_t size
= strlen(str
) + 1;
59 SetData(str
, 0, size
);
63 bool CommonDecoder::Bucket::GetAsString(std::string
* str
) {
68 str
->assign(GetDataAs
<const char*>(0, size_
- 1), size_
- 1);
72 CommonDecoder::CommonDecoder() : engine_(NULL
) {}
74 CommonDecoder::~CommonDecoder() {}
76 void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id
,
77 unsigned int data_offset
,
78 unsigned int data_size
) {
80 scoped_refptr
<gpu::Buffer
> buffer
= engine_
->GetSharedMemoryBuffer(shm_id
);
83 return buffer
->GetDataAddress(data_offset
, data_size
);
86 scoped_refptr
<gpu::Buffer
> CommonDecoder::GetSharedMemoryBuffer(
87 unsigned int shm_id
) {
88 return engine_
->GetSharedMemoryBuffer(shm_id
);
91 const char* CommonDecoder::GetCommonCommandName(
92 cmd::CommandId command_id
) const {
93 return cmd::GetCommandName(command_id
);
96 CommonDecoder::Bucket
* CommonDecoder::GetBucket(uint32 bucket_id
) const {
97 BucketMap::const_iterator
iter(buckets_
.find(bucket_id
));
98 return iter
!= buckets_
.end() ? &(*iter
->second
) : NULL
;
101 CommonDecoder::Bucket
* CommonDecoder::CreateBucket(uint32 bucket_id
) {
102 Bucket
* bucket
= GetBucket(bucket_id
);
104 bucket
= new Bucket();
105 buckets_
[bucket_id
] = linked_ptr
<Bucket
>(bucket
);
112 // Returns the address of the first byte after a struct.
113 template <typename T
>
114 const void* AddressAfterStruct(const T
& pod
) {
115 return reinterpret_cast<const uint8
*>(&pod
) + sizeof(pod
);
118 // Returns the address of the frst byte after the struct.
119 template <typename RETURN_TYPE
, typename COMMAND_TYPE
>
120 RETURN_TYPE
GetImmediateDataAs(const COMMAND_TYPE
& pod
) {
121 return static_cast<RETURN_TYPE
>(const_cast<void*>(AddressAfterStruct(pod
)));
124 } // anonymous namespace.
126 // Decode command with its arguments, and call the corresponding method.
127 // Note: args is a pointer to the command buffer. As such, it could be changed
128 // by a (malicious) client at any time, so if validation has to happen, it
129 // should operate on a copy of them.
130 error::Error
CommonDecoder::DoCommonCommand(
131 unsigned int command
,
132 unsigned int arg_count
,
133 const void* cmd_data
) {
134 if (command
< arraysize(command_info
)) {
135 const CommandInfo
& info
= command_info
[command
];
136 unsigned int info_arg_count
= static_cast<unsigned int>(info
.arg_count
);
137 if ((info
.arg_flags
== cmd::kFixed
&& arg_count
== info_arg_count
) ||
138 (info
.arg_flags
== cmd::kAtLeastN
&& arg_count
>= info_arg_count
)) {
139 uint32 immediate_data_size
=
140 (arg_count
- info_arg_count
) * sizeof(CommandBufferEntry
); // NOLINT
141 return (this->*info
.cmd_handler
)(immediate_data_size
, cmd_data
);
143 return error::kInvalidArguments
;
146 return error::kUnknownCommand
;
149 error::Error
CommonDecoder::HandleNoop(
150 uint32 immediate_data_size
,
151 const void* cmd_data
) {
152 return error::kNoError
;
155 error::Error
CommonDecoder::HandleSetToken(
156 uint32 immediate_data_size
,
157 const void* cmd_data
) {
158 const cmd::SetToken
& args
= *static_cast<const cmd::SetToken
*>(cmd_data
);
159 engine_
->set_token(args
.token
);
160 return error::kNoError
;
163 error::Error
CommonDecoder::HandleSetBucketSize(
164 uint32 immediate_data_size
,
165 const void* cmd_data
) {
166 const cmd::SetBucketSize
& args
=
167 *static_cast<const cmd::SetBucketSize
*>(cmd_data
);
168 uint32 bucket_id
= args
.bucket_id
;
169 uint32 size
= args
.size
;
171 Bucket
* bucket
= CreateBucket(bucket_id
);
172 bucket
->SetSize(size
);
173 return error::kNoError
;
176 error::Error
CommonDecoder::HandleSetBucketData(
177 uint32 immediate_data_size
,
178 const void* cmd_data
) {
179 const cmd::SetBucketData
& args
=
180 *static_cast<const cmd::SetBucketData
*>(cmd_data
);
181 uint32 bucket_id
= args
.bucket_id
;
182 uint32 offset
= args
.offset
;
183 uint32 size
= args
.size
;
184 const void* data
= GetSharedMemoryAs
<const void*>(
185 args
.shared_memory_id
, args
.shared_memory_offset
, size
);
187 return error::kInvalidArguments
;
189 Bucket
* bucket
= GetBucket(bucket_id
);
191 return error::kInvalidArguments
;
193 if (!bucket
->SetData(data
, offset
, size
)) {
194 return error::kInvalidArguments
;
197 return error::kNoError
;
200 error::Error
CommonDecoder::HandleSetBucketDataImmediate(
201 uint32 immediate_data_size
,
202 const void* cmd_data
) {
203 const cmd::SetBucketDataImmediate
& args
=
204 *static_cast<const cmd::SetBucketDataImmediate
*>(cmd_data
);
205 const void* data
= GetImmediateDataAs
<const void*>(args
);
206 uint32 bucket_id
= args
.bucket_id
;
207 uint32 offset
= args
.offset
;
208 uint32 size
= args
.size
;
209 if (size
> immediate_data_size
) {
210 return error::kInvalidArguments
;
212 Bucket
* bucket
= GetBucket(bucket_id
);
214 return error::kInvalidArguments
;
216 if (!bucket
->SetData(data
, offset
, size
)) {
217 return error::kInvalidArguments
;
219 return error::kNoError
;
222 error::Error
CommonDecoder::HandleGetBucketStart(
223 uint32 immediate_data_size
,
224 const void* cmd_data
) {
225 const cmd::GetBucketStart
& args
=
226 *static_cast<const cmd::GetBucketStart
*>(cmd_data
);
227 uint32 bucket_id
= args
.bucket_id
;
228 uint32
* result
= GetSharedMemoryAs
<uint32
*>(
229 args
.result_memory_id
, args
.result_memory_offset
, sizeof(*result
));
230 int32 data_memory_id
= args
.data_memory_id
;
231 uint32 data_memory_offset
= args
.data_memory_offset
;
232 uint32 data_memory_size
= args
.data_memory_size
;
234 if (data_memory_size
!= 0 || data_memory_id
!= 0 || data_memory_offset
!= 0) {
235 data
= GetSharedMemoryAs
<uint8
*>(
236 args
.data_memory_id
, args
.data_memory_offset
, args
.data_memory_size
);
238 return error::kInvalidArguments
;
242 return error::kInvalidArguments
;
244 // Check that the client initialized the result.
246 return error::kInvalidArguments
;
248 Bucket
* bucket
= GetBucket(bucket_id
);
250 return error::kInvalidArguments
;
252 uint32 bucket_size
= bucket
->size();
253 *result
= bucket_size
;
255 uint32 size
= std::min(data_memory_size
, bucket_size
);
256 memcpy(data
, bucket
->GetData(0, size
), size
);
258 return error::kNoError
;
261 error::Error
CommonDecoder::HandleGetBucketData(
262 uint32 immediate_data_size
,
263 const void* cmd_data
) {
264 const cmd::GetBucketData
& args
=
265 *static_cast<const cmd::GetBucketData
*>(cmd_data
);
266 uint32 bucket_id
= args
.bucket_id
;
267 uint32 offset
= args
.offset
;
268 uint32 size
= args
.size
;
269 void* data
= GetSharedMemoryAs
<void*>(
270 args
.shared_memory_id
, args
.shared_memory_offset
, size
);
272 return error::kInvalidArguments
;
274 Bucket
* bucket
= GetBucket(bucket_id
);
276 return error::kInvalidArguments
;
278 const void* src
= bucket
->GetData(offset
, size
);
280 return error::kInvalidArguments
;
282 memcpy(data
, src
, size
);
283 return error::kNoError
;