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