Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / content / browser / android / in_process / synchronous_compositor_output_surface.cc
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 "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"
24
25 namespace content {
26
27 namespace {
28
29 // Do not limit number of resources, so use an unrealistically high value.
30 const size_t kNumResourcesLimit = 10 * 1000 * 1000;
31
32 void DidActivatePendingTree(int routing_id) {
33   SynchronousCompositorOutputSurfaceDelegate* delegate =
34       SynchronousCompositorImpl::FromRoutingID(routing_id);
35   if (delegate)
36     delegate->DidActivatePendingTree();
37 }
38
39 } // namespace
40
41 class SynchronousCompositorOutputSurface::SoftwareDevice
42   : public cc::SoftwareOutputDevice {
43  public:
44   SoftwareDevice(SynchronousCompositorOutputSurface* surface)
45     : surface_(surface) {
46   }
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.
50   }
51   virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
52     if (!surface_->current_sw_canvas_) {
53       NOTREACHED() << "BeginPaint with no canvas set";
54       return &null_canvas_;
55     }
56     LOG_IF(WARNING, surface_->frame_holder_.get())
57         << "Mutliple calls to BeginPaint per frame";
58     return surface_->current_sw_canvas_;
59   }
60   virtual void EndPaint(cc::SoftwareFrameData* frame_data) override {
61   }
62   virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) override {
63     NOTIMPLEMENTED();
64   }
65
66  private:
67   SynchronousCompositorOutputSurface* surface_;
68   SkCanvas null_canvas_;
69
70   DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
71 };
72
73 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
74     int routing_id,
75     scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue)
76     : cc::OutputSurface(
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),
82       memory_policy_(0),
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.
92
93   memory_policy_.priority_cutoff_when_visible =
94       gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
95 }
96
97 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
98   DCHECK(CalledOnValidThread());
99   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
100   if (delegate)
101     delegate->DidDestroySynchronousOutputSurface(this);
102 }
103
104 bool SynchronousCompositorOutputSurface::BindToClient(
105     cc::OutputSurfaceClient* surface_client) {
106   DCHECK(CalledOnValidThread());
107   if (!cc::OutputSurface::BindToClient(surface_client))
108     return false;
109
110   output_surface_client_ = surface_client;
111   output_surface_client_->SetTreeActivationCallback(
112       base::Bind(&DidActivatePendingTree, routing_id_));
113   output_surface_client_->SetMemoryPolicy(memory_policy_);
114
115   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
116   if (delegate)
117     delegate->DidBindOutputSurface(this);
118
119   return true;
120 }
121
122 void SynchronousCompositorOutputSurface::Reshape(
123     const gfx::Size& size, float scale_factor) {
124   // Intentional no-op: surface size is controlled by the embedder.
125 }
126
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_);
133 }
134
135 void SynchronousCompositorOutputSurface::SwapBuffers(
136     cc::CompositorFrame* frame) {
137   DCHECK(CalledOnValidThread());
138
139   frame_holder_.reset(new cc::CompositorFrame);
140   frame->AssignTo(frame_holder_.get());
141
142   client_->DidSwapBuffers();
143 }
144
145 namespace {
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);
149 }
150 } // namespace
151
152 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
153     scoped_refptr<cc::ContextProvider> onscreen_context_provider) {
154   DCHECK(CalledOnValidThread());
155   DCHECK(HasClient());
156   DCHECK(!context_provider_.get());
157
158   return InitializeAndSetContext3d(onscreen_context_provider);
159 }
160
161 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
162   DCHECK(CalledOnValidThread());
163   cc::OutputSurface::ReleaseGL();
164 }
165
166 scoped_ptr<cc::CompositorFrame>
167 SynchronousCompositorOutputSurface::DemandDrawHw(
168     gfx::Size surface_size,
169     const gfx::Transform& transform,
170     gfx::Rect viewport,
171     gfx::Rect clip,
172     gfx::Rect viewport_rect_for_tile_priority,
173     const gfx::Transform& transform_for_tile_priority) {
174   DCHECK(CalledOnValidThread());
175   DCHECK(HasClient());
176   DCHECK(context_provider_.get());
177
178   surface_size_ = surface_size;
179   InvokeComposite(transform,
180                   viewport,
181                   clip,
182                   viewport_rect_for_tile_priority,
183                   transform_for_tile_priority,
184                   true);
185
186   return frame_holder_.Pass();
187 }
188
189 scoped_ptr<cc::CompositorFrame>
190 SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
191   DCHECK(CalledOnValidThread());
192   DCHECK(canvas);
193   DCHECK(!current_sw_canvas_);
194   base::AutoReset<SkCanvas*> canvas_resetter(&current_sw_canvas_, canvas);
195
196   SkIRect canvas_clip;
197   canvas->getClipDeviceBounds(&canvas_clip);
198   gfx::Rect clip = gfx::SkIRectToRect(canvas_clip);
199
200   gfx::Transform transform(gfx::Transform::kSkipInitialization);
201   transform.matrix() = canvas->getTotalMatrix();  // Converts 3x3 matrix to 4x4.
202
203   surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
204                             canvas->getDeviceSize().height());
205
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
208   // software draws.
209   InvokeComposite(transform,
210                   clip,
211                   clip,
212                   cached_hw_viewport_rect_for_tile_priority_,
213                   cached_hw_transform_for_tile_priority_,
214                   false);
215
216   return frame_holder_.Pass();
217 }
218
219 void SynchronousCompositorOutputSurface::InvokeComposite(
220     const gfx::Transform& transform,
221     gfx::Rect viewport,
222     gfx::Rect clip,
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);
229
230   gfx::Transform adjusted_transform = transform;
231   AdjustTransform(&adjusted_transform, viewport);
232   SetExternalDrawConstraints(adjusted_transform,
233                              viewport,
234                              clip,
235                              viewport_rect_for_tile_priority,
236                              transform_for_tile_priority,
237                              !hardware_draw);
238   SetNeedsRedrawRect(gfx::Rect(viewport.size()));
239   client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
240
241   // After software draws (which might move the viewport arbitrarily), restore
242   // the previous hardware viewport to allow CC's tile manager to prioritize
243   // properly.
244   if (hardware_draw) {
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;
251   } else {
252     bool resourceless_software_draw = false;
253     SetExternalDrawConstraints(cached_hw_transform_,
254                                cached_hw_viewport_,
255                                cached_hw_clip_,
256                                cached_hw_viewport_rect_for_tile_priority_,
257                                cached_hw_transform_for_tile_priority_,
258                                resourceless_software_draw);
259   }
260
261   if (frame_holder_.get())
262     client_->DidSwapBuffersComplete();
263
264   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
265   if (delegate)
266     delegate->SetContinuousInvalidate(needs_begin_frame_);
267 }
268
269 void SynchronousCompositorOutputSurface::ReturnResources(
270     const cc::CompositorFrameAck& frame_ack) {
271   ReclaimResources(&frame_ack);
272 }
273
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;
278
279   if (output_surface_client_)
280     output_surface_client_->SetMemoryPolicy(memory_policy_);
281 }
282
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);
289 }
290
291 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
292 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
293 // thread.
294 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
295   return BrowserThread::CurrentlyOn(BrowserThread::UI);
296 }
297
298 SynchronousCompositorOutputSurfaceDelegate*
299 SynchronousCompositorOutputSurface::GetDelegate() {
300   return SynchronousCompositorImpl::FromRoutingID(routing_id_);
301 }
302
303 }  // namespace content