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 // This file contains the implementation of the command parser. 6 7 #include "gpu/command_buffer/service/cmd_parser.h" 8 9 #include "base/logging.h" 10 #include "base/debug/trace_event.h" 11 12 namespace gpu { 13 14 CommandParser::CommandParser(AsyncAPIInterface* handler) 15 : get_(0), 16 put_(0), 17 buffer_(NULL), 18 entry_count_(0), 19 handler_(handler) { 20 } 21 22 void CommandParser::SetBuffer( 23 void* shm_address, 24 size_t shm_size, 25 ptrdiff_t offset, 26 size_t size) { 27 // check proper alignments. 28 DCHECK_EQ(0, (reinterpret_cast<intptr_t>(shm_address)) % 4); 29 DCHECK_EQ(0, offset % 4); 30 DCHECK_EQ(0u, size % 4); 31 // check that the command buffer fits into the memory buffer. 32 DCHECK_GE(shm_size, offset + size); 33 get_ = 0; 34 put_ = 0; 35 char* buffer_begin = static_cast<char*>(shm_address) + offset; 36 buffer_ = reinterpret_cast<CommandBufferEntry*>(buffer_begin); 37 entry_count_ = size / 4; 38 } 39 40 // Process one command, reading the header from the command buffer, and 41 // forwarding the command index and the arguments to the handler. 42 // Note that: 43 // - validation needs to happen on a copy of the data (to avoid race 44 // conditions). This function only validates the header, leaving the arguments 45 // validation to the handler, so it can pass a reference to them. 46 // - get_ is modified *after* the command has been executed. 47 error::Error CommandParser::ProcessCommands(int num_commands) { 48 int num_entries = put_ < get_ ? entry_count_ - get_ : put_ - get_; 49 int entries_processed = 0; 50 51 error::Error result = handler_->DoCommands( 52 num_commands, buffer_ + get_, num_entries, &entries_processed); 53 54 get_ += entries_processed; 55 if (get_ == entry_count_) 56 get_ = 0; 57 58 return result; 59 } 60 61 // Processes all the commands, while the buffer is not empty. Stop if an error 62 // is encountered. 63 error::Error CommandParser::ProcessAllCommands() { 64 while (!IsEmpty()) { 65 error::Error error = ProcessCommands(kParseCommandsSlice); 66 if (error) 67 return error; 68 } 69 return error::kNoError; 70 } 71 72 // Decode multiple commands, and call the corresponding GL functions. 73 // NOTE: buffer is a pointer to the command buffer. As such, it could be 74 // changed by a (malicious) client at any time, so if validation has to happen, 75 // it should operate on a copy of them. 76 error::Error AsyncAPIInterface::DoCommands(unsigned int num_commands, 77 const void* buffer, 78 int num_entries, 79 int* entries_processed) { 80 int commands_to_process = num_commands; 81 error::Error result = error::kNoError; 82 const CommandBufferEntry* cmd_data = 83 static_cast<const CommandBufferEntry*>(buffer); 84 int process_pos = 0; 85 86 while (process_pos < num_entries && result == error::kNoError && 87 commands_to_process--) { 88 CommandHeader header = cmd_data->value_header; 89 if (header.size == 0) { 90 DVLOG(1) << "Error: zero sized command in command buffer"; 91 return error::kInvalidSize; 92 } 93 94 if (static_cast<int>(header.size) + process_pos > num_entries) { 95 DVLOG(1) << "Error: get offset out of bounds"; 96 return error::kOutOfBounds; 97 } 98 99 const unsigned int command = header.command; 100 const unsigned int arg_count = header.size - 1; 101 102 result = DoCommand(command, arg_count, cmd_data); 103 104 if (result != error::kDeferCommandUntilLater) { 105 process_pos += header.size; 106 cmd_data += header.size; 107 } 108 } 109 110 if (entries_processed) 111 *entries_processed = process_pos; 112 113 return result; 114 } 115 116 } // namespace gpu 117