OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file contains the implementation of the command parser. | 5 // This file contains the implementation of the command parser. |
6 | 6 |
7 #include "gpu/command_buffer/service/cmd_parser.h" | 7 #include "gpu/command_buffer/service/cmd_parser.h" |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 26 matching lines...) Expand all Loading... |
37 entry_count_ = size / 4; | 37 entry_count_ = size / 4; |
38 } | 38 } |
39 | 39 |
40 // Process one command, reading the header from the command buffer, and | 40 // Process one command, reading the header from the command buffer, and |
41 // forwarding the command index and the arguments to the handler. | 41 // forwarding the command index and the arguments to the handler. |
42 // Note that: | 42 // Note that: |
43 // - validation needs to happen on a copy of the data (to avoid race | 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 | 44 // conditions). This function only validates the header, leaving the arguments |
45 // validation to the handler, so it can pass a reference to them. | 45 // validation to the handler, so it can pass a reference to them. |
46 // - get_ is modified *after* the command has been executed. | 46 // - get_ is modified *after* the command has been executed. |
47 error::Error CommandParser::ProcessCommand() { | 47 error::Error CommandParser::ProcessCommands(int num_commands) { |
48 CommandBufferOffset get = get_; | 48 int num_entries = put_ < get_ ? entry_count_ - get_ : put_ - get_; |
49 if (get == put_) | 49 int entries_processed = 0; |
50 return error::kNoError; | |
51 | 50 |
52 CommandHeader header = buffer_[get].value_header; | 51 error::Error result = handler_->DoCommands( |
53 if (header.size == 0) { | 52 num_commands, buffer_ + get_, num_entries, &entries_processed); |
54 LOG(ERROR) << "Parse error: zero sized command in command buffer"; | |
55 return error::kInvalidSize; | |
56 } | |
57 | 53 |
58 if (static_cast<int>(header.size) + get > entry_count_) { | 54 get_ += entries_processed; |
59 LOG(ERROR) << "Parse error: get offset out of bounds"; | 55 if (get_ == entry_count_) |
60 return error::kOutOfBounds; | 56 get_ = 0; |
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 if (error::IsError(result)) { | |
70 ReportError(header.command, result); | |
71 } | |
72 | |
73 // If get was not set somewhere else advance it. | |
74 if (get == get_ && result != error::kDeferCommandUntilLater) | |
75 get_ = (get + header.size) % entry_count_; | |
76 | 57 |
77 return result; | 58 return result; |
78 } | 59 } |
79 | 60 |
80 void CommandParser::ReportError(unsigned int command_id, | |
81 error::Error result) { | |
82 LOG(ERROR) << "Error: " << result << " for Command " | |
83 << handler_->GetCommandName(command_id); | |
84 } | |
85 | |
86 // Processes all the commands, while the buffer is not empty. Stop if an error | 61 // Processes all the commands, while the buffer is not empty. Stop if an error |
87 // is encountered. | 62 // is encountered. |
88 error::Error CommandParser::ProcessAllCommands() { | 63 error::Error CommandParser::ProcessAllCommands() { |
89 while (!IsEmpty()) { | 64 while (!IsEmpty()) { |
90 error::Error error = ProcessCommand(); | 65 error::Error error = ProcessCommands(kParseCommandsSlice); |
91 if (error) | 66 if (error) |
92 return error; | 67 return error; |
93 } | 68 } |
94 return error::kNoError; | 69 return error::kNoError; |
95 } | 70 } |
96 | 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. |
| 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 |
97 } // namespace gpu | 116 } // namespace gpu |
OLD | NEW |