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 "content/renderer/android/synchronous_compositor_output_surface.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
10 #include "cc/output/compositor_frame.h"
11 #include "cc/output/compositor_frame_ack.h"
12 #include "cc/output/output_surface_client.h"
13 #include "cc/output/software_output_device.h"
14 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/renderer/android/synchronous_compositor_client.h"
17 #include "content/public/renderer/content_renderer_client.h"
18 #include "skia/ext/refptr.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "third_party/skia/include/core/SkDevice.h"
21 #include "third_party/skia/include/core/SkPicture.h"
22 #include "ui/gfx/rect_conversions.h"
23 #include "ui/gfx/skia_util.h"
24 #include "ui/gfx/transform.h"
25 #include "webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
27 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl
;
33 // TODO(boliu): RenderThreadImpl should create in process contexts as well.
34 scoped_ptr
<WebKit::WebGraphicsContext3D
> CreateWebGraphicsContext3D() {
35 if (!CommandLine::ForCurrentProcess()->HasSwitch("testing-webview-gl-mode"))
36 return scoped_ptr
<WebKit::WebGraphicsContext3D
>();
38 WebKit::WebGraphicsContext3D::Attributes attributes
;
39 attributes
.antialias
= false;
40 attributes
.shareResources
= true;
41 attributes
.noAutomaticFlushes
= true;
43 return scoped_ptr
<WebKit::WebGraphicsContext3D
>(
44 WebGraphicsContext3DInProcessCommandBufferImpl
45 ::CreateViewContext(attributes
, NULL
));
50 class SynchronousCompositorOutputSurface::SoftwareDevice
51 : public cc::SoftwareOutputDevice
{
53 SoftwareDevice(SynchronousCompositorOutputSurface
* surface
)
55 null_device_(SkBitmap::kARGB_8888_Config
, 1, 1),
56 null_canvas_(&null_device_
) {
58 virtual void Resize(gfx::Size size
) OVERRIDE
{
59 // Intentional no-op: canvas size is controlled by the embedder.
61 virtual SkCanvas
* BeginPaint(gfx::Rect damage_rect
) OVERRIDE
{
62 DCHECK(surface_
->current_sw_canvas_
);
63 if (surface_
->current_sw_canvas_
)
64 return surface_
->current_sw_canvas_
;
67 virtual void EndPaint(cc::SoftwareFrameData
* frame_data
) OVERRIDE
{
68 surface_
->current_sw_canvas_
= NULL
;
70 virtual void CopyToBitmap(gfx::Rect rect
, SkBitmap
* output
) OVERRIDE
{
73 virtual void Scroll(gfx::Vector2d delta
,
74 gfx::Rect clip_rect
) OVERRIDE
{
77 virtual void ReclaimDIB(const TransportDIB::Id
& id
) OVERRIDE
{
82 SynchronousCompositorOutputSurface
* surface_
;
83 SkDevice null_device_
;
84 SkCanvas null_canvas_
;
86 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice
);
89 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
91 : cc::OutputSurface(CreateWebGraphicsContext3D(),
92 scoped_ptr
<cc::SoftwareOutputDevice
>(
93 new SoftwareDevice(this))),
94 compositor_client_(NULL
),
95 routing_id_(routing_id
),
96 needs_begin_frame_(false),
97 did_swap_buffer_(false),
98 current_sw_canvas_(NULL
) {
99 capabilities_
.deferred_gl_initialization
= true;
102 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
103 DCHECK(CalledOnValidThread());
104 if (compositor_client_
)
105 compositor_client_
->DidDestroyCompositor(this);
108 bool SynchronousCompositorOutputSurface::ForcedDrawToSoftwareDevice() const {
109 return current_sw_canvas_
!= NULL
;
112 bool SynchronousCompositorOutputSurface::BindToClient(
113 cc::OutputSurfaceClient
* surface_client
) {
114 DCHECK(CalledOnValidThread());
115 if (!cc::OutputSurface::BindToClient(surface_client
))
117 GetContentClient()->renderer()->DidCreateSynchronousCompositor(routing_id_
,
122 void SynchronousCompositorOutputSurface::Reshape(gfx::Size size
) {
123 // Intentional no-op: surface size is controlled by the embedder.
126 void SynchronousCompositorOutputSurface::SendFrameToParentCompositor(
127 cc::CompositorFrame
* frame
) {
129 // TODO(joth): Route page scale to the client, see http://crbug.com/237006
132 void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(
134 DCHECK(CalledOnValidThread());
135 needs_begin_frame_
= enable
;
136 UpdateCompositorClientSettings();
139 void SynchronousCompositorOutputSurface::SwapBuffers(
140 const cc::LatencyInfo
& info
) {
141 context3d()->shallowFlushCHROMIUM();
142 did_swap_buffer_
= true;
145 void SynchronousCompositorOutputSurface::SetClient(
146 SynchronousCompositorClient
* compositor_client
) {
147 DCHECK(CalledOnValidThread());
148 compositor_client_
= compositor_client
;
149 UpdateCompositorClientSettings();
152 bool SynchronousCompositorOutputSurface::IsHwReady() {
153 return context3d() != NULL
;
156 bool SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas
* canvas
) {
157 DCHECK(CalledOnValidThread());
159 DCHECK(!current_sw_canvas_
);
160 current_sw_canvas_
= canvas
;
163 gfx::Rect damage_area
;
164 if (canvas
->getClipBounds(&canvas_clip
)) {
165 damage_area
= gfx::ToEnclosedRect(gfx::SkRectToRectF(canvas_clip
));
167 damage_area
= gfx::Rect(kint16max
, kint16max
);
170 gfx::Transform transform
;
171 transform
.matrix() = canvas
->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
173 InvokeComposite(transform
, damage_area
);
175 bool finished_draw
= current_sw_canvas_
== NULL
;
176 current_sw_canvas_
= NULL
;
177 return finished_draw
;
180 bool SynchronousCompositorOutputSurface::DemandDrawHw(
182 const gfx::Transform
& transform
,
183 gfx::Rect damage_area
) {
184 DCHECK(CalledOnValidThread());
187 did_swap_buffer_
= false;
189 InvokeComposite(transform
, damage_area
);
191 return did_swap_buffer_
;
194 void SynchronousCompositorOutputSurface::InvokeComposite(
195 const gfx::Transform
& transform
,
196 gfx::Rect damage_area
) {
197 // TODO(boliu): This assumes |transform| is identity and |damage_area| is the
198 // whole view. Tracking bug to implement this: crbug.com/230463.
199 client_
->SetNeedsRedrawRect(damage_area
);
200 if (needs_begin_frame_
)
201 client_
->BeginFrame(base::TimeTicks::Now());
204 void SynchronousCompositorOutputSurface::UpdateCompositorClientSettings() {
205 if (compositor_client_
) {
206 compositor_client_
->SetContinuousInvalidate(needs_begin_frame_
);
210 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
211 // requirement: SynchronousCompositorOutputSurface() must only be used by
212 // embedders that supply their own compositor loop via
213 // OverrideCompositorMessageLoop().
214 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
215 return base::MessageLoop::current() && (base::MessageLoop::current() ==
216 GetContentClient()->renderer()->OverrideCompositorMessageLoop());
219 } // namespace content