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"
11 #include "base/bind.h"
12 #include "base/debug/trace_event.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/string_util.h"
17 #include "cc/output/compositor_frame.h"
18 #include "cc/output/managed_memory_policy.h"
19 #include "cc/output/output_surface_client.h"
20 #include "cc/scheduler/delay_based_time_source.h"
21 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
22 #include "third_party/khronos/GLES2/gl2.h"
23 #include "third_party/khronos/GLES2/gl2ext.h"
24 #include "ui/gfx/rect.h"
25 #include "ui/gfx/size.h"
33 OutputSurface::OutputSurface(scoped_refptr
<ContextProvider
> context_provider
)
34 : context_provider_(context_provider
),
35 has_gl_discard_backbuffer_(false),
36 has_swap_buffers_complete_callback_(false),
37 device_scale_factor_(-1),
38 weak_ptr_factory_(this),
39 max_frames_pending_(0),
40 pending_swap_buffers_(0),
41 needs_begin_frame_(false),
42 begin_frame_pending_(false),
44 check_for_retroactive_begin_frame_pending_(false),
45 external_stencil_test_enabled_(false) {}
47 OutputSurface::OutputSurface(
48 scoped_ptr
<cc::SoftwareOutputDevice
> software_device
)
49 : software_device_(software_device
.Pass()),
50 has_gl_discard_backbuffer_(false),
51 has_swap_buffers_complete_callback_(false),
52 device_scale_factor_(-1),
53 weak_ptr_factory_(this),
54 max_frames_pending_(0),
55 pending_swap_buffers_(0),
56 needs_begin_frame_(false),
57 begin_frame_pending_(false),
59 check_for_retroactive_begin_frame_pending_(false),
60 external_stencil_test_enabled_(false) {}
62 OutputSurface::OutputSurface(
63 scoped_refptr
<ContextProvider
> context_provider
,
64 scoped_ptr
<cc::SoftwareOutputDevice
> software_device
)
65 : context_provider_(context_provider
),
66 software_device_(software_device
.Pass()),
67 has_gl_discard_backbuffer_(false),
68 has_swap_buffers_complete_callback_(false),
69 device_scale_factor_(-1),
70 weak_ptr_factory_(this),
71 max_frames_pending_(0),
72 pending_swap_buffers_(0),
73 needs_begin_frame_(false),
74 begin_frame_pending_(false),
76 check_for_retroactive_begin_frame_pending_(false),
77 external_stencil_test_enabled_(false) {}
79 void OutputSurface::InitializeBeginFrameEmulation(
80 base::SingleThreadTaskRunner
* task_runner
,
81 bool throttle_frame_production
,
82 base::TimeDelta interval
) {
83 if (throttle_frame_production
) {
84 frame_rate_controller_
.reset(
85 new FrameRateController(
86 DelayBasedTimeSource::Create(interval
, task_runner
)));
88 frame_rate_controller_
.reset(new FrameRateController(task_runner
));
91 frame_rate_controller_
->SetClient(this);
92 frame_rate_controller_
->SetMaxSwapsPending(max_frames_pending_
);
93 frame_rate_controller_
->SetDeadlineAdjustment(
94 capabilities_
.adjust_deadline_for_parent
?
95 BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
97 // The new frame rate controller will consume the swap acks of the old
98 // frame rate controller, so we set that expectation up here.
99 for (int i
= 0; i
< pending_swap_buffers_
; i
++)
100 frame_rate_controller_
->DidSwapBuffers();
103 void OutputSurface::SetMaxFramesPending(int max_frames_pending
) {
104 if (frame_rate_controller_
)
105 frame_rate_controller_
->SetMaxSwapsPending(max_frames_pending
);
106 max_frames_pending_
= max_frames_pending
;
109 void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase
,
110 base::TimeDelta interval
) {
111 TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
112 "timebase", (timebase
- base::TimeTicks()).InSecondsF(),
113 "interval", interval
.InSecondsF());
114 if (frame_rate_controller_
)
115 frame_rate_controller_
->SetTimebaseAndInterval(timebase
, interval
);
118 void OutputSurface::FrameRateControllerTick(bool throttled
,
119 const BeginFrameArgs
& args
) {
120 DCHECK(frame_rate_controller_
);
122 skipped_begin_frame_args_
= args
;
127 // Forwarded to OutputSurfaceClient
128 void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect
) {
129 TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
130 client_
->SetNeedsRedrawRect(damage_rect
);
133 void OutputSurface::SetNeedsBeginFrame(bool enable
) {
134 TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginFrame", "enable", enable
);
135 needs_begin_frame_
= enable
;
136 begin_frame_pending_
= false;
137 if (frame_rate_controller_
) {
138 BeginFrameArgs skipped
= frame_rate_controller_
->SetActive(enable
);
139 if (skipped
.IsValid())
140 skipped_begin_frame_args_
= skipped
;
142 if (needs_begin_frame_
)
143 PostCheckForRetroactiveBeginFrame();
146 void OutputSurface::BeginFrame(const BeginFrameArgs
& args
) {
147 TRACE_EVENT2("cc", "OutputSurface::BeginFrame",
148 "begin_frame_pending_", begin_frame_pending_
,
149 "pending_swap_buffers_", pending_swap_buffers_
);
150 if (!needs_begin_frame_
|| begin_frame_pending_
||
151 (pending_swap_buffers_
>= max_frames_pending_
&&
152 max_frames_pending_
> 0)) {
153 skipped_begin_frame_args_
= args
;
155 begin_frame_pending_
= true;
156 client_
->BeginFrame(args
);
157 // args might be an alias for skipped_begin_frame_args_.
158 // Do not reset it before calling BeginFrame!
159 skipped_begin_frame_args_
= BeginFrameArgs();
163 base::TimeDelta
OutputSurface::AlternateRetroactiveBeginFramePeriod() {
164 return BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
167 void OutputSurface::PostCheckForRetroactiveBeginFrame() {
168 if (!skipped_begin_frame_args_
.IsValid() ||
169 check_for_retroactive_begin_frame_pending_
)
172 base::MessageLoop::current()->PostTask(
174 base::Bind(&OutputSurface::CheckForRetroactiveBeginFrame
,
175 weak_ptr_factory_
.GetWeakPtr()));
176 check_for_retroactive_begin_frame_pending_
= true;
179 void OutputSurface::CheckForRetroactiveBeginFrame() {
180 TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginFrame");
181 check_for_retroactive_begin_frame_pending_
= false;
182 base::TimeTicks now
= base::TimeTicks::Now();
183 // TODO(brianderson): Remove the alternative deadline once we have better
184 // deadline estimations.
185 base::TimeTicks alternative_deadline
=
186 skipped_begin_frame_args_
.frame_time
+
187 AlternateRetroactiveBeginFramePeriod();
188 if (now
< skipped_begin_frame_args_
.deadline
||
189 now
< alternative_deadline
) {
190 BeginFrame(skipped_begin_frame_args_
);
194 void OutputSurface::DidSwapBuffers() {
195 begin_frame_pending_
= false;
196 pending_swap_buffers_
++;
197 TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
198 "pending_swap_buffers_", pending_swap_buffers_
);
199 if (frame_rate_controller_
)
200 frame_rate_controller_
->DidSwapBuffers();
201 PostCheckForRetroactiveBeginFrame();
204 void OutputSurface::OnSwapBuffersComplete(const CompositorFrameAck
* ack
) {
205 pending_swap_buffers_
--;
206 TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
207 "pending_swap_buffers_", pending_swap_buffers_
);
208 client_
->OnSwapBuffersComplete(ack
);
209 if (frame_rate_controller_
)
210 frame_rate_controller_
->DidSwapBuffersComplete();
211 PostCheckForRetroactiveBeginFrame();
214 void OutputSurface::DidLoseOutputSurface() {
215 TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
216 begin_frame_pending_
= false;
217 pending_swap_buffers_
= 0;
218 client_
->DidLoseOutputSurface();
221 void OutputSurface::SetExternalStencilTest(bool enabled
) {
222 external_stencil_test_enabled_
= enabled
;
225 void OutputSurface::SetExternalDrawConstraints(const gfx::Transform
& transform
,
228 bool valid_for_tile_management
) {
229 client_
->SetExternalDrawConstraints(
230 transform
, viewport
, clip
, valid_for_tile_management
);
233 OutputSurface::~OutputSurface() {
234 if (frame_rate_controller_
)
235 frame_rate_controller_
->SetActive(false);
239 bool OutputSurface::HasExternalStencilTest() const {
240 return external_stencil_test_enabled_
;
243 bool OutputSurface::ForcedDrawToSoftwareDevice() const { return false; }
245 bool OutputSurface::BindToClient(cc::OutputSurfaceClient
* client
) {
250 if (context_provider_
) {
251 success
= context_provider_
->BindToCurrentThread();
262 bool OutputSurface::InitializeAndSetContext3d(
263 scoped_refptr
<ContextProvider
> context_provider
,
264 scoped_refptr
<ContextProvider
> offscreen_context_provider
) {
265 DCHECK(!context_provider_
);
266 DCHECK(context_provider
);
269 bool success
= false;
270 if (context_provider
->BindToCurrentThread()) {
271 context_provider_
= context_provider
;
273 if (client_
->DeferredInitialize(offscreen_context_provider
))
283 void OutputSurface::ReleaseGL() {
285 DCHECK(context_provider_
);
286 client_
->ReleaseGL();
290 void OutputSurface::SetUpContext3d() {
291 DCHECK(context_provider_
);
294 const ContextProvider::Capabilities
& caps
=
295 context_provider_
->ContextCapabilities();
297 has_gl_discard_backbuffer_
= caps
.discard_backbuffer
;
298 has_swap_buffers_complete_callback_
= caps
.swapbuffers_complete_callback
;
300 context_provider_
->SetLostContextCallback(
301 base::Bind(&OutputSurface::DidLoseOutputSurface
,
302 base::Unretained(this)));
303 context_provider_
->SetSwapBuffersCompleteCallback(
304 base::Bind(&OutputSurface::OnSwapBuffersComplete
,
305 base::Unretained(this),
306 static_cast<CompositorFrameAck
*>(NULL
)));
307 context_provider_
->SetMemoryPolicyChangedCallback(
308 base::Bind(&OutputSurface::SetMemoryPolicy
,
309 base::Unretained(this)));
312 void OutputSurface::ResetContext3d() {
313 if (context_provider_
.get()) {
314 context_provider_
->SetLostContextCallback(
315 ContextProvider::LostContextCallback());
316 context_provider_
->SetSwapBuffersCompleteCallback(
317 ContextProvider::SwapBuffersCompleteCallback());
318 context_provider_
->SetMemoryPolicyChangedCallback(
319 ContextProvider::MemoryPolicyChangedCallback());
321 context_provider_
= NULL
;
324 void OutputSurface::EnsureBackbuffer() {
325 if (context_provider_
&& has_gl_discard_backbuffer_
)
326 context_provider_
->Context3d()->ensureBackbufferCHROMIUM();
329 void OutputSurface::DiscardBackbuffer() {
330 if (context_provider_
&& has_gl_discard_backbuffer_
)
331 context_provider_
->Context3d()->discardBackbufferCHROMIUM();
334 void OutputSurface::Reshape(gfx::Size size
, float scale_factor
) {
335 if (size
== surface_size_
&& scale_factor
== device_scale_factor_
)
338 surface_size_
= size
;
339 device_scale_factor_
= scale_factor
;
340 if (context_provider_
) {
341 context_provider_
->Context3d()->reshapeWithScaleFactor(
342 size
.width(), size
.height(), scale_factor
);
344 if (software_device_
)
345 software_device_
->Resize(size
);
348 gfx::Size
OutputSurface::SurfaceSize() const {
349 return surface_size_
;
352 void OutputSurface::BindFramebuffer() {
353 DCHECK(context_provider_
);
354 context_provider_
->Context3d()->bindFramebuffer(GL_FRAMEBUFFER
, 0);
357 void OutputSurface::SwapBuffers(cc::CompositorFrame
* frame
) {
358 if (frame
->software_frame_data
) {
359 PostSwapBuffersComplete();
364 DCHECK(context_provider_
);
365 DCHECK(frame
->gl_frame_data
);
367 if (frame
->gl_frame_data
->sub_buffer_rect
==
368 gfx::Rect(frame
->gl_frame_data
->size
)) {
369 // Note that currently this has the same effect as SwapBuffers; we should
370 // consider exposing a different entry point on WebGraphicsContext3D.
371 context_provider_
->Context3d()->prepareTexture();
373 gfx::Rect sub_buffer_rect
= frame
->gl_frame_data
->sub_buffer_rect
;
374 context_provider_
->Context3d()->postSubBufferCHROMIUM(
377 sub_buffer_rect
.width(),
378 sub_buffer_rect
.height());
381 if (!has_swap_buffers_complete_callback_
)
382 PostSwapBuffersComplete();
387 void OutputSurface::PostSwapBuffersComplete() {
388 base::MessageLoop::current()->PostTask(
390 base::Bind(&OutputSurface::OnSwapBuffersComplete
,
391 weak_ptr_factory_
.GetWeakPtr(),
392 static_cast<CompositorFrameAck
*>(NULL
)));
395 void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy
& policy
,
396 bool discard_backbuffer
) {
397 TRACE_EVENT2("cc", "OutputSurface::SetMemoryPolicy",
398 "bytes_limit_when_visible", policy
.bytes_limit_when_visible
,
399 "discard_backbuffer", discard_backbuffer
);
400 // Just ignore the memory manager when it says to set the limit to zero
401 // bytes. This will happen when the memory manager thinks that the renderer
402 // is not visible (which the renderer knows better).
403 if (policy
.bytes_limit_when_visible
)
404 client_
->SetMemoryPolicy(policy
);
405 client_
->SetDiscardBackBufferWhenNotVisible(discard_backbuffer
);