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/begin_frame_args.h"
10 #include "cc/output/compositor_frame.h"
11 #include "cc/output/context_provider.h"
12 #include "cc/output/output_surface_client.h"
13 #include "cc/output/software_output_device.h"
14 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
15 #include "content/browser/gpu/compositor_util.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/renderer/gpu/frame_swap_message_queue.h"
18 #include "gpu/command_buffer/client/gles2_interface.h"
19 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
20 #include "third_party/skia/include/core/SkCanvas.h"
21 #include "ui/gfx/rect_conversions.h"
22 #include "ui/gfx/skia_util.h"
23 #include "ui/gfx/transform.h"
29 void DidActivatePendingTree(int routing_id
) {
30 SynchronousCompositorOutputSurfaceDelegate
* delegate
=
31 SynchronousCompositorImpl::FromRoutingID(routing_id
);
33 delegate
->DidActivatePendingTree();
38 class SynchronousCompositorOutputSurface::SoftwareDevice
39 : public cc::SoftwareOutputDevice
{
41 SoftwareDevice(SynchronousCompositorOutputSurface
* surface
)
44 virtual void Resize(const gfx::Size
& pixel_size
,
45 float scale_factor
) OVERRIDE
{
46 // Intentional no-op: canvas size is controlled by the embedder.
48 virtual SkCanvas
* BeginPaint(const gfx::Rect
& damage_rect
) OVERRIDE
{
49 if (!surface_
->current_sw_canvas_
) {
50 NOTREACHED() << "BeginPaint with no canvas set";
53 LOG_IF(WARNING
, surface_
->frame_holder_
.get())
54 << "Mutliple calls to BeginPaint per frame";
55 return surface_
->current_sw_canvas_
;
57 virtual void EndPaint(cc::SoftwareFrameData
* frame_data
) OVERRIDE
{
59 virtual void CopyToPixels(const gfx::Rect
& rect
, void* pixels
) OVERRIDE
{
64 SynchronousCompositorOutputSurface
* surface_
;
65 SkCanvas null_canvas_
;
67 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice
);
70 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
72 scoped_refptr
<FrameSwapMessageQueue
> frame_swap_message_queue
)
74 scoped_ptr
<cc::SoftwareOutputDevice
>(new SoftwareDevice(this))),
75 routing_id_(routing_id
),
76 needs_begin_frame_(false),
77 invoking_composite_(false),
78 current_sw_canvas_(NULL
),
80 output_surface_client_(NULL
),
81 frame_swap_message_queue_(frame_swap_message_queue
) {
82 capabilities_
.deferred_gl_initialization
= true;
83 capabilities_
.draw_and_swap_full_viewport_every_frame
= true;
84 capabilities_
.adjust_deadline_for_parent
= false;
85 capabilities_
.delegated_rendering
= true;
86 capabilities_
.max_frames_pending
= 1;
87 // Cannot call out to GetDelegate() here as the output surface is not
88 // constructed on the correct thread.
90 memory_policy_
.priority_cutoff_when_visible
=
91 gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE
;
94 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
95 DCHECK(CalledOnValidThread());
96 SynchronousCompositorOutputSurfaceDelegate
* delegate
= GetDelegate();
98 delegate
->DidDestroySynchronousOutputSurface(this);
101 bool SynchronousCompositorOutputSurface::BindToClient(
102 cc::OutputSurfaceClient
* surface_client
) {
103 DCHECK(CalledOnValidThread());
104 if (!cc::OutputSurface::BindToClient(surface_client
))
107 output_surface_client_
= surface_client
;
108 output_surface_client_
->SetTreeActivationCallback(
109 base::Bind(&DidActivatePendingTree
, routing_id_
));
110 output_surface_client_
->SetMemoryPolicy(memory_policy_
);
112 SynchronousCompositorOutputSurfaceDelegate
* delegate
= GetDelegate();
114 delegate
->DidBindOutputSurface(this);
119 void SynchronousCompositorOutputSurface::Reshape(
120 const gfx::Size
& size
, float scale_factor
) {
121 // Intentional no-op: surface size is controlled by the embedder.
124 void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(bool enable
) {
125 DCHECK(CalledOnValidThread());
126 needs_begin_frame_
= enable
;
127 SynchronousCompositorOutputSurfaceDelegate
* delegate
= GetDelegate();
128 if (delegate
&& !invoking_composite_
)
129 delegate
->SetContinuousInvalidate(needs_begin_frame_
);
132 void SynchronousCompositorOutputSurface::SwapBuffers(
133 cc::CompositorFrame
* frame
) {
134 DCHECK(CalledOnValidThread());
136 frame_holder_
.reset(new cc::CompositorFrame
);
137 frame
->AssignTo(frame_holder_
.get());
139 client_
->DidSwapBuffers();
143 void AdjustTransform(gfx::Transform
* transform
, gfx::Rect viewport
) {
144 // CC's draw origin starts at the viewport.
145 transform
->matrix().postTranslate(-viewport
.x(), -viewport
.y(), 0);
149 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
150 scoped_refptr
<cc::ContextProvider
> onscreen_context_provider
) {
151 DCHECK(CalledOnValidThread());
153 DCHECK(!context_provider_
);
155 return InitializeAndSetContext3d(onscreen_context_provider
);
158 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
159 DCHECK(CalledOnValidThread());
160 cc::OutputSurface::ReleaseGL();
163 scoped_ptr
<cc::CompositorFrame
>
164 SynchronousCompositorOutputSurface::DemandDrawHw(
165 gfx::Size surface_size
,
166 const gfx::Transform
& transform
,
169 gfx::Rect viewport_rect_for_tile_priority
,
170 const gfx::Transform
& transform_for_tile_priority
) {
171 DCHECK(CalledOnValidThread());
173 DCHECK(context_provider_
);
175 surface_size_
= surface_size
;
176 InvokeComposite(transform
,
179 viewport_rect_for_tile_priority
,
180 transform_for_tile_priority
,
183 return frame_holder_
.Pass();
186 scoped_ptr
<cc::CompositorFrame
>
187 SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas
* canvas
) {
188 DCHECK(CalledOnValidThread());
190 DCHECK(!current_sw_canvas_
);
191 base::AutoReset
<SkCanvas
*> canvas_resetter(¤t_sw_canvas_
, canvas
);
194 canvas
->getClipDeviceBounds(&canvas_clip
);
195 gfx::Rect clip
= gfx::SkIRectToRect(canvas_clip
);
197 gfx::Transform
transform(gfx::Transform::kSkipInitialization
);
198 transform
.matrix() = canvas
->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
200 surface_size_
= gfx::Size(canvas
->getDeviceSize().width(),
201 canvas
->getDeviceSize().height());
203 // Resourceless software draw does not need viewport_for_tiling.
205 InvokeComposite(transform
, clip
, clip
, empty
, gfx::Transform(), false);
207 return frame_holder_
.Pass();
210 void SynchronousCompositorOutputSurface::InvokeComposite(
211 const gfx::Transform
& transform
,
214 gfx::Rect viewport_rect_for_tile_priority
,
215 gfx::Transform transform_for_tile_priority
,
216 bool hardware_draw
) {
217 DCHECK(!invoking_composite_
);
218 DCHECK(!frame_holder_
.get());
219 base::AutoReset
<bool> invoking_composite_resetter(&invoking_composite_
, true);
221 gfx::Transform adjusted_transform
= transform
;
222 AdjustTransform(&adjusted_transform
, viewport
);
223 SetExternalDrawConstraints(adjusted_transform
,
226 viewport_rect_for_tile_priority
,
227 transform_for_tile_priority
,
229 SetNeedsRedrawRect(gfx::Rect(viewport
.size()));
230 client_
->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
232 // After software draws (which might move the viewport arbitrarily), restore
233 // the previous hardware viewport to allow CC's tile manager to prioritize
236 cached_hw_transform_
= adjusted_transform
;
237 cached_hw_viewport_
= viewport
;
238 cached_hw_clip_
= clip
;
239 cached_hw_viewport_rect_for_tile_priority_
=
240 viewport_rect_for_tile_priority
;
241 cached_hw_transform_for_tile_priority_
= transform_for_tile_priority
;
243 bool resourceless_software_draw
= false;
244 SetExternalDrawConstraints(cached_hw_transform_
,
247 cached_hw_viewport_rect_for_tile_priority_
,
248 cached_hw_transform_for_tile_priority_
,
249 resourceless_software_draw
);
252 if (frame_holder_
.get())
253 client_
->DidSwapBuffersComplete();
255 SynchronousCompositorOutputSurfaceDelegate
* delegate
= GetDelegate();
257 delegate
->SetContinuousInvalidate(needs_begin_frame_
);
260 void SynchronousCompositorOutputSurface::ReturnResources(
261 const cc::CompositorFrameAck
& frame_ack
) {
262 ReclaimResources(&frame_ack
);
265 void SynchronousCompositorOutputSurface::SetMemoryPolicy(
266 const SynchronousCompositorMemoryPolicy
& policy
) {
267 DCHECK(CalledOnValidThread());
268 memory_policy_
.bytes_limit_when_visible
= policy
.bytes_limit
;
269 memory_policy_
.num_resources_limit
= policy
.num_resources_limit
;
271 if (output_surface_client_
)
272 output_surface_client_
->SetMemoryPolicy(memory_policy_
);
275 void SynchronousCompositorOutputSurface::GetMessagesToDeliver(
276 ScopedVector
<IPC::Message
>* messages
) {
277 DCHECK(CalledOnValidThread());
278 scoped_ptr
<FrameSwapMessageQueue::SendMessageScope
> send_message_scope
=
279 frame_swap_message_queue_
->AcquireSendMessageScope();
280 frame_swap_message_queue_
->DrainMessages(messages
);
283 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
284 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
286 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
287 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
290 SynchronousCompositorOutputSurfaceDelegate
*
291 SynchronousCompositorOutputSurface::GetDelegate() {
292 return SynchronousCompositorImpl::FromRoutingID(routing_id_
);
295 } // namespace content