| 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 |