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.
ProcessCommands(int num_commands)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.
ProcessAllCommands()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.
DoCommands(unsigned int num_commands,const void * buffer,int num_entries,int * entries_processed)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