Unverified Commit adc8e159 authored by liyuqian's avatar liyuqian Committed by GitHub

Revert "Shader warm up (#27660)" (#28376)

This reverts commit a44f174e.

Reason: start_up tests become flaky.

See https://github.com/flutter/flutter/issues/28374

TBR: xster

Merge on red to fix the tree
parent a44f174e
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const String kCullOpacityRouteName = '/cull_opacity'; const String kCullOpacityRouteName = '/cull_opacity';
const String kCubicBezierRouteName = '/cubic_bezier';
// Copyright 2015 The Chromium 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 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'common.dart'; import 'common.dart';
import 'src/cubic_bezier.dart';
import 'src/cull_opacity.dart'; import 'src/cull_opacity.dart';
const String kMacrobenchmarks ='Macrobenchmarks'; const String kMacrobenchmarks ='Macrobenchmarks';
...@@ -21,7 +16,6 @@ class MacrobenchmarksApp extends StatelessWidget { ...@@ -21,7 +16,6 @@ class MacrobenchmarksApp extends StatelessWidget {
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'/': (BuildContext context) => HomePage(), '/': (BuildContext context) => HomePage(),
kCullOpacityRouteName: (BuildContext context) => CullOpacityPage(), kCullOpacityRouteName: (BuildContext context) => CullOpacityPage(),
kCubicBezierRouteName: (BuildContext context) => CubicBezierPage(),
}, },
); );
} }
...@@ -40,13 +34,6 @@ class HomePage extends StatelessWidget { ...@@ -40,13 +34,6 @@ class HomePage extends StatelessWidget {
onPressed: (){ onPressed: (){
Navigator.pushNamed(context, kCullOpacityRouteName); Navigator.pushNamed(context, kCullOpacityRouteName);
}, },
),
RaisedButton(
key: const Key(kCubicBezierRouteName),
child: const Text('Cubic Bezier'),
onPressed: (){
Navigator.pushNamed(context, kCubicBezierRouteName);
},
) )
], ],
), ),
......
// Copyright 2018 The Chromium 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:ui';
import 'package:flutter_driver/driver_extension.dart';
import 'package:flutter/painting.dart' show DefaultShaderWarmUp, PaintingBinding;
import 'package:macrobenchmarks/main.dart' as app;
class CubicBezierShaderWarmUp extends DefaultShaderWarmUp {
@override
void warmUpOnCanvas(Canvas canvas) {
super.warmUpOnCanvas(canvas);
// Warm up the cubic shaders used by CubicBezierPage.
//
// This tests that our custom shader warm up is working properly.
// Without this custom shader warm up, the worst frame time is about 115ms.
// With this, the worst frame time is about 70ms. (Data collected on a Moto
// G4 based on Flutter version 704814c67a874077710524d30412337884bf0254.
final Path path = Path();
path.moveTo(20.0, 20.0);
// This cubic path is based on
// https://skia.org/user/api/SkPath_Reference#SkPath_cubicTo
path.cubicTo(300.0, 80.0, -140.0, 90.0, 220.0, 10.0);
final Paint paint = Paint();
paint.isAntiAlias = true;
paint.strokeWidth = 18.0;
paint.style = PaintingStyle.stroke;
paint.strokeCap = StrokeCap.round;
canvas.drawPath(path, paint);
}
}
void main() {
PaintingBinding.shaderWarmUp = CubicBezierShaderWarmUp();
enableFlutterDriverExtension();
app.main();
}
// Copyright 2018 The Chromium 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 'package:macrobenchmarks/common.dart';
import 'util.dart';
void main() {
macroPerfTest('cubic_bezier_perf', kCubicBezierRouteName);
}
...@@ -2,15 +2,42 @@ ...@@ -2,15 +2,42 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:macrobenchmarks/common.dart'; import 'dart:async';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
import 'util.dart'; import 'package:macrobenchmarks/common.dart';
void main() { void main() {
macroPerfTest( const String kName = 'cull_opacity_perf';
'cull_opacity_perf',
kCullOpacityRouteName, test(kName, () async {
pageDelay: const Duration(seconds: 1), final FlutterDriver driver = await FlutterDriver.connect();
duration: const Duration(seconds: 10)
); // The slight initial delay avoids starting the timing during a
// period of increased load on the device. Without this delay, the
// benchmark has greater noise.
// See: https://github.com/flutter/flutter/issues/19434
await Future<void>.delayed(const Duration(milliseconds: 250));
await driver.forceGC();
final SerializableFinder button = find.byValueKey(kCullOpacityRouteName);
expect(button, isNotNull);
await driver.tap(button);
// Wait for the page to load
await Future<void>.delayed(const Duration(seconds: 1));
final Timeline timeline = await driver.traceAction(() async {
await Future<void>.delayed(const Duration(seconds: 10));
});
final TimelineSummary summary = TimelineSummary.summarize(timeline);
summary.writeSummaryToFile(kName, pretty: true);
summary.writeTimelineToFile(kName, pretty: true);
driver.close();
});
} }
// Copyright 2015 The Chromium 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 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void macroPerfTest(
String testName,
String routeName,
{Duration pageDelay, Duration duration = const Duration(seconds: 3)}) {
test(testName, () async {
final FlutterDriver driver = await FlutterDriver.connect();
// The slight initial delay avoids starting the timing during a
// period of increased load on the device. Without this delay, the
// benchmark has greater noise.
// See: https://github.com/flutter/flutter/issues/19434
await Future<void>.delayed(const Duration(milliseconds: 250));
await driver.forceGC();
final SerializableFinder button = find.byValueKey(routeName);
expect(button, isNotNull);
await driver.tap(button);
if (pageDelay != null) {
// Wait for the page to load
await Future<void>.delayed(pageDelay);
}
final Timeline timeline = await driver.traceAction(() async {
await Future<void>.delayed(duration);
});
final TimelineSummary summary = TimelineSummary.summarize(timeline);
summary.writeSummaryToFile(testName, pretty: true);
summary.writeTimelineToFile(testName, pretty: true);
driver.close();
});
}
// Copyright 2018 The Chromium 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 'package:flutter_devicelab/tasks/perf_tests.dart';
import 'package:flutter_devicelab/framework/adb.dart';
import 'package:flutter_devicelab/framework/framework.dart';
Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.android;
await task(createCubicBezierPerfTest());
}
...@@ -46,14 +46,6 @@ TaskFunction createCullOpacityPerfTest() { ...@@ -46,14 +46,6 @@ TaskFunction createCullOpacityPerfTest() {
).run; ).run;
} }
TaskFunction createCubicBezierPerfTest() {
return PerfTest(
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
'test_driver/cubic_bezier_perf.dart',
'cubic_bezier_perf',
).run;
}
TaskFunction createFlutterGalleryStartupTest() { TaskFunction createFlutterGalleryStartupTest() {
return StartupTest( return StartupTest(
'${flutterDirectory.path}/examples/flutter_gallery', '${flutterDirectory.path}/examples/flutter_gallery',
......
...@@ -134,13 +134,6 @@ tasks: ...@@ -134,13 +134,6 @@ tasks:
stage: devicelab stage: devicelab
required_agent_capabilities: ["mac/android"] required_agent_capabilities: ["mac/android"]
cubic_bezier_perf__timeline_summary:
description: >
Measures the runtime performance of cubic bezier animations on Android.
stage: devicelab
required_agent_capabilities: ["mac/android"]
flaky: true
flavors_test: flavors_test:
description: > description: >
Checks that flavored builds work on Android. Checks that flavored builds work on Android.
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This example shows the draw operations to warm up the GPU shaders by default.
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart' show DefaultShaderWarmUp;
void beginFrame(Duration timeStamp) {
// PAINT
final ui.PictureRecorder recorder = ui.PictureRecorder();
final ui.Rect paintBounds = ui.Rect.fromLTRB(0, 0, 1000, 1000);
final ui.Canvas canvas = ui.Canvas(recorder, paintBounds);
final ui.Paint backgroundPaint = ui.Paint()..color = Colors.white;
canvas.drawRect(paintBounds, backgroundPaint);
const DefaultShaderWarmUp().warmUpOnCanvas(canvas);
final ui.Picture picture = recorder.endRecording();
// COMPOSITE
final ui.SceneBuilder sceneBuilder = ui.SceneBuilder()
..pushClipRect(paintBounds)
..addPicture(ui.Offset.zero, picture)
..pop();
ui.window.render(sceneBuilder.build());
}
void main() {
ui.window.onBeginFrame = beginFrame;
ui.window.scheduleFrame();
}
// Copyright 2017 The Chromium 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 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf;
import '../../../raw/shader_warm_up.dart' as demo;
void main() {
test('layers smoketest for raw/shader_warm_up.dart', () {
demo.main();
});
}
...@@ -50,7 +50,6 @@ export 'src/painting/matrix_utils.dart'; ...@@ -50,7 +50,6 @@ export 'src/painting/matrix_utils.dart';
export 'src/painting/notched_shapes.dart'; export 'src/painting/notched_shapes.dart';
export 'src/painting/paint_utilities.dart'; export 'src/painting/paint_utilities.dart';
export 'src/painting/rounded_rectangle_border.dart'; export 'src/painting/rounded_rectangle_border.dart';
export 'src/painting/shader_warm_up.dart';
export 'src/painting/shape_decoration.dart'; export 'src/painting/shape_decoration.dart';
export 'src/painting/stadium_border.dart'; export 'src/painting/stadium_border.dart';
export 'src/painting/strut_style.dart'; export 'src/painting/strut_style.dart';
......
...@@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; ...@@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart' show ServicesBinding; import 'package:flutter/services.dart' show ServicesBinding;
import 'image_cache.dart'; import 'image_cache.dart';
import 'shader_warm_up.dart';
const double _kDefaultDecodedCacheRatioCap = 0.0; const double _kDefaultDecodedCacheRatioCap = 0.0;
...@@ -23,34 +22,12 @@ mixin PaintingBinding on BindingBase, ServicesBinding { ...@@ -23,34 +22,12 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
super.initInstances(); super.initInstances();
_instance = this; _instance = this;
_imageCache = createImageCache(); _imageCache = createImageCache();
if (shaderWarmUp != null) {
shaderWarmUp.execute();
}
} }
/// The current [PaintingBinding], if one has been created. /// The current [PaintingBinding], if one has been created.
static PaintingBinding get instance => _instance; static PaintingBinding get instance => _instance;
static PaintingBinding _instance; static PaintingBinding _instance;
/// [ShaderWarmUp] to be executed during [initInstances].
///
/// If the application has scenes that require the compilation of complex
/// shaders that are not covered by [DefaultShaderWarmUp], it may cause jank
/// in the middle of an animation or interaction. In that case, set
/// [shaderWarmUp] to a custom [ShaderWarmUp] before calling [initInstances]
/// (usually before [runApp] for normal flutter apps, and before
/// [enableFlutterDriverExtension] for flutter drive tests). Paint the scene
/// in the custom [ShaderWarmUp] so Flutter can pre-compile and cache the
/// shaders during startup. The warm up is only costly (100ms-200ms,
/// depending on the shaders to compile) during the first run after the
/// installation or a data wipe. The warm up does not block the main thread
/// so there should be no "Application Not Responding" warning.
///
/// Currently the warm-up happens synchronously on the GPU thread which means
/// the rendering of the first frame on the GPU thread will be postponed until
/// the warm-up is finished.
static ShaderWarmUp shaderWarmUp = const DefaultShaderWarmUp();
/// The singleton that implements the Flutter framework's image cache. /// The singleton that implements the Flutter framework's image cache.
/// ///
/// The cache is used internally by [ImageProvider] and should generally not /// The cache is used internally by [ImageProvider] and should generally not
......
// Copyright 2015 The Chromium 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:developer';
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
/// Interface for drawing an image to warm up Skia shader compilations.
///
/// When Skia first sees a certain type of draw operations on GPU, it needs to
/// compile the corresponding shader. The compilation can be slow (20ms-200ms).
/// Having that time as a startup latency is often better than having a jank in
/// the middle of an animation.
///
/// Therefore, we use this during the [PaintingBinding.initInstances] call to
/// move common shader compilations from animation time to startup time. By
/// default, a [DefaultShaderWarmUp] is used. Create a custom [ShaderWarmUp]
/// subclass to replace [PaintingBinding.shaderWarmUp] before
/// [PaintingBinding.initInstances] is called. Usually, that can be done before
/// calling [runApp].
///
/// This warm up needs to be run on each individual device because the shader
/// compilation depends on the specific GPU hardware and driver a device has. It
/// can't be pre-computed during the Flutter engine compilation as the engine is
/// device agnostic.
///
/// If no warm up is desired (e.g., when the startup latency is crucial), set
/// [PaintingBinding.shaderWarmUp] either to a custom ShaderWarmUp with an empty
/// [warmUpOnCanvas] or null.
abstract class ShaderWarmUp {
/// Allow const constructors for subclasses.
const ShaderWarmUp();
/// The size of the warm up image.
///
/// The exact size shouldn't matter much as long as it's not too far away from
/// the target device's screen. 1024x1024 is a good choice as it is within an
/// order of magnitude of most devices.
///
/// A custom shader warm up can override this based on targeted devices.
ui.Size get size => const ui.Size(1024.0, 1024.0);
/// Trigger draw operations on a given canvas to warm up GPU shader
/// compilation cache.
///
/// To decide which draw operations to be added to your custom warm up
/// process, try capture an skp using `flutter screenshot --observatory-
/// port=<port> --type=skia` and analyze it with https://debugger.skia.org.
/// Alternatively, one may run the app with `flutter run --trace-skia` and
/// then examine the GPU thread in the observatory timeline to see which
/// Skia draw operations are commonly used, and which shader compilations
/// are causing janks.
@protected
void warmUpOnCanvas(ui.Canvas canvas);
/// Construct an offscreen image of [size], and execute [warmUpOnCanvas] on a
/// canvas associated with that image.
void execute() {
final ui.PictureRecorder recorder = ui.PictureRecorder();
final ui.Canvas canvas = ui.Canvas(recorder);
warmUpOnCanvas(canvas);
final ui.Picture picture = recorder.endRecording();
final TimelineTask shaderWarmUpTask = TimelineTask();
shaderWarmUpTask.start('Warm-up shader');
picture.toImage(size.width.ceil(), size.height.ceil()).then((ui.Image image) {
shaderWarmUpTask.finish();
});
}
}
/// Default way of warming up Skia shader compilations.
///
/// The draw operations being warmed up here are decided according to Flutter
/// engineers' observation and experience based on the apps and the performance
/// issues seen so far.
class DefaultShaderWarmUp extends ShaderWarmUp {
/// Allow [DefaultShaderWarmUp] to be used as the default value of parameters.
const DefaultShaderWarmUp();
/// Trigger common draw operations on a canvas to warm up GPU shader
/// compilation cache.
@override
void warmUpOnCanvas(ui.Canvas canvas) {
final ui.RRect rrect = ui.RRect.fromLTRBXY(20.0, 20.0, 60.0, 60.0, 10.0, 10.0);
final ui.Path rrectPath = ui.Path()..addRRect(rrect);
final ui.Path circlePath = ui.Path()..addOval(
ui.Rect.fromCircle(center: const ui.Offset(40.0, 40.0), radius: 20.0)
);
// The following path is based on
// https://skia.org/user/api/SkCanvas_Reference#SkCanvas_drawPath
final ui.Path path = ui.Path();
path.moveTo(20.0, 60.0);
path.quadraticBezierTo(60.0, 20.0, 60.0, 60.0);
path.close();
path.moveTo(60.0, 20.0);
path.quadraticBezierTo(60.0, 60.0, 20.0, 60.0);
final List<ui.Path> paths = <ui.Path>[rrectPath, circlePath, path];
final List<ui.Paint> paints = <ui.Paint>[
ui.Paint()
..isAntiAlias = true
..style = ui.PaintingStyle.fill,
ui.Paint()
..isAntiAlias = true
..style = ui.PaintingStyle.stroke
..strokeWidth = 10,
ui.Paint()
..isAntiAlias = true
..style = ui.PaintingStyle.stroke
..strokeWidth = 0.1 // hairline
];
// Warm up path stroke and fill shaders.
for (int i = 0; i < paths.length; i += 1) {
canvas.save();
for (ui.Paint paint in paints) {
canvas.drawPath(paths[i], paint);
canvas.translate(80.0, 0.0);
}
canvas.restore();
canvas.translate(0.0, 80.0);
}
// Warm up shadow shaders.
const ui.Color black = ui.Color(0xFF000000);
canvas.save();
canvas.drawShadow(rrectPath, black, 10.0, true);
canvas.translate(80.0, 0.0);
canvas.drawShadow(rrectPath, black, 10.0, false);
canvas.restore();
// Warm up text shaders.
canvas.translate(0.0, 80.0);
final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(
ui.ParagraphStyle(textDirection: ui.TextDirection.ltr),
)..pushStyle(ui.TextStyle(color: black))..addText('_');
final ui.Paragraph paragraph = paragraphBuilder.build()
..layout(const ui.ParagraphConstraints(width: 60.0));
canvas.drawParagraph(paragraph, const ui.Offset(20.0, 20.0));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment