Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / gpu / command_buffer / service / gpu_scheduler.cc
blob2a15dc76f9c06d14914f5b2470a5c758f8eeeb4e
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 #include "gpu/command_buffer/service/gpu_scheduler.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/compiler_specific.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/time/time.h"
12 #include "base/trace_event/trace_event.h"
13 #include "gpu/command_buffer/service/logger.h"
14 #include "ui/gl/gl_bindings.h"
15 #include "ui/gl/gl_fence.h"
16 #include "ui/gl/gl_switches.h"
18 #if defined(OS_WIN)
19 #include "base/win/windows_version.h"
20 #endif
22 using ::base::SharedMemory;
24 namespace gpu {
26 #if defined(OS_WIN)
27 const int64 kRescheduleTimeOutDelay = 1000;
28 #endif
30 GpuScheduler::GpuScheduler(CommandBufferServiceBase* command_buffer,
31 AsyncAPIInterface* handler,
32 gles2::GLES2Decoder* decoder)
33 : command_buffer_(command_buffer),
34 handler_(handler),
35 decoder_(decoder),
36 unscheduled_count_(0),
37 rescheduled_count_(0),
38 was_preempted_(false),
39 reschedule_task_factory_(this) {}
41 GpuScheduler::~GpuScheduler() {
44 void GpuScheduler::PutChanged() {
45 TRACE_EVENT1(
46 "gpu", "GpuScheduler:PutChanged",
47 "decoder", decoder_ ? decoder_->GetLogger()->GetLogPrefix() : "None");
49 CommandBuffer::State state = command_buffer_->GetLastState();
51 // If there is no parser, exit.
52 if (!parser_.get()) {
53 DCHECK_EQ(state.get_offset, command_buffer_->GetPutOffset());
54 return;
57 parser_->set_put(command_buffer_->GetPutOffset());
58 if (state.error != error::kNoError)
59 return;
61 // One of the unschedule fence tasks might have unscheduled us.
62 if (!IsScheduled())
63 return;
65 base::TimeTicks begin_time(base::TimeTicks::Now());
66 error::Error error = error::kNoError;
67 if (decoder_)
68 decoder_->BeginDecoding();
69 while (!parser_->IsEmpty()) {
70 if (IsPreempted())
71 break;
73 DCHECK(IsScheduled());
75 error = parser_->ProcessCommands(CommandParser::kParseCommandsSlice);
77 if (error == error::kDeferCommandUntilLater) {
78 DCHECK_GT(unscheduled_count_, 0);
79 break;
82 // TODO(piman): various classes duplicate various pieces of state, leading
83 // to needlessly complex update logic. It should be possible to simply
84 // share the state across all of them.
85 command_buffer_->SetGetOffset(static_cast<int32>(parser_->get()));
87 if (error::IsError(error)) {
88 command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
89 command_buffer_->SetParseError(error);
90 break;
93 if (!command_processed_callback_.is_null())
94 command_processed_callback_.Run();
96 if (unscheduled_count_ > 0)
97 break;
100 if (decoder_) {
101 if (!error::IsError(error) && decoder_->WasContextLost()) {
102 command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
103 command_buffer_->SetParseError(error::kLostContext);
105 decoder_->EndDecoding();
106 decoder_->AddProcessingCommandsTime(base::TimeTicks::Now() - begin_time);
110 void GpuScheduler::SetScheduled(bool scheduled) {
111 TRACE_EVENT2("gpu", "GpuScheduler:SetScheduled", "this", this,
112 "new unscheduled_count_",
113 unscheduled_count_ + (scheduled? -1 : 1));
114 if (scheduled) {
115 // If the scheduler was rescheduled after a timeout, ignore the subsequent
116 // calls to SetScheduled when they eventually arrive until they are all
117 // accounted for.
118 if (rescheduled_count_ > 0) {
119 --rescheduled_count_;
120 return;
121 } else {
122 --unscheduled_count_;
125 DCHECK_GE(unscheduled_count_, 0);
127 if (unscheduled_count_ == 0) {
128 TRACE_EVENT_ASYNC_END1("gpu", "ProcessingSwap", this,
129 "GpuScheduler", this);
130 // When the scheduler transitions from the unscheduled to the scheduled
131 // state, cancel the task that would reschedule it after a timeout.
132 reschedule_task_factory_.InvalidateWeakPtrs();
134 if (!scheduling_changed_callback_.is_null())
135 scheduling_changed_callback_.Run(true);
137 } else {
138 ++unscheduled_count_;
139 if (unscheduled_count_ == 1) {
140 TRACE_EVENT_ASYNC_BEGIN1("gpu", "ProcessingSwap", this,
141 "GpuScheduler", this);
142 #if defined(OS_WIN)
143 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
144 // When the scheduler transitions from scheduled to unscheduled, post a
145 // delayed task that it will force it back into a scheduled state after
146 // a timeout. This should only be necessary on pre-Vista.
147 base::MessageLoop::current()->PostDelayedTask(
148 FROM_HERE,
149 base::Bind(&GpuScheduler::RescheduleTimeOut,
150 reschedule_task_factory_.GetWeakPtr()),
151 base::TimeDelta::FromMilliseconds(kRescheduleTimeOutDelay));
153 #endif
154 if (!scheduling_changed_callback_.is_null())
155 scheduling_changed_callback_.Run(false);
160 bool GpuScheduler::IsScheduled() {
161 return unscheduled_count_ == 0;
164 bool GpuScheduler::HasMoreWork() {
165 return (decoder_ && decoder_->ProcessPendingQueries(false)) ||
166 HasMoreIdleWork();
169 void GpuScheduler::SetSchedulingChangedCallback(
170 const SchedulingChangedCallback& callback) {
171 scheduling_changed_callback_ = callback;
174 scoped_refptr<Buffer> GpuScheduler::GetSharedMemoryBuffer(int32 shm_id) {
175 return command_buffer_->GetTransferBuffer(shm_id);
178 void GpuScheduler::set_token(int32 token) {
179 command_buffer_->SetToken(token);
182 bool GpuScheduler::SetGetBuffer(int32 transfer_buffer_id) {
183 scoped_refptr<Buffer> ring_buffer =
184 command_buffer_->GetTransferBuffer(transfer_buffer_id);
185 if (!ring_buffer.get()) {
186 return false;
189 if (!parser_.get()) {
190 parser_.reset(new CommandParser(handler_));
193 parser_->SetBuffer(
194 ring_buffer->memory(), ring_buffer->size(), 0, ring_buffer->size());
196 SetGetOffset(0);
197 return true;
200 bool GpuScheduler::SetGetOffset(int32 offset) {
201 if (parser_->set_get(offset)) {
202 command_buffer_->SetGetOffset(static_cast<int32>(parser_->get()));
203 return true;
205 return false;
208 int32 GpuScheduler::GetGetOffset() {
209 return parser_->get();
212 void GpuScheduler::SetCommandProcessedCallback(
213 const base::Closure& callback) {
214 command_processed_callback_ = callback;
217 bool GpuScheduler::IsPreempted() {
218 if (!preemption_flag_.get())
219 return false;
221 if (!was_preempted_ && preemption_flag_->IsSet()) {
222 TRACE_COUNTER_ID1("gpu", "GpuScheduler::Preempted", this, 1);
223 was_preempted_ = true;
224 } else if (was_preempted_ && !preemption_flag_->IsSet()) {
225 TRACE_COUNTER_ID1("gpu", "GpuScheduler::Preempted", this, 0);
226 was_preempted_ = false;
229 return preemption_flag_->IsSet();
232 bool GpuScheduler::HasMoreIdleWork() {
233 return (decoder_ && decoder_->HasMoreIdleWork());
236 void GpuScheduler::PerformIdleWork() {
237 if (!decoder_)
238 return;
239 decoder_->PerformIdleWork();
242 void GpuScheduler::RescheduleTimeOut() {
243 int new_count = unscheduled_count_ + rescheduled_count_;
245 rescheduled_count_ = 0;
247 while (unscheduled_count_)
248 SetScheduled(true);
250 rescheduled_count_ = new_count;
253 } // namespace gpu