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.
5 // This file contains the implementation of the command parser.
7 #include "gpu/command_buffer/service/cmd_parser.h"
9 #include "base/logging.h"
10 #include "base/trace_event/trace_event.h"
14 CommandParser::CommandParser(AsyncAPIInterface
* handler
)
22 void CommandParser::SetBuffer(
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
);
35 char* buffer_begin
= static_cast<char*>(shm_address
) + offset
;
36 buffer_
= reinterpret_cast<CommandBufferEntry
*>(buffer_begin
);
37 entry_count_
= size
/ 4;
40 // Process one command, reading the header from the command buffer, and
41 // forwarding the command index and the arguments to the handler.
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.
47 error::Error
CommandParser::ProcessCommands(int num_commands
) {
48 int num_entries
= put_
< get_
? entry_count_
- get_
: put_
- get_
;
49 int entries_processed
= 0;
51 error::Error result
= handler_
->DoCommands(
52 num_commands
, buffer_
+ get_
, num_entries
, &entries_processed
);
54 get_
+= entries_processed
;
55 if (get_
== entry_count_
)
61 // Processes all the commands, while the buffer is not empty. Stop if an error
63 error::Error
CommandParser::ProcessAllCommands() {
65 error::Error error
= ProcessCommands(kParseCommandsSlice
);
69 return error::kNoError
;
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
,
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
);
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
;
94 if (static_cast<int>(header
.size
) + process_pos
> num_entries
) {
95 DVLOG(1) << "Error: get offset out of bounds";
96 return error::kOutOfBounds
;
99 const unsigned int command
= header
.command
;
100 const unsigned int arg_count
= header
.size
- 1;
102 result
= DoCommand(command
, arg_count
, cmd_data
);
104 if (result
!= error::kDeferCommandUntilLater
) {
105 process_pos
+= header
.size
;
106 cmd_data
+= header
.size
;
110 if (entries_processed
)
111 *entries_processed
= process_pos
;