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 // Do not limit number of resources, so use an unrealistically high value.
30 const size_t kNumResourcesLimit = 10 * 1000 * 1000;
32 void DidActivatePendingTree(int routing_id) {
33 SynchronousCompositorOutputSurfaceDelegate* delegate =
34 SynchronousCompositorImpl::FromRoutingID(routing_id);
36 delegate->DidActivatePendingTree();
41 class SynchronousCompositorOutputSurface::SoftwareDevice
42 : public cc::SoftwareOutputDevice {
44 SoftwareDevice(SynchronousCompositorOutputSurface* surface)
47 virtual void Resize(const gfx::Size& pixel_size,
48 float scale_factor) override {
49 // Intentional no-op: canvas size is controlled by the embedder.
51 virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
52 if (!surface_->current_sw_canvas_) {
53 NOTREACHED() << "BeginPaint with no canvas set";
56 LOG_IF(WARNING, surface_->frame_holder_.get())
57 << "Mutliple calls to BeginPaint per frame";
58 return surface_->current_sw_canvas_;
60 virtual void EndPaint(cc::SoftwareFrameData* frame_data) override {
62 virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) override {
67 SynchronousCompositorOutputSurface* surface_;
68 SkCanvas null_canvas_;
70 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
73 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
75 scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue)
77 scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
78 routing_id_(routing_id),
79 needs_begin_frame_(false),
80 invoking_composite_(false),
81 current_sw_canvas_(NULL),
83 output_surface_client_(NULL),
84 frame_swap_message_queue_(frame_swap_message_queue) {
85 capabilities_.deferred_gl_initialization = true;
86 capabilities_.draw_and_swap_full_viewport_every_frame = true;
87 capabilities_.adjust_deadline_for_parent = false;
88 capabilities_.delegated_rendering = true;
89 capabilities_.max_frames_pending = 1;
90 // Cannot call out to GetDelegate() here as the output surface is not
91 // constructed on the correct thread.
93 memory_policy_.priority_cutoff_when_visible =
94 gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
97 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
98 DCHECK(CalledOnValidThread());
99 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
101 delegate->DidDestroySynchronousOutputSurface(this);
104 bool SynchronousCompositorOutputSurface::BindToClient(
105 cc::OutputSurfaceClient* surface_client) {
106 DCHECK(CalledOnValidThread());
107 if (!cc::OutputSurface::BindToClient(surface_client))
110 output_surface_client_ = surface_client;
111 output_surface_client_->SetTreeActivationCallback(
112 base::Bind(&DidActivatePendingTree, routing_id_));
113 output_surface_client_->SetMemoryPolicy(memory_policy_);
115 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
117 delegate->DidBindOutputSurface(this);
122 void SynchronousCompositorOutputSurface::Reshape(
123 const gfx::Size& size, float scale_factor) {
124 // Intentional no-op: surface size is controlled by the embedder.
127 void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(bool enable) {
128 DCHECK(CalledOnValidThread());
129 needs_begin_frame_ = enable;
130 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
131 if (delegate && !invoking_composite_)
132 delegate->SetContinuousInvalidate(needs_begin_frame_);
135 void SynchronousCompositorOutputSurface::SwapBuffers(
136 cc::CompositorFrame* frame) {
137 DCHECK(CalledOnValidThread());
139 frame_holder_.reset(new cc::CompositorFrame);
140 frame->AssignTo(frame_holder_.get());
142 client_->DidSwapBuffers();
146 void AdjustTransform(gfx::Transform* transform, gfx::Rect viewport) {
147 // CC's draw origin starts at the viewport.
148 transform->matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
152 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
153 scoped_refptr<cc::ContextProvider> onscreen_context_provider) {
154 DCHECK(CalledOnValidThread());
156 DCHECK(!context_provider_.get());
158 return InitializeAndSetContext3d(onscreen_context_provider);
161 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
162 DCHECK(CalledOnValidThread());
163 cc::OutputSurface::ReleaseGL();
166 scoped_ptr<cc::CompositorFrame>
167 SynchronousCompositorOutputSurface::DemandDrawHw(
168 gfx::Size surface_size,
169 const gfx::Transform& transform,
172 gfx::Rect viewport_rect_for_tile_priority,
173 const gfx::Transform& transform_for_tile_priority) {
174 DCHECK(CalledOnValidThread());
176 DCHECK(context_provider_.get());
178 surface_size_ = surface_size;
179 InvokeComposite(transform,
182 viewport_rect_for_tile_priority,
183 transform_for_tile_priority,
186 return frame_holder_.Pass();
189 scoped_ptr<cc::CompositorFrame>
190 SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
191 DCHECK(CalledOnValidThread());
193 DCHECK(!current_sw_canvas_);
194 base::AutoReset<SkCanvas*> canvas_resetter(¤t_sw_canvas_, canvas);
197 canvas->getClipDeviceBounds(&canvas_clip);
198 gfx::Rect clip = gfx::SkIRectToRect(canvas_clip);
200 gfx::Transform transform(gfx::Transform::kSkipInitialization);
201 transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
203 surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
204 canvas->getDeviceSize().height());
206 // Pass in the cached hw viewport and transform for tile priority to avoid
207 // tile thrashing when the WebView is alternating between hardware and
209 InvokeComposite(transform,
212 cached_hw_viewport_rect_for_tile_priority_,
213 cached_hw_transform_for_tile_priority_,
216 return frame_holder_.Pass();
219 void SynchronousCompositorOutputSurface::InvokeComposite(
220 const gfx::Transform& transform,
223 gfx::Rect viewport_rect_for_tile_priority,
224 gfx::Transform transform_for_tile_priority,
225 bool hardware_draw) {
226 DCHECK(!invoking_composite_);
227 DCHECK(!frame_holder_.get());
228 base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, true);
230 gfx::Transform adjusted_transform = transform;
231 AdjustTransform(&adjusted_transform, viewport);
232 SetExternalDrawConstraints(adjusted_transform,
235 viewport_rect_for_tile_priority,
236 transform_for_tile_priority,
238 SetNeedsRedrawRect(gfx::Rect(viewport.size()));
239 client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
241 // After software draws (which might move the viewport arbitrarily), restore
242 // the previous hardware viewport to allow CC's tile manager to prioritize
245 cached_hw_transform_ = adjusted_transform;
246 cached_hw_viewport_ = viewport;
247 cached_hw_clip_ = clip;
248 cached_hw_viewport_rect_for_tile_priority_ =
249 viewport_rect_for_tile_priority;
250 cached_hw_transform_for_tile_priority_ = transform_for_tile_priority;
252 bool resourceless_software_draw = false;
253 SetExternalDrawConstraints(cached_hw_transform_,
256 cached_hw_viewport_rect_for_tile_priority_,
257 cached_hw_transform_for_tile_priority_,
258 resourceless_software_draw);
261 if (frame_holder_.get())
262 client_->DidSwapBuffersComplete();
264 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
266 delegate->SetContinuousInvalidate(needs_begin_frame_);
269 void SynchronousCompositorOutputSurface::ReturnResources(
270 const cc::CompositorFrameAck& frame_ack) {
271 ReclaimResources(&frame_ack);
274 void SynchronousCompositorOutputSurface::SetMemoryPolicy(size_t bytes_limit) {
275 DCHECK(CalledOnValidThread());
276 memory_policy_.bytes_limit_when_visible = bytes_limit;
277 memory_policy_.num_resources_limit = kNumResourcesLimit;
279 if (output_surface_client_)
280 output_surface_client_->SetMemoryPolicy(memory_policy_);
283 void SynchronousCompositorOutputSurface::GetMessagesToDeliver(
284 ScopedVector<IPC::Message>* messages) {
285 DCHECK(CalledOnValidThread());
286 scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
287 frame_swap_message_queue_->AcquireSendMessageScope();
288 frame_swap_message_queue_->DrainMessages(messages);
291 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
292 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
294 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
295 return BrowserThread::CurrentlyOn(BrowserThread::UI);
298 SynchronousCompositorOutputSurfaceDelegate*
299 SynchronousCompositorOutputSurface::GetDelegate() {
300 return SynchronousCompositorImpl::FromRoutingID(routing_id_);
303 } // namespace content