diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index fa1d073306c96..5f38d9e2f0414 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -135,7 +135,7 @@ RasterStatus CompositorContext::ScopedFrame::Raster( } if (needs_save_layer) { - FML_LOG(INFO) << "Using SaveLayer to protect non-readback surface"; + TRACE_EVENT0("flutter", "Canvas::saveLayer"); SkRect bounds = SkRect::Make(layer_tree.frame_size()); SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 4ca8ede34a71e..ca30baf2ac8cc 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -59,6 +59,7 @@ void ClipPathLayer::Paint(PaintContext& context) const { clip_behavior_ != Clip::hardEdge); if (UsesSaveLayer()) { + TRACE_EVENT0("flutter", "Canvas::saveLayer"); context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr); } PaintChildren(context); diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index 7adfa04285ed6..8504d41ed15b4 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -58,6 +58,7 @@ void ClipRectLayer::Paint(PaintContext& context) const { clip_behavior_ != Clip::hardEdge); if (UsesSaveLayer()) { + TRACE_EVENT0("flutter", "Canvas::saveLayer"); context.internal_nodes_canvas->saveLayer(clip_rect_, nullptr); } PaintChildren(context); diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 8446075dc1e58..511b3da5526da 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -59,6 +59,7 @@ void ClipRRectLayer::Paint(PaintContext& context) const { clip_behavior_ != Clip::hardEdge); if (UsesSaveLayer()) { + TRACE_EVENT0("flutter", "Canvas::saveLayer"); context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr); } PaintChildren(context); diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index b1674e1a74c9b..d443448ed97e6 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -97,10 +97,11 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { case Clip::antiAlias: context.internal_nodes_canvas->clipPath(path_, true); break; - case Clip::antiAliasWithSaveLayer: + case Clip::antiAliasWithSaveLayer: { + TRACE_EVENT0("flutter", "Canvas::saveLayer"); context.internal_nodes_canvas->clipPath(path_, true); context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr); - break; + } break; case Clip::none: break; } diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 66c1bcdd2ba1b..14270e994137f 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -105,6 +105,7 @@ void Canvas::saveLayerWithoutBounds(const Paint& paint, if (!canvas_) { return; } + TRACE_EVENT0("flutter", "Canvas::saveLayer"); canvas_->saveLayer(nullptr, paint.paint()); } @@ -117,6 +118,7 @@ void Canvas::saveLayer(double left, if (!canvas_) { return; } + TRACE_EVENT0("flutter", "Canvas::saveLayer"); SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); canvas_->saveLayer(&bounds, paint.paint()); } diff --git a/testing/dart/observatory/BUILD.gn b/testing/dart/observatory/BUILD.gn index ea5d285e0fd2c..e2acc5af47800 100644 --- a/testing/dart/observatory/BUILD.gn +++ b/testing/dart/observatory/BUILD.gn @@ -4,7 +4,10 @@ import("//flutter/testing/dart/compile_test.gni") -tests = [ "skp_test.dart" ] +tests = [ + "skp_test.dart", + "tracing_test.dart", +] foreach(test, tests) { compile_flutter_dart_test("compile_$test") { diff --git a/testing/dart/observatory/tracing_test.dart b/testing/dart/observatory/tracing_test.dart new file mode 100644 index 0000000000000..50274db5bcfa8 --- /dev/null +++ b/testing/dart/observatory/tracing_test.dart @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:developer' as developer; +import 'dart:ui'; + +import 'package:litetest/litetest.dart'; +import 'package:vm_service/vm_service.dart' as vms; +import 'package:vm_service/vm_service_io.dart'; + +void main() { + test('Canvas.saveLayer emits tracing', () async { + final developer.ServiceProtocolInfo info = await developer.Service.getInfo(); + + if (info.serverUri == null) { + fail('This test must not be run with --disable-observatory.'); + } + + final vms.VmService vmService = await vmServiceConnectUri( + 'ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws', + ); + + final Completer completer = Completer(); + window.onBeginFrame = (Duration timeStamp) { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.saveLayer(null, Paint()); + canvas.saveLayer(const Rect.fromLTWH(0, 0, 100, 100), Paint()); + canvas.drawRect(const Rect.fromLTRB(10, 10, 20, 20), Paint()); + canvas.restore(); + canvas.restore(); + final Picture picture = recorder.endRecording(); + + final SceneBuilder builder = SceneBuilder(); + builder.addPicture(Offset.zero, picture); + final Scene scene = builder.build(); + + window.render(scene); + scene.dispose(); + completer.complete(); + }; + window.scheduleFrame(); + await completer.future; + + final vms.Timeline timeline = await vmService.getVMTimeline(); + await vmService.dispose(); + + int saveLayerCount = 0; + for (final vms.TimelineEvent event in timeline.traceEvents!) { + final Map json = event.json!; + if (json['name'] == 'Canvas::saveLayer' && json['ph'] == 'B') { + saveLayerCount += 1; + } + } + expect(saveLayerCount, 2); + }); +}