cc: Implement shared worker contexts.
[chromium-blink-merge.git] / content / browser / android / in_process / synchronous_compositor_output_surface.cc
blobf03f992d83d4a289296527d774ef66aa65783037
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/compositor_frame.h"
10 #include "cc/output/context_provider.h"
11 #include "cc/output/output_surface_client.h"
12 #include "cc/output/software_output_device.h"
13 #include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
14 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
15 #include "content/browser/android/in_process/synchronous_compositor_registry.h"
16 #include "content/browser/gpu/compositor_util.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/renderer/gpu/frame_swap_message_queue.h"
19 #include "gpu/command_buffer/client/context_support.h"
20 #include "gpu/command_buffer/client/gles2_interface.h"
21 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
22 #include "third_party/skia/include/core/SkCanvas.h"
23 #include "ui/gfx/geometry/rect_conversions.h"
24 #include "ui/gfx/skia_util.h"
25 #include "ui/gfx/transform.h"
27 namespace content {
29 namespace {
31 // Do not limit number of resources, so use an unrealistically high value.
32 const size_t kNumResourcesLimit = 10 * 1000 * 1000;
34 } // namespace
36 class SynchronousCompositorOutputSurface::SoftwareDevice
37 : public cc::SoftwareOutputDevice {
38 public:
39 SoftwareDevice(SynchronousCompositorOutputSurface* surface)
40 : surface_(surface) {
42 void Resize(const gfx::Size& pixel_size, float scale_factor) override {
43 // Intentional no-op: canvas size is controlled by the embedder.
45 SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
46 if (!surface_->current_sw_canvas_) {
47 NOTREACHED() << "BeginPaint with no canvas set";
48 return &null_canvas_;
50 LOG_IF(WARNING, surface_->frame_holder_.get())
51 << "Mutliple calls to BeginPaint per frame";
52 return surface_->current_sw_canvas_;
54 void EndPaint() override {}
56 private:
57 SynchronousCompositorOutputSurface* surface_;
58 SkCanvas null_canvas_;
60 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
63 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
64 const scoped_refptr<cc::ContextProvider>& context_provider,
65 const scoped_refptr<cc::ContextProvider>& worker_context_provider,
66 int routing_id,
67 scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue)
68 : cc::OutputSurface(
69 context_provider,
70 worker_context_provider,
71 scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
72 routing_id_(routing_id),
73 registered_(false),
74 current_sw_canvas_(nullptr),
75 memory_policy_(0),
76 frame_swap_message_queue_(frame_swap_message_queue) {
77 capabilities_.draw_and_swap_full_viewport_every_frame = true;
78 capabilities_.adjust_deadline_for_parent = false;
79 capabilities_.delegated_rendering = true;
80 capabilities_.max_frames_pending = 1;
81 memory_policy_.priority_cutoff_when_visible =
82 gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
85 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
88 bool SynchronousCompositorOutputSurface::BindToClient(
89 cc::OutputSurfaceClient* surface_client) {
90 DCHECK(CalledOnValidThread());
91 if (!cc::OutputSurface::BindToClient(surface_client))
92 return false;
94 client_->SetMemoryPolicy(memory_policy_);
96 SynchronousCompositorRegistry::GetInstance()->RegisterOutputSurface(
97 routing_id_, this);
98 registered_ = true;
100 return true;
103 void SynchronousCompositorOutputSurface::DetachFromClient() {
104 DCHECK(CalledOnValidThread());
105 if (registered_) {
106 SynchronousCompositorRegistry::GetInstance()->UnregisterOutputSurface(
107 routing_id_, this);
109 cc::OutputSurface::DetachFromClient();
112 void SynchronousCompositorOutputSurface::SetCompositor(
113 SynchronousCompositorImpl* compositor) {
114 DCHECK(CalledOnValidThread());
115 compositor_ = compositor;
118 void SynchronousCompositorOutputSurface::Reshape(
119 const gfx::Size& size, float scale_factor) {
120 // Intentional no-op: surface size is controlled by the embedder.
123 void SynchronousCompositorOutputSurface::SwapBuffers(
124 cc::CompositorFrame* frame) {
125 DCHECK(CalledOnValidThread());
127 frame_holder_.reset(new cc::CompositorFrame);
128 frame->AssignTo(frame_holder_.get());
130 client_->DidSwapBuffers();
133 void SynchronousCompositorOutputSurface::Invalidate() {
134 DCHECK(CalledOnValidThread());
135 compositor_->PostInvalidate();
138 namespace {
139 void AdjustTransform(gfx::Transform* transform, gfx::Rect viewport) {
140 // CC's draw origin starts at the viewport.
141 transform->matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
143 } // namespace
145 scoped_ptr<cc::CompositorFrame>
146 SynchronousCompositorOutputSurface::DemandDrawHw(
147 gfx::Size surface_size,
148 const gfx::Transform& transform,
149 gfx::Rect viewport,
150 gfx::Rect clip,
151 gfx::Rect viewport_rect_for_tile_priority,
152 const gfx::Transform& transform_for_tile_priority) {
153 DCHECK(CalledOnValidThread());
154 DCHECK(HasClient());
155 DCHECK(context_provider_.get());
157 surface_size_ = surface_size;
158 InvokeComposite(transform,
159 viewport,
160 clip,
161 viewport_rect_for_tile_priority,
162 transform_for_tile_priority,
163 true);
165 return frame_holder_.Pass();
168 scoped_ptr<cc::CompositorFrame>
169 SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
170 DCHECK(CalledOnValidThread());
171 DCHECK(canvas);
172 DCHECK(!current_sw_canvas_);
174 base::AutoReset<SkCanvas*> canvas_resetter(&current_sw_canvas_, canvas);
176 SkIRect canvas_clip;
177 canvas->getClipDeviceBounds(&canvas_clip);
178 gfx::Rect clip = gfx::SkIRectToRect(canvas_clip);
180 gfx::Transform transform(gfx::Transform::kSkipInitialization);
181 transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
183 surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
184 canvas->getDeviceSize().height());
186 // Pass in the cached hw viewport and transform for tile priority to avoid
187 // tile thrashing when the WebView is alternating between hardware and
188 // software draws.
189 InvokeComposite(transform,
190 clip,
191 clip,
192 cached_hw_viewport_rect_for_tile_priority_,
193 cached_hw_transform_for_tile_priority_,
194 false);
196 return frame_holder_.Pass();
199 void SynchronousCompositorOutputSurface::InvokeComposite(
200 const gfx::Transform& transform,
201 gfx::Rect viewport,
202 gfx::Rect clip,
203 gfx::Rect viewport_rect_for_tile_priority,
204 gfx::Transform transform_for_tile_priority,
205 bool hardware_draw) {
206 DCHECK(!frame_holder_.get());
208 gfx::Transform adjusted_transform = transform;
209 AdjustTransform(&adjusted_transform, viewport);
210 SetExternalDrawConstraints(adjusted_transform,
211 viewport,
212 clip,
213 viewport_rect_for_tile_priority,
214 transform_for_tile_priority,
215 !hardware_draw);
216 SetNeedsRedrawRect(gfx::Rect(viewport.size()));
218 client_->OnDraw();
220 // After software draws (which might move the viewport arbitrarily), restore
221 // the previous hardware viewport to allow CC's tile manager to prioritize
222 // properly.
223 if (hardware_draw) {
224 cached_hw_transform_ = adjusted_transform;
225 cached_hw_viewport_ = viewport;
226 cached_hw_clip_ = clip;
227 cached_hw_viewport_rect_for_tile_priority_ =
228 viewport_rect_for_tile_priority;
229 cached_hw_transform_for_tile_priority_ = transform_for_tile_priority;
230 } else {
231 bool resourceless_software_draw = false;
232 SetExternalDrawConstraints(cached_hw_transform_,
233 cached_hw_viewport_,
234 cached_hw_clip_,
235 cached_hw_viewport_rect_for_tile_priority_,
236 cached_hw_transform_for_tile_priority_,
237 resourceless_software_draw);
240 if (frame_holder_.get())
241 client_->DidSwapBuffersComplete();
244 void SynchronousCompositorOutputSurface::ReturnResources(
245 const cc::CompositorFrameAck& frame_ack) {
246 ReclaimResources(&frame_ack);
249 void SynchronousCompositorOutputSurface::SetMemoryPolicy(size_t bytes_limit) {
250 DCHECK(CalledOnValidThread());
251 bool became_zero = memory_policy_.bytes_limit_when_visible && !bytes_limit;
252 bool became_non_zero =
253 !memory_policy_.bytes_limit_when_visible && bytes_limit;
254 memory_policy_.bytes_limit_when_visible = bytes_limit;
255 memory_policy_.num_resources_limit = kNumResourcesLimit;
257 if (client_)
258 client_->SetMemoryPolicy(memory_policy_);
260 if (became_zero) {
261 // This is small hack to drop context resources without destroying it
262 // when this compositor is put into the background.
263 context_provider()->ContextSupport()->SetAggressivelyFreeResources(
264 true /* aggressively_free_resources */);
265 } else if (became_non_zero) {
266 context_provider()->ContextSupport()->SetAggressivelyFreeResources(
267 false /* aggressively_free_resources */);
271 void SynchronousCompositorOutputSurface::SetTreeActivationCallback(
272 const base::Closure& callback) {
273 DCHECK(client_);
274 client_->SetTreeActivationCallback(callback);
277 void SynchronousCompositorOutputSurface::GetMessagesToDeliver(
278 ScopedVector<IPC::Message>* messages) {
279 DCHECK(CalledOnValidThread());
280 scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
281 frame_swap_message_queue_->AcquireSendMessageScope();
282 frame_swap_message_queue_->DrainMessages(messages);
285 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
286 // requirement: SynchronousCompositorOutputSurface() must only be used on the UI
287 // thread.
288 bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
289 return BrowserThread::CurrentlyOn(BrowserThread::UI);
292 } // namespace content