summaryrefslogtreecommitdiff
path: root/chromium/gpu/command_buffer/service/common_decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/gpu/command_buffer/service/common_decoder.cc')
-rw-r--r--chromium/gpu/command_buffer/service/common_decoder.cc292
1 files changed, 292 insertions, 0 deletions
diff --git a/chromium/gpu/command_buffer/service/common_decoder.cc b/chromium/gpu/command_buffer/service/common_decoder.cc
new file mode 100644
index 00000000000..72f30a30bfc
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/common_decoder.cc
@@ -0,0 +1,292 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+
+namespace gpu {
+
+CommonDecoder::Bucket::Bucket() : size_(0) {}
+
+CommonDecoder::Bucket::~Bucket() {}
+
+void* CommonDecoder::Bucket::GetData(size_t offset, size_t size) const {
+ if (OffsetSizeValid(offset, size)) {
+ return data_.get() + offset;
+ }
+ return NULL;
+}
+
+void CommonDecoder::Bucket::SetSize(size_t size) {
+ if (size != size_) {
+ data_.reset(size ? new int8[size] : NULL);
+ size_ = size;
+ memset(data_.get(), 0, size);
+ }
+}
+
+bool CommonDecoder::Bucket::SetData(
+ const void* src, size_t offset, size_t size) {
+ if (OffsetSizeValid(offset, size)) {
+ memcpy(data_.get() + offset, src, size);
+ return true;
+ }
+ return false;
+}
+
+void CommonDecoder::Bucket::SetFromString(const char* str) {
+ // Strings are passed NULL terminated to distinguish between empty string
+ // and no string.
+ if (!str) {
+ SetSize(0);
+ } else {
+ size_t size = strlen(str) + 1;
+ SetSize(size);
+ SetData(str, 0, size);
+ }
+}
+
+bool CommonDecoder::Bucket::GetAsString(std::string* str) {
+ DCHECK(str);
+ if (size_ == 0) {
+ return false;
+ }
+ str->assign(GetDataAs<const char*>(0, size_ - 1), size_ - 1);
+ return true;
+}
+
+CommonDecoder::CommonDecoder() : engine_(NULL) {}
+
+CommonDecoder::~CommonDecoder() {}
+
+void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
+ unsigned int offset,
+ unsigned int size) {
+ CHECK(engine_);
+ Buffer buffer = engine_->GetSharedMemoryBuffer(shm_id);
+ if (!buffer.ptr)
+ return NULL;
+ unsigned int end = offset + size;
+ if (end > buffer.size || end < offset) {
+ return NULL;
+ }
+ return static_cast<int8*>(buffer.ptr) + offset;
+}
+
+Buffer CommonDecoder::GetSharedMemoryBuffer(unsigned int shm_id) {
+ return engine_->GetSharedMemoryBuffer(shm_id);
+}
+
+const char* CommonDecoder::GetCommonCommandName(
+ cmd::CommandId command_id) const {
+ return cmd::GetCommandName(command_id);
+}
+
+CommonDecoder::Bucket* CommonDecoder::GetBucket(uint32 bucket_id) const {
+ BucketMap::const_iterator iter(buckets_.find(bucket_id));
+ return iter != buckets_.end() ? &(*iter->second) : NULL;
+}
+
+CommonDecoder::Bucket* CommonDecoder::CreateBucket(uint32 bucket_id) {
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ bucket = new Bucket();
+ buckets_[bucket_id] = linked_ptr<Bucket>(bucket);
+ }
+ return bucket;
+}
+
+namespace {
+
+// Returns the address of the first byte after a struct.
+template <typename T>
+const void* AddressAfterStruct(const T& pod) {
+ return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
+}
+
+// Returns the address of the frst byte after the struct.
+template <typename RETURN_TYPE, typename COMMAND_TYPE>
+RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod) {
+ return static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod)));
+}
+
+// A struct to hold info about each command.
+struct CommandInfo {
+ int arg_flags; // How to handle the arguments for this command
+ int arg_count; // How many arguments are expected for this command.
+};
+
+// A table of CommandInfo for all the commands.
+const CommandInfo g_command_info[] = {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) { \
+ cmd::name::kArgFlags, \
+ sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+};
+
+} // anonymous namespace.
+
+// Decode command with its arguments, and call the corresponding method.
+// Note: args is a pointer to the command buffer. As such, it could be changed
+// by a (malicious) client at any time, so if validation has to happen, it
+// should operate on a copy of them.
+error::Error CommonDecoder::DoCommonCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) {
+ if (command < arraysize(g_command_info)) {
+ const CommandInfo& info = g_command_info[command];
+ unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
+ if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
+ (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
+ uint32 immediate_data_size =
+ (arg_count - info_arg_count) * sizeof(CommandBufferEntry); // NOLINT
+ switch (command) {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
+ case cmd::name::kCmdId: \
+ return Handle ## name( \
+ immediate_data_size, \
+ *static_cast<const cmd::name*>(cmd_data)); \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+ }
+ } else {
+ return error::kInvalidArguments;
+ }
+ }
+ return error::kUnknownCommand;
+}
+
+error::Error CommonDecoder::HandleNoop(
+ uint32 immediate_data_size,
+ const cmd::Noop& args) {
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetToken(
+ uint32 immediate_data_size,
+ const cmd::SetToken& args) {
+ engine_->set_token(args.token);
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetBucketSize(
+ uint32 immediate_data_size,
+ const cmd::SetBucketSize& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32 size = args.size;
+
+ Bucket* bucket = CreateBucket(bucket_id);
+ bucket->SetSize(size);
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetBucketData(
+ uint32 immediate_data_size,
+ const cmd::SetBucketData& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32 offset = args.offset;
+ uint32 size = args.size;
+ const void* data = GetSharedMemoryAs<const void*>(
+ args.shared_memory_id, args.shared_memory_offset, size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ if (!bucket->SetData(data, offset, size)) {
+ return error::kInvalidArguments;
+ }
+
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetBucketDataImmediate(
+ uint32 immediate_data_size,
+ const cmd::SetBucketDataImmediate& args) {
+ const void* data = GetImmediateDataAs<const void*>(args);
+ uint32 bucket_id = args.bucket_id;
+ uint32 offset = args.offset;
+ uint32 size = args.size;
+ if (size > immediate_data_size) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ if (!bucket->SetData(data, offset, size)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleGetBucketStart(
+ uint32 immediate_data_size,
+ const cmd::GetBucketStart& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32* result = GetSharedMemoryAs<uint32*>(
+ args.result_memory_id, args.result_memory_offset, sizeof(*result));
+ int32 data_memory_id = args.data_memory_id;
+ uint32 data_memory_offset = args.data_memory_offset;
+ uint32 data_memory_size = args.data_memory_size;
+ uint8* data = NULL;
+ if (data_memory_size != 0 || data_memory_id != 0 || data_memory_offset != 0) {
+ data = GetSharedMemoryAs<uint8*>(
+ args.data_memory_id, args.data_memory_offset, args.data_memory_size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ }
+ if (!result) {
+ return error::kInvalidArguments;
+ }
+ // Check that the client initialized the result.
+ if (*result != 0) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ uint32 bucket_size = bucket->size();
+ *result = bucket_size;
+ if (data) {
+ uint32 size = std::min(data_memory_size, bucket_size);
+ memcpy(data, bucket->GetData(0, size), size);
+ }
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleGetBucketData(
+ uint32 immediate_data_size,
+ const cmd::GetBucketData& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32 offset = args.offset;
+ uint32 size = args.size;
+ void* data = GetSharedMemoryAs<void*>(
+ args.shared_memory_id, args.shared_memory_offset, size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ const void* src = bucket->GetData(offset, size);
+ if (!src) {
+ return error::kInvalidArguments;
+ }
+ memcpy(data, src, size);
+ return error::kNoError;
+}
+
+} // namespace gpu