Upstream version 5.34.104.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/public/browser/browser_thread.h"
16 #include "gpu/command_buffer/client/gles2_interface.h"
17 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
18 #include "third_party/skia/include/core/SkBitmapDevice.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
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:
40   SoftwareDevice(SynchronousCompositorOutputSurface* surface)
41     : surface_(surface),
42       null_device_(SkBitmap::kARGB_8888_Config, 1, 1),
43       null_canvas_(&null_device_) {
44   }
45   virtual void Resize(const gfx::Size& size) OVERRIDE {
46     // Intentional no-op: canvas size is controlled by the embedder.
47   }
48   virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) OVERRIDE {
49     if (!surface_->current_sw_canvas_) {
50       NOTREACHED() << "BeginPaint with no canvas set";
51       return &null_canvas_;
52     }
53     LOG_IF(WARNING, surface_->did_swap_buffer_)
54         << "Mutliple calls to BeginPaint per frame";
55     return surface_->current_sw_canvas_;
56   }
57   virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE {
58   }
59   virtual void CopyToBitmap(const gfx::Rect& rect, SkBitmap* output) OVERRIDE {
60     NOTIMPLEMENTED();
61   }
62
63  private:
64   SynchronousCompositorOutputSurface* surface_;
65   SkBitmapDevice null_device_;
66   SkCanvas null_canvas_;
67
68   DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
69 };
70
71 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
72     int routing_id)
73     : cc::OutputSurface(
74           scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
75       routing_id_(routing_id),
76       needs_begin_impl_frame_(false),
77       invoking_composite_(false),
78       did_swap_buffer_(false),
79       current_sw_canvas_(NULL),
80       memory_policy_(0),
81       output_surface_client_(NULL) {
82   capabilities_.deferred_gl_initialization = true;
83   capabilities_.draw_and_swap_full_viewport_every_frame = true;
84   capabilities_.adjust_deadline_for_parent = false;
85   // Cannot call out to GetDelegate() here as the output surface is not
86   // constructed on the correct thread.
87
88   memory_policy_.priority_cutoff_when_visible =
89       gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
90 }
91
92 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
93   DCHECK(CalledOnValidThread());
94   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
95   if (delegate)
96     delegate->DidDestroySynchronousOutputSurface(this);
97 }
98
99 bool SynchronousCompositorOutputSurface::ForcedDrawToSoftwareDevice() const {
100   // |current_sw_canvas_| indicates we're in a DemandDrawSw call. In addition
101   // |invoking_composite_| == false indicates an attempt to draw outside of
102   // the synchronous compositor's control: force it into SW path and hence to
103   // the null canvas (and will log a warning there).
104   return current_sw_canvas_ != NULL || !invoking_composite_;
105 }
106
107 bool SynchronousCompositorOutputSurface::BindToClient(
108     cc::OutputSurfaceClient* surface_client) {
109   DCHECK(CalledOnValidThread());
110   if (!cc::OutputSurface::BindToClient(surface_client))
111     return false;
112
113   output_surface_client_ = surface_client;
114   output_surface_client_->SetTreeActivationCallback(
115       base::Bind(&DidActivatePendingTree, routing_id_));
116   output_surface_client_->SetMemoryPolicy(memory_policy_);
117
118   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
119   if (delegate)
120     delegate->DidBindOutputSurface(this);
121
122   return true;
123 }
124
125 void SynchronousCompositorOutputSurface::Reshape(
126     const gfx::Size& size, float scale_factor) {
127   // Intentional no-op: surface size is controlled by the embedder.
128 }
129
130 void SynchronousCompositorOutputSurface::SetNeedsBeginImplFrame(
131     bool enable) {
132   DCHECK(CalledOnValidThread());
133   cc::OutputSurface::SetNeedsBeginImplFrame(enable);
134   needs_begin_impl_frame_ = enable;
135   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
136   if (delegate)
137     delegate->SetContinuousInvalidate(needs_begin_impl_frame_);
138 }
139
140 void SynchronousCompositorOutputSurface::SwapBuffers(
141     cc::CompositorFrame* frame) {
142   DCHECK(CalledOnValidThread());
143   if (!ForcedDrawToSoftwareDevice()) {
144     DCHECK(context_provider_);
145     context_provider_->ContextGL()->ShallowFlushCHROMIUM();
146   }
147   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
148   if (delegate)
149     delegate->UpdateFrameMetaData(frame->metadata);
150
151   did_swap_buffer_ = true;
152   DidSwapBuffers();
153 }
154
155 namespace {
156 void AdjustTransform(gfx::Transform* transform, gfx::Rect viewport) {
157   // CC's draw origin starts at the viewport.
158   transform->matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
159 }
160 } // namespace
161
162 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
163     scoped_refptr<cc::ContextProvider> onscreen_context_provider,
164     scoped_refptr<cc::ContextProvider> offscreen_context_provider) {
165   DCHECK(CalledOnValidThread());
166   DCHECK(HasClient());
167   DCHECK(!context_provider_);
168
169   return InitializeAndSetContext3d(onscreen_context_provider,
170                                    offscreen_context_provider);
171 }
172
173 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
174   DCHECK(CalledOnValidThread());
175   cc::OutputSurface::ReleaseGL();
176 }
177
178 bool SynchronousCompositorOutputSurface::DemandDrawHw(
179     gfx::Size surface_size,
180     const gfx::Transform& transform,
181     gfx::Rect viewport,
182     gfx::Rect clip,
183     bool stencil_enabled) {
184   DCHECK(CalledOnValidThread());
185   DCHECK(HasClient());
186   DCHECK(context_provider_);
187
188   surface_size_ = surface_size;
189   SetExternalStencilTest(stencil_enabled);
190   InvokeComposite(transform, viewport, clip, true);
191
192   return did_swap_buffer_;
193 }
194
195 bool SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
196   DCHECK(CalledOnValidThread());
197   DCHECK(canvas);
198   DCHECK(!current_sw_canvas_);
199   base::AutoReset<SkCanvas*> canvas_resetter(&current_sw_canvas_, canvas);
200
201   SkIRect canvas_clip;
202   canvas->getClipDeviceBounds(&canvas_clip);
203   gfx::Rect clip = gfx::SkIRectToRect(canvas_clip);
204
205   gfx::Transform transform(gfx::Transform::kSkipInitialization);
206   transform.matrix() = canvas->getTotalMatrix();  // Converts 3x3 matrix to 4x4.
207
208   surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
209                             canvas->getDeviceSize().height());
210   SetExternalStencilTest(false);
211
212   InvokeComposite(transform, clip, clip, false);
213
214   return did_swap_buffer_;
215 }
216
217 void SynchronousCompositorOutputSurface::InvokeComposite(
218     const gfx::Transform& transform,
219     gfx::Rect viewport,
220     gfx::Rect clip,
221     bool valid_for_tile_management) {
222   DCHECK(!invoking_composite_);
223   base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, true);
224   did_swap_buffer_ = false;
225
226   gfx::Transform adjusted_transform = transform;
227   AdjustTransform(&adjusted_transform, viewport);
228   SetExternalDrawConstraints(
229       adjusted_transform, viewport, clip, valid_for_tile_management);
230   SetNeedsRedrawRect(gfx::Rect(viewport.size()));
231
232   if (needs_begin_impl_frame_)
233     BeginImplFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
234
235   // After software draws (which might move the viewport arbitrarily), restore
236   // the previous hardware viewport to allow CC's tile manager to prioritize
237   // properly.
238   if (valid_for_tile_management) {
239     cached_hw_transform_ = adjusted_transform;
240     cached_hw_viewport_ = viewport;
241     cached_hw_clip_ = clip;
242   } else {
243     SetExternalDrawConstraints(
244         cached_hw_transform_, cached_hw_viewport_, cached_hw_clip_, true);
245   }
246
247   if (did_swap_buffer_)
248     OnSwapBuffersComplete();
249 }
250
251 void
252 SynchronousCompositorOutputSurface::PostCheckForRetroactiveBeginImplFrame() {
253   // Synchronous compositor cannot perform retroactive BeginImplFrames, so
254   // intentionally no-op here.
255 }
256
257 void SynchronousCompositorOutputSurface::SetMemoryPolicy(
258     const SynchronousCompositorMemoryPolicy& policy) {
259   DCHECK(CalledOnValidThread());
260   memory_policy_.bytes_limit_when_visible = policy.bytes_limit;
261   memory_policy_.num_resources_limit = policy.num_resources_limit;
262
263   if (output_surface_client_)
264     output_surface_client_->SetMemoryPolicy(memory_policy_);
265 }
266
267 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
268 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
269 // thread.
270 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
271   return BrowserThread::CurrentlyOn(BrowserThread::UI);
272 }
273
274 SynchronousCompositorOutputSurfaceDelegate*
275 SynchronousCompositorOutputSurface::GetDelegate() {
276   return SynchronousCompositorImpl::FromRoutingID(routing_id_);
277 }
278
279 }  // namespace content