IndexedDB: fsync after transactions.
[chromium-blink-merge.git] / cc / output / output_surface.cc
blobf3952d51b877cb8360453a215b18f223405a511f
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.
5 #include "cc/output/output_surface.h"
7 #include <algorithm>
8 #include <set>
9 #include <string>
10 #include <vector>
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/khronos/GLES2/gl2.h"
28 #include "third_party/khronos/GLES2/gl2ext.h"
29 #include "ui/gfx/frame_time.h"
30 #include "ui/gfx/rect.h"
31 #include "ui/gfx/size.h"
33 using std::set;
34 using std::string;
35 using std::vector;
37 namespace {
39 const size_t kGpuLatencyHistorySize = 60;
40 const double kGpuLatencyEstimationPercentile = 100.0;
44 namespace cc {
46 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
47 : context_provider_(context_provider),
48 device_scale_factor_(-1),
49 max_frames_pending_(0),
50 pending_swap_buffers_(0),
51 needs_begin_impl_frame_(false),
52 client_ready_for_begin_impl_frame_(true),
53 client_(NULL),
54 check_for_retroactive_begin_impl_frame_pending_(false),
55 external_stencil_test_enabled_(false),
56 weak_ptr_factory_(this),
57 gpu_latency_history_(kGpuLatencyHistorySize) {}
59 OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
60 : software_device_(software_device.Pass()),
61 device_scale_factor_(-1),
62 max_frames_pending_(0),
63 pending_swap_buffers_(0),
64 needs_begin_impl_frame_(false),
65 client_ready_for_begin_impl_frame_(true),
66 client_(NULL),
67 check_for_retroactive_begin_impl_frame_pending_(false),
68 external_stencil_test_enabled_(false),
69 weak_ptr_factory_(this),
70 gpu_latency_history_(kGpuLatencyHistorySize) {}
72 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider,
73 scoped_ptr<SoftwareOutputDevice> software_device)
74 : context_provider_(context_provider),
75 software_device_(software_device.Pass()),
76 device_scale_factor_(-1),
77 max_frames_pending_(0),
78 pending_swap_buffers_(0),
79 needs_begin_impl_frame_(false),
80 client_ready_for_begin_impl_frame_(true),
81 client_(NULL),
82 check_for_retroactive_begin_impl_frame_pending_(false),
83 external_stencil_test_enabled_(false),
84 weak_ptr_factory_(this),
85 gpu_latency_history_(kGpuLatencyHistorySize) {}
87 void OutputSurface::InitializeBeginImplFrameEmulation(
88 base::SingleThreadTaskRunner* task_runner,
89 bool throttle_frame_production,
90 base::TimeDelta interval) {
91 if (throttle_frame_production) {
92 scoped_refptr<DelayBasedTimeSource> time_source;
93 if (gfx::FrameTime::TimestampsAreHighRes())
94 time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner);
95 else
96 time_source = DelayBasedTimeSource::Create(interval, task_runner);
97 frame_rate_controller_.reset(new FrameRateController(time_source));
98 } else {
99 frame_rate_controller_.reset(new FrameRateController(task_runner));
102 frame_rate_controller_->SetClient(this);
103 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_);
104 frame_rate_controller_->SetDeadlineAdjustment(
105 capabilities_.adjust_deadline_for_parent ?
106 BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
108 // The new frame rate controller will consume the swap acks of the old
109 // frame rate controller, so we set that expectation up here.
110 for (int i = 0; i < pending_swap_buffers_; i++)
111 frame_rate_controller_->DidSwapBuffers();
114 void OutputSurface::SetMaxFramesPending(int max_frames_pending) {
115 if (frame_rate_controller_)
116 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending);
117 max_frames_pending_ = max_frames_pending;
120 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase,
121 base::TimeDelta interval) {
122 TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
123 "timebase", (timebase - base::TimeTicks()).InSecondsF(),
124 "interval", interval.InSecondsF());
125 if (frame_rate_controller_)
126 frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
129 void OutputSurface::FrameRateControllerTick(bool throttled,
130 const BeginFrameArgs& args) {
131 DCHECK(frame_rate_controller_);
132 if (throttled)
133 skipped_begin_impl_frame_args_ = args;
134 else
135 BeginImplFrame(args);
138 // Forwarded to OutputSurfaceClient
139 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
140 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
141 client_->SetNeedsRedrawRect(damage_rect);
144 void OutputSurface::SetNeedsBeginImplFrame(bool enable) {
145 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable);
146 needs_begin_impl_frame_ = enable;
147 client_ready_for_begin_impl_frame_ = true;
148 if (frame_rate_controller_) {
149 BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable);
150 if (skipped.IsValid())
151 skipped_begin_impl_frame_args_ = skipped;
153 if (needs_begin_impl_frame_)
154 PostCheckForRetroactiveBeginImplFrame();
157 void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) {
158 TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
159 "client_ready_for_begin_impl_frame_",
160 client_ready_for_begin_impl_frame_,
161 "pending_swap_buffers_", pending_swap_buffers_);
162 if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ ||
163 (pending_swap_buffers_ >= max_frames_pending_ &&
164 max_frames_pending_ > 0)) {
165 skipped_begin_impl_frame_args_ = args;
166 } else {
167 client_ready_for_begin_impl_frame_ = false;
168 client_->BeginImplFrame(args);
169 // args might be an alias for skipped_begin_impl_frame_args_.
170 // Do not reset it before calling BeginImplFrame!
171 skipped_begin_impl_frame_args_ = BeginFrameArgs();
175 base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() {
176 // TODO(brianderson): Remove the alternative deadline once we have better
177 // deadline estimations.
178 base::TimeTicks alternative_deadline =
179 skipped_begin_impl_frame_args_.frame_time +
180 BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
181 return std::max(skipped_begin_impl_frame_args_.deadline,
182 alternative_deadline);
185 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
186 if (!skipped_begin_impl_frame_args_.IsValid() ||
187 check_for_retroactive_begin_impl_frame_pending_)
188 return;
190 base::MessageLoop::current()->PostTask(
191 FROM_HERE,
192 base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
193 weak_ptr_factory_.GetWeakPtr()));
194 check_for_retroactive_begin_impl_frame_pending_ = true;
197 void OutputSurface::CheckForRetroactiveBeginImplFrame() {
198 TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
199 check_for_retroactive_begin_impl_frame_pending_ = false;
200 if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
201 BeginImplFrame(skipped_begin_impl_frame_args_);
204 void OutputSurface::DidSwapBuffers() {
205 pending_swap_buffers_++;
206 TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
207 "pending_swap_buffers_", pending_swap_buffers_);
208 client_->DidSwapBuffers();
209 if (frame_rate_controller_)
210 frame_rate_controller_->DidSwapBuffers();
211 PostCheckForRetroactiveBeginImplFrame();
214 void OutputSurface::OnSwapBuffersComplete() {
215 pending_swap_buffers_--;
216 TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
217 "pending_swap_buffers_", pending_swap_buffers_);
218 client_->OnSwapBuffersComplete();
219 if (frame_rate_controller_)
220 frame_rate_controller_->DidSwapBuffersComplete();
221 PostCheckForRetroactiveBeginImplFrame();
224 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
225 client_->ReclaimResources(ack);
228 void OutputSurface::DidLoseOutputSurface() {
229 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
230 client_ready_for_begin_impl_frame_ = true;
231 pending_swap_buffers_ = 0;
232 skipped_begin_impl_frame_args_ = BeginFrameArgs();
233 if (frame_rate_controller_)
234 frame_rate_controller_->SetActive(false);
235 pending_gpu_latency_query_ids_.clear();
236 available_gpu_latency_query_ids_.clear();
237 client_->DidLoseOutputSurface();
240 void OutputSurface::SetExternalStencilTest(bool enabled) {
241 external_stencil_test_enabled_ = enabled;
244 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
245 const gfx::Rect& viewport,
246 const gfx::Rect& clip,
247 bool valid_for_tile_management) {
248 client_->SetExternalDrawConstraints(
249 transform, viewport, clip, valid_for_tile_management);
252 OutputSurface::~OutputSurface() {
253 if (frame_rate_controller_)
254 frame_rate_controller_->SetActive(false);
255 ResetContext3d();
258 bool OutputSurface::HasExternalStencilTest() const {
259 return external_stencil_test_enabled_;
262 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
264 bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
265 DCHECK(client);
266 client_ = client;
267 bool success = true;
269 if (context_provider_) {
270 success = context_provider_->BindToCurrentThread();
271 if (success)
272 SetUpContext3d();
275 if (!success)
276 client_ = NULL;
278 return success;
281 bool OutputSurface::InitializeAndSetContext3d(
282 scoped_refptr<ContextProvider> context_provider,
283 scoped_refptr<ContextProvider> offscreen_context_provider) {
284 DCHECK(!context_provider_);
285 DCHECK(context_provider);
286 DCHECK(client_);
288 bool success = false;
289 if (context_provider->BindToCurrentThread()) {
290 context_provider_ = context_provider;
291 SetUpContext3d();
292 if (client_->DeferredInitialize(offscreen_context_provider))
293 success = true;
296 if (!success)
297 ResetContext3d();
299 return success;
302 void OutputSurface::ReleaseGL() {
303 DCHECK(client_);
304 DCHECK(context_provider_);
305 client_->ReleaseGL();
306 ResetContext3d();
309 void OutputSurface::SetUpContext3d() {
310 DCHECK(context_provider_);
311 DCHECK(client_);
313 context_provider_->SetLostContextCallback(
314 base::Bind(&OutputSurface::DidLoseOutputSurface,
315 base::Unretained(this)));
316 context_provider_->ContextSupport()->SetSwapBuffersCompleteCallback(
317 base::Bind(&OutputSurface::OnSwapBuffersComplete,
318 base::Unretained(this)));
319 context_provider_->SetMemoryPolicyChangedCallback(
320 base::Bind(&OutputSurface::SetMemoryPolicy,
321 base::Unretained(this)));
324 void OutputSurface::ResetContext3d() {
325 if (context_provider_.get()) {
326 while (!pending_gpu_latency_query_ids_.empty()) {
327 unsigned query_id = pending_gpu_latency_query_ids_.front();
328 pending_gpu_latency_query_ids_.pop_front();
329 context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
331 while (!available_gpu_latency_query_ids_.empty()) {
332 unsigned query_id = available_gpu_latency_query_ids_.front();
333 available_gpu_latency_query_ids_.pop_front();
334 context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
336 context_provider_->SetLostContextCallback(
337 ContextProvider::LostContextCallback());
338 context_provider_->SetMemoryPolicyChangedCallback(
339 ContextProvider::MemoryPolicyChangedCallback());
340 if (gpu::ContextSupport* support = context_provider_->ContextSupport())
341 support->SetSwapBuffersCompleteCallback(base::Closure());
343 context_provider_ = NULL;
346 void OutputSurface::EnsureBackbuffer() {
347 if (software_device_)
348 software_device_->EnsureBackbuffer();
351 void OutputSurface::DiscardBackbuffer() {
352 if (context_provider_)
353 context_provider_->ContextGL()->DiscardBackbufferCHROMIUM();
354 if (software_device_)
355 software_device_->DiscardBackbuffer();
358 void OutputSurface::Reshape(gfx::Size size, float scale_factor) {
359 if (size == surface_size_ && scale_factor == device_scale_factor_)
360 return;
362 surface_size_ = size;
363 device_scale_factor_ = scale_factor;
364 if (context_provider_) {
365 context_provider_->ContextGL()->ResizeCHROMIUM(
366 size.width(), size.height(), scale_factor);
368 if (software_device_)
369 software_device_->Resize(size);
372 gfx::Size OutputSurface::SurfaceSize() const {
373 return surface_size_;
376 void OutputSurface::BindFramebuffer() {
377 DCHECK(context_provider_);
378 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
381 void OutputSurface::SwapBuffers(CompositorFrame* frame) {
382 if (frame->software_frame_data) {
383 PostSwapBuffersComplete();
384 DidSwapBuffers();
385 return;
388 DCHECK(context_provider_);
389 DCHECK(frame->gl_frame_data);
391 UpdateAndMeasureGpuLatency();
392 if (frame->gl_frame_data->sub_buffer_rect ==
393 gfx::Rect(frame->gl_frame_data->size)) {
394 context_provider_->ContextSupport()->Swap();
395 } else {
396 context_provider_->ContextSupport()->PartialSwapBuffers(
397 frame->gl_frame_data->sub_buffer_rect);
400 DidSwapBuffers();
403 base::TimeDelta OutputSurface::GpuLatencyEstimate() {
404 if (context_provider_ && !capabilities_.adjust_deadline_for_parent)
405 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
406 else
407 return base::TimeDelta();
410 void OutputSurface::UpdateAndMeasureGpuLatency() {
411 return; // http://crbug.com/306690 tracks re-enabling latency queries.
413 // We only care about GPU latency for surfaces that do not have a parent
414 // compositor, since surfaces that do have a parent compositor can use
415 // mailboxes or delegated rendering to send frames to their parent without
416 // incurring GPU latency.
417 if (capabilities_.adjust_deadline_for_parent)
418 return;
420 while (pending_gpu_latency_query_ids_.size()) {
421 unsigned query_id = pending_gpu_latency_query_ids_.front();
422 unsigned query_complete = 1;
423 context_provider_->ContextGL()->GetQueryObjectuivEXT(
424 query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete);
425 if (!query_complete)
426 break;
428 unsigned value = 0;
429 context_provider_->ContextGL()->GetQueryObjectuivEXT(
430 query_id, GL_QUERY_RESULT_EXT, &value);
431 pending_gpu_latency_query_ids_.pop_front();
432 available_gpu_latency_query_ids_.push_back(query_id);
434 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
435 base::TimeDelta latency_estimate = GpuLatencyEstimate();
436 gpu_latency_history_.InsertSample(latency);
438 base::TimeDelta latency_overestimate;
439 base::TimeDelta latency_underestimate;
440 if (latency > latency_estimate)
441 latency_underestimate = latency - latency_estimate;
442 else
443 latency_overestimate = latency_estimate - latency;
444 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
445 latency,
446 base::TimeDelta::FromMilliseconds(1),
447 base::TimeDelta::FromMilliseconds(100),
448 50);
449 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
450 latency_underestimate,
451 base::TimeDelta::FromMilliseconds(1),
452 base::TimeDelta::FromMilliseconds(100),
453 50);
454 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
455 latency_overestimate,
456 base::TimeDelta::FromMilliseconds(1),
457 base::TimeDelta::FromMilliseconds(100),
458 50);
461 unsigned gpu_latency_query_id;
462 if (available_gpu_latency_query_ids_.size()) {
463 gpu_latency_query_id = available_gpu_latency_query_ids_.front();
464 available_gpu_latency_query_ids_.pop_front();
465 } else {
466 context_provider_->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id);
469 context_provider_->ContextGL()->BeginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
470 gpu_latency_query_id);
471 context_provider_->ContextGL()->EndQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
472 pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id);
475 void OutputSurface::PostSwapBuffersComplete() {
476 base::MessageLoop::current()->PostTask(
477 FROM_HERE,
478 base::Bind(&OutputSurface::OnSwapBuffersComplete,
479 weak_ptr_factory_.GetWeakPtr()));
482 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
483 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
484 "bytes_limit_when_visible", policy.bytes_limit_when_visible);
485 // Just ignore the memory manager when it says to set the limit to zero
486 // bytes. This will happen when the memory manager thinks that the renderer
487 // is not visible (which the renderer knows better).
488 if (policy.bytes_limit_when_visible)
489 client_->SetMemoryPolicy(policy);
492 } // namespace cc