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
OutputSurface(scoped_refptr<ContextProvider> context_provider)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
OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)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
OutputSurface(scoped_refptr<ContextProvider> context_provider,scoped_ptr<SoftwareOutputDevice> software_device)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
InitializeBeginImplFrameEmulation(base::SingleThreadTaskRunner * task_runner,bool throttle_frame_production,base::TimeDelta interval)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
SetMaxFramesPending(int max_frames_pending)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
OnVSyncParametersChanged(base::TimeTicks timebase,base::TimeDelta interval)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
FrameRateControllerTick(bool throttled,const BeginFrameArgs & args)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
SetNeedsRedrawRect(gfx::Rect damage_rect)140 void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) {
141 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
142 client_->SetNeedsRedrawRect(damage_rect);
143 }
144
SetNeedsBeginImplFrame(bool enable)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
BeginImplFrame(const BeginFrameArgs & args)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
RetroactiveBeginImplFrameDeadline()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
PostCheckForRetroactiveBeginImplFrame()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
CheckForRetroactiveBeginImplFrame()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
DidSwapBuffers()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
OnSwapBuffersComplete()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
ReclaimResources(const CompositorFrameAck * ack)225 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
226 client_->ReclaimResources(ack);
227 }
228
DidLoseOutputSurface()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
SetExternalStencilTest(bool enabled)241 void OutputSurface::SetExternalStencilTest(bool enabled) {
242 external_stencil_test_enabled_ = enabled;
243 }
244
SetExternalDrawConstraints(const gfx::Transform & transform,gfx::Rect viewport,gfx::Rect clip,bool valid_for_tile_management)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
~OutputSurface()253 OutputSurface::~OutputSurface() {
254 if (frame_rate_controller_)
255 frame_rate_controller_->SetActive(false);
256 ResetContext3d();
257 }
258
HasExternalStencilTest() const259 bool OutputSurface::HasExternalStencilTest() const {
260 return external_stencil_test_enabled_;
261 }
262
ForcedDrawToSoftwareDevice() const263 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
264
BindToClient(OutputSurfaceClient * client)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
InitializeAndSetContext3d(scoped_refptr<ContextProvider> context_provider,scoped_refptr<ContextProvider> offscreen_context_provider)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
ReleaseGL()303 void OutputSurface::ReleaseGL() {
304 DCHECK(client_);
305 DCHECK(context_provider_);
306 client_->ReleaseGL();
307 ResetContext3d();
308 }
309
SetUpContext3d()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
ResetContext3d()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
EnsureBackbuffer()347 void OutputSurface::EnsureBackbuffer() {
348 if (software_device_)
349 software_device_->EnsureBackbuffer();
350 }
351
DiscardBackbuffer()352 void OutputSurface::DiscardBackbuffer() {
353 if (context_provider_)
354 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
355 if (software_device_)
356 software_device_->DiscardBackbuffer();
357 }
358
Reshape(gfx::Size size,float scale_factor)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
SurfaceSize() const373 gfx::Size OutputSurface::SurfaceSize() const {
374 return surface_size_;
375 }
376
BindFramebuffer()377 void OutputSurface::BindFramebuffer() {
378 DCHECK(context_provider_);
379 context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0);
380 }
381
SwapBuffers(CompositorFrame * frame)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
GpuLatencyEstimate()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
UpdateAndMeasureGpuLatency()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
PostSwapBuffersComplete()476 void OutputSurface::PostSwapBuffersComplete() {
477 base::MessageLoop::current()->PostTask(
478 FROM_HERE,
479 base::Bind(&OutputSurface::OnSwapBuffersComplete,
480 weak_ptr_factory_.GetWeakPtr()));
481 }
482
SetMemoryPolicy(const ManagedMemoryPolicy & policy)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