• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CommandParser(AsyncAPIInterface * handler)14 CommandParser::CommandParser(AsyncAPIInterface* handler)
15     : get_(0),
16       put_(0),
17       buffer_(NULL),
18       entry_count_(0),
19       handler_(handler) {
20 }
21 
SetBuffer(void * shm_address,size_t shm_size,ptrdiff_t offset,size_t size)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.
ProcessCommand()47 error::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 
ReportError(unsigned int command_id,error::Error result)83 void 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.
ProcessAllCommands()91 error::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