Skip to content
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

[WIP]RasterCache adds a new mechanism for particularly complex pictures or display lists #31925

Conversation

ColdPaleLight
Copy link
Member

@ColdPaleLight ColdPaleLight commented Mar 9, 2022

RasterCach::Prepare adds the new parameter is_high_priority to specify whether the raster cache entry is high priority. If the raster cache entry is high priority, it will always cache on first usage and survive 3 frames without usage.

Partially fix issues:
flutter/flutter#87827
flutter/flutter#87826

If this PR can land, the following PRs will expose this mechanism to Layer of dart:ui and add zombie algorithm as mentioned in flutter/flutter#87827 (comment)

cc @flar @jonahwilliams

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides].
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See [testing the engine] for instructions on
    writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the [CLA].
  • All existing and new tests are passing.

@jonahwilliams
Copy link
Member

In principle, I like this change, for the issues described in the bug. The only potential downside is that we cache more than we were caching before - but I think it is rare that the framework would display one 1 frame for something. most of the short animations are ~100ms at least.

@jonahwilliams
Copy link
Member

I think the bigger question is: if this change is worthwhile, then what is the downside of always caching on the first frame?

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a flag for complexity and it is called "is_complex". We should not make a new flag that is "something something AND complex". We should keep the flags orthogonal. If something isn't complex then it is slower to cache it than it is to render it from scratch so providing yet another way for developers to defeat the complexity scoring is just another rope for them to hang themselves with.

@ColdPaleLight
Copy link
Member Author

ColdPaleLight commented Mar 22, 2022

We already have a flag for complexity and it is called "is_complex". We should not make a new flag that is "something something AND complex". We should keep the flags orthogonal. If something isn't complex then it is slower to cache it than it is to render it from scratch so providing yet another way for developers to defeat the complexity scoring is just another rope for them to hang themselves with.

I was hesitant before whether to add a new flag. If isComplex is reused, many current tests will fail, because the picture or displaylist in the test depends on isComplex to participate raster cache. So if we reuse isComplex, we need to provide a new way to fix these tests. WDYT?

@ColdPaleLight ColdPaleLight force-pushed the particularly_complex_cache_entry branch from a00ae5e to 0a4e7c0 Compare March 23, 2022 10:03
@ColdPaleLight
Copy link
Member Author

Hi, @flar
I renamed the original is_complex to for_testing, provided it for unit testing. and renamed the flag is_high_priority to is_complex. This way we don't need to add new flags and we can make the unit tests work as before. Please let me know if this makes sense, thanks.

@ColdPaleLight ColdPaleLight requested a review from flar March 23, 2022 14:12
@flar
Copy link
Contributor

flar commented Mar 23, 2022

We already have a flag for complexity and it is called "is_complex". We should not make a new flag that is "something something AND complex". We should keep the flags orthogonal. If something isn't complex then it is slower to cache it than it is to render it from scratch so providing yet another way for developers to defeat the complexity scoring is just another rope for them to hang themselves with.

I was hesitant before whether to add a new flag. If isComplex is reused, many current tests will fail, because the picture or displaylist in the test depends on isComplex to participate raster cache. So if we reuse isComplex, we need to provide a new way to fix these tests. WDYT?

Oh dear, my comment was taken the wrong way.

My comment was about the meaning of the new flag, not whether or not to add one.

We have is_complex to mean the drawing is complex. You were adding "is_high_priority" and making it mean "is_complex" as well. I'm OK with 3 flags, but their meaning should be orthogonal. "is_high_priority" should only affect "when" we cache, not "whether it is complex enough to cache".

In particular, you had this code (in both the picture and display_list code):

  if (is_complex || is_high_priority) {
    // The caller seems to have extra information about the picture and thinks
    // the picture is always worth rasterizing.
    return true;
  }

The "high priority" flag should not be overriding our metrics as to whether or not the picture is worth rasterizing. If something is not worth rasterizing then we should not rasterize it even if it is high priority.

They already have the ability to set "is_complex" to override that logic. We should not have another flag also indicate complexity. For whatever changes "high_priority" makes to our caching logic, the parts that it should not impact are the parts that are already controlled by "is_complex". Instead "high_priority" should impact whether we count down from 3 before we cache it and whether we keep it after its last use for a few frames, but it should not impact our complexity rating.

@flar
Copy link
Contributor

flar commented Mar 23, 2022

In short, I think what was intended here was 3 flags, meaning:

  • will_change: only tells us that the picture will change frequently (on every frame)
  • is_complex: only provides an override for our complexity metrics
  • is_high_priority: only suggests we be more aggressive about populating the cache entry and more lax about evicting it

As your original PR was implemented, you had "is_high_priority" also interfering with our complexity evaluation - which is the job of "is_complex" and should not be a side effect of "is_high_priority".

@ColdPaleLight
Copy link
Member Author

@flar Sorry, I misunderstood your comment. Thank you for your kind comments, I tweaked the code as you suggested, please take a look again, thanks!

@flar
Copy link
Contributor

flar commented Mar 24, 2022

We recently revisited one of the issues that suggested this PR and were concerned that the needs were not adequately predetermined. In other words, this concept is a working hypothesis, not an immediate need.

I'm tagging @dnfield and @jonahwilliams to weigh in on the empirical evidence that this particular solution might address, or how to collect such evidence and evaluate that this solution makes a difference.

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor nits and a potential logic change once we look at some more empirical data, but I think this concept is implemented well here.

I'm flagging this as "Request changes" only on the basis that I'd like to see more buy-in on the concept and a way to measure this empirically before we move forward.

@@ -245,7 +247,8 @@ bool RasterCache::Prepare(PrerollContext* context,

// Creates an entry, if not present prior.
Entry& entry = cache_[cache_key];
if (entry.access_count < access_threshold_) {
entry.is_high_priority = is_high_priority;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have entry.is_high_priority be a one-way latch, or a most-recently-specified flag? This might depend on what the recent request for empirical evidence turns up.

std::unique_ptr<RasterCacheResult> image;
// Return the number of frames the entry survives if it is not used. If the
// number is 0, then it will be evicted when not in use.
size_t unused_threshold() const { return is_high_priority ? 3 : 0; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move "3" to a class constant (something like kHighPriorityEvictionThreshold) so its meaning is more obvious and the number is more visible for when we want to tweak it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (entry.unused_count < entry.unused_threshold()) {
entry.unused_count++;
if (entry.image) {
RasterCacheKeyKind kind = it->first.kind();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe have a function metrics_for(kind) or metrics_for(<type of it.first>) to simplify all 3 cases where we have to choose a metrics to modify?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, added a new method GetMetricsForKind.

@dnfield
Copy link
Contributor

dnfield commented Mar 24, 2022

This has been tricky to nail down. I'm less convinced now that using the raster cache more will help us. Jonah may have more data on this, but in various experiments I tried using the raster cache more actually slowed things down. It'd help to see the benchmark(s) this helps.

@ColdPaleLight
Copy link
Member Author

ColdPaleLight commented Mar 25, 2022

I used https://github.com/dnfield/flutter_svg/tree/master/example as benchmark and made a little tweak in bench_test.dart

    final Timeline timeline = await driver.traceAction(() async {
      await driver.scroll(
        view,
        0,
-       -3400,
+       -1800
-       const Duration(seconds: 10),
+       const Duration(seconds: 3),
        timeout: const Duration(seconds: 15),
      );
    });

It can be seen from the benchmark that if is_high_priority is used properly, it can bring optimization effects for 90th_percentile_frame_rasterizer_time_millis and average_frame_rasterizer_time_millis

Device: Xiaomi Mi 11 (M2102K1C)

with is_high_priority

summary 1

 "average_frame_build_time_millis": 1.146054054054053,
  "90th_percentile_frame_build_time_millis": 1.369,
  "99th_percentile_frame_build_time_millis": 2.096,
  "worst_frame_build_time_millis": 2.521,
  "missed_frame_build_budget_count": 0,
  "average_frame_rasterizer_time_millis": 4.054405405405405,
  "90th_percentile_frame_rasterizer_time_millis": 4.295,
  "99th_percentile_frame_rasterizer_time_millis": 19.372,
  "worst_frame_rasterizer_time_millis": 20.306,
  "missed_frame_rasterizer_budget_count": 5,
  "frame_count": 185,
  "frame_rasterizer_count": 185,
  "new_gen_gc_count": 6,
  "old_gen_gc_count": 0,
  "average_vsync_transitions_missed": 1.4285714285714286,
  "90th_percentile_vsync_transitions_missed": 2.0,
  "99th_percentile_vsync_transitions_missed": 2.0,
  "average_vsync_frame_lag": 106.78494623655914,
  "90th_percentile_vsync_frame_lag": 127.0,
  "99th_percentile_vsync_frame_lag": 162.0,
  "average_layer_cache_count": 0.0,
  "90th_percentile_layer_cache_count": 0.0,
  "99th_percentile_layer_cache_count": 0.0,
  "worst_layer_cache_count": 0.0,
  "average_layer_cache_memory": 0.0,
  "90th_percentile_layer_cache_memory": 0.0,
  "99th_percentile_layer_cache_memory": 0.0,
  "worst_layer_cache_memory": 0.0,
  "average_picture_cache_count": 9.281081081081082,
  "90th_percentile_picture_cache_count": 10.0,
  "99th_percentile_picture_cache_count": 10.0,
  "worst_picture_cache_count": 10.0,
  "average_picture_cache_memory": 10.475058508108127,
  "90th_percentile_picture_cache_memory": 12.672665,
  "99th_percentile_picture_cache_memory": 12.889874,
  "worst_picture_cache_memory": 12.889874,
  "total_ui_gc_time": 3.201,
  "30hz_frame_percentage": 0.0,
  "60hz_frame_percentage": 0.0,
  "90hz_frame_percentage": 0.0,
  "120hz_frame_percentage": 100.0,
  "illegal_refresh_rate_frame_count": 0

summary 2

"average_frame_build_time_millis": 1.0943882978723412,
  "90th_percentile_frame_build_time_millis": 1.332,
  "99th_percentile_frame_build_time_millis": 2.408,
  "worst_frame_build_time_millis": 4.388,
  "missed_frame_build_budget_count": 0,
  "average_frame_rasterizer_time_millis": 3.6251170212765955,
  "90th_percentile_frame_rasterizer_time_millis": 3.927,
  "99th_percentile_frame_rasterizer_time_millis": 19.192,
  "worst_frame_rasterizer_time_millis": 20.304,
  "missed_frame_rasterizer_budget_count": 5,
  "frame_count": 188,
  "frame_rasterizer_count": 188,
  "new_gen_gc_count": 6,
  "old_gen_gc_count": 0,
  "average_vsync_transitions_missed": 1.5833333333333333,
  "90th_percentile_vsync_transitions_missed": 2.0,
  "99th_percentile_vsync_transitions_missed": 2.0,
  "average_vsync_frame_lag": 93.64550264550265,
  "90th_percentile_vsync_frame_lag": 126.0,
  "99th_percentile_vsync_frame_lag": 204.0,
  "average_layer_cache_count": 0.0,
  "90th_percentile_layer_cache_count": 0.0,
  "99th_percentile_layer_cache_count": 0.0,
  "worst_layer_cache_count": 0.0,
  "average_layer_cache_memory": 0.0,
  "90th_percentile_layer_cache_memory": 0.0,
  "99th_percentile_layer_cache_memory": 0.0,
  "worst_layer_cache_memory": 0.0,
  "average_picture_cache_count": 9.26063829787234,
  "90th_percentile_picture_cache_count": 10.0,
  "99th_percentile_picture_cache_count": 10.0,
  "worst_picture_cache_count": 10.0,
  "average_picture_cache_memory": 10.45393879787236,
  "90th_percentile_picture_cache_memory": 12.672665,
  "99th_percentile_picture_cache_memory": 12.889874,
  "worst_picture_cache_memory": 12.889874,
  "total_ui_gc_time": 3.045,
  "30hz_frame_percentage": 0.0,
  "60hz_frame_percentage": 0.0,
  "90hz_frame_percentage": 0.0,
  "120hz_frame_percentage": 100.0,
  "illegal_refresh_rate_frame_count": 0

without is_high_priority

summary 3

"average_frame_build_time_millis": 1.1423155080213905,
  "90th_percentile_frame_build_time_millis": 1.366,
  "99th_percentile_frame_build_time_millis": 2.016,
  "worst_frame_build_time_millis": 4.415,
  "missed_frame_build_budget_count": 0,
  "average_frame_rasterizer_time_millis": 4.173855614973264,
  "90th_percentile_frame_rasterizer_time_millis": 5.739,
  "99th_percentile_frame_rasterizer_time_millis": 18.807,
  "worst_frame_rasterizer_time_millis": 24.477,
  "missed_frame_rasterizer_budget_count": 6,
  "frame_count": 187,
  "frame_rasterizer_count": 187,
  "new_gen_gc_count": 6,
  "old_gen_gc_count": 0,
  "average_vsync_transitions_missed": 1.625,
  "90th_percentile_vsync_transitions_missed": 3.0,
  "99th_percentile_vsync_transitions_missed": 3.0,
  "average_vsync_frame_lag": 104.87765957446808,
  "90th_percentile_vsync_frame_lag": 124.0,
  "99th_percentile_vsync_frame_lag": 187.0,
  "average_layer_cache_count": 0.0,
  "90th_percentile_layer_cache_count": 0.0,
  "99th_percentile_layer_cache_count": 0.0,
  "worst_layer_cache_count": 0.0,
  "average_layer_cache_memory": 0.0,
  "90th_percentile_layer_cache_memory": 0.0,
  "99th_percentile_layer_cache_memory": 0.0,
  "worst_layer_cache_memory": 0.0,
  "average_picture_cache_count": 8.609625668449198,
  "90th_percentile_picture_cache_count": 10.0,
  "99th_percentile_picture_cache_count": 10.0,
  "worst_picture_cache_count": 10.0,
  "average_picture_cache_memory": 9.755210443850283,
  "90th_percentile_picture_cache_memory": 12.449623,
  "99th_percentile_picture_cache_memory": 12.889874,
  "worst_picture_cache_memory": 12.889874,
  "total_ui_gc_time": 3.4190000000000005,
  "30hz_frame_percentage": 0.0,
  "60hz_frame_percentage": 0.0,
  "90hz_frame_percentage": 0.0,
  "120hz_frame_percentage": 100.0,
  "illegal_refresh_rate_frame_count": 0

summary 4

  "average_frame_build_time_millis": 1.1156436170212765,
  "90th_percentile_frame_build_time_millis": 1.353,
  "99th_percentile_frame_build_time_millis": 2.819,
  "worst_frame_build_time_millis": 4.604,
  "missed_frame_build_budget_count": 0,
  "average_frame_rasterizer_time_millis": 3.97781914893617,
  "90th_percentile_frame_rasterizer_time_millis": 5.608,
  "99th_percentile_frame_rasterizer_time_millis": 17.764,
  "worst_frame_rasterizer_time_millis": 20.71,
  "missed_frame_rasterizer_budget_count": 4,
  "frame_count": 188,
  "frame_rasterizer_count": 188,
  "new_gen_gc_count": 6,
  "old_gen_gc_count": 0,
  "average_vsync_transitions_missed": 1.3333333333333333,
  "90th_percentile_vsync_transitions_missed": 2.0,
  "99th_percentile_vsync_transitions_missed": 2.0,
  "average_vsync_frame_lag": 99.63297872340425,
  "90th_percentile_vsync_frame_lag": 123.0,
  "99th_percentile_vsync_frame_lag": 156.0,
  "average_layer_cache_count": 0.0,
  "90th_percentile_layer_cache_count": 0.0,
  "99th_percentile_layer_cache_count": 0.0,
  "worst_layer_cache_count": 0.0,
  "average_layer_cache_memory": 0.0,
  "90th_percentile_layer_cache_memory": 0.0,
  "99th_percentile_layer_cache_memory": 0.0,
  "worst_layer_cache_memory": 0.0,
  "average_picture_cache_count": 8.606382978723405,
  "90th_percentile_picture_cache_count": 10.0,
  "99th_percentile_picture_cache_count": 10.0,
  "worst_picture_cache_count": 10.0,
  "average_picture_cache_memory": 9.75341423404257,
  "90th_percentile_picture_cache_memory": 12.449623,
  "99th_percentile_picture_cache_memory": 12.889874,
  "worst_picture_cache_memory": 12.889874,
  "total_ui_gc_time": 3.7119999999999997,
  "30hz_frame_percentage": 0.0,
  "60hz_frame_percentage": 0.0,
  "90hz_frame_percentage": 0.0,
  "120hz_frame_percentage": 100.0,
  "illegal_refresh_rate_frame_count": 0

But not in all scenarios, is_high_priority must perform better, I found that in the example of flutter_svg, assets/wikimedia/Firefox_Logo_2017.svg will perform worse if is_high_priority is true, the worst_frame_rasterizer_time_millis will change from 77ms to 135ms, I don't know why it happens.

c.f.
https://github.com/dnfield/flutter_svg/blob/c1e76895c2f2ce82ac6fac653cfbe7cc939932e0/example/lib/main.dart#L35

cc @flar @dnfield @jonahwilliams

@ColdPaleLight ColdPaleLight requested a review from flar March 29, 2022 01:51
Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an interesting idea, but we need to have a better motivating case for this. Even in the linked case, we can see that some SVGs benefit from this and others regress. Our customers are likely to not use this correctly.

We already have two flags that feed into raster caching behavior, and that customers don't really know how to use and/or rarely use.

What really need here are some solid benchmarks and docs that explain what we want to do with the raster cache. I personally have had a hard time coming up with motivating cases to show that using it more would be better, or that holding on to entries longer would be better. The GPU seems to start to get into a poor state when it has to work with too many textures, and making a change that will both be correct in most cases and be relatively easy for developers to use is hard.

@dnfield
Copy link
Contributor

dnfield commented Mar 31, 2022

Happy to discuss this more on discord and/or in a doc.

@flar
Copy link
Contributor

flar commented Mar 31, 2022

What @dnfield said. I have been reviewing this PR mostly for "correctness in how it integrates with our caching mechanisms" and not "whether developers could or would take advantage of this flag as proposed". Dan knows much more about that end of things and so I encourage you to engage on the "why" of this PR with him.

@ColdPaleLight
Copy link
Member Author

ColdPaleLight commented Apr 1, 2022

@dnfield You're right, we need more information to help us decide whether this feature will work as well as expected. I think I'll have to do some more in-depth and comprehensive research

I believe is_high_priority can optimize our performance. Here I found another case, After turning on is_high_priority, the performance of raster is greatly improved:

Test: color_filter_and_fade_perf_test
Device: Nexus 6P, Android 8.1.0

run with is_high_priority

  "average_frame_build_time_millis": 1.7323963414634147,
  "90th_percentile_frame_build_time_millis": 2.155,
  "99th_percentile_frame_build_time_millis": 3.22,
  "worst_frame_build_time_millis": 4.108,
  "missed_frame_build_budget_count": 0,
  "average_frame_rasterizer_time_millis": 7.300478527607361,
  "90th_percentile_frame_rasterizer_time_millis": 9.777,
  "99th_percentile_frame_rasterizer_time_millis": 10.941,
  "worst_frame_rasterizer_time_millis": 11.129,
  "missed_frame_rasterizer_budget_count": 0,
  "frame_count": 164,
  "frame_rasterizer_count": 163,
  "new_gen_gc_count": 4,
  "old_gen_gc_count": 0,
  "average_vsync_transitions_missed": 0.0,
  "90th_percentile_vsync_transitions_missed": 0.0,
  "99th_percentile_vsync_transitions_missed": 0.0,
  "average_vsync_frame_lag": 255.53048780487805,
  "90th_percentile_vsync_frame_lag": 314.0,
  "99th_percentile_vsync_frame_lag": 615.0,
  "average_layer_cache_count": 0.0,
  "90th_percentile_layer_cache_count": 0.0,
  "99th_percentile_layer_cache_count": 0.0,
  "worst_layer_cache_count": 0.0,
  "average_layer_cache_memory": 0.0,
  "90th_percentile_layer_cache_memory": 0.0,
  "99th_percentile_layer_cache_memory": 0.0,
  "worst_layer_cache_memory": 0.0,
  "average_picture_cache_count": 5.975609756097561,
  "90th_percentile_picture_cache_count": 6.0,
  "99th_percentile_picture_cache_count": 6.0,
  "worst_picture_cache_count": 6.0,
  "average_picture_cache_memory": 2.914349195121945,
  "90th_percentile_picture_cache_memory": 2.92231,
  "99th_percentile_picture_cache_memory": 2.92231,
  "worst_picture_cache_memory": 2.92231,
  "total_ui_gc_time": 5.76,
  "30hz_frame_percentage": 0.0,
  "60hz_frame_percentage": 100.0,
  "80hz_frame_percentage": 0.0,
  "90hz_frame_percentage": 0.0,
  "120hz_frame_percentage": 0.0,
  "illegal_refresh_rate_frame_count": 0

run without is_high_priority

  "average_frame_build_time_millis": 2.4726395348837205,
  "90th_percentile_frame_build_time_millis": 3.532,
  "99th_percentile_frame_build_time_millis": 6.294,
  "worst_frame_build_time_millis": 7.509,
  "missed_frame_build_budget_count": 0,
  "average_frame_rasterizer_time_millis": 9.358485380116957,
  "90th_percentile_frame_rasterizer_time_millis": 15.959,
  "99th_percentile_frame_rasterizer_time_millis": 23.66,
  "worst_frame_rasterizer_time_millis": 114.63,
  "missed_frame_rasterizer_budget_count": 17,
  "frame_count": 172,
  "frame_rasterizer_count": 171,
  "new_gen_gc_count": 6,
  "old_gen_gc_count": 0,
  "average_vsync_transitions_missed": 1.2571428571428571,
  "90th_percentile_vsync_transitions_missed": 1.0,
  "99th_percentile_vsync_transitions_missed": 7.0,
  "average_vsync_frame_lag": 319.0722222222222,
  "90th_percentile_vsync_frame_lag": 397.0,
  "99th_percentile_vsync_frame_lag": 656.0,
  "average_layer_cache_count": 1.0,
  "90th_percentile_layer_cache_count": 1.0,
  "99th_percentile_layer_cache_count": 1.0,
  "worst_layer_cache_count": 1.0,
  "average_layer_cache_memory": 1.290344000000003,
  "90th_percentile_layer_cache_memory": 1.290344,
  "99th_percentile_layer_cache_memory": 1.290344,
  "worst_layer_cache_memory": 1.290344,
  "average_picture_cache_count": 0.0,
  "90th_percentile_picture_cache_count": 0.0,
  "99th_percentile_picture_cache_count": 0.0,
  "worst_picture_cache_count": 0.0,
  "average_picture_cache_memory": 0.0,
  "90th_percentile_picture_cache_memory": 0.0,
  "99th_percentile_picture_cache_memory": 0.0,
  "worst_picture_cache_memory": 0.0,
  "total_ui_gc_time": 16.191,
  "30hz_frame_percentage": 0.0,
  "60hz_frame_percentage": 100.0,
  "80hz_frame_percentage": 0.0,
  "90hz_frame_percentage": 0.0,
  "120hz_frame_percentage": 0.0,
  "illegal_refresh_rate_frame_count": 0

@ColdPaleLight ColdPaleLight added the Work in progress (WIP) Not ready (yet) for review! label Apr 5, 2022
@ColdPaleLight ColdPaleLight changed the title RasterCache adds a new mechanism for particularly complex pictures or display lists [WIP]RasterCache adds a new mechanism for particularly complex pictures or display lists Apr 5, 2022
@ColdPaleLight
Copy link
Member Author

ColdPaleLight commented Apr 7, 2022

I investigated the two features that is_high_priority wanted to add separately.

  1. Raster cache should allow a configuration to always cache on first usage
    I've been trying for a long time and haven't found conclusive proof that this can benefit raster caching. In theory, this should pay off, but turning theory into reality looks very difficult.

  2. Consider allowing raster cache entries to survive 1+ frames without usage
    This link (Consider allowing raster cache entries to survive 1+ frames without usage flutter#87827 (comment)) is the result of the benchmark. I believe that fixing this issue will benefit the scene where the scrollview scrolls up and down.
    But it seems a bit difficult for the user to mark which pictures should not be cleaned up when unused. Maybe we should introduce an LRU cache to cache the unused picture raster cache entry.

@flar
Copy link
Contributor

flar commented Apr 11, 2022

I investigated the two features that is_high_priority wanted to add separately.

  1. Raster cache should allow a configuration to always cache on first usage
    I've been trying for a long time and haven't found conclusive proof that this can benefit raster caching. In theory, this should pay off, but turning theory into reality looks very difficult.
  2. Consider allowing raster cache entries to survive 1+ frames without usage
    This link (Consider allowing raster cache entries to survive 1+ frames without usage flutter#87827 (comment)) is the result of the benchmark. I believe that fixing this issue will benefit the scene where the scrollview scrolls up and down.
    But it seems a bit difficult for the user to mark which pictures should not be cleaned up when unused. Maybe we should introduce an LRU cache to cache the unused picture raster cache entry.

Doesn't flutter have a mechanism by which you can express a range around the visible field during which the elements will be included in the tree? If so, then they might remain cached if they are just off the screen. I think when I found it one day I asked around and there may be some issues with how it is implemented. If we can get that mechanism to work right, then the above conditions may fall out from it.

We'd also have to look into how we "RasterCache::Touch" the entries when they are in that "included in the tree, but not visible" state.

@flar
Copy link
Contributor

flar commented Apr 11, 2022

Other things to consider - does the extra memory for "potentially reusable" cache entries negatively impact apps? Does it cost extra battery to keep the app warm or to wake it up on a phone with a lot of background tasks?

(Note - fixed a typo. If it actually does cost extra "batter" then we must address this extreme waste of uncooked baked goods...)

@ColdPaleLight
Copy link
Member Author

ColdPaleLight commented Apr 19, 2022

Doesn't flutter have a mechanism by which you can express a range around the visible field during which the elements will be included in the tree? If so, then they might remain cached if they are just off the screen. I think when I found it one day I asked around and there may be some issues with how it is implemented. If we can get that mechanism to work right, then the above conditions may fall out from it.

This is common in ListViews, if an item scrolls out of the visible area but is still in the cache area, it will be cached instead of disposed.

c.f.
https://api.flutter.dev/flutter/widgets/ScrollView/cacheExtent.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Work in progress (WIP) Not ready (yet) for review!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants