|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "gpu/command_buffer/service/command_executor.h" | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/command_line.h" | 
|  | #include "base/compiler_specific.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/time/time.h" | 
|  | #include "base/trace_event/trace_event.h" | 
|  | #include "gpu/command_buffer/service/logger.h" | 
|  | #include "ui/gl/gl_bindings.h" | 
|  | #include "ui/gl/gl_fence.h" | 
|  | #include "ui/gl/gl_switches.h" | 
|  |  | 
|  | using ::base::SharedMemory; | 
|  |  | 
|  | namespace gpu { | 
|  |  | 
|  | CommandExecutor::CommandExecutor(CommandBufferServiceBase* command_buffer, | 
|  | AsyncAPIInterface* handler, | 
|  | gles2::GLES2Decoder* decoder) | 
|  | : command_buffer_(command_buffer), | 
|  | handler_(handler), | 
|  | decoder_(decoder), | 
|  | scheduled_(true), | 
|  | was_preempted_(false) {} | 
|  |  | 
|  | CommandExecutor::~CommandExecutor() {} | 
|  |  | 
|  | void CommandExecutor::PutChanged() { | 
|  | TRACE_EVENT1("gpu", "CommandExecutor:PutChanged", "decoder", | 
|  | decoder_ ? decoder_->GetLogger()->GetLogPrefix() : "None"); | 
|  |  | 
|  | CommandBuffer::State state = command_buffer_->GetLastState(); | 
|  |  | 
|  | // If there is no parser, exit. | 
|  | if (!parser_.get()) { | 
|  | DCHECK_EQ(state.get_offset, command_buffer_->GetPutOffset()); | 
|  | return; | 
|  | } | 
|  |  | 
|  | parser_->set_put(command_buffer_->GetPutOffset()); | 
|  | if (state.error != error::kNoError) | 
|  | return; | 
|  |  | 
|  | base::TimeTicks begin_time(base::TimeTicks::Now()); | 
|  | error::Error error = error::kNoError; | 
|  | if (decoder_) | 
|  | decoder_->BeginDecoding(); | 
|  | while (!parser_->IsEmpty()) { | 
|  | if (IsPreempted()) | 
|  | break; | 
|  |  | 
|  | DCHECK(scheduled()); | 
|  |  | 
|  | error = parser_->ProcessCommands(CommandParser::kParseCommandsSlice); | 
|  |  | 
|  | if (error == error::kDeferCommandUntilLater) { | 
|  | DCHECK(!scheduled()); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // TODO(piman): various classes duplicate various pieces of state, leading | 
|  | // to needlessly complex update logic. It should be possible to simply | 
|  | // share the state across all of them. | 
|  | command_buffer_->SetGetOffset(static_cast<int32_t>(parser_->get())); | 
|  |  | 
|  | if (error::IsError(error)) { | 
|  | command_buffer_->SetContextLostReason(decoder_->GetContextLostReason()); | 
|  | command_buffer_->SetParseError(error); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!command_processed_callback_.is_null()) | 
|  | command_processed_callback_.Run(); | 
|  |  | 
|  | if (!scheduled()) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (decoder_) { | 
|  | if (!error::IsError(error) && decoder_->WasContextLost()) { | 
|  | command_buffer_->SetContextLostReason(decoder_->GetContextLostReason()); | 
|  | command_buffer_->SetParseError(error::kLostContext); | 
|  | } | 
|  | decoder_->EndDecoding(); | 
|  | decoder_->AddProcessingCommandsTime(base::TimeTicks::Now() - begin_time); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CommandExecutor::SetScheduled(bool scheduled) { | 
|  | TRACE_EVENT2("gpu", "CommandExecutor:SetScheduled", "this", this, "scheduled", | 
|  | scheduled); | 
|  | scheduled_ = scheduled; | 
|  | } | 
|  |  | 
|  | bool CommandExecutor::HasPendingQueries() const { | 
|  | return (decoder_ && decoder_->HasPendingQueries()); | 
|  | } | 
|  |  | 
|  | void CommandExecutor::ProcessPendingQueries() { | 
|  | if (!decoder_) | 
|  | return; | 
|  | decoder_->ProcessPendingQueries(false); | 
|  | } | 
|  |  | 
|  | scoped_refptr<Buffer> CommandExecutor::GetSharedMemoryBuffer(int32_t shm_id) { | 
|  | return command_buffer_->GetTransferBuffer(shm_id); | 
|  | } | 
|  |  | 
|  | void CommandExecutor::set_token(int32_t token) { | 
|  | command_buffer_->SetToken(token); | 
|  | } | 
|  |  | 
|  | bool CommandExecutor::SetGetBuffer(int32_t transfer_buffer_id) { | 
|  | scoped_refptr<Buffer> ring_buffer = | 
|  | command_buffer_->GetTransferBuffer(transfer_buffer_id); | 
|  | if (!ring_buffer.get()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!parser_.get()) { | 
|  | parser_.reset(new CommandParser(handler_)); | 
|  | } | 
|  |  | 
|  | parser_->SetBuffer(ring_buffer->memory(), ring_buffer->size(), 0, | 
|  | ring_buffer->size()); | 
|  |  | 
|  | SetGetOffset(0); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool CommandExecutor::SetGetOffset(int32_t offset) { | 
|  | if (parser_->set_get(offset)) { | 
|  | command_buffer_->SetGetOffset(static_cast<int32_t>(parser_->get())); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int32_t CommandExecutor::GetGetOffset() { | 
|  | return parser_->get(); | 
|  | } | 
|  |  | 
|  | void CommandExecutor::SetCommandProcessedCallback( | 
|  | const base::Closure& callback) { | 
|  | command_processed_callback_ = callback; | 
|  | } | 
|  |  | 
|  | bool CommandExecutor::IsPreempted() { | 
|  | if (!preemption_flag_.get()) | 
|  | return false; | 
|  |  | 
|  | if (!was_preempted_ && preemption_flag_->IsSet()) { | 
|  | TRACE_COUNTER_ID1("gpu", "CommandExecutor::Preempted", this, 1); | 
|  | was_preempted_ = true; | 
|  | } else if (was_preempted_ && !preemption_flag_->IsSet()) { | 
|  | TRACE_COUNTER_ID1("gpu", "CommandExecutor::Preempted", this, 0); | 
|  | was_preempted_ = false; | 
|  | } | 
|  |  | 
|  | return preemption_flag_->IsSet(); | 
|  | } | 
|  |  | 
|  | bool CommandExecutor::HasMoreIdleWork() const { | 
|  | return (decoder_ && decoder_->HasMoreIdleWork()); | 
|  | } | 
|  |  | 
|  | void CommandExecutor::PerformIdleWork() { | 
|  | if (!decoder_) | 
|  | return; | 
|  | decoder_->PerformIdleWork(); | 
|  | } | 
|  |  | 
|  | bool CommandExecutor::HasPollingWork() const { | 
|  | return (decoder_ && decoder_->HasPollingWork()); | 
|  | } | 
|  |  | 
|  | void CommandExecutor::PerformPollingWork() { | 
|  | if (!decoder_) | 
|  | return; | 
|  | decoder_->PerformPollingWork(); | 
|  | } | 
|  |  | 
|  | }  // namespace gpu |