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 12namespace gpu { 13 14CommandParser::CommandParser(AsyncAPIInterface* handler) 15 : get_(0), 16 put_(0), 17 buffer_(NULL), 18 entry_count_(0), 19 handler_(handler) { 20} 21 22void 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. 47error::Error CommandParser::ProcessCommand() { 48 CommandBufferOffset get = get_; 49 if (get == put_) 50 return error::kNoError; 51 52 CommandHeader header = buffer_[get].value_header; 53 if (header.size == 0) { 54 DVLOG(1) << "Error: zero sized command in command buffer"; 55 return error::kInvalidSize; 56 } 57 58 if (static_cast<int>(header.size) + get > entry_count_) { 59 DVLOG(1) << "Error: get offset out of bounds"; 60 return error::kOutOfBounds; 61 } 62 63 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cb_command"), 64 handler_->GetCommandName(header.command)); 65 66 error::Error result = handler_->DoCommand( 67 header.command, header.size - 1, buffer_ + get); 68 69 // TODO(gman): If you want to log errors this is the best place to catch them. 70 // It seems like we need an official way to turn on a debug mode and 71 // get these errors. 72 if (error::IsError(result)) { 73 ReportError(header.command, result); 74 } 75 76 // If get was not set somewhere else advance it. 77 if (get == get_ && result != error::kDeferCommandUntilLater) 78 get_ = (get + header.size) % entry_count_; 79 80 return result; 81} 82 83void CommandParser::ReportError(unsigned int command_id, 84 error::Error result) { 85 DVLOG(1) << "Error: " << result << " for Command " 86 << handler_->GetCommandName(command_id); 87} 88 89// Processes all the commands, while the buffer is not empty. Stop if an error 90// is encountered. 91error::Error CommandParser::ProcessAllCommands() { 92 while (!IsEmpty()) { 93 error::Error error = ProcessCommand(); 94 if (error) 95 return error; 96 } 97 return error::kNoError; 98} 99 100} // namespace gpu 101