Home | History | Annotate | Download | only in service
      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 
     14 CommandParser::CommandParser(AsyncAPIInterface* handler)
     15     : get_(0),
     16       put_(0),
     17       buffer_(NULL),
     18       entry_count_(0),
     19       handler_(handler) {
     20 }
     21 
     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.
     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.
     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.
     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