| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |