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.
4
5 #include "content/browser/android/in_process/synchronous_compositor_output_surface.h"
6
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 "gpu/command_buffer/client/gles2_interface.h"
18 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "ui/gfx/rect_conversions.h"
21 #include "ui/gfx/skia_util.h"
22 #include "ui/gfx/transform.h"
23
24 namespace content {
25
26 namespace {
27
DidActivatePendingTree(int routing_id)28 void DidActivatePendingTree(int routing_id) {
29 SynchronousCompositorOutputSurfaceDelegate* delegate =
30 SynchronousCompositorImpl::FromRoutingID(routing_id);
31 if (delegate)
32 delegate->DidActivatePendingTree();
33 }
34
35 } // namespace
36
37 class SynchronousCompositorOutputSurface::SoftwareDevice
38 : public cc::SoftwareOutputDevice {
39 public:
SoftwareDevice(SynchronousCompositorOutputSurface * surface)40 SoftwareDevice(SynchronousCompositorOutputSurface* surface)
41 : surface_(surface) {
42 }
Resize(const gfx::Size & pixel_size,float scale_factor)43 virtual void Resize(const gfx::Size& pixel_size,
44 float scale_factor) OVERRIDE {
45 // Intentional no-op: canvas size is controlled by the embedder.
46 }
BeginPaint(const gfx::Rect & damage_rect)47 virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) OVERRIDE {
48 if (!surface_->current_sw_canvas_) {
49 NOTREACHED() << "BeginPaint with no canvas set";
50 return &null_canvas_;
51 }
52 LOG_IF(WARNING, surface_->frame_holder_.get())
53 << "Mutliple calls to BeginPaint per frame";
54 return surface_->current_sw_canvas_;
55 }
EndPaint(cc::SoftwareFrameData * frame_data)56 virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE {
57 }
CopyToPixels(const gfx::Rect & rect,void * pixels)58 virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) OVERRIDE {
59 NOTIMPLEMENTED();
60 }
61
62 private:
63 SynchronousCompositorOutputSurface* surface_;
64 SkCanvas null_canvas_;
65
66 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
67 };
68
SynchronousCompositorOutputSurface(int routing_id)69 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
70 int routing_id)
71 : cc::OutputSurface(
72 scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
73 routing_id_(routing_id),
74 needs_begin_frame_(false),
75 invoking_composite_(false),
76 current_sw_canvas_(NULL),
77 memory_policy_(0),
78 output_surface_client_(NULL) {
79 capabilities_.deferred_gl_initialization = true;
80 capabilities_.draw_and_swap_full_viewport_every_frame = true;
81 capabilities_.adjust_deadline_for_parent = false;
82 capabilities_.delegated_rendering = true;
83 capabilities_.max_frames_pending = 1;
84 // Cannot call out to GetDelegate() here as the output surface is not
85 // constructed on the correct thread.
86
87 memory_policy_.priority_cutoff_when_visible =
88 gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
89 }
90
~SynchronousCompositorOutputSurface()91 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
92 DCHECK(CalledOnValidThread());
93 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
94 if (delegate)
95 delegate->DidDestroySynchronousOutputSurface(this);
96 }
97
BindToClient(cc::OutputSurfaceClient * surface_client)98 bool SynchronousCompositorOutputSurface::BindToClient(
99 cc::OutputSurfaceClient* surface_client) {
100 DCHECK(CalledOnValidThread());
101 if (!cc::OutputSurface::BindToClient(surface_client))
102 return false;
103
104 output_surface_client_ = surface_client;
105 output_surface_client_->SetTreeActivationCallback(
106 base::Bind(&DidActivatePendingTree, routing_id_));
107 output_surface_client_->SetMemoryPolicy(memory_policy_);
108
109 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
110 if (delegate)
111 delegate->DidBindOutputSurface(this);
112
113 return true;
114 }
115
Reshape(const gfx::Size & size,float scale_factor)116 void SynchronousCompositorOutputSurface::Reshape(
117 const gfx::Size& size, float scale_factor) {
118 // Intentional no-op: surface size is controlled by the embedder.
119 }
120
SetNeedsBeginFrame(bool enable)121 void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(bool enable) {
122 DCHECK(CalledOnValidThread());
123 needs_begin_frame_ = enable;
124 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
125 if (delegate && !invoking_composite_)
126 delegate->SetContinuousInvalidate(needs_begin_frame_);
127 }
128
SwapBuffers(cc::CompositorFrame * frame)129 void SynchronousCompositorOutputSurface::SwapBuffers(
130 cc::CompositorFrame* frame) {
131 DCHECK(CalledOnValidThread());
132
133 frame_holder_.reset(new cc::CompositorFrame);
134 frame->AssignTo(frame_holder_.get());
135
136 client_->DidSwapBuffers();
137 }
138
139 namespace {
AdjustTransform(gfx::Transform * transform,gfx::Rect viewport)140 void AdjustTransform(gfx::Transform* transform, gfx::Rect viewport) {
141 // CC's draw origin starts at the viewport.
142 transform->matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
143 }
144 } // namespace
145
InitializeHwDraw(scoped_refptr<cc::ContextProvider> onscreen_context_provider)146 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
147 scoped_refptr<cc::ContextProvider> onscreen_context_provider) {
148 DCHECK(CalledOnValidThread());
149 DCHECK(HasClient());
150 DCHECK(!context_provider_);
151
152 return InitializeAndSetContext3d(onscreen_context_provider);
153 }
154
ReleaseHwDraw()155 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
156 DCHECK(CalledOnValidThread());
157 cc::OutputSurface::ReleaseGL();
158 }
159
160 scoped_ptr<cc::CompositorFrame>
DemandDrawHw(gfx::Size surface_size,const gfx::Transform & transform,gfx::Rect viewport,gfx::Rect clip,gfx::Rect viewport_rect_for_tile_priority,const gfx::Transform & transform_for_tile_priority)161 SynchronousCompositorOutputSurface::DemandDrawHw(
162 gfx::Size surface_size,
163 const gfx::Transform& transform,
164 gfx::Rect viewport,
165 gfx::Rect clip,
166 gfx::Rect viewport_rect_for_tile_priority,
167 const gfx::Transform& transform_for_tile_priority) {
168 DCHECK(CalledOnValidThread());
169 DCHECK(HasClient());
170 DCHECK(context_provider_);
171
172 surface_size_ = surface_size;
173 InvokeComposite(transform,
174 viewport,
175 clip,
176 viewport_rect_for_tile_priority,
177 transform_for_tile_priority,
178 true);
179
180 return frame_holder_.Pass();
181 }
182
183 scoped_ptr<cc::CompositorFrame>
DemandDrawSw(SkCanvas * canvas)184 SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
185 DCHECK(CalledOnValidThread());
186 DCHECK(canvas);
187 DCHECK(!current_sw_canvas_);
188 base::AutoReset<SkCanvas*> canvas_resetter(¤t_sw_canvas_, canvas);
189
190 SkIRect canvas_clip;
191 canvas->getClipDeviceBounds(&canvas_clip);
192 gfx::Rect clip = gfx::SkIRectToRect(canvas_clip);
193
194 gfx::Transform transform(gfx::Transform::kSkipInitialization);
195 transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
196
197 surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
198 canvas->getDeviceSize().height());
199
200 // Resourceless software draw does not need viewport_for_tiling.
201 gfx::Rect empty;
202 InvokeComposite(transform, clip, clip, empty, gfx::Transform(), false);
203
204 return frame_holder_.Pass();
205 }
206
InvokeComposite(const gfx::Transform & transform,gfx::Rect viewport,gfx::Rect clip,gfx::Rect viewport_rect_for_tile_priority,gfx::Transform transform_for_tile_priority,bool hardware_draw)207 void SynchronousCompositorOutputSurface::InvokeComposite(
208 const gfx::Transform& transform,
209 gfx::Rect viewport,
210 gfx::Rect clip,
211 gfx::Rect viewport_rect_for_tile_priority,
212 gfx::Transform transform_for_tile_priority,
213 bool hardware_draw) {
214 DCHECK(!invoking_composite_);
215 DCHECK(!frame_holder_.get());
216 base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, true);
217
218 gfx::Transform adjusted_transform = transform;
219 AdjustTransform(&adjusted_transform, viewport);
220 SetExternalDrawConstraints(adjusted_transform,
221 viewport,
222 clip,
223 viewport_rect_for_tile_priority,
224 transform_for_tile_priority,
225 !hardware_draw);
226 SetNeedsRedrawRect(gfx::Rect(viewport.size()));
227 client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
228
229 // After software draws (which might move the viewport arbitrarily), restore
230 // the previous hardware viewport to allow CC's tile manager to prioritize
231 // properly.
232 if (hardware_draw) {
233 cached_hw_transform_ = adjusted_transform;
234 cached_hw_viewport_ = viewport;
235 cached_hw_clip_ = clip;
236 cached_hw_viewport_rect_for_tile_priority_ =
237 viewport_rect_for_tile_priority;
238 cached_hw_transform_for_tile_priority_ = transform_for_tile_priority;
239 } else {
240 bool resourceless_software_draw = false;
241 SetExternalDrawConstraints(cached_hw_transform_,
242 cached_hw_viewport_,
243 cached_hw_clip_,
244 cached_hw_viewport_rect_for_tile_priority_,
245 cached_hw_transform_for_tile_priority_,
246 resourceless_software_draw);
247 }
248
249 if (frame_holder_.get())
250 client_->DidSwapBuffersComplete();
251
252 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
253 if (delegate)
254 delegate->SetContinuousInvalidate(needs_begin_frame_);
255 }
256
ReturnResources(const cc::CompositorFrameAck & frame_ack)257 void SynchronousCompositorOutputSurface::ReturnResources(
258 const cc::CompositorFrameAck& frame_ack) {
259 ReclaimResources(&frame_ack);
260 }
261
SetMemoryPolicy(const SynchronousCompositorMemoryPolicy & policy)262 void SynchronousCompositorOutputSurface::SetMemoryPolicy(
263 const SynchronousCompositorMemoryPolicy& policy) {
264 DCHECK(CalledOnValidThread());
265 memory_policy_.bytes_limit_when_visible = policy.bytes_limit;
266 memory_policy_.num_resources_limit = policy.num_resources_limit;
267
268 if (output_surface_client_)
269 output_surface_client_->SetMemoryPolicy(memory_policy_);
270 }
271
272 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
273 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
274 // thread.
CalledOnValidThread() const275 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
276 return BrowserThread::CurrentlyOn(BrowserThread::UI);
277 }
278
279 SynchronousCompositorOutputSurfaceDelegate*
GetDelegate()280 SynchronousCompositorOutputSurface::GetDelegate() {
281 return SynchronousCompositorImpl::FromRoutingID(routing_id_);
282 }
283
284 } // namespace content
285