Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: gpu/command_buffer/service/gpu_scheduler.cc

Issue 7253052: Execute all GL commands up to the put offset reported by a flush. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "gpu/command_buffer/service/gpu_scheduler.h" 5 #include "gpu/command_buffer/service/gpu_scheduler.h"
6 6
7 #include "base/callback.h" 7 #include "base/callback.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/time.h" 12 #include "base/time.h"
13 #include "ui/gfx/gl/gl_context.h" 13 #include "ui/gfx/gl/gl_context.h"
14 #include "ui/gfx/gl/gl_bindings.h" 14 #include "ui/gfx/gl/gl_bindings.h"
15 #include "ui/gfx/gl/gl_surface.h" 15 #include "ui/gfx/gl/gl_surface.h"
16 #include "ui/gfx/gl/gl_switches.h" 16 #include "ui/gfx/gl/gl_switches.h"
17 17
18 using ::base::SharedMemory; 18 using ::base::SharedMemory;
19 19
20 namespace gpu { 20 namespace gpu {
21 21
22 GpuScheduler::GpuScheduler(CommandBuffer* command_buffer, 22 GpuScheduler::GpuScheduler(CommandBuffer* command_buffer,
23 SurfaceManager* surface_manager, 23 SurfaceManager* surface_manager,
24 gles2::ContextGroup* group) 24 gles2::ContextGroup* group)
25 : command_buffer_(command_buffer), 25 : command_buffer_(command_buffer),
26 commands_per_update_(100),
27 unscheduled_count_(0), 26 unscheduled_count_(0),
28 #if defined(OS_MACOSX) || defined(TOUCH_UI) 27 #if defined(OS_MACOSX) || defined(TOUCH_UI)
29 swap_buffers_count_(0), 28 swap_buffers_count_(0),
30 acknowledged_swap_buffers_count_(0), 29 acknowledged_swap_buffers_count_(0),
31 #endif 30 #endif
32 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { 31 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
33 DCHECK(command_buffer); 32 DCHECK(command_buffer);
34 decoder_.reset(gles2::GLES2Decoder::Create(surface_manager, group)); 33 decoder_.reset(gles2::GLES2Decoder::Create(surface_manager, group));
35 decoder_->set_engine(this); 34 decoder_->set_engine(this);
36 if (CommandLine::ForCurrentProcess()->HasSwitch( 35 if (CommandLine::ForCurrentProcess()->HasSwitch(
37 switches::kEnableGPUServiceLogging)) { 36 switches::kEnableGPUServiceLogging)) {
38 decoder_->set_debug(true); 37 decoder_->set_debug(true);
39 } 38 }
40 } 39 }
41 40
42 GpuScheduler::GpuScheduler(CommandBuffer* command_buffer, 41 GpuScheduler::GpuScheduler(CommandBuffer* command_buffer,
43 gles2::GLES2Decoder* decoder, 42 gles2::GLES2Decoder* decoder,
44 CommandParser* parser, 43 CommandParser* parser)
45 int commands_per_update)
46 : command_buffer_(command_buffer), 44 : command_buffer_(command_buffer),
47 commands_per_update_(commands_per_update),
48 unscheduled_count_(0), 45 unscheduled_count_(0),
49 #if defined(OS_MACOSX) || defined(TOUCH_UI) 46 #if defined(OS_MACOSX) || defined(TOUCH_UI)
50 swap_buffers_count_(0), 47 swap_buffers_count_(0),
51 acknowledged_swap_buffers_count_(0), 48 acknowledged_swap_buffers_count_(0),
52 #endif 49 #endif
53 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { 50 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
54 DCHECK(command_buffer); 51 DCHECK(command_buffer);
55 decoder_.reset(decoder); 52 decoder_.reset(decoder);
56 parser_.reset(parser); 53 parser_.reset(parser);
57 } 54 }
(...skipping 17 matching lines...) Expand all
75 #if !defined(OS_MACOSX) 72 #if !defined(OS_MACOSX)
76 // Set up swap interval for onscreen contexts. 73 // Set up swap interval for onscreen contexts.
77 if (!surface->IsOffscreen()) { 74 if (!surface->IsOffscreen()) {
78 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) 75 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
79 context->SetSwapInterval(0); 76 context->SetSwapInterval(0);
80 else 77 else
81 context->SetSwapInterval(1); 78 context->SetSwapInterval(1);
82 } 79 }
83 #endif 80 #endif
84 81
85 // Do not limit to a certain number of commands before scheduling another
86 // update when rendering onscreen.
87 if (!surface->IsOffscreen())
88 commands_per_update_ = INT_MAX;
89
90 // Map the ring buffer and create the parser. 82 // Map the ring buffer and create the parser.
91 Buffer ring_buffer = command_buffer_->GetRingBuffer(); 83 Buffer ring_buffer = command_buffer_->GetRingBuffer();
92 if (ring_buffer.ptr) { 84 if (ring_buffer.ptr) {
93 parser_.reset(new CommandParser(ring_buffer.ptr, 85 parser_.reset(new CommandParser(ring_buffer.ptr,
94 ring_buffer.size, 86 ring_buffer.size,
95 0, 87 0,
96 ring_buffer.size, 88 ring_buffer.size,
97 0, 89 0,
98 decoder_.get())); 90 decoder_.get()));
99 } else { 91 } else {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 else 129 else
138 return decoder_->SetParent(NULL, 0); 130 return decoder_->SetParent(NULL, 0);
139 } 131 }
140 132
141 #if defined(OS_MACOSX) || defined(TOUCH_UI) 133 #if defined(OS_MACOSX) || defined(TOUCH_UI)
142 namespace { 134 namespace {
143 const unsigned int kMaxOutstandingSwapBuffersCallsPerOnscreenContext = 1; 135 const unsigned int kMaxOutstandingSwapBuffersCallsPerOnscreenContext = 1;
144 } 136 }
145 #endif 137 #endif
146 138
147 void GpuScheduler::PutChanged(bool sync) { 139 void GpuScheduler::PutChanged() {
148 TRACE_EVENT1("gpu", "GpuScheduler:PutChanged", "this", this); 140 TRACE_EVENT1("gpu", "GpuScheduler:PutChanged", "this", this);
141
142 DCHECK(IsScheduled());
143
149 CommandBuffer::State state = command_buffer_->GetState(); 144 CommandBuffer::State state = command_buffer_->GetState();
150 parser_->set_put(state.put_offset); 145 parser_->set_put(state.put_offset);
151
152 if (sync)
153 ProcessCommands();
154 else
155 ScheduleProcessCommands();
156 }
157
158 void GpuScheduler::ProcessCommands() {
159 TRACE_EVENT1("gpu", "GpuScheduler:ProcessCommands", "this", this);
160 CommandBuffer::State state = command_buffer_->GetState();
161 if (state.error != error::kNoError) 146 if (state.error != error::kNoError)
162 return; 147 return;
163 148
164 if (unscheduled_count_ > 0) {
165 TRACE_EVENT1("gpu", "EarlyOut_Unscheduled",
166 "unscheduled_count_", unscheduled_count_);
167 return;
168 }
169
170 if (decoder_.get()) { 149 if (decoder_.get()) {
171 if (!decoder_->MakeCurrent()) { 150 if (!decoder_->MakeCurrent()) {
172 LOG(ERROR) << "Context lost because MakeCurrent failed."; 151 LOG(ERROR) << "Context lost because MakeCurrent failed.";
173 command_buffer_->SetParseError(error::kLostContext); 152 command_buffer_->SetParseError(error::kLostContext);
174 return; 153 return;
175 } 154 }
176 } 155 }
177 156
178 #if defined(OS_MACOSX) 157 #if defined(OS_MACOSX)
179 bool do_rate_limiting = surface_.get() != NULL; 158 bool do_rate_limiting = surface_.get() != NULL;
180 #elif defined(TOUCH_UI) 159 #elif defined(TOUCH_UI)
181 bool do_rate_limiting = back_surface_.get() != NULL; 160 bool do_rate_limiting = back_surface_.get() != NULL;
182 #endif 161 #endif
183 162
184 #if defined(OS_MACOSX) || defined(TOUCH_UI) 163 #if defined(OS_MACOSX) || defined(TOUCH_UI)
185 // Don't swamp the browser process with SwapBuffers calls it can't handle. 164 // Don't swamp the browser process with SwapBuffers calls it can't handle.
186 if (do_rate_limiting && 165 DCHECK(!do_rate_limiting ||
187 swap_buffers_count_ - acknowledged_swap_buffers_count_ >= 166 swap_buffers_count_ - acknowledged_swap_buffers_count_ == 0);
188 kMaxOutstandingSwapBuffersCallsPerOnscreenContext) {
189 TRACE_EVENT0("gpu", "EarlyOut_OSX_Throttle");
190 // Stop doing work on this command buffer. In the GPU process,
191 // receipt of the GpuMsg_AcceleratedSurfaceBuffersSwappedACK
192 // message causes ProcessCommands to be scheduled again.
193 return;
194 }
195 #endif 167 #endif
196 168
197 base::TimeTicks start_time = base::TimeTicks::Now();
198 base::TimeDelta elapsed;
199 bool is_break = false;
200 error::Error error = error::kNoError; 169 error::Error error = error::kNoError;
201 do { 170 while (!parser_->IsEmpty()) {
202 int commands_processed = 0; 171 error = parser_->ProcessCommand();
203 while (commands_processed < commands_per_update_ &&
204 !parser_->IsEmpty()) {
205 error = parser_->ProcessCommand();
206 172
207 // TODO(piman): various classes duplicate various pieces of state, leading 173 // TODO(piman): various classes duplicate various pieces of state, leading
208 // to needlessly complex update logic. It should be possible to simply 174 // to needlessly complex update logic. It should be possible to simply
209 // share the state across all of them. 175 // share the state across all of them.
210 command_buffer_->SetGetOffset(static_cast<int32>(parser_->get())); 176 command_buffer_->SetGetOffset(static_cast<int32>(parser_->get()));
211 177
212 if (error == error::kWaiting || error == error::kYield) { 178 if (error::IsError(error)) {
213 is_break = true; 179 command_buffer_->SetParseError(error);
214 break; 180 return;
215 } else if (error::IsError(error)) { 181 }
216 command_buffer_->SetParseError(error);
217 return;
218 }
219 182
220 if (unscheduled_count_ > 0) { 183 if (command_processed_callback_.get())
221 is_break = true; 184 command_processed_callback_->Run();
222 break;
223 }
224 185
225 ++commands_processed; 186 if (unscheduled_count_ > 0)
226 if (command_processed_callback_.get()) { 187 return;
227 command_processed_callback_->Run();
228 }
229 }
230 elapsed = base::TimeTicks::Now() - start_time;
231 } while(!is_break &&
232 !parser_->IsEmpty() &&
233 elapsed.InMicroseconds() < kMinimumSchedulerQuantumMicros);
234
235 if (unscheduled_count_ == 0 &&
236 error != error::kWaiting &&
237 !parser_->IsEmpty()) {
238 ScheduleProcessCommands();
239 } 188 }
240 } 189 }
241 190
242 void GpuScheduler::SetScheduled(bool scheduled) { 191 void GpuScheduler::SetScheduled(bool scheduled) {
243 TRACE_EVENT2("gpu", "GpuScheduler:SetScheduled", "this", this, 192 TRACE_EVENT2("gpu", "GpuScheduler:SetScheduled", "this", this,
244 "new unscheduled_count_", 193 "new unscheduled_count_",
245 unscheduled_count_ + (scheduled? -1 : 1)); 194 unscheduled_count_ + (scheduled? -1 : 1));
246 if (scheduled) { 195 if (scheduled) {
247 --unscheduled_count_; 196 --unscheduled_count_;
248 DCHECK_GE(unscheduled_count_, 0); 197 DCHECK_GE(unscheduled_count_, 0);
249 198
250 if (unscheduled_count_ == 0) { 199 if (unscheduled_count_ == 0 && scheduled_callback_.get())
251 if (scheduled_callback_.get()) 200 scheduled_callback_->Run();
252 scheduled_callback_->Run();
253
254 ScheduleProcessCommands();
255 }
256 } else { 201 } else {
257 ++unscheduled_count_; 202 ++unscheduled_count_;
258 } 203 }
259 } 204 }
260 205
261 bool GpuScheduler::IsScheduled() { 206 bool GpuScheduler::IsScheduled() {
262 return unscheduled_count_ == 0; 207 return unscheduled_count_ == 0;
263 } 208 }
264 209
265 void GpuScheduler::SetScheduledCallback(Callback0::Type* scheduled_callback) { 210 void GpuScheduler::SetScheduledCallback(Callback0::Type* scheduled_callback) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 Callback0::Type* callback) { 256 Callback0::Type* callback) {
312 command_processed_callback_.reset(callback); 257 command_processed_callback_.reset(callback);
313 } 258 }
314 259
315 void GpuScheduler::SetTokenCallback( 260 void GpuScheduler::SetTokenCallback(
316 const base::Callback<void(int32)>& callback) { 261 const base::Callback<void(int32)>& callback) {
317 DCHECK(set_token_callback_.is_null()); 262 DCHECK(set_token_callback_.is_null());
318 set_token_callback_ = callback; 263 set_token_callback_ = callback;
319 } 264 }
320 265
321 void GpuScheduler::ScheduleProcessCommands() {
322 MessageLoop::current()->PostTask(
323 FROM_HERE,
324 method_factory_.NewRunnableMethod(&GpuScheduler::ProcessCommands));
325 }
326
327 void GpuScheduler::WillResize(gfx::Size size) { 266 void GpuScheduler::WillResize(gfx::Size size) {
328 if (wrapped_resize_callback_.get()) { 267 if (wrapped_resize_callback_.get()) {
329 wrapped_resize_callback_->Run(size); 268 wrapped_resize_callback_->Run(size);
330 } 269 }
331 } 270 }
332 271
333 } // namespace gpu 272 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698