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