chrome.windows.create should return new window id in Guest mode
[chromium-blink-merge.git] / cc / output / output_surface.cc
blobf7b3b36219b6da5cc0a0994d2744d1120f6fdf5a
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 "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
26 #include "third_party/khronos/GLES2/gl2.h"
27 #include "third_party/khronos/GLES2/gl2ext.h"
28 #include "ui/gfx/frame_time.h"
29 #include "ui/gfx/rect.h"
30 #include "ui/gfx/size.h"
32 using std::set;
33 using std::string;
34 using std::vector;
36 namespace {
38 const size_t kGpuLatencyHistorySize = 60;
39 const double kGpuLatencyEstimationPercentile = 100.0;
43 namespace cc {
45 OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
46 : context_provider_(context_provider),
47 has_gl_discard_backbuffer_(false),
48 has_swap_buffers_complete_callback_(false),
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) {}
60 OutputSurface::OutputSurface(
61 scoped_ptr<cc::SoftwareOutputDevice> software_device)
62 : software_device_(software_device.Pass()),
63 has_gl_discard_backbuffer_(false),
64 has_swap_buffers_complete_callback_(false),
65 device_scale_factor_(-1),
66 max_frames_pending_(0),
67 pending_swap_buffers_(0),
68 needs_begin_impl_frame_(false),
69 client_ready_for_begin_impl_frame_(true),
70 client_(NULL),
71 check_for_retroactive_begin_impl_frame_pending_(false),
72 external_stencil_test_enabled_(false),
73 weak_ptr_factory_(this),
74 gpu_latency_history_(kGpuLatencyHistorySize) {}
76 OutputSurface::OutputSurface(
77 scoped_refptr<ContextProvider> context_provider,
78 scoped_ptr<cc::SoftwareOutputDevice> software_device)
79 : context_provider_(context_provider),
80 software_device_(software_device.Pass()),
81 has_gl_discard_backbuffer_(false),
82 has_swap_buffers_complete_callback_(false),
83 device_scale_factor_(-1),
84 max_frames_pending_(0),
85 pending_swap_buffers_(0),
86 needs_begin_impl_frame_(false),
87 client_ready_for_begin_impl_frame_(true),
88 client_(NULL),
89 check_for_retroactive_begin_impl_frame_pending_(false),
90 external_stencil_test_enabled_(false),
91 weak_ptr_factory_(this),
92 gpu_latency_history_(kGpuLatencyHistorySize) {}
94 void OutputSurface::InitializeBeginImplFrameEmulation(
95 base::SingleThreadTaskRunner* task_runner,
96 bool throttle_frame_production,
97 base::TimeDelta interval) {
98 if (throttle_frame_production) {
99 scoped_refptr<DelayBasedTimeSource> time_source;
100 if (gfx::FrameTime::TimestampsAreHighRes())
101 time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner);
102 else
103 time_source = DelayBasedTimeSource::Create(interval, task_runner);
104 frame_rate_controller_.reset(new FrameRateController(time_source));
105 } else {
106 frame_rate_controller_.reset(new FrameRateController(task_runner));
109 frame_rate_controller_->SetClient(this);
110 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_);
111 frame_rate_controller_->SetDeadlineAdjustment(
112 capabilities_.adjust_deadline_for_parent ?
113 BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
115 // The new frame rate controller will consume the swap acks of the old
116 // frame rate controller, so we set that expectation up here.
117 for (int i = 0; i < pending_swap_buffers_; i++)
118 frame_rate_controller_->DidSwapBuffers();
121 void OutputSurface::SetMaxFramesPending(int max_frames_pending) {
122 if (frame_rate_controller_)
123 frame_rate_controller_->SetMaxSwapsPending(max_frames_pending);
124 max_frames_pending_ = max_frames_pending;
127 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase,
128 base::TimeDelta interval) {
129 TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
130 "timebase", (timebase - base::TimeTicks()).InSecondsF(),
131 "interval", interval.InSecondsF());
132 if (frame_rate_controller_)
133 frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
136 void OutputSurface::FrameRateControllerTick(bool throttled,
137 const BeginFrameArgs& args) {
138 DCHECK(frame_rate_controller_);
139 if (throttled)
140 skipped_begin_impl_frame_args_ = args;
141 else
142 BeginImplFrame(args);
145 // Forwarded to OutputSurfaceClient
146 void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) {
147 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
148 client_->SetNeedsRedrawRect(damage_rect);
151 void OutputSurface::SetNeedsBeginImplFrame(bool enable) {
152 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable);
153 needs_begin_impl_frame_ = enable;
154 client_ready_for_begin_impl_frame_ = true;
155 if (frame_rate_controller_) {
156 BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable);
157 if (skipped.IsValid())
158 skipped_begin_impl_frame_args_ = skipped;
160 if (needs_begin_impl_frame_)
161 PostCheckForRetroactiveBeginImplFrame();
164 void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) {
165 TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
166 "client_ready_for_begin_impl_frame_",
167 client_ready_for_begin_impl_frame_,
168 "pending_swap_buffers_", pending_swap_buffers_);
169 if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ ||
170 (pending_swap_buffers_ >= max_frames_pending_ &&
171 max_frames_pending_ > 0)) {
172 skipped_begin_impl_frame_args_ = args;
173 } else {
174 client_ready_for_begin_impl_frame_ = false;
175 client_->BeginImplFrame(args);
176 // args might be an alias for skipped_begin_impl_frame_args_.
177 // Do not reset it before calling BeginImplFrame!
178 skipped_begin_impl_frame_args_ = BeginFrameArgs();
182 base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() {
183 // TODO(brianderson): Remove the alternative deadline once we have better
184 // deadline estimations.
185 base::TimeTicks alternative_deadline =
186 skipped_begin_impl_frame_args_.frame_time +
187 BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
188 return std::max(skipped_begin_impl_frame_args_.deadline,
189 alternative_deadline);
192 void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
193 if (!skipped_begin_impl_frame_args_.IsValid() ||
194 check_for_retroactive_begin_impl_frame_pending_)
195 return;
197 base::MessageLoop::current()->PostTask(
198 FROM_HERE,
199 base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
200 weak_ptr_factory_.GetWeakPtr()));
201 check_for_retroactive_begin_impl_frame_pending_ = true;
204 void OutputSurface::CheckForRetroactiveBeginImplFrame() {
205 TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
206 check_for_retroactive_begin_impl_frame_pending_ = false;
207 if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
208 BeginImplFrame(skipped_begin_impl_frame_args_);
211 void OutputSurface::DidSwapBuffers() {
212 pending_swap_buffers_++;
213 TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
214 "pending_swap_buffers_", pending_swap_buffers_);
215 if (frame_rate_controller_)
216 frame_rate_controller_->DidSwapBuffers();
217 PostCheckForRetroactiveBeginImplFrame();
220 void OutputSurface::OnSwapBuffersComplete() {
221 pending_swap_buffers_--;
222 TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
223 "pending_swap_buffers_", pending_swap_buffers_);
224 client_->OnSwapBuffersComplete();
225 if (frame_rate_controller_)
226 frame_rate_controller_->DidSwapBuffersComplete();
227 PostCheckForRetroactiveBeginImplFrame();
230 void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
231 client_->ReclaimResources(ack);
234 void OutputSurface::DidLoseOutputSurface() {
235 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
236 client_ready_for_begin_impl_frame_ = true;
237 pending_swap_buffers_ = 0;
238 skipped_begin_impl_frame_args_ = BeginFrameArgs();
239 if (frame_rate_controller_)
240 frame_rate_controller_->SetActive(false);
241 pending_gpu_latency_query_ids_.clear();
242 available_gpu_latency_query_ids_.clear();
243 client_->DidLoseOutputSurface();
246 void OutputSurface::SetExternalStencilTest(bool enabled) {
247 external_stencil_test_enabled_ = enabled;
250 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
251 gfx::Rect viewport,
252 gfx::Rect clip,
253 bool valid_for_tile_management) {
254 client_->SetExternalDrawConstraints(
255 transform, viewport, clip, valid_for_tile_management);
258 OutputSurface::~OutputSurface() {
259 if (frame_rate_controller_)
260 frame_rate_controller_->SetActive(false);
261 ResetContext3d();
264 bool OutputSurface::HasExternalStencilTest() const {
265 return external_stencil_test_enabled_;
268 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
270 bool OutputSurface::BindToClient(cc::OutputSurfaceClient* client) {
271 DCHECK(client);
272 client_ = client;
273 bool success = true;
275 if (context_provider_) {
276 success = context_provider_->BindToCurrentThread();
277 if (success)
278 SetUpContext3d();
281 if (!success)
282 client_ = NULL;
284 return success;
287 bool OutputSurface::InitializeAndSetContext3d(
288 scoped_refptr<ContextProvider> context_provider,
289 scoped_refptr<ContextProvider> offscreen_context_provider) {
290 DCHECK(!context_provider_);
291 DCHECK(context_provider);
292 DCHECK(client_);
294 bool success = false;
295 if (context_provider->BindToCurrentThread()) {
296 context_provider_ = context_provider;
297 SetUpContext3d();
298 if (client_->DeferredInitialize(offscreen_context_provider))
299 success = true;
302 if (!success)
303 ResetContext3d();
305 return success;
308 void OutputSurface::ReleaseGL() {
309 DCHECK(client_);
310 DCHECK(context_provider_);
311 client_->ReleaseGL();
312 ResetContext3d();
315 void OutputSurface::SetUpContext3d() {
316 DCHECK(context_provider_);
317 DCHECK(client_);
319 const ContextProvider::Capabilities& caps =
320 context_provider_->ContextCapabilities();
322 has_gl_discard_backbuffer_ = caps.discard_backbuffer;
323 has_swap_buffers_complete_callback_ = caps.swapbuffers_complete_callback;
325 context_provider_->SetLostContextCallback(
326 base::Bind(&OutputSurface::DidLoseOutputSurface,
327 base::Unretained(this)));
328 context_provider_->SetSwapBuffersCompleteCallback(base::Bind(
329 &OutputSurface::OnSwapBuffersComplete, base::Unretained(this)));
330 context_provider_->SetMemoryPolicyChangedCallback(
331 base::Bind(&OutputSurface::SetMemoryPolicy,
332 base::Unretained(this)));
335 void OutputSurface::ResetContext3d() {
336 if (context_provider_.get()) {
337 context_provider_->SetLostContextCallback(
338 ContextProvider::LostContextCallback());
339 context_provider_->SetSwapBuffersCompleteCallback(
340 ContextProvider::SwapBuffersCompleteCallback());
341 context_provider_->SetMemoryPolicyChangedCallback(
342 ContextProvider::MemoryPolicyChangedCallback());
344 context_provider_ = NULL;
347 void OutputSurface::EnsureBackbuffer() {
348 if (context_provider_ && has_gl_discard_backbuffer_)
349 context_provider_->Context3d()->ensureBackbufferCHROMIUM();
350 if (software_device_)
351 software_device_->EnsureBackbuffer();
354 void OutputSurface::DiscardBackbuffer() {
355 if (context_provider_ && has_gl_discard_backbuffer_)
356 context_provider_->Context3d()->discardBackbufferCHROMIUM();
357 if (software_device_)
358 software_device_->DiscardBackbuffer();
361 void OutputSurface::Reshape(gfx::Size size, float scale_factor) {
362 if (size == surface_size_ && scale_factor == device_scale_factor_)
363 return;
365 surface_size_ = size;
366 device_scale_factor_ = scale_factor;
367 if (context_provider_) {
368 context_provider_->Context3d()->reshapeWithScaleFactor(
369 size.width(), size.height(), scale_factor);
371 if (software_device_)
372 software_device_->Resize(size);
375 gfx::Size OutputSurface::SurfaceSize() const {
376 return surface_size_;
379 void OutputSurface::BindFramebuffer() {
380 DCHECK(context_provider_);
381 context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0);
384 void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
385 if (frame->software_frame_data) {
386 PostSwapBuffersComplete();
387 DidSwapBuffers();
388 return;
391 DCHECK(context_provider_);
392 DCHECK(frame->gl_frame_data);
394 UpdateAndMeasureGpuLatency();
395 if (frame->gl_frame_data->sub_buffer_rect ==
396 gfx::Rect(frame->gl_frame_data->size)) {
397 // Note that currently this has the same effect as SwapBuffers; we should
398 // consider exposing a different entry point on WebGraphicsContext3D.
399 context_provider_->Context3d()->prepareTexture();
400 } else {
401 gfx::Rect sub_buffer_rect = frame->gl_frame_data->sub_buffer_rect;
402 context_provider_->Context3d()->postSubBufferCHROMIUM(
403 sub_buffer_rect.x(),
404 sub_buffer_rect.y(),
405 sub_buffer_rect.width(),
406 sub_buffer_rect.height());
409 if (!has_swap_buffers_complete_callback_)
410 PostSwapBuffersComplete();
412 DidSwapBuffers();
415 base::TimeDelta OutputSurface::GpuLatencyEstimate() {
416 if (context_provider_ && !capabilities_.adjust_deadline_for_parent)
417 return gpu_latency_history_.Percentile(kGpuLatencyEstimationPercentile);
418 else
419 return base::TimeDelta();
422 void OutputSurface::UpdateAndMeasureGpuLatency() {
423 // We only care about GPU latency for surfaces that do not have a parent
424 // compositor, since surfaces that do have a parent compositor can use
425 // mailboxes or delegated rendering to send frames to their parent without
426 // incurring GPU latency.
427 if (capabilities_.adjust_deadline_for_parent)
428 return;
430 while (pending_gpu_latency_query_ids_.size()) {
431 unsigned query_id = pending_gpu_latency_query_ids_.front();
432 unsigned query_complete = 1;
433 context_provider_->Context3d()->getQueryObjectuivEXT(
434 query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete);
435 if (!query_complete)
436 break;
438 unsigned value = 0;
439 context_provider_->Context3d()->getQueryObjectuivEXT(
440 query_id, GL_QUERY_RESULT_EXT, &value);
441 pending_gpu_latency_query_ids_.pop_front();
442 available_gpu_latency_query_ids_.push_back(query_id);
444 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(value);
445 base::TimeDelta latency_estimate = GpuLatencyEstimate();
446 gpu_latency_history_.InsertSample(latency);
448 base::TimeDelta latency_overestimate;
449 base::TimeDelta latency_underestimate;
450 if (latency > latency_estimate)
451 latency_underestimate = latency - latency_estimate;
452 else
453 latency_overestimate = latency_estimate - latency;
454 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatency",
455 latency,
456 base::TimeDelta::FromMilliseconds(1),
457 base::TimeDelta::FromMilliseconds(100),
458 50);
459 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyUnderestimate",
460 latency_underestimate,
461 base::TimeDelta::FromMilliseconds(1),
462 base::TimeDelta::FromMilliseconds(100),
463 50);
464 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.GpuLatencyOverestimate",
465 latency_overestimate,
466 base::TimeDelta::FromMilliseconds(1),
467 base::TimeDelta::FromMilliseconds(100),
468 50);
471 unsigned gpu_latency_query_id;
472 if (available_gpu_latency_query_ids_.size()) {
473 gpu_latency_query_id = available_gpu_latency_query_ids_.front();
474 available_gpu_latency_query_ids_.pop_front();
475 } else {
476 gpu_latency_query_id = context_provider_->Context3d()->createQueryEXT();
479 context_provider_->Context3d()->beginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
480 gpu_latency_query_id);
481 context_provider_->Context3d()->endQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
482 pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id);
485 void OutputSurface::PostSwapBuffersComplete() {
486 base::MessageLoop::current()->PostTask(
487 FROM_HERE,
488 base::Bind(&OutputSurface::OnSwapBuffersComplete,
489 weak_ptr_factory_.GetWeakPtr()));
492 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
493 TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
494 "bytes_limit_when_visible", policy.bytes_limit_when_visible);
495 // Just ignore the memory manager when it says to set the limit to zero
496 // bytes. This will happen when the memory manager thinks that the renderer
497 // is not visible (which the renderer knows better).
498 if (policy.bytes_limit_when_visible)
499 client_->SetMemoryPolicy(policy);
502 } // namespace cc