blob: a6115e989942203974653fd321462b4b25de467d [file] [log] [blame]
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001// 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
Ben Murdocheb525c52013-07-10 11:40:50 +01007#include "base/auto_reset.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01008#include "base/logging.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01009#include "cc/output/begin_frame_args.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010010#include "cc/output/compositor_frame.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010011#include "cc/output/context_provider.h"
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010012#include "cc/output/managed_memory_policy.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010013#include "cc/output/output_surface_client.h"
14#include "cc/output/software_output_device.h"
15#include "content/browser/android/in_process/synchronous_compositor_impl.h"
16#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010017#include "content/public/browser/browser_thread.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010018#include "gpu/command_buffer/client/gl_in_process_context.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010019#include "third_party/skia/include/core/SkCanvas.h"
20#include "third_party/skia/include/core/SkDevice.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010021#include "ui/gfx/rect_conversions.h"
22#include "ui/gfx/skia_util.h"
23#include "ui/gfx/transform.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010024#include "ui/gl/gl_surface.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010025#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
26
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010027
28namespace content {
29
30namespace {
31
Ben Murdochbb1529c2013-08-08 10:24:53 +010032scoped_ptr<WebKit::WebGraphicsContext3D> CreateWebGraphicsContext3D(
33 scoped_refptr<gfx::GLSurface> surface) {
34 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
35 if (!gfx::GLSurface::InitializeOneOff())
36 return scoped_ptr<WebKit::WebGraphicsContext3D>();
37
38 const char* allowed_extensions = "*";
39 const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
40
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010041 WebKit::WebGraphicsContext3D::Attributes attributes;
42 attributes.antialias = false;
43 attributes.shareResources = true;
44 attributes.noAutomaticFlushes = true;
45
Ben Murdochbb1529c2013-08-08 10:24:53 +010046 gpu::GLInProcessContextAttribs in_process_attribs;
47 WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
48 attributes, &in_process_attribs);
49 scoped_ptr<gpu::GLInProcessContext> context(
50 gpu::GLInProcessContext::CreateWithSurface(surface,
51 attributes.shareResources,
52 allowed_extensions,
53 in_process_attribs,
54 gpu_preference));
55
56 if (!context.get())
57 return scoped_ptr<WebKit::WebGraphicsContext3D>();
58
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010059 return scoped_ptr<WebKit::WebGraphicsContext3D>(
Ben Murdochbb1529c2013-08-08 10:24:53 +010060 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
61 context.Pass(), attributes));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010062}
63
Ben Murdochca12bfa2013-07-23 11:17:05 +010064void DidActivatePendingTree(int routing_id) {
65 SynchronousCompositorOutputSurfaceDelegate* delegate =
66 SynchronousCompositorImpl::FromRoutingID(routing_id);
67 if (delegate)
68 delegate->DidActivatePendingTree();
69}
70
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010071} // namespace
72
73class SynchronousCompositorOutputSurface::SoftwareDevice
74 : public cc::SoftwareOutputDevice {
75 public:
76 SoftwareDevice(SynchronousCompositorOutputSurface* surface)
77 : surface_(surface),
78 null_device_(SkBitmap::kARGB_8888_Config, 1, 1),
79 null_canvas_(&null_device_) {
80 }
81 virtual void Resize(gfx::Size size) OVERRIDE {
82 // Intentional no-op: canvas size is controlled by the embedder.
83 }
84 virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE {
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +010085 if (!surface_->current_sw_canvas_) {
86 NOTREACHED() << "BeginPaint with no canvas set";
87 return &null_canvas_;
88 }
89 LOG_IF(WARNING, surface_->did_swap_buffer_)
90 << "Mutliple calls to BeginPaint per frame";
91 return surface_->current_sw_canvas_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010092 }
93 virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010094 }
95 virtual void CopyToBitmap(gfx::Rect rect, SkBitmap* output) OVERRIDE {
96 NOTIMPLEMENTED();
97 }
98
99 private:
100 SynchronousCompositorOutputSurface* surface_;
101 SkDevice null_device_;
102 SkCanvas null_canvas_;
103
104 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
105};
106
107SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
108 int routing_id)
109 : cc::OutputSurface(
110 scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
111 routing_id_(routing_id),
112 needs_begin_frame_(false),
Ben Murdocheb525c52013-07-10 11:40:50 +0100113 invoking_composite_(false),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100114 did_swap_buffer_(false),
115 current_sw_canvas_(NULL) {
116 capabilities_.deferred_gl_initialization = true;
Ben Murdochfb250652013-07-31 11:42:55 +0100117 capabilities_.draw_and_swap_full_viewport_every_frame = true;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100118 capabilities_.adjust_deadline_for_parent = false;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100119 // Cannot call out to GetDelegate() here as the output surface is not
120 // constructed on the correct thread.
121}
122
123SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
124 DCHECK(CalledOnValidThread());
125 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
126 if (delegate)
127 delegate->DidDestroySynchronousOutputSurface(this);
128}
129
130bool SynchronousCompositorOutputSurface::ForcedDrawToSoftwareDevice() const {
Ben Murdocheb525c52013-07-10 11:40:50 +0100131 // |current_sw_canvas_| indicates we're in a DemandDrawSw call. In addition
132 // |invoking_composite_| == false indicates an attempt to draw outside of
133 // the synchronous compositor's control: force it into SW path and hence to
134 // the null canvas (and will log a warning there).
135 return current_sw_canvas_ != NULL || !invoking_composite_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100136}
137
138bool SynchronousCompositorOutputSurface::BindToClient(
139 cc::OutputSurfaceClient* surface_client) {
140 DCHECK(CalledOnValidThread());
141 if (!cc::OutputSurface::BindToClient(surface_client))
142 return false;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100143 surface_client->SetTreeActivationCallback(
144 base::Bind(&DidActivatePendingTree, routing_id_));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100145 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
146 if (delegate)
147 delegate->DidBindOutputSurface(this);
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100148
149 const int bytes_limit = 64 * 1024 * 1024;
150 const int num_resources_limit = 100;
151 surface_client->SetMemoryPolicy(
152 cc::ManagedMemoryPolicy(bytes_limit,
153 cc::ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
154 0,
155 cc::ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING,
156 num_resources_limit));
157
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100158 return true;
159}
160
161void SynchronousCompositorOutputSurface::Reshape(
162 gfx::Size size, float scale_factor) {
163 // Intentional no-op: surface size is controlled by the embedder.
164}
165
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100166void SynchronousCompositorOutputSurface::SetNeedsBeginFrame(
167 bool enable) {
168 DCHECK(CalledOnValidThread());
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100169 cc::OutputSurface::SetNeedsBeginFrame(enable);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100170 needs_begin_frame_ = enable;
171 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
172 if (delegate)
173 delegate->SetContinuousInvalidate(needs_begin_frame_);
174}
175
176void SynchronousCompositorOutputSurface::SwapBuffers(
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +0100177 cc::CompositorFrame* frame) {
178 if (!ForcedDrawToSoftwareDevice()) {
179 DCHECK(context3d());
180 context3d()->shallowFlushCHROMIUM();
181 }
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100182 SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
183 if (delegate)
184 delegate->UpdateFrameMetaData(frame->metadata);
185
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100186 did_swap_buffer_ = true;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100187 DidSwapBuffers();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100188}
189
190namespace {
191void AdjustTransformForClip(gfx::Transform* transform, gfx::Rect clip) {
192 // The system-provided transform translates us from the screen origin to the
193 // origin of the clip rect, but CC's draw origin starts at the clip.
194 transform->matrix().postTranslate(-clip.x(), -clip.y(), 0);
195}
196} // namespace
197
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100198bool SynchronousCompositorOutputSurface::InitializeHwDraw(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100199 scoped_refptr<gfx::GLSurface> surface,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100200 scoped_refptr<cc::ContextProvider> offscreen_context) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100201 DCHECK(CalledOnValidThread());
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100202 DCHECK(HasClient());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100203 DCHECK(!context3d_);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100204 DCHECK(surface);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100205
Ben Murdochbb1529c2013-08-08 10:24:53 +0100206 return InitializeAndSetContext3D(
207 CreateWebGraphicsContext3D(surface).Pass(), offscreen_context);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100208}
209
210void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
211 cc::OutputSurface::ReleaseGL();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100212}
213
214bool SynchronousCompositorOutputSurface::DemandDrawHw(
215 gfx::Size surface_size,
216 const gfx::Transform& transform,
Ben Murdochfb250652013-07-31 11:42:55 +0100217 gfx::Rect clip,
218 bool stencil_enabled) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100219 DCHECK(CalledOnValidThread());
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100220 DCHECK(HasClient());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100221 DCHECK(context3d());
222
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100223 gfx::Transform adjusted_transform = transform;
224 AdjustTransformForClip(&adjusted_transform, clip);
225 surface_size_ = surface_size;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100226 SetExternalDrawConstraints(adjusted_transform, clip);
Ben Murdochfb250652013-07-31 11:42:55 +0100227 SetExternalStencilTest(stencil_enabled);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100228 InvokeComposite(clip.size());
229
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100230 return did_swap_buffer_;
231}
232
233bool SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
234 DCHECK(CalledOnValidThread());
235 DCHECK(canvas);
236 DCHECK(!current_sw_canvas_);
Ben Murdocheb525c52013-07-10 11:40:50 +0100237 base::AutoReset<SkCanvas*> canvas_resetter(&current_sw_canvas_, canvas);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100238
239 SkIRect canvas_clip;
240 canvas->getClipDeviceBounds(&canvas_clip);
241 gfx::Rect clip = gfx::SkIRectToRect(canvas_clip);
242
243 gfx::Transform transform(gfx::Transform::kSkipInitialization);
244 transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
245 AdjustTransformForClip(&transform, clip);
246
247 surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
248 canvas->getDeviceSize().height());
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100249 SetExternalDrawConstraints(transform, clip);
Ben Murdochfb250652013-07-31 11:42:55 +0100250 SetExternalStencilTest(false);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100251
252 InvokeComposite(clip.size());
253
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +0100254 return did_swap_buffer_;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100255}
256
257void SynchronousCompositorOutputSurface::InvokeComposite(
258 gfx::Size damage_size) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100259 DCHECK(!invoking_composite_);
260 base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, true);
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +0100261 did_swap_buffer_ = false;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100262 SetNeedsRedrawRect(gfx::Rect(damage_size));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100263 if (needs_begin_frame_)
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100264 BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
Torne (Richard Coles)5e3f23d2013-06-11 16:24:11 +0100265
266 if (did_swap_buffer_)
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100267 OnSwapBuffersComplete(NULL);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100268}
269
Ben Murdocheb525c52013-07-10 11:40:50 +0100270void SynchronousCompositorOutputSurface::PostCheckForRetroactiveBeginFrame() {
271 // Synchronous compositor cannot perform retroactive begin frames, so
272 // intentionally no-op here.
273}
274
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100275// Not using base::NonThreadSafe as we want to enforce a more exacting threading
276// requirement: SynchronousCompositorOutputSurface() must only be used on the UI
277// thread.
278bool SynchronousCompositorOutputSurface::CalledOnValidThread() const {
279 return BrowserThread::CurrentlyOn(BrowserThread::UI);
280}
281
282SynchronousCompositorOutputSurfaceDelegate*
283SynchronousCompositorOutputSurface::GetDelegate() {
284 return SynchronousCompositorImpl::FromRoutingID(routing_id_);
285}
286
287} // namespace content