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 "third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h"
6
7 #include <vector>
8
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/check.h"
12 #include "base/command_line.h"
13 #include "base/location.h"
14 #include "base/macros.h"
15 #include "base/notreached.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "cc/trees/layer_tree_frame_sink_client.h"
19 #include "components/viz/common/display/renderer_settings.h"
20 #include "components/viz/common/features.h"
21 #include "components/viz/common/gpu/context_provider.h"
22 #include "components/viz/common/quads/compositor_frame.h"
23 #include "components/viz/common/quads/compositor_render_pass.h"
24 #include "components/viz/common/quads/surface_draw_quad.h"
25 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
26 #include "components/viz/service/display/display.h"
27 #include "components/viz/service/display/output_surface.h"
28 #include "components/viz/service/display/output_surface_frame.h"
29 #include "components/viz/service/display/overlay_processor_stub.h"
30 #include "components/viz/service/display/software_output_device.h"
31 #include "components/viz/service/display/texture_deleter.h"
32 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
33 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
34 #include "gpu/command_buffer/client/context_support.h"
35 #include "gpu/command_buffer/client/gles2_interface.h"
36 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
37 #include "third_party/blink/public/platform/platform.h"
38 #include "third_party/skia/include/core/SkCanvas.h"
39 #include "ui/gfx/geometry/rect_conversions.h"
40 #include "ui/gfx/skia_util.h"
41 #include "ui/gfx/transform.h"
42
43 namespace blink {
44
45 namespace {
46
47 const viz::FrameSinkId kRootFrameSinkId(1, 1);
48 const viz::FrameSinkId kChildFrameSinkId(1, 2);
49
50 // Do not limit number of resources, so use an unrealistically high value.
51 const size_t kNumResourcesLimit = 10 * 1000 * 1000;
52
53 class SoftwareDevice : public viz::SoftwareOutputDevice {
54 public:
SoftwareDevice(SkCanvas ** canvas)55 SoftwareDevice(SkCanvas** canvas) : canvas_(canvas) {}
56
Resize(const gfx::Size & pixel_size,float device_scale_factor)57 void Resize(const gfx::Size& pixel_size, float device_scale_factor) override {
58 // Intentional no-op: canvas size is controlled by the embedder.
59 }
BeginPaint(const gfx::Rect & damage_rect)60 SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
61 DCHECK(*canvas_) << "BeginPaint with no canvas set";
62 return *canvas_;
63 }
EndPaint()64 void EndPaint() override {}
65
66 private:
67 SkCanvas** canvas_;
68
69 DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
70 };
71
72 // This is used with resourceless software draws.
73 class SoftwareCompositorFrameSinkClient
74 : public viz::mojom::CompositorFrameSinkClient {
75 public:
76 SoftwareCompositorFrameSinkClient() = default;
77 ~SoftwareCompositorFrameSinkClient() override = default;
78
DidReceiveCompositorFrameAck(const std::vector<viz::ReturnedResource> & resources)79 void DidReceiveCompositorFrameAck(
80 const std::vector<viz::ReturnedResource>& resources) override {
81 DCHECK(resources.empty());
82 }
OnBeginFrame(const viz::BeginFrameArgs & args,const viz::FrameTimingDetailsMap & timing_details)83 void OnBeginFrame(const viz::BeginFrameArgs& args,
84 const viz::FrameTimingDetailsMap& timing_details) override {
85 }
ReclaimResources(const std::vector<viz::ReturnedResource> & resources)86 void ReclaimResources(
87 const std::vector<viz::ReturnedResource>& resources) override {
88 DCHECK(resources.empty());
89 }
OnBeginFramePausedChanged(bool paused)90 void OnBeginFramePausedChanged(bool paused) override {}
91
92 private:
93 DISALLOW_COPY_AND_ASSIGN(SoftwareCompositorFrameSinkClient);
94 };
95
96 } // namespace
97
98 class SynchronousLayerTreeFrameSink::SoftwareOutputSurface
99 : public viz::OutputSurface {
100 public:
SoftwareOutputSurface(std::unique_ptr<SoftwareDevice> software_device)101 SoftwareOutputSurface(std::unique_ptr<SoftwareDevice> software_device)
102 : viz::OutputSurface(std::move(software_device)) {}
103
104 // viz::OutputSurface implementation.
BindToClient(viz::OutputSurfaceClient * client)105 void BindToClient(viz::OutputSurfaceClient* client) override {}
EnsureBackbuffer()106 void EnsureBackbuffer() override {}
DiscardBackbuffer()107 void DiscardBackbuffer() override {}
BindFramebuffer()108 void BindFramebuffer() override {}
SwapBuffers(viz::OutputSurfaceFrame frame)109 void SwapBuffers(viz::OutputSurfaceFrame frame) override {}
Reshape(const gfx::Size & size,float scale_factor,const gfx::ColorSpace & color_space,gfx::BufferFormat format,bool use_stencil)110 void Reshape(const gfx::Size& size,
111 float scale_factor,
112 const gfx::ColorSpace& color_space,
113 gfx::BufferFormat format,
114 bool use_stencil) override {}
GetFramebufferCopyTextureFormat()115 uint32_t GetFramebufferCopyTextureFormat() override { return 0; }
IsDisplayedAsOverlayPlane() const116 bool IsDisplayedAsOverlayPlane() const override { return false; }
GetOverlayTextureId() const117 unsigned GetOverlayTextureId() const override { return 0; }
HasExternalStencilTest() const118 bool HasExternalStencilTest() const override { return false; }
ApplyExternalStencil()119 void ApplyExternalStencil() override {}
UpdateGpuFence()120 unsigned UpdateGpuFence() override { return 0; }
SetUpdateVSyncParametersCallback(viz::UpdateVSyncParametersCallback callback)121 void SetUpdateVSyncParametersCallback(
122 viz::UpdateVSyncParametersCallback callback) override {}
SetDisplayTransformHint(gfx::OverlayTransform transform)123 void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
GetDisplayTransform()124 gfx::OverlayTransform GetDisplayTransform() override {
125 return gfx::OVERLAY_TRANSFORM_NONE;
126 }
127 };
128
129 base::TimeDelta SynchronousLayerTreeFrameSink::StubDisplayClient::
GetPreferredFrameIntervalForFrameSinkId(const viz::FrameSinkId & id,viz::mojom::blink::CompositorFrameSinkType * type)130 GetPreferredFrameIntervalForFrameSinkId(
131 const viz::FrameSinkId& id,
132 viz::mojom::blink::CompositorFrameSinkType* type) {
133 return viz::BeginFrameArgs::MinInterval();
134 }
135
SynchronousLayerTreeFrameSink(scoped_refptr<viz::ContextProvider> context_provider,scoped_refptr<viz::RasterContextProvider> worker_context_provider,scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,gpu::GpuMemoryBufferManager * gpu_memory_buffer_manager,uint32_t layer_tree_frame_sink_id,std::unique_ptr<viz::BeginFrameSource> synthetic_begin_frame_source,SynchronousCompositorRegistry * registry,mojo::PendingRemote<viz::mojom::blink::CompositorFrameSink> compositor_frame_sink_remote,mojo::PendingReceiver<viz::mojom::blink::CompositorFrameSinkClient> client_receiver)136 SynchronousLayerTreeFrameSink::SynchronousLayerTreeFrameSink(
137 scoped_refptr<viz::ContextProvider> context_provider,
138 scoped_refptr<viz::RasterContextProvider> worker_context_provider,
139 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
140 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
141 uint32_t layer_tree_frame_sink_id,
142 std::unique_ptr<viz::BeginFrameSource> synthetic_begin_frame_source,
143 SynchronousCompositorRegistry* registry,
144 mojo::PendingRemote<viz::mojom::blink::CompositorFrameSink>
145 compositor_frame_sink_remote,
146 mojo::PendingReceiver<viz::mojom::blink::CompositorFrameSinkClient>
147 client_receiver)
148 : cc::LayerTreeFrameSink(std::move(context_provider),
149 std::move(worker_context_provider),
150 std::move(compositor_task_runner),
151 gpu_memory_buffer_manager),
152 layer_tree_frame_sink_id_(layer_tree_frame_sink_id),
153 registry_(registry),
154 memory_policy_(0u),
155 unbound_compositor_frame_sink_(std::move(compositor_frame_sink_remote)),
156 unbound_client_(std::move(client_receiver)),
157 synthetic_begin_frame_source_(std::move(synthetic_begin_frame_source)),
158 viz_frame_submission_enabled_(
159 features::IsUsingVizFrameSubmissionForWebView()),
160 use_zero_copy_sw_draw_(
161 Platform::Current()
162 ->IsZeroCopySynchronousSwDrawEnabledForAndroidWebView()) {
163 DCHECK(registry_);
164 DETACH_FROM_THREAD(thread_checker_);
165 memory_policy_.priority_cutoff_when_visible =
166 gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
167 }
168
169 SynchronousLayerTreeFrameSink::~SynchronousLayerTreeFrameSink() = default;
170
SetSyncClient(SynchronousLayerTreeFrameSinkClient * compositor)171 void SynchronousLayerTreeFrameSink::SetSyncClient(
172 SynchronousLayerTreeFrameSinkClient* compositor) {
173 sync_client_ = compositor;
174 }
175
BindToClient(cc::LayerTreeFrameSinkClient * sink_client)176 bool SynchronousLayerTreeFrameSink::BindToClient(
177 cc::LayerTreeFrameSinkClient* sink_client) {
178 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
179 if (!cc::LayerTreeFrameSink::BindToClient(sink_client))
180 return false;
181
182 if (viz_frame_submission_enabled_) {
183 compositor_frame_sink_.Bind(std::move(unbound_compositor_frame_sink_));
184 client_receiver_.Bind(std::move(unbound_client_), compositor_task_runner_);
185 }
186
187 // The SharedBitmapManager is null since software compositing is not supported
188 // or used on Android.
189 frame_sink_manager_ = std::make_unique<viz::FrameSinkManagerImpl>(
190 /*shared_bitmap_manager=*/nullptr);
191
192 if (synthetic_begin_frame_source_) {
193 client_->SetBeginFrameSource(synthetic_begin_frame_source_.get());
194 } else {
195 external_begin_frame_source_ =
196 std::make_unique<viz::ExternalBeginFrameSource>(this);
197 external_begin_frame_source_->OnSetBeginFrameSourcePaused(
198 begin_frames_paused_);
199 client_->SetBeginFrameSource(external_begin_frame_source_.get());
200 }
201
202 client_->SetMemoryPolicy(memory_policy_);
203 client_->SetTreeActivationCallback(base::BindRepeating(
204 &SynchronousLayerTreeFrameSink::DidActivatePendingTree,
205 base::Unretained(this)));
206 registry_->RegisterLayerTreeFrameSink(this);
207
208 software_frame_sink_client_ =
209 std::make_unique<SoftwareCompositorFrameSinkClient>();
210 constexpr bool root_support_is_root = true;
211 constexpr bool child_support_is_root = false;
212 root_support_ = std::make_unique<viz::CompositorFrameSinkSupport>(
213 software_frame_sink_client_.get(), frame_sink_manager_.get(),
214 kRootFrameSinkId, root_support_is_root);
215 child_support_ = std::make_unique<viz::CompositorFrameSinkSupport>(
216 software_frame_sink_client_.get(), frame_sink_manager_.get(),
217 kChildFrameSinkId, child_support_is_root);
218
219 viz::RendererSettings software_renderer_settings;
220
221 auto output_surface = std::make_unique<SoftwareOutputSurface>(
222 std::make_unique<SoftwareDevice>(¤t_sw_canvas_));
223 software_output_surface_ = output_surface.get();
224
225 auto overlay_processor = std::make_unique<viz::OverlayProcessorStub>();
226
227 // The gpu_memory_buffer_manager here is null as the Display is only used for
228 // resourcesless software draws, where no resources are included in the frame
229 // swapped from the compositor. So there is no need for it.
230 // The shared_bitmap_manager_ is provided for the Display to allocate
231 // resources.
232 // TODO(crbug.com/692814): The Display never sends its resources out of
233 // process so there is no reason for it to use a SharedBitmapManager.
234 // The gpu::GpuTaskSchedulerHelper here is null as the OutputSurface is
235 // software only and the overlay processor is a stub.
236 display_ = std::make_unique<viz::Display>(
237 &shared_bitmap_manager_, software_renderer_settings, &debug_settings_,
238 kRootFrameSinkId, nullptr /* gpu::GpuTaskSchedulerHelper */,
239 std::move(output_surface), std::move(overlay_processor),
240 nullptr /* scheduler */, nullptr /* current_task_runner */);
241 display_->Initialize(&display_client_,
242 frame_sink_manager_->surface_manager());
243 display_->SetVisible(true);
244 return true;
245 }
246
DetachFromClient()247 void SynchronousLayerTreeFrameSink::DetachFromClient() {
248 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
249 client_->SetBeginFrameSource(nullptr);
250 // Destroy the begin frame source on the same thread it was bound on.
251 synthetic_begin_frame_source_ = nullptr;
252 external_begin_frame_source_ = nullptr;
253 if (sync_client_)
254 sync_client_->SinkDestroyed();
255 registry_->UnregisterLayerTreeFrameSink(this);
256 client_->SetTreeActivationCallback(base::RepeatingClosure());
257 root_support_.reset();
258 child_support_.reset();
259 software_frame_sink_client_ = nullptr;
260 software_output_surface_ = nullptr;
261 display_ = nullptr;
262 frame_sink_manager_ = nullptr;
263
264 client_receiver_.reset();
265 compositor_frame_sink_.reset();
266
267 cc::LayerTreeFrameSink::DetachFromClient();
268 }
269
SetLocalSurfaceId(const viz::LocalSurfaceId & local_surface_id)270 void SynchronousLayerTreeFrameSink::SetLocalSurfaceId(
271 const viz::LocalSurfaceId& local_surface_id) {
272 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
273 local_surface_id_ = local_surface_id;
274 }
275
SubmitCompositorFrame(viz::CompositorFrame frame,bool hit_test_data_changed,bool show_hit_test_borders)276 void SynchronousLayerTreeFrameSink::SubmitCompositorFrame(
277 viz::CompositorFrame frame,
278 bool hit_test_data_changed,
279 bool show_hit_test_borders) {
280 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
281 DCHECK(sync_client_);
282
283 base::Optional<viz::CompositorFrame> submit_frame;
284 gfx::Size child_size = in_software_draw_
285 ? sw_viewport_for_current_draw_.size()
286 : frame.size_in_pixels();
287 if (!child_local_surface_id_.is_valid() || child_size_ != child_size ||
288 device_scale_factor_ != frame.metadata.device_scale_factor) {
289 child_local_surface_id_allocator_.GenerateId();
290 child_local_surface_id_ =
291 child_local_surface_id_allocator_.GetCurrentLocalSurfaceId();
292 child_size_ = child_size;
293 device_scale_factor_ = frame.metadata.device_scale_factor;
294 }
295
296 if (in_software_draw_) {
297 // The frame we send to the client is actually just the metadata. Preserve
298 // the |frame| for the software path below.
299 submit_frame.emplace();
300 submit_frame->metadata = frame.metadata.Clone();
301
302 // The layer compositor should be giving a frame that covers the
303 // |sw_viewport_for_current_draw_| but at 0,0.
304 DCHECK(gfx::Rect(child_size) == frame.render_pass_list.back()->output_rect);
305
306 // Make a size that covers from 0,0 and includes the area coming from the
307 // layer compositor.
308 gfx::Size display_size(sw_viewport_for_current_draw_.right(),
309 sw_viewport_for_current_draw_.bottom());
310 display_->Resize(display_size);
311
312 if (!root_local_surface_id_.is_valid() || display_size_ != display_size ||
313 device_scale_factor_ != frame.metadata.device_scale_factor) {
314 root_local_surface_id_allocator_.GenerateId();
315 root_local_surface_id_ =
316 root_local_surface_id_allocator_.GetCurrentLocalSurfaceId();
317 display_size_ = display_size;
318 device_scale_factor_ = frame.metadata.device_scale_factor;
319 }
320
321 display_->SetLocalSurfaceId(root_local_surface_id_,
322 frame.metadata.device_scale_factor);
323
324 // The offset for the child frame relative to the origin of the canvas being
325 // drawn into.
326 gfx::Transform child_transform;
327 child_transform.Translate(
328 gfx::Vector2dF(sw_viewport_for_current_draw_.OffsetFromOrigin()));
329
330 // Make a root frame that embeds the frame coming from the layer compositor
331 // and positions it based on the provided viewport.
332 // TODO(danakj): We could apply the transform here instead of passing it to
333 // the LayerTreeFrameSink client too? (We'd have to do the same for
334 // hardware frames in SurfacesInstance?)
335 viz::CompositorFrame embed_frame;
336 embed_frame.metadata.begin_frame_ack = frame.metadata.begin_frame_ack;
337 embed_frame.metadata.device_scale_factor =
338 frame.metadata.device_scale_factor;
339 embed_frame.render_pass_list.push_back(viz::CompositorRenderPass::Create());
340
341 // The embedding RenderPass covers the entire Display's area.
342 const auto& embed_render_pass = embed_frame.render_pass_list.back();
343 embed_render_pass->SetNew(viz::CompositorRenderPassId{1},
344 gfx::Rect(display_size), gfx::Rect(display_size),
345 gfx::Transform());
346 embed_render_pass->has_transparent_background = false;
347
348 // The RenderPass has a single SurfaceDrawQuad (and SharedQuadState for it).
349 bool are_contents_opaque =
350 !frame.render_pass_list.back()->has_transparent_background;
351 auto* shared_quad_state =
352 embed_render_pass->CreateAndAppendSharedQuadState();
353 auto* surface_quad =
354 embed_render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
355 shared_quad_state->SetAll(
356 child_transform, gfx::Rect(child_size), gfx::Rect(child_size),
357 gfx::MaskFilterInfo(), gfx::Rect() /* clip_rect */,
358 false /* is_clipped */, are_contents_opaque /* are_contents_opaque */,
359 1.f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
360 surface_quad->SetNew(
361 shared_quad_state, gfx::Rect(child_size), gfx::Rect(child_size),
362 viz::SurfaceRange(
363 base::nullopt,
364 viz::SurfaceId(kChildFrameSinkId, child_local_surface_id_)),
365 SK_ColorWHITE, false /* stretch_content_to_fill_bounds */);
366
367 child_support_->SubmitCompositorFrame(child_local_surface_id_,
368 std::move(frame));
369 root_support_->SubmitCompositorFrame(root_local_surface_id_,
370 std::move(embed_frame));
371 display_->DrawAndSwap(base::TimeTicks::Now());
372
373 // We don't track metrics for frames submitted to |display_| but it still
374 // expects that every frame will receive a swap ack and presentation
375 // feedback so we send null signals here.
376 display_->DidReceiveSwapBuffersAck(gfx::SwapTimings());
377 display_->DidReceivePresentationFeedback(
378 gfx::PresentationFeedback::Failure());
379 } else {
380 if (viz_frame_submission_enabled_) {
381 frame.metadata.begin_frame_ack =
382 viz::BeginFrameAck::CreateManualAckWithDamage();
383
384 // For hardware draws with viz we send frame to compositor_frame_sink_
385 compositor_frame_sink_->SubmitCompositorFrame(
386 local_surface_id_, std::move(frame), client_->BuildHitTestData(), 0);
387 } else {
388 // For hardware draws without viz we send the whole frame to the client so
389 // it can draw the content in it.
390 submit_frame = std::move(frame);
391 }
392 }
393 // NOTE: submit_frame will be empty if viz_frame_submission_enabled_ enabled,
394 // but it won't be used upstream
395 sync_client_->SubmitCompositorFrame(layer_tree_frame_sink_id_,
396 std::move(submit_frame),
397 client_->BuildHitTestData());
398 did_submit_frame_ = true;
399 }
400
DidNotProduceFrame(const viz::BeginFrameAck & ack)401 void SynchronousLayerTreeFrameSink::DidNotProduceFrame(
402 const viz::BeginFrameAck& ack) {
403 // We do not call CompositorFrameSink::DidNotProduceFrame here because
404 // submission of frame depends on DemandDraw calls. DidNotProduceFrame will be
405 // called there or during OnBeginFrame as fallback.
406 }
407
DidAllocateSharedBitmap(base::ReadOnlySharedMemoryRegion region,const viz::SharedBitmapId & id)408 void SynchronousLayerTreeFrameSink::DidAllocateSharedBitmap(
409 base::ReadOnlySharedMemoryRegion region,
410 const viz::SharedBitmapId& id) {
411 // Webview does not use software compositing (other than resourceless draws,
412 // but this is called for software /resources/).
413 NOTREACHED();
414 }
415
DidDeleteSharedBitmap(const viz::SharedBitmapId & id)416 void SynchronousLayerTreeFrameSink::DidDeleteSharedBitmap(
417 const viz::SharedBitmapId& id) {
418 // Webview does not use software compositing (other than resourceless draws,
419 // but this is called for software /resources/).
420 NOTREACHED();
421 }
422
Invalidate(bool needs_draw)423 void SynchronousLayerTreeFrameSink::Invalidate(bool needs_draw) {
424 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
425 if (sync_client_)
426 sync_client_->Invalidate(needs_draw);
427 }
428
DemandDrawHw(const gfx::Size & viewport_size,const gfx::Rect & viewport_rect_for_tile_priority,const gfx::Transform & transform_for_tile_priority)429 void SynchronousLayerTreeFrameSink::DemandDrawHw(
430 const gfx::Size& viewport_size,
431 const gfx::Rect& viewport_rect_for_tile_priority,
432 const gfx::Transform& transform_for_tile_priority) {
433 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
434 DCHECK(HasClient());
435 DCHECK(context_provider_.get());
436
437 client_->SetExternalTilePriorityConstraints(viewport_rect_for_tile_priority,
438 transform_for_tile_priority);
439 InvokeComposite(gfx::Transform(), gfx::Rect(viewport_size));
440 }
441
DemandDrawSwZeroCopy()442 void SynchronousLayerTreeFrameSink::DemandDrawSwZeroCopy() {
443 DCHECK(use_zero_copy_sw_draw_);
444 DemandDrawSw(
445 Platform::Current()->SynchronousCompositorGetSkCanvasForAndroidWebView());
446 }
447
DemandDrawSw(SkCanvas * canvas)448 void SynchronousLayerTreeFrameSink::DemandDrawSw(SkCanvas* canvas) {
449 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
450 DCHECK(canvas);
451 DCHECK(!current_sw_canvas_);
452
453 base::AutoReset<SkCanvas*> canvas_resetter(¤t_sw_canvas_, canvas);
454
455 SkIRect canvas_clip = canvas->getDeviceClipBounds();
456 gfx::Rect viewport = gfx::SkIRectToRect(canvas_clip);
457
458 gfx::Transform transform(gfx::Transform::kSkipInitialization);
459 transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4.
460
461 // We will resize the Display to ensure it covers the entire |viewport|, so
462 // save it for later.
463 sw_viewport_for_current_draw_ = viewport;
464
465 base::AutoReset<bool> set_in_software_draw(&in_software_draw_, true);
466 InvokeComposite(transform, viewport);
467 }
468
WillSkipDraw()469 void SynchronousLayerTreeFrameSink::WillSkipDraw() {
470 client_->OnDraw(gfx::Transform(), gfx::Rect(), in_software_draw_,
471 true /*skip_draw*/);
472 }
473
UseZeroCopySoftwareDraw()474 bool SynchronousLayerTreeFrameSink::UseZeroCopySoftwareDraw() {
475 return use_zero_copy_sw_draw_;
476 }
477
InvokeComposite(const gfx::Transform & transform,const gfx::Rect & viewport)478 void SynchronousLayerTreeFrameSink::InvokeComposite(
479 const gfx::Transform& transform,
480 const gfx::Rect& viewport) {
481 did_submit_frame_ = false;
482 // Adjust transform so that the layer compositor draws the |viewport| rect
483 // at its origin. The offset of the |viewport| we pass to the layer compositor
484 // must also be zero, since the rect needs to be in the coordinates of the
485 // layer compositor.
486 gfx::Transform adjusted_transform = transform;
487 adjusted_transform.matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
488 // Don't propagate the viewport origin, as it will affect the clip rect.
489 client_->OnDraw(adjusted_transform, gfx::Rect(viewport.size()),
490 in_software_draw_, false /*skip_draw*/);
491
492 if (did_submit_frame_) {
493 // This must happen after unwinding the stack and leaving the compositor.
494 // Usually it is a separate task but we just defer it until OnDraw
495 // completes instead.
496 client_->DidReceiveCompositorFrameAck();
497 }
498 }
499
ReclaimResources(uint32_t layer_tree_frame_sink_id,const Vector<viz::ReturnedResource> & resources)500 void SynchronousLayerTreeFrameSink::ReclaimResources(
501 uint32_t layer_tree_frame_sink_id,
502 const Vector<viz::ReturnedResource>& resources) {
503 // Ignore message if it's a stale one coming from a different output surface
504 // (e.g. after a lost context).
505 if (layer_tree_frame_sink_id != layer_tree_frame_sink_id_)
506 return;
507 client_->ReclaimResources(
508 std::vector<viz::ReturnedResource>(resources.begin(), resources.end()));
509 }
510
SetMemoryPolicy(size_t bytes_limit)511 void SynchronousLayerTreeFrameSink::SetMemoryPolicy(size_t bytes_limit) {
512 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
513 bool became_zero = memory_policy_.bytes_limit_when_visible && !bytes_limit;
514 bool became_non_zero =
515 !memory_policy_.bytes_limit_when_visible && bytes_limit;
516 memory_policy_.bytes_limit_when_visible = bytes_limit;
517 memory_policy_.num_resources_limit = kNumResourcesLimit;
518
519 if (client_)
520 client_->SetMemoryPolicy(memory_policy_);
521
522 if (became_zero) {
523 // This is small hack to drop context resources without destroying it
524 // when this compositor is put into the background.
525 context_provider()->ContextSupport()->SetAggressivelyFreeResources(
526 true /* aggressively_free_resources */);
527 } else if (became_non_zero) {
528 context_provider()->ContextSupport()->SetAggressivelyFreeResources(
529 false /* aggressively_free_resources */);
530 }
531 }
532
DidActivatePendingTree()533 void SynchronousLayerTreeFrameSink::DidActivatePendingTree() {
534 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
535 if (sync_client_)
536 sync_client_->DidActivatePendingTree();
537 }
538
DidReceiveCompositorFrameAck(const Vector<viz::ReturnedResource> & resources)539 void SynchronousLayerTreeFrameSink::DidReceiveCompositorFrameAck(
540 const Vector<viz::ReturnedResource>& resources) {
541 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
542 DCHECK(viz_frame_submission_enabled_);
543 client_->ReclaimResources(
544 std::vector<viz::ReturnedResource>(resources.begin(), resources.end()));
545 // client_->DidReceiveCompositorFrameAck() is called just after frame
546 // submission so cc won't be throttled on actual draw which can happen late
547 // (or not happen at all) for WebView.
548 }
549
OnBeginFrame(const viz::BeginFrameArgs & args,const HashMap<uint32_t,viz::FrameTimingDetails> & timing_details)550 void SynchronousLayerTreeFrameSink::OnBeginFrame(
551 const viz::BeginFrameArgs& args,
552 const HashMap<uint32_t, viz::FrameTimingDetails>& timing_details) {
553 DCHECK(viz_frame_submission_enabled_);
554
555 // We do not receive BeginFrames via CompositorFrameSink, so we do not forward
556 // it to cc. We still might get one with FrameTimingDetailsMap, so we report
557 // it here.
558
559 if (client_) {
560 for (const auto& pair : timing_details) {
561 client_->DidPresentCompositorFrame(pair.key, pair.value);
562 }
563 }
564 }
565
ReclaimResources(const Vector<viz::ReturnedResource> & resources)566 void SynchronousLayerTreeFrameSink::ReclaimResources(
567 const Vector<viz::ReturnedResource>& resources) {
568 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
569 DCHECK(viz_frame_submission_enabled_);
570 client_->ReclaimResources(
571 std::vector<viz::ReturnedResource>(resources.begin(), resources.end()));
572 }
573
OnBeginFramePausedChanged(bool paused)574 void SynchronousLayerTreeFrameSink::OnBeginFramePausedChanged(bool paused) {
575 DCHECK(viz_frame_submission_enabled_);
576 }
577
OnNeedsBeginFrames(bool needs_begin_frames)578 void SynchronousLayerTreeFrameSink::OnNeedsBeginFrames(
579 bool needs_begin_frames) {
580 needs_begin_frames_ = needs_begin_frames;
581 if (sync_client_) {
582 sync_client_->SetNeedsBeginFrames(needs_begin_frames);
583 }
584 }
585
DidPresentCompositorFrame(const viz::FrameTimingDetailsMap & timing_details)586 void SynchronousLayerTreeFrameSink::DidPresentCompositorFrame(
587 const viz::FrameTimingDetailsMap& timing_details) {
588 DCHECK(!viz_frame_submission_enabled_ || timing_details.empty());
589
590 if (!client_)
591 return;
592 for (const auto& pair : timing_details)
593 client_->DidPresentCompositorFrame(pair.first, pair.second);
594 }
595
BeginFrame(const viz::BeginFrameArgs & args)596 void SynchronousLayerTreeFrameSink::BeginFrame(
597 const viz::BeginFrameArgs& args) {
598 if (external_begin_frame_source_)
599 external_begin_frame_source_->OnBeginFrame(args);
600 }
601
SetBeginFrameSourcePaused(bool paused)602 void SynchronousLayerTreeFrameSink::SetBeginFrameSourcePaused(bool paused) {
603 if (external_begin_frame_source_)
604 external_begin_frame_source_->OnSetBeginFrameSourcePaused(paused);
605 }
606
607 } // namespace blink
608