• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&current_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