1 // Copyright (c) 2013 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 #include "cc/output/output_surface.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <string> 10 #include <vector> 11 12 #include "base/bind.h" 13 #include "base/debug/trace_event.h" 14 #include "base/logging.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/metrics/histogram.h" 17 #include "base/strings/string_split.h" 18 #include "base/strings/string_util.h" 19 #include "cc/output/compositor_frame.h" 20 #include "cc/output/compositor_frame_ack.h" 21 #include "cc/output/managed_memory_policy.h" 22 #include "cc/output/output_surface_client.h" 23 #include "cc/scheduler/delay_based_time_source.h" 24 #include "gpu/GLES2/gl2extchromium.h" 25 #include "gpu/command_buffer/client/context_support.h" 26 #include "gpu/command_buffer/client/gles2_interface.h" 27 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 28 #include "third_party/khronos/GLES2/gl2.h" 29 #include "third_party/khronos/GLES2/gl2ext.h" 30 #include "ui/gfx/frame_time.h" 31 #include "ui/gfx/rect.h" 32 #include "ui/gfx/size.h" 33 34 using std::set; 35 using std::string; 36 using std::vector; 37 38 namespace { 39 40 const size_t kGpuLatencyHistorySize = 60; 41 const double kGpuLatencyEstimationPercentile = 100.0; 42 43 } 44 45 namespace cc { 46 47 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider) 48 : context_provider_(context_provider), 49 device_scale_factor_(-1), 50 max_frames_pending_(0), 51 pending_swap_buffers_(0), 52 needs_begin_impl_frame_(false), 53 client_ready_for_begin_impl_frame_(true), 54 client_(NULL), 55 check_for_retroactive_begin_impl_frame_pending_(false), 56 external_stencil_test_enabled_(false), 57 weak_ptr_factory_(this), 58 gpu_latency_history_(kGpuLatencyHistorySize) {} 59 60 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device) 61 : software_device_(software_device.Pass()), 62 device_scale_factor_(-1), 63 max_frames_pending_(0), 64 pending_swap_buffers_(0), 65 needs_begin_impl_frame_(false), 66 client_ready_for_begin_impl_frame_(true), 67 client_(NULL), 68 check_for_retroactive_begin_impl_frame_pending_(false), 69 external_stencil_test_enabled_(false), 70 weak_ptr_factory_(this), 71 gpu_latency_history_(kGpuLatencyHistorySize) {} 72 73 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider, 74 scoped_ptr<SoftwareOutputDevice> software_device) 75 : context_provider_(context_provider), 76 software_device_(software_device.Pass()), 77 device_scale_factor_(-1), 78 max_frames_pending_(0), 79 pending_swap_buffers_(0), 80 needs_begin_impl_frame_(false), 81 client_ready_for_begin_impl_frame_(true), 82 client_(NULL), 83 check_for_retroactive_begin_impl_frame_pending_(false), 84 external_stencil_test_enabled_(false), 85 weak_ptr_factory_(this), 86 gpu_latency_history_(kGpuLatencyHistorySize) {} 87 88 void OutputSurface::InitializeBeginImplFrameEmulation( 89 base::SingleThreadTaskRunner* task_runner, 90 bool throttle_frame_production, 91 base::TimeDelta interval) { 92 if (throttle_frame_production) { 93 scoped_refptr<DelayBasedTimeSource> time_source; 94 if (gfx::FrameTime::TimestampsAreHighRes()) 95 time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner); 96 else 97 time_source = DelayBasedTimeSource::Create(interval, task_runner); 98 frame_rate_controller_.reset(new FrameRateController(time_source)); 99 } else { 100 frame_rate_controller_.reset(new FrameRateController(task_runner)); 101 } 102 103 frame_rate_controller_->SetClient(this); 104 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_); 105 frame_rate_controller_->SetDeadlineAdjustment( 106 capabilities_.adjust_deadline_for_parent ? 107 BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta()); 108 109 // The new frame rate controller will consume the swap acks of the old 110 // frame rate controller, so we set that expectation up here. 111 for (int i = 0; i < pending_swap_buffers_; i++) 112 frame_rate_controller_->DidSwapBuffers(); 113 } 114 115 void OutputSurface::SetMaxFramesPending(int max_frames_pending) { 116 if (frame_rate_controller_) 117 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending); 118 max_frames_pending_ = max_frames_pending; 119 } 120 121 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase, 122 base::TimeDelta interval) { 123 TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged", 124 "timebase", (timebase - base::TimeTicks()).InSecondsF(), 125 "interval", interval.InSecondsF()); 126 if (frame_rate_controller_) 127 frame_rate_controller_->SetTimebaseAndInterval(timebase, interval); 128 } 129 130 void OutputSurface::FrameRateControllerTick(bool throttled, 131 const BeginFrameArgs& args) { 132 DCHECK(frame_rate_controller_); 133 if (throttled) 134 skipped_begin_impl_frame_args_ = args; 135 else 136 BeginImplFrame(args); 137 } 138 139 // Forwarded to OutputSurfaceClient 140 void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) { 141 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect"); 142 client_->SetNeedsRedrawRect(damage_rect); 143 } 144 145 void OutputSurface::SetNeedsBeginImplFrame(bool enable) { 146 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable); 147 needs_begin_impl_frame_ = enable; 148 client_ready_for_begin_impl_frame_ = true; 149 if (frame_rate_controller_) { 150 BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable); 151 if (skipped.IsValid()) 152 skipped_begin_impl_frame_args_ = skipped; 153 } 154 if (needs_begin_impl_frame_) 155 PostCheckForRetroactiveBeginImplFrame(); 156 } 157 158 void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) { 159 TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame", 160 "client_ready_for_begin_impl_frame_", 161 client_ready_for_begin_impl_frame_, 162 "pending_swap_buffers_", pending_swap_buffers_); 163 if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ || 164 (pending_swap_buffers_ >= max_frames_pending_ && 165 max_frames_pending_ > 0)) { 166 skipped_begin_impl_frame_args_ = args; 167 } else { 168 client_ready_for_begin_impl_frame_ = false; 169 client_->BeginImplFrame(args); 170 // args might be an alias for skipped_begin_impl_frame_args_. 171 // Do not reset it before calling BeginImplFrame! 172 skipped_begin_impl_frame_args_ = BeginFrameArgs(); 173 } 174 } 175 176 base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() { 177 // TODO(brianderson): Remove the alternative deadline once we have better 178 // deadline estimations. 179 base::TimeTicks alternative_deadline = 180 skipped_begin_impl_frame_args_.frame_time + 181 BeginFrameArgs::DefaultRetroactiveBeginFramePeriod(); 182 return std::max(skipped_begin_impl_frame_args_.deadline, 183 alternative_deadline); 184 } 185 186 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() { 187 if (!skipped_begin_impl_frame_args_.IsValid() || 188 check_for_retroactive_begin_impl_frame_pending_) 189 return; 190 191 base::MessageLoop::current()->PostTask( 192 FROM_HERE, 193 base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame, 194 weak_ptr_factory_.GetWeakPtr())); 195 check_for_retroactive_begin_impl_frame_pending_ = true; 196 } 197 198 void OutputSurface::CheckForRetroactiveBeginImplFrame() { 199 TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame"); 200 check_for_retroactive_begin_impl_frame_pending_ = false; 201 if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline()) 202 BeginImplFrame(skipped_begin_impl_frame_args_); 203 } 204 205 void OutputSurface::DidSwapBuffers() { 206 pending_swap_buffers_++; 207 TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers", 208 "pending_swap_buffers_", pending_swap_buffers_); 209 client_->DidSwapBuffers(); 210 if (frame_rate_controller_) 211 frame_rate_controller_->DidSwapBuffers(); 212 PostCheckForRetroactiveBeginImplFrame(); 213 } 214 215 void OutputSurface::OnSwapBuffersComplete() { 216 pending_swap_buffers_--; 217 TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete", 218 "pending_swap_buffers_", pending_swap_buffers_); 219 client_->OnSwapBuffersComplete(); 220 if (frame_rate_controller_) 221 frame_rate_controller_->DidSwapBuffersComplete(); 222 PostCheckForRetroactiveBeginImplFrame(); 223 } 224 225 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) { 226 client_->ReclaimResources(ack); 227 } 228 229 void OutputSurface::DidLoseOutputSurface() { 230 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface"); 231 client_ready_for_begin_impl_frame_ = true; 232 pending_swap_buffers_ = 0; 233 skipped_begin_impl_frame_args_ = BeginFrameArgs(); 234 if (frame_rate_controller_) 235 frame_rate_controller_->SetActive(false); 236 pending_gpu_latency_query_ids_.clear(); 237 available_gpu_latency_query_ids_.clear(); 238 client_->DidLoseOutputSurface(); 239 } 240 241 void OutputSurface::SetExternalStencilTest(bool enabled) { 242 external_stencil_test_enabled_ = enabled; 243 } 244 245 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform, 246 gfx::Rect viewport, 247 gfx::Rect clip, 248 bool valid_for_tile_management) { 249 client_->SetExternalDrawConstraints( 250 transform, viewport, clip, valid_for_tile_management); 251 } 252 253 OutputSurface::~OutputSurface() { 254 if (frame_rate_controller_) 255 frame_rate_controller_->SetActive(false); 256 ResetContext3d(); 257 } 258 259 bool OutputSurface::HasExternalStencilTest() const { 260 return external_stencil_test_enabled_; 261 } 262 263 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; } 264 265 bool OutputSurface::BindToClient(OutputSurfaceClient* client) { 266 DCHECK(client); 267 client_ = client; 268 bool success = true; 269 270 if (context_provider_) { 271 success = context_provider_->BindToCurrentThread(); 272 if (success) 273 SetUpContext3d(); 274 } 275 276 if (!success) 277 client_ = NULL; 278 279 return success; 280 } 281 282 bool OutputSurface::InitializeAndSetContext3d( 283 scoped_refptr<ContextProvider> context_provider, 284 scoped_refptr<ContextProvider> offscreen_context_provider) { 285 DCHECK(!context_provider_); 286 DCHECK(context_provider); 287 DCHECK(client_); 288 289 bool success = false; 290 if (context_provider->BindToCurrentThread()) { 291 context_provider_ = context_provider; 292 SetUpContext3d(); 293 if (client_->DeferredInitialize(offscreen_context_provider)) 294 success = true; 295 } 296 297 if (!success) 298 ResetContext3d(); 299 300 return success; 301 } 302 303 void OutputSurface::ReleaseGL() { 304 DCHECK(client_); 305 DCHECK(context_provider_); 306 client_->ReleaseGL(); 307 ResetContext3d(); 308 } 309 310 void OutputSurface::SetUpContext3d() { 311 DCHECK(context_provider_); 312 DCHECK(client_); 313 314 context_provider_->SetLostContextCallback( 315 base::Bind(&OutputSurface::DidLoseOutputSurface, 316 base::Unretained(this))); 317 context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback( 318 base::Bind(&OutputSurface::OnSwapBuffersComplete, 319 base::Unretained(this))); 320 context_provider_->SetMemoryPolicyChangedCallback( 321 base::Bind(&OutputSurface::SetMemoryPolicy, 322 base::Unretained(this))); 323 } 324 325 void OutputSurface::ResetContext3d() { 326 if (context_provider_.get()) { 327 while (!pending_gpu_latency_query_ids_.empty()) { 328 unsigned query_id = pending_gpu_latency_query_ids_.front(); 329 pending_gpu_latency_query_ids_.pop_front(); 330 context_provider_->Context3d()->deleteQueryEXT(query_id); 331 } 332 while (!available_gpu_latency_query_ids_.empty()) { 333 unsigned query_id = available_gpu_latency_query_ids_.front(); 334 available_gpu_latency_query_ids_.pop_front(); 335 context_provider_->Context3d()->deleteQueryEXT(query_id); 336 } 337 context_provider_->SetLostContextCallback( 338 ContextProvider::LostContextCallback()); 339 context_provider_->SetMemoryPolicyChangedCallback( 340 ContextProvider::MemoryPolicyChangedCallback()); 341 if (gpu::ContextSupport* support = context_provider_->ContextSupport()) 342 support->SetSwapBuffersCompleteCallback(base::Closure()); 343 } 344 context_provider_ = NULL; 345 } 346 347 void OutputSurface::EnsureBackbuffer() { 348 if (software_device_) 349 software_device_->EnsureBackbuffer(); 350 } 351 352 void OutputSurface::DiscardBackbuffer() { 353 if (context_provider_) 354 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM(); 355 if (software_device_) 356 software_device_->DiscardBackbuffer(); 357 } 358 359 void OutputSurface::Reshape(gfx::Size size, float scale_factor) { 360 if (size == surface_size_ && scale_factor == device_scale_factor_) 361 return; 362 363 surface_size_ = size; 364 device_scale_factor_ = scale_factor; 365 if (context_provider_) { 366 context_provider_->Context3d()->reshapeWithScaleFactor( 367 size.width(), size.height(), scale_factor); 368 } 369 if (software_device_) 370 software_device_->Resize(size); 371 } 372 373 gfx::Size OutputSurface::SurfaceSize() const { 374 return surface_size_; 375 } 376 377 void OutputSurface::BindFramebuffer() { 378 DCHECK(context_provider_); 379 context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0); 380 } 381 382 void OutputSurface::SwapBuffers(CompositorFrame* frame) { 383 if (frame->software_frame_data) { 384 PostSwapBuffersComplete(); 385 DidSwapBuffers(); 386 return; 387 } 388 389 DCHECK(context_provider_); 390 DCHECK(frame->gl_frame_data); 391 392 UpdateAndMeasureGpuLatency(); 393 if (frame->gl_frame_data->sub_buffer_rect == 394 gfx::Rect(frame->gl_frame_data->size)) { 395 context_provider_->ContextSupport()->Swap(); 396 } else { 397 context_provider_->ContextSupport()->PartialSwapBuffers( 398 frame->gl_frame_data->sub_buffer_rect); 399 } 400 401 DidSwapBuffers(); 402 } 403 404 base::TimeDelta OutputSurface::GpuLatencyEstimate() { 405 if (context_provider_ && !capabilities_.adjust_deadline_for_parent) 406 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile); 407 else 408 return base::TimeDelta(); 409 } 410 411 void OutputSurface::UpdateAndMeasureGpuLatency() { 412 return; // http://crbug.com/306690 tracks re-enabling latency queries. 413 414 // We only care about GPU latency for surfaces that do not have a parent 415 // compositor, since surfaces that do have a parent compositor can use 416 // mailboxes or delegated rendering to send frames to their parent without 417 // incurring GPU latency. 418 if (capabilities_.adjust_deadline_for_parent) 419 return; 420 421 while (pending_gpu_latency_query_ids_.size()) { 422 unsigned query_id = pending_gpu_latency_query_ids_.front(); 423 unsigned query_complete = 1; 424 context_provider_->Context3d()->getQueryObjectuivEXT( 425 query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete); 426 if (!query_complete) 427 break; 428 429 unsigned value = 0; 430 context_provider_->Context3d()->getQueryObjectuivEXT( 431 query_id, GL_QUERY_RESULT_EXT, &value); 432 pending_gpu_latency_query_ids_.pop_front(); 433 available_gpu_latency_query_ids_.push_back(query_id); 434 435 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value); 436 base::TimeDelta latency_estimate = GpuLatencyEstimate(); 437 gpu_latency_history_.InsertSample(latency); 438 439 base::TimeDelta latency_overestimate; 440 base::TimeDelta latency_underestimate; 441 if (latency > latency_estimate) 442 latency_underestimate = latency - latency_estimate; 443 else 444 latency_overestimate = latency_estimate - latency; 445 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency", 446 latency, 447 base::TimeDelta::FromMilliseconds(1), 448 base::TimeDelta::FromMilliseconds(100), 449 50); 450 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate", 451 latency_underestimate, 452 base::TimeDelta::FromMilliseconds(1), 453 base::TimeDelta::FromMilliseconds(100), 454 50); 455 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate", 456 latency_overestimate, 457 base::TimeDelta::FromMilliseconds(1), 458 base::TimeDelta::FromMilliseconds(100), 459 50); 460 } 461 462 unsigned gpu_latency_query_id; 463 if (available_gpu_latency_query_ids_.size()) { 464 gpu_latency_query_id = available_gpu_latency_query_ids_.front(); 465 available_gpu_latency_query_ids_.pop_front(); 466 } else { 467 gpu_latency_query_id = context_provider_->Context3d()->createQueryEXT(); 468 } 469 470 context_provider_->Context3d()->beginQueryEXT(GL_LATENCY_QUERY_CHROMIUM, 471 gpu_latency_query_id); 472 context_provider_->Context3d()->endQueryEXT(GL_LATENCY_QUERY_CHROMIUM); 473 pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id); 474 } 475 476 void OutputSurface::PostSwapBuffersComplete() { 477 base::MessageLoop::current()->PostTask( 478 FROM_HERE, 479 base::Bind(&OutputSurface::OnSwapBuffersComplete, 480 weak_ptr_factory_.GetWeakPtr())); 481 } 482 483 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) { 484 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy", 485 "bytes_limit_when_visible", policy.bytes_limit_when_visible); 486 // Just ignore the memory manager when it says to set the limit to zero 487 // bytes. This will happen when the memory manager thinks that the renderer 488 // is not visible (which the renderer knows better). 489 if (policy.bytes_limit_when_visible) 490 client_->SetMemoryPolicy(policy); 491 } 492 493 } // namespace cc 494