1 // Copyright 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 "content/browser/android/in_process/synchronous_compositor_output_surface.h"
7 #include "base/auto_reset.h"
8 #include "base/logging.h"
9 #include "cc/output/compositor_frame.h"
10 #include "cc/output/context_provider.h"
11 #include "cc/output/output_surface_client.h"
12 #include "cc/output/software_output_device.h"
13 #include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
14 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
15 #include "content/browser/android/in_process/synchronous_compositor_registry.h"
16 #include "content/browser/gpu/compositor_util.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/renderer/gpu/frame_swap_message_queue.h"
19 #include "gpu/command_buffer/client/context_support.h"
20 #include "gpu/command_buffer/client/gles2_interface.h"
21 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
22 #include "third_party/skia/include/core/SkCanvas.h"
23 #include "ui/gfx/geometry/rect_conversions.h"
24 #include "ui/gfx/skia_util.h"
25 #include "ui/gfx/transform.h"
31 // Do not limit number of resources, so use an unrealistically high value.
32 const size_t kNumResourcesLimit
= 10 * 1000 * 1000;
36 class SynchronousCompositorOutputSurface::SoftwareDevice
37 : public cc::SoftwareOutputDevice
{
39 SoftwareDevice(SynchronousCompositorOutputSurface
* surface
)
42 void Resize(const gfx::Size
& pixel_size
, float scale_factor
) override
{
43 // Intentional no-op: canvas size is controlled by the embedder.
45 SkCanvas
* BeginPaint(const gfx::Rect
& damage_rect
) override
{
46 if (!surface_
->current_sw_canvas_
) {
47 NOTREACHED() << "BeginPaint with no canvas set";
50 LOG_IF(WARNING
, surface_
->frame_holder_
.get())
51 << "Mutliple calls to BeginPaint per frame";
52 return surface_
->current_sw_canvas_
;
54 void EndPaint() override
{}
57 SynchronousCompositorOutputSurface
* surface_
;
58 SkCanvas null_canvas_
;
60 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice
);
63 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
64 const scoped_refptr
<cc::ContextProvider
>& context_provider
,
65 const scoped_refptr
<cc::ContextProvider
>& worker_context_provider
,
67 scoped_refptr
<FrameSwapMessageQueue
> frame_swap_message_queue
)
70 worker_context_provider
,
71 scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareDevice(this))),
72 routing_id_(routing_id
),
74 current_sw_canvas_(nullptr),
76 frame_swap_message_queue_(frame_swap_message_queue
) {
77 capabilities_
.draw_and_swap_full_viewport_every_frame
= true;
78 capabilities_
.adjust_deadline_for_parent
= false;
79 capabilities_
.delegated_rendering
= true;
80 capabilities_
.max_frames_pending
= 1;
81 memory_policy_
.priority_cutoff_when_visible
=
82 gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE
;
85 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
88 bool SynchronousCompositorOutputSurface::BindToClient(
89 cc::OutputSurfaceClient
* surface_client
) {
90 DCHECK(CalledOnValidThread());
91 if (!cc::OutputSurface::BindToClient(surface_client
))
94 client_
->SetMemoryPolicy(memory_policy_
);
96 SynchronousCompositorRegistry::GetInstance()->RegisterOutputSurface(
103 void SynchronousCompositorOutputSurface::DetachFromClient() {
104 DCHECK(CalledOnValidThread());
106 SynchronousCompositorRegistry::GetInstance()->UnregisterOutputSurface(
109 cc::OutputSurface::DetachFromClient();
112 void SynchronousCompositorOutputSurface::SetCompositor(
113 SynchronousCompositorImpl
* compositor
) {
114 DCHECK(CalledOnValidThread());
115 compositor_
= compositor
;
118 void SynchronousCompositorOutputSurface::Reshape(
119 const gfx::Size
& size
, float scale_factor
) {
120 // Intentional no-op: surface size is controlled by the embedder.
123 void SynchronousCompositorOutputSurface::SwapBuffers(
124 cc::CompositorFrame
* frame
) {
125 DCHECK(CalledOnValidThread());
127 frame_holder_
.reset(new cc::CompositorFrame
);
128 frame
->AssignTo(frame_holder_
.get());
130 client_
->DidSwapBuffers();
133 void SynchronousCompositorOutputSurface::Invalidate() {
134 DCHECK(CalledOnValidThread());
135 compositor_
->PostInvalidate();
139 void AdjustTransform(gfx::Transform
* transform
, gfx::Rect viewport
) {
140 // CC's draw origin starts at the viewport.
141 transform
->matrix().postTranslate(-viewport
.x(), -viewport
.y(), 0);
145 scoped_ptr
<cc::CompositorFrame
>
146 SynchronousCompositorOutputSurface::DemandDrawHw(
147 gfx::Size surface_size
,
148 const gfx::Transform
& transform
,
151 gfx::Rect viewport_rect_for_tile_priority
,
152 const gfx::Transform
& transform_for_tile_priority
) {
153 DCHECK(CalledOnValidThread());
155 DCHECK(context_provider_
.get());
157 surface_size_
= surface_size
;
158 InvokeComposite(transform
,
161 viewport_rect_for_tile_priority
,
162 transform_for_tile_priority
,
165 return frame_holder_
.Pass();
168 scoped_ptr
<cc::CompositorFrame
>
169 SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas
* canvas
) {
170 DCHECK(CalledOnValidThread());
172 DCHECK(!current_sw_canvas_
);
174 base::AutoReset
<SkCanvas
*> canvas_resetter(¤t_sw_canvas_
, canvas
);
177 canvas
->getClipDeviceBounds(&canvas_clip
);
178 gfx::Rect clip
= gfx::SkIRectToRect(canvas_clip
);
180 gfx::Transform
transform(gfx::Transform::kSkipInitialization
);
181 transform
.matrix() = canvas
->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
183 surface_size_
= gfx::Size(canvas
->getDeviceSize().width(),
184 canvas
->getDeviceSize().height());
186 // Pass in the cached hw viewport and transform for tile priority to avoid
187 // tile thrashing when the WebView is alternating between hardware and
189 InvokeComposite(transform
,
192 cached_hw_viewport_rect_for_tile_priority_
,
193 cached_hw_transform_for_tile_priority_
,
196 return frame_holder_
.Pass();
199 void SynchronousCompositorOutputSurface::InvokeComposite(
200 const gfx::Transform
& transform
,
203 gfx::Rect viewport_rect_for_tile_priority
,
204 gfx::Transform transform_for_tile_priority
,
205 bool hardware_draw
) {
206 DCHECK(!frame_holder_
.get());
208 gfx::Transform adjusted_transform
= transform
;
209 AdjustTransform(&adjusted_transform
, viewport
);
210 SetExternalDrawConstraints(adjusted_transform
,
213 viewport_rect_for_tile_priority
,
214 transform_for_tile_priority
,
216 SetNeedsRedrawRect(gfx::Rect(viewport
.size()));
220 // After software draws (which might move the viewport arbitrarily), restore
221 // the previous hardware viewport to allow CC's tile manager to prioritize
224 cached_hw_transform_
= adjusted_transform
;
225 cached_hw_viewport_
= viewport
;
226 cached_hw_clip_
= clip
;
227 cached_hw_viewport_rect_for_tile_priority_
=
228 viewport_rect_for_tile_priority
;
229 cached_hw_transform_for_tile_priority_
= transform_for_tile_priority
;
231 bool resourceless_software_draw
= false;
232 SetExternalDrawConstraints(cached_hw_transform_
,
235 cached_hw_viewport_rect_for_tile_priority_
,
236 cached_hw_transform_for_tile_priority_
,
237 resourceless_software_draw
);
240 if (frame_holder_
.get())
241 client_
->DidSwapBuffersComplete();
244 void SynchronousCompositorOutputSurface::ReturnResources(
245 const cc::CompositorFrameAck
& frame_ack
) {
246 ReclaimResources(&frame_ack
);
249 void SynchronousCompositorOutputSurface::SetMemoryPolicy(size_t bytes_limit
) {
250 DCHECK(CalledOnValidThread());
251 bool became_zero
= memory_policy_
.bytes_limit_when_visible
&& !bytes_limit
;
252 bool became_non_zero
=
253 !memory_policy_
.bytes_limit_when_visible
&& bytes_limit
;
254 memory_policy_
.bytes_limit_when_visible
= bytes_limit
;
255 memory_policy_
.num_resources_limit
= kNumResourcesLimit
;
258 client_
->SetMemoryPolicy(memory_policy_
);
261 // This is small hack to drop context resources without destroying it
262 // when this compositor is put into the background.
263 context_provider()->ContextSupport()->SetAggressivelyFreeResources(
264 true /* aggressively_free_resources */);
265 } else if (became_non_zero
) {
266 context_provider()->ContextSupport()->SetAggressivelyFreeResources(
267 false /* aggressively_free_resources */);
271 void SynchronousCompositorOutputSurface::SetTreeActivationCallback(
272 const base::Closure
& callback
) {
274 client_
->SetTreeActivationCallback(callback
);
277 void SynchronousCompositorOutputSurface::GetMessagesToDeliver(
278 ScopedVector
<IPC::Message
>* messages
) {
279 DCHECK(CalledOnValidThread());
280 scoped_ptr
<FrameSwapMessageQueue::SendMessageScope
> send_message_scope
=
281 frame_swap_message_queue_
->AcquireSendMessageScope();
282 frame_swap_message_queue_
->DrainMessages(messages
);
285 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
286 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
288 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
289 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
292 } // namespace content