cmd_parser.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// Use of this source code is governed by a BSD-style license that can be 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// found in the LICENSE file. 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// This file contains the implementation of the command parser. 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "gpu/command_buffer/service/cmd_parser.h" 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "base/logging.h" 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "base/command_line.h" 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "base/debug/trace_event.h" 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "gpu/command_buffer/service/gpu_switches.h" 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectnamespace gpu { 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source ProjectCommandParser::CommandParser(AsyncAPIInterface* handler) 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project : get_(0), 18f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson put_(0), 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project buffer_(NULL), 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project entry_count_(0), 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project handler_(handler), 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project trace_gl_commands_(false) { 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project trace_gl_commands_ = 24f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceGL); 25f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson} 26f921579f87fa63204b4a4bef39ed27e7835aec45Jesse Wilson 27b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubinvoid CommandParser::SetBuffer( 28b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin void* shm_address, 29b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin size_t shm_size, 30b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin ptrdiff_t offset, 31b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin size_t size) { 32b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin // check proper alignments. 33b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin DCHECK_EQ(0, (reinterpret_cast<intptr_t>(shm_address)) % 4); 34b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin DCHECK_EQ(0, offset % 4); 35b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin DCHECK_EQ(0u, size % 4); 36b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin // check that the command buffer fits into the memory buffer. 37b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin DCHECK_GE(shm_size, offset + size); 38b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin get_ = 0; 39b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin put_ = 0; 40b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin char* buffer_begin = static_cast<char*>(shm_address) + offset; 41b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin buffer_ = reinterpret_cast<CommandBufferEntry*>(buffer_begin); 42b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin entry_count_ = size / 4; 43b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin} 44b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 45b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin// Process one command, reading the header from the command buffer, and 46b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin// forwarding the command index and the arguments to the handler. 47b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin// Note that: 48b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin// - validation needs to happen on a copy of the data (to avoid race 49b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin// conditions). This function only validates the header, leaving the arguments 50b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin// validation to the handler, so it can pass a reference to them. 51024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin// - get_ is modified *after* the command has been executed. 52024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubinerror::Error CommandParser::ProcessCommand() { 53024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin CommandBufferOffset get = get_; 54024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin if (get == put_) 55024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin return error::kNoError; 56024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin 57024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin CommandHeader header = buffer_[get].value_header; 58024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin if (header.size == 0) { 59024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin DVLOG(1) << "Error: zero sized command in command buffer"; 60024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin return error::kInvalidSize; 61b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin } 62b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 63b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin if (static_cast<int>(header.size) + get > entry_count_) { 64b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin DVLOG(1) << "Error: get offset out of bounds"; 65b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin return error::kOutOfBounds; 66b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin } 67b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 68b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin if (trace_gl_commands_) 69b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin TRACE_EVENT_BEGIN0("cb_command", handler_->GetCommandName(header.command)); 70b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 71b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin error::Error result = handler_->DoCommand( 72b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin header.command, header.size - 1, buffer_ + get); 73b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 74b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin // TODO(gman): If you want to log errors this is the best place to catch them. 75024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin // It seems like we need an official way to turn on a debug mode and 76b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin // get these errors. 77024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin if (error::IsError(result)) { 78b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin ReportError(header.command, result); 79b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin } 80024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin 81b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin // If get was not set somewhere else advance it. 82024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin if (get == get_ && result != error::kDeferCommandUntilLater) 83b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin get_ = (get + header.size) % entry_count_; 84b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 85024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin if (trace_gl_commands_) 86b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin TRACE_EVENT_END0("cb_command", handler_->GetCommandName(header.command)); 87024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin return result; 88b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin} 89b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 90024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubinvoid CommandParser::ReportError(unsigned int command_id, 91b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin error::Error result) { 92024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin DVLOG(1) << "Error: " << result << " for Command " 93b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin << handler_->GetCommandName(command_id); 94b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin} 95024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin 96b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin// Processes all the commands, while the buffer is not empty. Stop if an error 97024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin// is encountered. 98b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubinerror::Error CommandParser::ProcessAllCommands() { 99b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin while (!IsEmpty()) { 100024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin error::Error error = ProcessCommand(); 101b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin if (error) 102b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin return error; 103b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin } 104b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin return error::kNoError; 105024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin} 106b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin 107024b80ccf9d9f2dc3b1527cfc46d28bfb2ba0d6dAlex Klyubin} // namespace gpu 108b4675a53abbbb55acad213485636cf6a0d8b5bf6Alex Klyubin