Skip to content

[Android] Severe jank with custom paint #92366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sidetraxaudio opened this issue Oct 23, 2021 · 21 comments
Closed

[Android] Severe jank with custom paint #92366

sidetraxaudio opened this issue Oct 23, 2021 · 21 comments
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) c: regression It was better in the past than it is now dependency: skia Skia team may need to help us engine flutter/engine repository. See also e: labels. found in release: 2.6 Found to occur in 2.6 has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list perf: speed Performance issues related to (mostly rendering) speed platform-android Android applications specifically r: duplicate Issue is closed as a duplicate of an existing issue

Comments

@sidetraxaudio
Copy link

sidetraxaudio commented Oct 23, 2021

2 VIDEO FILES ATTACHED:
1x no jank w/2.6.0-5.2.pre and below
1x bad jank w/2.7.0-3.0pre

beta 2.6.0-5.2.pre and BELOW works perfect
beta 2.7.0-3.0.pre and ABOVE creates massive jank : custompaint in any kind of scrollview. Unsure if its a custompaint issue, scrollview issue or optimisation issue.
-confirmed 2 physical devices w/8 and 12gb ram

Int16List (pcm audio) int values are being thinned and custom-painted as an audio waveform inside horizontal singlechildscrollview. Prior to latest beta performance was exceptional. After latest beta (and including master ch releases) something is broken and screen redraws are as if they're not cached/rasterised at all irrespective of custompaint settings and are drawing on the fly???.

  1. ...
    -Find a wave file to dump in assets
    (suspect a complex paint object will suffice)
    -Implement attached code.
    -Switch between any release ABOVE 2.6.0-5.2.pre to see massive jank or BELOW (and including) to see perfect operation

  2. ...
    -Scroll left or right to see massive jank above 2.6.0-5.2.pre
    -Even scroll to the scrollview bounds and see jank on overscroll glow

Expected results:
-Smooth scrolling/rasterising/screen update as per prior release

Actual results:
-Massive jank

Please see attached video files.

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: FutureBuilder(
        future: loadGraph(),
        builder: (context, AsyncSnapshot<Int16List> waveData) {
          return (!waveData.hasData)
              ? const CircularProgressIndicator.adaptive()
              : SizedBox(
                  width: MediaQuery.of(context).size.width,
                  height: MediaQuery.of(context).size.height,
                  child: SingleChildScrollView(
                    scrollDirection: Axis.horizontal,
                    child: SizedBox(
                      width: MediaQuery.of(context).size.width * 20,
                      height: MediaQuery.of(context).size.height,
                      child: RepaintBoundary(
                        child: CustomPaint(
                          willChange: false,
                          isComplex: true,
                          painter: PaintTest(
                            waveData: waveData.data!,
                          ),
                        ),
                      ),
                    ),
                  ),
                );
        },
      ),
    );
  }
}

class PaintTest extends CustomPainter {
  final Int16List waveData;

  const PaintTest({
    required this.waveData,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final _height = size.height;
    double x = 0;
    double strokeSize = .5;
    const 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;
    for (index = 0; index < waveData.length; index++) {
      if (waveData[index].isNegative) {
        canvas.drawLine(Offset(x, _height * 1 / 2), Offset(x, _height * 1 / 2 - waveData[index] / 32768 * (_height / 2)), paintPos);
        x += zoomFactor;
      } else {
        (waveData[index] == 0)
            ? canvas.drawLine(Offset(x, _height * 1 / 2), Offset(x, _height * 1 / 2 + 1), paintZero)
            : canvas.drawLine(Offset(x, _height * 1 / 2), Offset(x, _height * 1 / 2 - waveData[index] / 32767 * (_height / 2)), paintNeg);
        x += zoomFactor;
      }
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

Future<Int16List> loadGraph() async {
  //*_____________________________________________
  //! LOAD ANY WAVE FILE - THIS IS 16bit 44.1 MONO
  //*_____________________________________________
  Int16List load16bitMonoWave = await rootBundle.load('assets/rawalice.raw').then((value) => value.buffer.asInt16List());
  //! THIN WAVE FILE TO 1/20
  Int16List waveDataThinned = Int16List((load16bitMonoWave.length * 1 / 20).round());
  int reducedIndex = 0;
  for (int index = 0; index + 20 < load16bitMonoWave.length; index += 20) {
    waveDataThinned[reducedIndex] = load16bitMonoWave[index];
    reducedIndex++;
  }
  return waveDataThinned;
}
Logs
[  +47 ms] executing: [c:\flutter/] git -c log.showSignature=false log -n 1 --pretty=format:%H
[ +171 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H
[   +1 ms] c19845a8c347adebc2c672f5e51b74855e645be2
[        ] executing: [c:\flutter/] git tag --points-at c19845a8c347adebc2c672f5e51b74855e645be2
[  +24 ms] Exit code 0 from: git tag --points-at c19845a8c347adebc2c672f5e51b74855e645be2
[        ] 2.7.0-3.0.pre
[   +6 ms] executing: [c:\flutter/] git rev-parse --abbrev-ref --symbolic @{u}
[  +18 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{u}
[        ] origin/beta
[        ] executing: [c:\flutter/] git ls-remote --get-url origin
[  +16 ms] Exit code 0 from: git ls-remote --get-url origin
[        ] https://github.com/flutter/flutter.git
[  +68 ms] executing: [c:\flutter/] git rev-parse --abbrev-ref HEAD
[  +18 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
[        ] beta
[  +49 ms] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[   +2 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'WindowsUwpEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[  +40 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe devices -l
[  +35 ms] List of devices attached
           192.168.0.38:5555      device product:CPH1979 model:CPH1979 device:OP48A1 transport_id:1      
[   +5 ms] C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555 shell
getprop
[  +64 ms] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[   +3 ms] Artifact Instance of 'WindowsUwpEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[  +60 ms] Skipping pub get: version match.
[  +77 ms] Generating C:\Users\mark\OneDrive\Desktop\SS
Development\janktest\android\app\src\main\java\io\flutter\plugins\GeneratedPluginRegistrant.java
[  +43 ms] ro.hardware = mt6779
[        ] ro.build.characteristics = default
[  +25 ms] Initializing file store
[   +7 ms] Skipping target: gen_localizations
[   +4 ms] gen_dart_plugin_registrant: Starting due to {InvalidatedReasonKind.inputChanged: The following
inputs have updated contents: C:\Users\mark\OneDrive\Desktop\SS
Development\janktest\.dart_tool\package_config_subset}
[  +16 ms] gen_dart_plugin_registrant: Complete
[   +1 ms] Skipping target: _composite
[   +1 ms] complete
[   +4 ms] Launching lib\main.dart on CPH1979 in debug mode...
[   +3 ms] c:\flutter\bin\cache\dart-sdk\bin\dart.exe --disable-dart-dev
c:\flutter\bin\cache\artifacts\engine\windows-x64\frontend_server.dart.snapshot --sdk-root
c:\flutter\bin\cache\artifacts\engine\common\flutter_patched_sdk/ --incremental --target=flutter
--debugger-module-names --experimental-emit-debug-metadata -DFLUTTER_WEB_AUTO_DETECT=true --output-dill  
C:\Users\mark\AppData\Local\Temp\flutter_tools.dd32c6e6\flutter_tool.a597404c\app.dill --packages        
C:\Users\mark\OneDrive\Desktop\SS Development\janktest\.dart_tool\package_config.json
-Ddart.vm.profile=false -Ddart.vm.product=false --enable-asserts --track-widget-creation
--filesystem-scheme org-dartlang-root --initialize-from-dill
build\c075001b96339384a97db4862b8ab8db.cache.dill.track.dill
--enable-experiment=alternative-invalidation-strategy
[   +6 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\build-tools\31.0.0\aapt dump xmltree       
C:\Users\mark\OneDrive\Desktop\SS Development\janktest\build\app\outputs\flutter-apk\app.apk
AndroidManifest.xml
[   +7 ms] Exit code 0 from: C:\Users\mark\AppData\Local\Android\sdk\build-tools\31.0.0\aapt dump xmltree
C:\Users\mark\OneDrive\Desktop\SS Development\janktest\build\app\outputs\flutter-apk\app.apk
AndroidManifest.xml
[        ] N: android=http://schemas.android.com/apk/res/android
             E: manifest (line=2)
               A: android:versionCode(0x0101021b)=(type 0x10)0x1
               A: android:versionName(0x0101021c)="1.0.0" (Raw: "1.0.0")
               A: android:compileSdkVersion(0x01010572)=(type 0x10)0x1e
               A: android:compileSdkVersionCodename(0x01010573)="11" (Raw: "11")
               A: package="com.example.janktest" (Raw: "com.example.janktest")
               A: platformBuildVersionCode=(type 0x10)0x1e
               A: platformBuildVersionName=(type 0x10)0xb
               E: uses-sdk (line=7)
                 A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
                 A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1e
               E: uses-permission (line=14)
                 A: android:name(0x01010003)="android.permission.INTERNET" (Raw:
                 "android.permission.INTERNET")
               E: application (line=16)
                 A: android:label(0x01010001)="janktest" (Raw: "janktest")
                 A: android:icon(0x01010002)=@0x7f080000
                 A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
                 A: android:appComponentFactory(0x0101057a)="androidx.core.app.CoreComponentFactory"     
                 (Raw: "androidx.core.app.CoreComponentFactory")
                 E: activity (line=21)
                   A: android:theme(0x01010000)=@0x7f0a0000
                   A: android:name(0x01010003)="com.example.janktest.MainActivity" (Raw:
                   "com.example.janktest.MainActivity")
                   A: android:launchMode(0x0101001d)=(type 0x10)0x1
                   A: android:configChanges(0x0101001f)=(type 0x11)0x40003fb4
                   A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
                   A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
                   E: meta-data (line=35)
                     A: android:name(0x01010003)="io.flutter.embedding.android.NormalTheme" (Raw:        
                     "io.flutter.embedding.android.NormalTheme")
                     A: android:resource(0x01010025)=@0x7f0a0001
                   E: intent-filter (line=39)
                     E: action (line=40)
                       A: android:name(0x01010003)="android.intent.action.MAIN" (Raw:
                       "android.intent.action.MAIN")
                     E: category (line=42)
                       A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw:
                       "android.intent.category.LAUNCHER")
                 E: meta-data (line=49)
                   A: android:name(0x01010003)="flutterEmbedding" (Raw: "flutterEmbedding")
                   A: android:value(0x01010024)=(type 0x10)0x2
[   +8 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555
shell -x logcat -v time -t 1
[  +10 ms] <- compile package:janktest/main.dart
[ +292 ms] --------- beginning of main
                    10-24 08:17:10.264 E/android.system.suspend@1.0-service(  512): updateSleepTime      
                    mSleepTime=200: Device or resource busy
[   +7 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe version
[  +10 ms] Android Debug Bridge version 1.0.41
           Version 31.0.3-7562133
           Installed as C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe
[   +1 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe start-server        
[  +11 ms] Building APK
[  +11 ms] Running Gradle task 'assembleDebug'...
[   +3 ms] Using gradle from C:\Users\mark\OneDrive\Desktop\SS Development\janktest\android\gradlew.bat. 
[   +3 ms] executing: C:\Program Files\Android\Android Studio\jre\bin\java -version
[  +99 ms] Exit code 0 from: C:\Program Files\Android\Android Studio\jre\bin\java -version
[        ] openjdk version "11.0.10" 2021-01-19
           OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
           OpenJDK 64-Bit Server VM (build 11.0.10+0-b96-7249189, mixed mode)
[   +1 ms] executing: [C:\Users\mark\OneDrive\Desktop\SS Development\janktest\android/]
C:\Users\mark\OneDrive\Desktop\SS Development\janktest\android\gradlew.bat -Pverbose=true
-Ptarget-platform=android-arm64 -Ptarget=C:\Users\mark\OneDrive\Desktop\SS
Development\janktest\lib\main.dart -Pdart-defines=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==
-Pdart-obfuscation=false -Ptrack-widget-creation=true -Ptree-shake-icons=false
-Pfilesystem-scheme=org-dartlang-root assembleDebug
[ +773 ms] Warning: Mapping new ns http://schemas.android.com/repository/android/common/02 to old ns
http://schemas.android.com/repository/android/common/01
[   +1 ms] Warning: Mapping new ns http://schemas.android.com/repository/android/generic/02 to old ns
http://schemas.android.com/repository/android/generic/01
[        ] Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/addon2/02 to old ns       
http://schemas.android.com/sdk/android/repo/addon2/01
[        ] Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/repository2/02 to old ns  
http://schemas.android.com/sdk/android/repo/repository2/01
[        ] Warning: Mapping new ns http://schemas.android.com/sdk/android/repo/sys-img2/02 to old ns     
http://schemas.android.com/sdk/android/repo/sys-img2/01
[+1994 ms] > Task :app:compileFlutterBuildDebug
[        ] [  +45 ms] executing: [c:\flutter/] git -c log.showSignature=false log -n 1 --pretty=format:%H
[        ] [ +174 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H       
[        ] [        ] c19845a8c347adebc2c672f5e51b74855e645be2
[        ] [        ] executing: [c:\flutter/] git tag --points-at
c19845a8c347adebc2c672f5e51b74855e645be2
[        ] [  +25 ms] Exit code 0 from: git tag --points-at c19845a8c347adebc2c672f5e51b74855e645be2     
[        ] [        ] 2.7.0-3.0.pre
[        ] [   +6 ms] executing: [c:\flutter/] git rev-parse --abbrev-ref --symbolic @{u}
[        ] [  +18 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{u}
[        ] [        ] origin/beta
[        ] [        ] executing: [c:\flutter/] git ls-remote --get-url origin
[        ] [  +15 ms] Exit code 0 from: git ls-remote --get-url origin
[        ] [        ] https://github.com/flutter/flutter.git
[        ] [  +38 ms] executing: [c:\flutter/] git rev-parse --abbrev-ref HEAD
[        ] [  +18 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
[        ] [        ] beta
[        ] [  +39 ms] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping       
update.
[        ] [        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping     
update.
[        ] [        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.        
[        ] [        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[        ] [   +2 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.    
[        ] [        ] Artifact Instance of 'WindowsUwpEngineArtifacts' is not required, skipping update. 
[        ] [        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.      
[        ] [        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.      
[        ] [        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.  
[        ] [        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.  
[        ] [        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update. 
[        ] [        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update. 
[        ] [  +68 ms] Artifact Instance of 'MaterialFonts' is not required, skipping update.
[        ] [        ] Artifact Instance of 'GradleWrapper' is not required, skipping update.
[        ] [   +2 ms] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping     
update.
[        ] [        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.        
[        ] [        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[        ] [        ] Artifact Instance of 'FlutterSdk' is not required, skipping update.
[        ] [        ] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.    
[        ] [        ] Artifact Instance of 'WindowsUwpEngineArtifacts' is not required, skipping update. 
[        ] [        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.      
[        ] [        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.      
[        ] [        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.  
[        ] [        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.  
[        ] [        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] [        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update. 
[        ] [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] [        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] [        ] Artifact Instance of 'FontSubsetArtifacts' is not required, skipping update.       
[        ] [        ] Artifact Instance of 'PubDependencies' is not required, skipping update.
[        ] [  +27 ms] Initializing file store
[        ] [  +15 ms] Skipping target: gen_localizations
[        ] [   +8 ms] gen_dart_plugin_registrant: Starting due to {InvalidatedReasonKind.inputChanged:   
The following inputs have updated contents: C:\Users\mark\OneDrive\Desktop\SS
Development\janktest\.dart_tool\package_config_subset}
[        ] [  +27 ms] gen_dart_plugin_registrant: Complete
[        ] [   +1 ms] kernel_snapshot: Starting due to {}
[        ] [   +8 ms] c:\flutter\bin\cache\dart-sdk\bin\dart.exe --disable-dart-dev
c:\flutter\bin\

https://user-images.githubusercontent.com/80554643/138573736-cea995fe-73c3-42a0-ace3-28afa952f2b8.MP4

cache\artifacts\engine\windows-x64\frontend_server.dart.snapshot --sdk-root
c:\flutter\bin\cache\artifacts\engine\common\flutter_patched_sdk/ --target=flutter
--no-print-incremental-dependencies -DFLUTTER_WEB_AUTO_DETECT=true -Ddart.vm.profile=false
-Ddart.vm.product=false --enable-asserts --track-widget-creation --no-link-platform --packages
C:\Users\mark\OneDrive\Desktop\SS Development\janktest\.dart_tool\package_config.json --output-dill      
C:\Users\mark\OneDrive\Desktop\SS
Development\janktest\.dart_tool\flutter_build\6f2d2252579d7f67f96a4aeb04bf2037\app.dill --depfile        
C:\Users\mark\OneDrive\Desktop\SS
Development\janktest\.dart_tool\flutter_build\6f2d2252579d7f67f96a4aeb04bf2037\kernel_snapshot.d
package:janktest/main.dart
[+4486 ms] [+5541 ms] kernel_snapshot: Complete
[ +293 ms] [ +336 ms] debug_android_application: Starting due to {}
[ +104 ms] [ +117 ms] Manifest contained wildcard assets. Inserting missing file into build graph to
force rerun. for more information see #56466.
[ +108 ms] [  +30 ms] debug_android_application: Complete
[ +496 ms] [ +523 ms] Persisting file store
[        ] [   +5 ms] Done persisting file store
[        ] [   +3 ms] build succeeded.
[        ] [   +8 ms] "flutter assemble" took 6,737ms.
[ +289 ms] [ +260 ms] ensureAnalyticsSent: 257ms
[        ] [        ] Running shutdown hooks
[        ] [        ] Shutdown hooks complete
[        ] [        ] exiting with code 0
[        ] Parameter format not correct -
[ +114 ms] > Task :app:packLibsflutterBuildDebug UP-TO-DATE
[        ] > Task :app:preBuild UP-TO-DATE
[        ] > Task :app:preDebugBuild UP-TO-DATE
[        ] > Task :app:compileDebugAidl NO-SOURCE
[        ] > Task :app:compileDebugRenderscript NO-SOURCE
[        ] > Task :app:generateDebugBuildConfig UP-TO-DATE
[        ] > Task :app:checkDebugAarMetadata UP-TO-DATE
[        ] > Task :app:cleanMergeDebugAssets
[        ] > Task :app:mergeDebugShaders UP-TO-DATE
[        ] > Task :app:compileDebugShaders NO-SOURCE
[        ] > Task :app:generateDebugAssets UP-TO-DATE
[        ] > Task :app:mergeDebugAssets
[ +288 ms] > Task :app:copyFlutterAssetsDebug
[        ] > Task :app:generateDebugResValues UP-TO-DATE
[        ] > Task :app:generateDebugResources UP-TO-DATE
[        ] > Task :app:mergeDebugResources UP-TO-DATE
[        ] > Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
[        ] > Task :app:extractDeepLinksDebug UP-TO-DATE
[        ] > Task :app:processDebugMainManifest UP-TO-DATE
[        ] > Task :app:processDebugManifest UP-TO-DATE
[        ] > Task :app:processDebugManifestForPackage UP-TO-DATE
[        ] > Task :app:processDebugResources UP-TO-DATE
[        ] > Task :app:compileDebugKotlin UP-TO-DATE
[        ] > Task :app:javaPreCompileDebug UP-TO-DATE
[        ] > Task :app:compileDebugJavaWithJavac UP-TO-DATE
[        ] > Task :app:compileDebugSources UP-TO-DATE
[        ] > Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
[        ] > Task :app:compressDebugAssets UP-TO-DATE
[        ] > Task :app:processDebugJavaRes NO-SOURCE
[        ] > Task :app:mergeDebugJavaResource UP-TO-DATE
[        ] > Task :app:checkDebugDuplicateClasses UP-TO-DATE
[        ] > Task :app:dexBuilderDebug UP-TO-DATE
[        ] > Task :app:desugarDebugFileDependencies UP-TO-DATE
[        ] > Task :app:mergeExtDexDebug UP-TO-DATE
[ +102 ms] > Task :app:mergeDexDebug UP-TO-DATE
[        ] > Task :app:mergeDebugJniLibFolders UP-TO-DATE
[        ] > Task :app:mergeDebugNativeLibs UP-TO-DATE
[        ] > Task :app:stripDebugDebugSymbols UP-TO-DATE
[        ] > Task :app:validateSigningDebug UP-TO-DATE
[        ] > Task :app:packageDebug UP-TO-DATE
[  +51 ms] > Task :app:assembleDebug
[        ] Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
[        ] Use '--warning-mode all' to show the individual deprecation warnings.
[        ] See
https://docs.gradle.org/6.7/userguide/command_line_interface.html#sec:command_line_warnings
[        ] BUILD SUCCESSFUL in 9s
[        ] 32 actionable tasks: 5 executed, 27 up-to-date
[ +509 ms] Running Gradle task 'assembleDebug'... (completed in 9.8s)
[  +40 ms] calculateSha: LocalDirectory: 'C:\Users\mark\OneDrive\Desktop\SS
Development\janktest\build\app\outputs\flutter-apk'/app.apk
[ +625 ms] √  Built build\app\outputs\flutter-apk\app-debug.apk.
[   +2 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\build-tools\31.0.0\aapt dump xmltree
C:\Users\mark\OneDrive\Desktop\SS Development\janktest\build\app\outputs\flutter-apk\app.apk
AndroidManifest.xml
[   +7 ms] Exit code 0 from: C:\Users\mark\AppData\Local\Android\sdk\build-tools\31.0.0\aapt dump xmltree
C:\Users\mark\OneDrive\Desktop\SS Development\janktest\build\app\outputs\flutter-apk\app.apk
AndroidManifest.xml
[        ] N: android=http://schemas.android.com/apk/res/android
             E: manifest (line=2)
               A: android:versionCode(0x0101021b)=(type 0x10)0x1
               A: android:versionName(0x0101021c)="1.0.0" (Raw: "1.0.0")
               A: android:compileSdkVersion(0x01010572)=(type 0x10)0x1e
               A: android:compileSdkVersionCodename(0x01010573)="11" (Raw: "11")
               A: package="com.example.janktest" (Raw: "com.example.janktest")
               A: platformBuildVersionCode=(type 0x10)0x1e
               A: platformBuildVersionName=(type 0x10)0xb
               E: uses-sdk (line=7)
                 A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
                 A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1e
               E: uses-permission (line=14)
                 A: android:name(0x01010003)="android.permission.INTERNET" (Raw:
                 "android.permission.INTERNET")
               E: application (line=16)
                 A: android:label(0x01010001)="janktest" (Raw: "janktest")
                 A: android:icon(0x01010002)=@0x7f080000
                 A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
                 A: android:appComponentFactory(0x0101057a)="androidx.core.app.CoreComponentFactory"     
                 (Raw: "androidx.core.app.CoreComponentFactory")
                 E: activity (line=21)
                   A: android:theme(0x01010000)=@0x7f0a0000
                   A: android:name(0x01010003)="com.example.janktest.MainActivity" (Raw:
                   "com.example.janktest.MainActivity")
                   A: android:launchMode(0x0101001d)=(type 0x10)0x1
                   A: android:configChanges(0x0101001f)=(type 0x11)0x40003fb4
                   A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
                   A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
                   E: meta-data (line=35)
                     A: android:name(0x01010003)="io.flutter.embedding.android.NormalTheme" (Raw:        
                     "io.flutter.embedding.android.NormalTheme")
                     A: android:resource(0x01010025)=@0x7f0a0001
                   E: intent-filter (line=39)
                     E: action (line=40)
                       A: android:name(0x01010003)="android.intent.action.MAIN" (Raw:
                       "android.intent.action.MAIN")
                     E: category (line=42)
                       A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw:
                       "android.intent.category.LAUNCHER")
                 E: meta-data (line=49)
                   A: android:name(0x01010003)="flutterEmbedding" (Raw: "flutterEmbedding")
                   A: android:value(0x01010024)=(type 0x10)0x2
[   +3 ms] Stopping app 'app.apk' on CPH1979.
[        ] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555
shell am force-stop com.example.janktest
[ +547 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555
shell pm list packages com.example.janktest
[ +105 ms] package:com.example.janktest
[   +1 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555
shell cat /data/local/tmp/sky.com.example.janktest.sha1
[  +37 ms] 9d2b1e045f1269930aa2c064d8115030fbd2cbaf
[        ] Latest build already installed.
[        ] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555
shell -x logcat -v time -t 1
[  +51 ms] --------- beginning of main
           10-24 08:17:21.810 E/android.system.suspend@1.0-service(  512): updateSleepTime 1: Device or  
           resource busy
[   +3 ms] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555
shell am start -a android.intent.action.RUN -f 0x20000000 --ez enable-background-compilation true --ez   
enable-dart-profiling true --ez enable-checked-mode true --ez verify-entry-points true
com.example.janktest/com.example.janktest.MainActivity
[ +111 ms] Starting: Intent { act=android.intent.action.RUN flg=0x20000000
cmp=com.example.janktest/.MainActivity (has extras) }
[        ] Waiting for observatory port to be available...
[ +631 ms] Observatory URL on device: http://127.0.0.1:43367/4H9fTxRs6nk=/
[        ] executing: C:\Users\mark\AppData\Local\Android\sdk\platform-tools\adb.exe -s 192.168.0.38:5555
forward tcp:0 tcp:43367
[  +11 ms] 61006
[        ] Forwarded host port 61006 to device port 43367 for Observatory
[   +3 ms] Caching compiled dill
[  +15 ms] Connecting to service protocol: http://127.0.0.1:61006/4H9fTxRs6nk=/
[ +422 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM
service at http://127.0.0.1:61006/4H9fTxRs6nk=/.
[ +445 ms] DDS is listening at http://127.0.0.1:61010/iQhhoxGEvu0=/.
[  +35 ms] Successfully connected to service protocol: http://127.0.0.1:61006/4H9fTxRs6nk=/
[ +118 ms] DevFS: Creating new filesystem on the device (null)
[  +57 ms] DevFS: Created new filesystem on the device
(file:///data/user/0/com.example.janktest/code_cache/janktestJOQOIJ/janktest/)
[   +1 ms] Updating assets
[  +46 ms] Manifest contained wildcard assets. Inserting missing file into build graph to force rerun.
for more information see #56466.
[   +3 ms] Syncing files to device CPH1979...
[   +1 ms] <- reset
[        ] Compiling dart to kernel with 0 updated files
[   +1 ms] <- recompile package:janktest/main.dart ee1d23bd-4d88-4d7b-ad09-f8874bba0b20
[        ] <- ee1d23bd-4d88-4d7b-ad09-f8874bba0b20
[  +62 ms] Updating files.
[        ] DevFS: Sync finished
[        ] Syncing files to device CPH1979... (completed in 66ms)
[        ] Synced 0.0MB.
[   +1 ms] <- accept
[   +4 ms] Connected to _flutterView/0xb4000076132d3220.
[   +1 ms] Flutter run key commands.
[   +1 ms] r Hot reload. 
[        ] R Hot restart.
[        ] h List all available interactive commands.
[        ] d Detach (terminate "flutter run" but leave application running).
[        ] c Clear the screen
[        ] q Quit (terminate the application on the device).
[        ]  Running with sound null safety 
[        ] An Observatory debugger and profiler on CPH1979 is available at:
http://127.0.0.1:61010/iQhhoxGEvu0=/
[+2206 ms] The Flutter DevTools debugger and profiler on CPH1979 is available at:
                    http://127.0.0.1:9103?uri=http://127.0.0.1:61010/iQhhoxGEvu0=/
[+28440 ms] V/PhoneWindow(30325): DecorView setVisiblity: visibility = 0, Parent =
android.view.ViewRootImpl@1808d83, this = DecorView@52c5b00[MainActivity]
[        ] V/PhoneWindow(30325): DecorView setVisiblity: visibility = 0, Parent =
android.view.ViewRootImpl@1808d83, this = DecorView@52c5b00[MainActivity]
[        ] V/OplusZoomWindowDecorViewHelper(30325): setLastReportedMergedConfiguration
mZoomDisplayHeight: 1080 getDecorView.DecorView@52c5b00[MainActivity]
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] D/libMEOW (30325): applied 1 plugins for [com.example.janktest]:
[        ] D/libMEOW (30325):   plugin 1: [libMEOW_gift.so]:
[        ] I/libMEOW_gift(30325): ctx:0xb400007663491d80, ARC not Enabled.
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] I/chatty  (30325): uid=10511(com.example.janktest) RenderThread identical 5 lines
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] D/libMEOW (30325): applied 1 plugins for [com.example.janktest]:
[        ] D/libMEOW (30325):   plugin 1: [libMEOW_gift.so]:
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] I/chatty  (30325): uid=10511(com.example.janktest) RenderThread identical 7 lines
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] I/chatty  (30325): uid=10511(com.example.janktest) RenderThread identical 49 lines
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] E/ion     (30325): ioctl c0044901 failed with code -1: Invalid argument
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[  +15 ms] I/chatty  (30325): uid=10511(com.example.janktest) 1.raster identical 15 lines
[  +12 ms] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
[        ] I/chatty  (30325): uid=10511(com.example.janktest) 1.raster identical 41 lines
[        ] E/libEGL  (30325): Invalid file path for libcolorx-loader.so
Analyzing janktest...                                                   
No issues found! (ran in 2.2s)
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel beta, 2.7.0-3.0.pre, on Microsoft Windows [Version 10.0.22000.282], locale en-AU)
[√] Android toolchain - develop for Android devices (Android SDK version 31.0.0)[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2019 16.11.2)
[√] Android Studio (version 2020.3)
[√] VS Code (version 1.61.2)
[√] Connected device (4 available)
• No issues found!
@sidetraxaudio
Copy link
Author

JANK.-.2.7.0-3.0pre.MP4
NO.JANK.-.2.6.0-5.2.pre.MP4

@maheshj01 maheshj01 added the in triage Presently being triaged by the triage team label Oct 25, 2021
@maheshj01
Copy link
Member

maheshj01 commented Oct 25, 2021

Hi @sidetraxaudio, Thanks for filing the issue. I can reproduce the issue on the latest master 2.6.0-12.0.pre.453 channel the app is very janky and is hardly scrollable and works smoothly at 60 fps on the stable 2.5.3 channel. For the below reports the app was run with trace-skia flag by running

flutter run --profile --trace-skia

Heres the jank_report containing

  • the timeline trace
  • the audio file
  • exported dev tools data

for both stable and the master channel.

Output video

master

jank.mov

stable

stable.MOV
flutter doctor -v
[✓] Flutter (Channel master, 2.6.0-12.0.pre.453, on macOS 11.6 20G165 darwin-arm, locale en-GB)
    • Flutter version 2.6.0-12.0.pre.453 at /Users/mahesh/Documents/flutter_master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision c0e0f4f82e (3 days ago), 2021-10-22 12:26:36 +0800
    • Engine revision d8a54333e5
    • Dart version 2.15.0 (build 2.15.0-233.0.dev)

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 60.1.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.59.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.27.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 11.6 20G165 darwin-arm
    • Chrome (web)    • chrome • web-javascript • Google Chrome 95.0.4638.54

• No issues found!
[✓] Flutter (Channel stable, 2.5.3, on macOS 11.6 20G165 darwin-arm, locale en-GB)
    • Flutter version 2.5.3 at /Users/mahesh/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 18116933e7 (10 days ago), 2021-10-15 10:46:35 -0700
    • Engine revision d3ea636dc5
    • Dart version 2.14.4

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 13.0, Build version 13A233
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 60.1.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.59.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.27.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 11.6 20G165 darwin-arm
    • Chrome (web)    • chrome • web-javascript • Google Chrome 95.0.4638.54

• No issues found!
code sample
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.transparent,
      body: FutureBuilder(
        future: loadGraph(),
        builder: (context, AsyncSnapshot<Int16List> waveData) {
          return (!waveData.hasData)
              ? const CircularProgressIndicator.adaptive()
              : SizedBox(
                  width: MediaQuery.of(context).size.width,
                  height: MediaQuery.of(context).size.height,
                  child: SingleChildScrollView(
                    scrollDirection: Axis.horizontal,
                    child: SizedBox(
                      width: MediaQuery.of(context).size.width * 20,
                      height: MediaQuery.of(context).size.height,
                      child: RepaintBoundary(
                        child: CustomPaint(
                          willChange: false,
                          isComplex: true,
                          painter: PaintTest(
                            waveData: waveData.data!,
                          ),
                        ),
                      ),
                    ),
                  ),
                );
        },
      ),
    );
  }
}

class PaintTest extends CustomPainter {
  final Int16List waveData;

  const PaintTest({
    required this.waveData,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final _height = size.height;
    double x = 0;
    double strokeSize = .5;
    const 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;
    for (index = 0; index < waveData.length; index++) {
      if (waveData[index].isNegative) {
        canvas.drawLine(
            Offset(x, _height * 1 / 2),
            Offset(
                x, _height * 1 / 2 - waveData[index] / 32768 * (_height / 2)),
            paintPos);
        x += zoomFactor;
      } else {
        (waveData[index] == 0)
            ? canvas.drawLine(Offset(x, _height * 1 / 2),
                Offset(x, _height * 1 / 2 + 1), paintZero)
            : canvas.drawLine(
                Offset(x, _height * 1 / 2),
                Offset(x,
                    _height * 1 / 2 - waveData[index] / 32767 * (_height / 2)),
                paintNeg);
        x += zoomFactor;
      }
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

Future<Int16List> loadGraph() async {
  //*_____________________________________________
  //! LOAD ANY WAVE FILE - THIS IS 16bit 44.1 MONO
  //*_____________________________________________
  Int16List load16bitMonoWave = await rootBundle
      .load('assets/twinkle_twinkle_little_star.wav')
      .then((value) => value.buffer.asInt16List());
  //! THIN WAVE FILE TO 1/20
  Int16List waveDataThinned =
      Int16List((load16bitMonoWave.length * 1 / 20).round());
  int reducedIndex = 0;
  for (int index = 0; index + 20 < load16bitMonoWave.length; index += 20) {
    waveDataThinned[reducedIndex] = load16bitMonoWave[index];
    reducedIndex++;
  }
  return waveDataThinned;
}

@maheshj01 maheshj01 added engine flutter/engine repository. See also e: labels. found in release: 2.6 Found to occur in 2.6 has reproducible steps The issue has been confirmed reproducible and is ready to work on perf: speed Performance issues related to (mostly rendering) speed c: regression It was better in the past than it is now c: performance Relates to speed or footprint issues (see "perf:" labels) and removed in triage Presently being triaged by the triage team labels Oct 25, 2021
@maheshj01 maheshj01 changed the title Massive Jank > beta 2.7.0-3.0.pre and ABOVE including master chs [Regression]: App is Janky when painting a waveform Oct 25, 2021
@maheshj01 maheshj01 changed the title [Regression]: App is Janky when painting a waveform Severe jank when painting a waveform Oct 25, 2021
@maheshj01 maheshj01 changed the title Severe jank when painting a waveform [Android] Severe jank when painting a waveform Oct 25, 2021
@maheshj01 maheshj01 added the platform-android Android applications specifically label Oct 25, 2021
@maheshj01
Copy link
Member

cc: @chinmaygarde

@chinmaygarde chinmaygarde added dependency: skia Skia team may need to help us P2 Important issues not at the top of the work list labels Oct 25, 2021
@chinmaygarde
Copy link
Member

In the updated trace, the line segments seem to be rendered into separate surfaces. Not sure why this is happening and this definitely does indicate a regression. We will need to followup with the Skia team on this.

A side note on optimizing this application further: Instead of making multiple calls on the canvas, it would be more efficient to construct an equivalent ui.Path and then make a single draw call. Obviously, that is not the point of this issue which details a regression that must be fixed as well.
Screen Shot 2021-10-25 at 10 55 01 AM

@dnfield
Copy link
Contributor

dnfield commented Oct 25, 2021

@sidetraxaudio - it would be really helpful if you could further bisect this to a specific commit using git bisect. We can do this but you might be able to get to it sooner than any of us :)

@sidetraxaudio
Copy link
Author

Hi @maheshmnj it may be better to remove 'waveform' from title - in the example the CustomPaint is only drawing lines from a list of doubles and the problem will be evident in any process using the engine in a similar way. Someone drawing anything abstract from a dataset. Labelling it so specific may cause duplicates and stop other people from dropping by.

Hi @chinmaygarde Re: Path() efficiency Yes you're certainly right for the simple example I provided to demonstrate the problem but in the actual development there requires far more varied output based on the incoming data on a sample by sample basis- there'd be a lot more paths and passes with many different paints. I'll be profiling and optimising on my refactoring pass over the app. I was originally surprised at how well it worked with so many paint passes.

Hi @dnfield - I'll look into doing a git bisect as soon as I get a chance.

Thanks gents.

@maheshj01 maheshj01 changed the title [Android] Severe jank when painting a waveform [Android] Severe jank with custom paint Oct 26, 2021
@maheshj01
Copy link
Member

maheshj01 commented Oct 29, 2021

I tried bisecting the commits and looks like this commit introduced the jank.

git bisect logs
Note: Bisection was done on master channel

mahesh@Maheshs-Air-M1 flutter_beta % git bisect bad
mahesh@Maheshs-Air-M1 flutter_beta % git bisect good 2.5.3
Bisecting: a merge base must be tested
[0f465e5b2a3ed2431321b490a614c3d15089854c] Revert "update ScrollMetricsNotification (#87421)" (#87693)
mahesh@Maheshs-Air-M1 flutter_beta % pwd                                    
/Users/mahesh/Documents/flutter_beta
mahesh@Maheshs-Air-M1 flutter_beta % git bisect good
Bisecting: 397 revisions left to test after this (roughly 9 steps)
[33755f203dfeae491f586a73abdf4e400749f32a] [autofill] opt-out instead of opt-in (#86312)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect good
Bisecting: 198 revisions left to test after this (roughly 8 steps)
[169020719bc5882e746b836629721644633b6c8a] cc3c53cde [webview_flutter] Update version number app_facing package (flutter/plugins#4375) (#90690)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect good
Bisecting: 99 revisions left to test after this (roughly 7 steps)
[0e72f992371765d41147bae5a21095b2ae817e7a] Restart input connection after `EditableText.onSubmitted` (#84307)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect bad
Bisecting: 49 revisions left to test after this (roughly 6 steps)
[2e663b2472a549ffbae197a14aa1251715c7cfe9] [bots] Print more on --verbose analyze_sample_code (#90880)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect good
Bisecting: 24 revisions left to test after this (roughly 5 steps)
[131b6b18916995916d5387df3130be50bf0e19fd] 90b2844ce [google_maps_flutter_web] Add Marker drag events (flutter/plugins#4385) (#91002)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect good
Bisecting: 12 revisions left to test after this (roughly 4 steps)
[a20743ddfe61208eb1c778c105d96b316b6005d1] Roll Engine from 1f8fa8041d49 to 8ec71b64f6ca (12 revisions) (#91071)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect bad 
Bisecting: 5 revisions left to test after this (roughly 3 steps)
[c48c428e46d57b289f7becce0cec4e75c80c5489] Xcode 13 as minimum recommended version (#90906)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect bad
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[fc02dcbb4ca632fcb08c31c36b398b69d8c56683] Roll Plugins from 90b2844ce7e5 to 63eb67532a7a (2 revisions) (#91039)
mahesh@Maheshs-Air-M1 flutter_beta % 
mahesh@Maheshs-Air-M1 flutter_beta % git bisect bad
Bisecting: 0 revisions left to test after this (roughly 1 step)
[c54e9d2fda3045bff8e53bcad6ad27bcef2185e4] Roll Engine from d0d8e348b6b4 to e83795a0a7c7 (11 revisions) (#91036)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[faaca13f22647c647e5c7d20d55c0fed9e06ca19] Catch FormatException from bad simulator log output (#90966)
mahesh@Maheshs-Air-M1 flutter_beta % git bisect good
c54e9d2fda3045bff8e53bcad6ad27bcef2185e4 is the first bad commit
commit c54e9d2fda3045bff8e53bcad6ad27bcef2185e4
Author: engine-flutter-autoroll <engine-flutter-autoroll@skia.org>
Date:   Thu Sep 30 13:18:05 2021 -0400

    Roll Engine from d0d8e348b6b4 to e83795a0a7c7 (11 revisions) (#91036)

 bin/internal/engine.version        | 2 +-
 bin/internal/fuchsia-linux.version | 2 +-
 bin/internal/fuchsia-mac.version   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
mahesh@Maheshs-Air-M1 flutter_beta % 

Checking out 1 consecutive commit behind faaca13 it works fine.

cc: @dnfield

@dnfield
Copy link
Contributor

dnfield commented Oct 29, 2021

None of the skia commits in https://skia.googlesource.com/skia.git/+log/a20c60d9e5d5..c076abe32ab5 look suspicious, but that engine roll also enabled DisplayList by default.

/cc @flar

@flar
Copy link
Contributor

flar commented Oct 29, 2021

The devtools_master.json file does not include any trace events to analyze.

@flar
Copy link
Contributor

flar commented Oct 29, 2021

Using a path would require more processing on the segments to compute the joins. That processing is great if you can see the joins and want them to have a given style, but when there are so many segments and you can't really see the joins, it is just wasted computations.

@dnfield
Copy link
Contributor

dnfield commented Oct 29, 2021

@flar can you think of why #92366 (comment) would happen?

@flar
Copy link
Contributor

flar commented Oct 29, 2021

@flar can you think of why #92366 (comment) would happen?

You'd have to ask Skia.

@dnfield
Copy link
Contributor

dnfield commented Oct 29, 2021

Ok, backing up a step -

  • I don't think we have tracing to show that the linked commit provides different tracing before or after. It's possible this unfortunate looking tracing is unrelated.
  • The linked commit does cause jank
  • The skia rolls in the linked commit are all either related to testing/infra, Darwin specific, or CPU specific (this is GPU).
  • The linked commit contains the switch to go from SkPicture to DisplayList

My question is: can @flar think of any reason why enabling display list would have introduced jank here?

@flar
Copy link
Contributor

flar commented Oct 29, 2021

Running the test case locally I'm seeing 100ms per call to the Dart Paint phase. This would be the phase during which the DisplayList is constructed.

Using the supplied twinkle-twinkle WAV file I get 333k samples to render. Each is a drawLine call which is 24bytes per record which is an 8mb display list. The current buffer growth algorithm, copied from Skia's SkLiteDL is to bump it by 4k per buffer overrun which means that the buffer will be grown from 4k to 8m over 2000 reallocs. I'll check it's behavior with an exponential growth algorithm (and we could also consider saving the temp grow buffers from one frame to the next) and see how that impacts things.

Looking at how SkPictureRecorder worked, it looks like it would double (starting from an initial buffer of 4 records) on each growth.

@flar
Copy link
Contributor

flar commented Oct 29, 2021

The buffer growth was a red herring. Switching to a doubling algorithm decreased reallocs from 1985 to 12, but the time spent still averaged 150ms.

@flar
Copy link
Contributor

flar commented Oct 30, 2021

To answer the question directly, you can verify that this is a DisplayList issue simply by running with it enabled and disabled, no bisecting or theorizing required:

--dart-flags=--enable-display-list (display list is used and a printout on the console confirms this)
--dart-flags=--no-enable-display-list (display list is disabled and a printout on the console confirms this)

As to why DisplayList is slower here, it is executing the same drawLine calls that were originally captured by the SkPicture and playing them back to Skia. There is likely an optimization inside SkPicture to batch the calls that are not being batched by the Painter. I tried manually batching them and performance improved 5x, but still not to the level of SkPicture. As far as I can tell from reading the code for the SkPictureRecorder it does not actually do any batching of the line calls, but there could be something deeper. I'm still investigating along those lines.

@flar
Copy link
Contributor

flar commented Oct 30, 2021

It looks like SkPicture uses nested bounding boxes to quickly pinpoint the part of a picture that is visible when the picture greatly exceeds the clip. DisplayList doesn't have a mechanism like that. The SkCanvas draw calls often have a quick reject, but it has a tiny cost to be executed on every line in that picture.

There are 333,775 lines in the waveform generated if I use the twinkle-twinkle WAV file from the jank report above. Of those, about 0.2% of them (1 out of 500) are rendered on any given frame on my Moto G4.

I'll file a bug/feature_request? against DisplayList to cull by the bounds of the records which will hopefully bridge this gap.

@flar
Copy link
Contributor

flar commented Nov 11, 2021

I created a new suggested implementation of the sample code that uses a scrolling ListView.builder to render the waveform section by section to avoid both the performance problems seen here as well as significantly reducing the memory usage to store the very large pictures. Some stats on frame times and the size of the Picture objects generated by the 3 implementations (data from a Moto G4):

Screen Shot 2021-11-10 at 7 53 13 PM

The DisplayList uses a lot less memory than SkPicture in all 3 implementations, but it does not perform well for the 2 cases that render the entire waveform in a single picture. Fortunately, it does perform equally on the last implementation that uses a ListView and both the SkPicture and DisplayList mechanisms perform better than any of the other approaches (and use a lot less memory as well).

New example with 3 implementations
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    Key? key,
  }) : super(key: key);

  @override
  State createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  bool consolidate = false;
  bool useList = false;
  Future<Int16List> waveform = loadGraph();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          Row(
            children: <Widget>[
              const Text('list:'),
              Checkbox(value: useList, onChanged: (value) => setState(() {
                useList = value!;
              }),),
            ],
          ),
          Row(
            children: <Widget>[
              const Text('consolidate:'),
              Checkbox(value: consolidate, onChanged: (value) => setState(() {
                consolidate = value!;
              }),),
            ],
          ),
        ],
      ),
      backgroundColor: Colors.transparent,
      body: FutureBuilder(
        future: waveform,
        builder: (context, AsyncSnapshot<Int16List> waveData) {
          return (!waveData.hasData)
              ? const CircularProgressIndicator.adaptive()
              : SizedBox(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: useList
            ? ListView.builder(
              scrollDirection: Axis.horizontal,
              clipBehavior: Clip.none,
              itemCount: (waveData.data!.length / 200).ceil(),
              addRepaintBoundaries: true,
              itemExtent: 100,
              itemBuilder: (context, index) => CustomPaint(
                painter: PaintSomeTest(
                  waveData: waveData.data!,
                  from: index * 200,
                  to: min((index + 1) * 200, waveData.data!.length - 1),
                )
              ),
            )
            : SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: SizedBox(
                width: MediaQuery.of(context).size.width * 20,
                height: MediaQuery.of(context).size.height,
                child: RepaintBoundary(
                  child: CustomPaint(
                    willChange: false,
                    isComplex: true,
                    painter: PaintTest(
                      consolidate: consolidate,
                      waveData: waveData.data!,
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class PaintTest extends CustomPainter {
  final bool consolidate;
  final Int16List waveData;

  const PaintTest({
    required this.consolidate,
    required this.waveData,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final _height = size.height;
    double x = 0;
    double strokeSize = .5;
    const 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;
    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));
        // canvas.drawLine(Offset(x, _height * 1 / 2), Offset(x, _height * 1 / 2 - waveData[index] / 32768 * (_height / 2)), paintPos);
        // x += zoomFactor;
      } 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));
        // (waveData[index] == 0)
        //     ? canvas.drawLine(Offset(x, _height * 1 / 2), Offset(x, _height * 1 / 2 + 1), paintZero)
        //     : canvas.drawLine(Offset(x, _height * 1 / 2), Offset(x, _height * 1 / 2 - waveData[index] / 32767 * (_height / 2)), paintNeg);
        // x += zoomFactor;
      }
      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 {
  final Int16List waveData;
  final int from;
  final int to;

  const PaintSomeTest({
    required this.waveData,
    int? from,
    int? to,
  }) : from = from ?? 0, to = to?? waveData.length;

  @override
  void paint(Canvas canvas, Size size) {
    final _height = size.height;
    double x = 0;
    double strokeSize = .5;
    const 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));
      }
      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;
  }
}

Future<Int16List> loadGraph() async {
  //*_____________________________________________
  //! LOAD ANY WAVE FILE - THIS IS 16bit 44.1 MONO
  //*_____________________________________________
  Int16List load16bitMonoWave = await rootBundle.load('assets/audio.wav').then((value) => value.buffer.asInt16List());
  //! THIN WAVE FILE TO 1/20
  Int16List waveDataThinned = Int16List((load16bitMonoWave.length * 1 / 20).round());
  int reducedIndex = 0;
  for (int index = 0; index + 20 < load16bitMonoWave.length; index += 20) {
    waveDataThinned[reducedIndex] = load16bitMonoWave[index];
    reducedIndex++;
  }
  return waveDataThinned;
}

@GaryQian
Copy link
Contributor

GaryQian commented Nov 1, 2022

@flar This issue has been sitting for a while, do we want to close this or is it still beneficial to keep open?

@flar
Copy link
Contributor

flar commented Nov 7, 2022

The underlying issue is now being tracked under #92740

The specific problem here has a workaround, so I'm going to close this issue.

@flar flar closed this as completed Nov 7, 2022
@maheshj01 maheshj01 added the r: duplicate Issue is closed as a duplicate of an existing issue label Nov 8, 2022
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) c: regression It was better in the past than it is now dependency: skia Skia team may need to help us engine flutter/engine repository. See also e: labels. found in release: 2.6 Found to occur in 2.6 has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list perf: speed Performance issues related to (mostly rendering) speed platform-android Android applications specifically r: duplicate Issue is closed as a duplicate of an existing issue
Projects
None yet
Development

No branches or pull requests

7 participants