
This benchmark will track the performance of the RTree implementation to cull very large pictures down to just the portion visible on the screen.
241 lines
7.0 KiB
Dart
241 lines
7.0 KiB
Dart
// Copyright 2014 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:math';
|
|
import 'dart:typed_data';
|
|
import 'dart:ui';
|
|
import 'package:flutter/material.dart';
|
|
|
|
// Adapted from test case submitted in
|
|
// https://github.com/flutter/flutter/issues/92366
|
|
// Converted to use fixed data rather than reading a waveform file
|
|
class VeryLongPictureScrollingPerf extends StatefulWidget {
|
|
const VeryLongPictureScrollingPerf({super.key});
|
|
|
|
@override
|
|
State createState() => VeryLongPictureScrollingPerfState();
|
|
}
|
|
|
|
class VeryLongPictureScrollingPerfState extends State<VeryLongPictureScrollingPerf> {
|
|
bool consolidate = false;
|
|
bool useList = false;
|
|
Int16List waveData = loadGraph();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
actions: <Widget>[
|
|
Row(
|
|
children: <Widget>[
|
|
const Text('list:'),
|
|
Checkbox(value: useList, onChanged: (bool? value) => setState(() {
|
|
useList = value!;
|
|
}),),
|
|
],
|
|
),
|
|
Row(
|
|
children: <Widget>[
|
|
const Text('consolidate:'),
|
|
Checkbox(value: consolidate, onChanged: (bool? value) => setState(() {
|
|
consolidate = value!;
|
|
}),),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
backgroundColor: Colors.transparent,
|
|
body: SizedBox(
|
|
width: MediaQuery.of(context).size.width,
|
|
height: MediaQuery.of(context).size.height,
|
|
child: useList
|
|
? ListView.builder(
|
|
key: const ValueKey<String>('vlp_list_view_scrollable'),
|
|
scrollDirection: Axis.horizontal,
|
|
clipBehavior: Clip.none,
|
|
itemCount: (waveData.length / 200).ceil(),
|
|
itemExtent: 100,
|
|
itemBuilder: (BuildContext context, int index) => CustomPaint(
|
|
painter: PaintSomeTest(
|
|
waveData: waveData,
|
|
from: index * 200,
|
|
to: min((index + 1) * 200, waveData.length - 1),
|
|
)
|
|
),
|
|
)
|
|
: SingleChildScrollView(
|
|
key: const ValueKey<String>('vlp_single_child_scrollable'),
|
|
scrollDirection: Axis.horizontal,
|
|
child: SizedBox(
|
|
width: MediaQuery.of(context).size.width * 20,
|
|
height: MediaQuery.of(context).size.height,
|
|
child: RepaintBoundary(
|
|
child: CustomPaint(
|
|
isComplex: true,
|
|
painter: PaintTest(
|
|
consolidate: consolidate,
|
|
waveData: waveData,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class PaintTest extends CustomPainter {
|
|
const PaintTest({
|
|
required this.consolidate,
|
|
required this.waveData,
|
|
});
|
|
|
|
final bool consolidate;
|
|
final Int16List waveData;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final double height = size.height;
|
|
double x = 0;
|
|
const double strokeSize = .5;
|
|
const double zoomFactor = .5;
|
|
|
|
final Paint paintPos = Paint()
|
|
..color = Colors.pink
|
|
..strokeWidth = strokeSize
|
|
..isAntiAlias = false
|
|
..style = PaintingStyle.stroke;
|
|
|
|
final Paint paintNeg = Paint()
|
|
..color = Colors.pink
|
|
..strokeWidth = strokeSize
|
|
..isAntiAlias = false
|
|
..style = PaintingStyle.stroke;
|
|
|
|
final Paint paintZero = Paint()
|
|
..color = Colors.green
|
|
..strokeWidth = strokeSize
|
|
..isAntiAlias = false
|
|
..style = PaintingStyle.stroke;
|
|
|
|
int index = 0;
|
|
Paint? listPaint;
|
|
final Float32List offsets = Float32List(consolidate ? waveData.length * 4 : 4);
|
|
int used = 0;
|
|
for (index = 0; index < waveData.length; index++) {
|
|
Paint curPaint;
|
|
Offset p1;
|
|
if (waveData[index].isNegative) {
|
|
curPaint = paintPos;
|
|
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32768 * (height / 2));
|
|
} else if (waveData[index] == 0) {
|
|
curPaint = paintZero;
|
|
p1 = Offset(x, height * 1 / 2 + 1);
|
|
} else {
|
|
curPaint = (waveData[index] == 0) ? paintZero : paintNeg;
|
|
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32767 * (height / 2));
|
|
}
|
|
final Offset p0 = Offset(x, height * 1 / 2);
|
|
if (consolidate) {
|
|
if (listPaint != null && listPaint != curPaint) {
|
|
canvas.drawRawPoints(PointMode.lines, offsets.sublist(0, used), listPaint);
|
|
used = 0;
|
|
}
|
|
listPaint = curPaint;
|
|
offsets[used++] = p0.dx;
|
|
offsets[used++] = p0.dy;
|
|
offsets[used++] = p1.dx;
|
|
offsets[used++] = p1.dy;
|
|
} else {
|
|
canvas.drawLine(p0, p1, curPaint);
|
|
}
|
|
x += zoomFactor;
|
|
}
|
|
if (consolidate && used > 0) {
|
|
canvas.drawRawPoints(PointMode.lines, offsets.sublist(0, used), listPaint!);
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(CustomPainter oldDelegate) {
|
|
return oldDelegate is! PaintTest ||
|
|
oldDelegate.consolidate != consolidate ||
|
|
oldDelegate.waveData != waveData;
|
|
}
|
|
}
|
|
|
|
class PaintSomeTest extends CustomPainter {
|
|
const PaintSomeTest({
|
|
required this.waveData,
|
|
int? from,
|
|
int? to,
|
|
}) : from = from ?? 0, to = to?? waveData.length;
|
|
|
|
final Int16List waveData;
|
|
final int from;
|
|
final int to;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final double height = size.height;
|
|
double x = 0;
|
|
const double strokeSize = .5;
|
|
const double zoomFactor = .5;
|
|
|
|
final Paint paintPos = Paint()
|
|
..color = Colors.pink
|
|
..strokeWidth = strokeSize
|
|
..isAntiAlias = false
|
|
..style = PaintingStyle.stroke;
|
|
|
|
final Paint paintNeg = Paint()
|
|
..color = Colors.pink
|
|
..strokeWidth = strokeSize
|
|
..isAntiAlias = false
|
|
..style = PaintingStyle.stroke;
|
|
|
|
final Paint paintZero = Paint()
|
|
..color = Colors.green
|
|
..strokeWidth = strokeSize
|
|
..isAntiAlias = false
|
|
..style = PaintingStyle.stroke;
|
|
|
|
for (int index = from; index <= to; index++) {
|
|
Paint curPaint;
|
|
Offset p1;
|
|
if (waveData[index].isNegative) {
|
|
curPaint = paintPos;
|
|
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32768 * (height / 2));
|
|
} else if (waveData[index] == 0) {
|
|
curPaint = paintZero;
|
|
p1 = Offset(x, height * 1 / 2 + 1);
|
|
} else {
|
|
curPaint = (waveData[index] == 0) ? paintZero : paintNeg;
|
|
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32767 * (height / 2));
|
|
}
|
|
final Offset p0 = Offset(x, height * 1 / 2);
|
|
canvas.drawLine(p0, p1, curPaint);
|
|
x += zoomFactor;
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(CustomPainter oldDelegate) {
|
|
return oldDelegate is! PaintSomeTest ||
|
|
oldDelegate.waveData != waveData ||
|
|
oldDelegate.from != from ||
|
|
oldDelegate.to != to;
|
|
}
|
|
}
|
|
|
|
Int16List loadGraph() {
|
|
final Int16List waveData = Int16List(350000);
|
|
final Random r = Random(0x42);
|
|
for (int i = 0; i < waveData.length; i++) {
|
|
waveData[i] = r.nextInt(32768) - 16384;
|
|
}
|
|
return waveData;
|
|
}
|