feat: [flame_svg] Prevent cache thrashing in class Svg by adding cache parameters/properties.#3956
Conversation
These are available at construction/loading, as well as at runtime; the latter is probably overkill.
spydon
left a comment
There was a problem hiding this comment.
Lgtm!
What do you think about adding a follow-up where we remove bool integralSize = false, completely and just have it as true, but marking that PR a breaking change?
| resolution: workspace | ||
| description: Package to add SVG rendering support for the Flame game engine | ||
| version: 1.12.2 | ||
| version: 1.13.0 |
There was a problem hiding this comment.
Don't change anything regarding this version, it's automatically handled by Melos
There was a problem hiding this comment.
Don't change anything regarding this version, it's automatically handled by Melos
Sorry about that: I've reverted commit d419623
There was a problem hiding this comment.
Pull request overview
This PR updates flame_svg to reduce image-cache thrashing in Svg by adding cache-configuration parameters and exposing them as mutable properties, along with a package version/dependency bump.
Changes:
- Add
integralSize,fixedRatio, andcacheSizeparameters toSvg(constructor +load/loadFromString) and toGame.loadSvg. - Rework cache key generation in
_getImageand add cache emptying behavior on configuration changes /dispose(). - Bump
flame_svgversion and update theflutter_svgdependency.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/flame_svg/lib/svg.dart | Adds cache configuration parameters/properties and adjusts cache keying + cache lifecycle handling. |
| packages/flame_svg/pubspec.yaml | Bumps package version to 1.13.0 and updates flutter_svg constraint. |
Comments suppressed due to low confidence (1)
packages/flame_svg/lib/svg.dart:198
MemoryCacheevicts entries by removing keys but doesn't dispose the removedImage. With the new configurablecacheSize(and the existing default of 10), this can lead to unbounded native memory growth during normal operation as entries churn. It would be safer to explicitly dispose the image that will be evicted before inserting a new entry.
picture.dispose();
_imageCache.setValue(cacheKey, image);
return image;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| final width = size.width * widthRatio; | ||
| final height = size.height * heightRatio; | ||
| Size cacheKey; | ||
| if (fixedRatio || integralSize) { | ||
| cacheKey = Size(width.roundToDouble(), height.roundToDouble()); |
There was a problem hiding this comment.
Ah nvm, saw that you replied in the other comment.
There was a problem hiding this comment.
Ah nvm, saw that you replied in the other comment.
I've fixed the first two Copilot issues in commit 4895884.
Please let me know what I should do about the integralSize property — thank you.
This reverts commit d419623.
Sure, whatever you deem best; should I modify the class and create a new branch/PR, or just modify In any case, I'll address the first two issues raised by Copilot. |
|
@spydon I've sync'd the fork with the latest changes from main. |
Thanks! Let's merge this first and I'll do a release of it, and then you can submit another breaking change PR that removes the |
Sounds good: thank you for merging. |
It'll be easier if you create a new branch from main, because the other branch was squash merged. |
Description
Existing behaviour
Currently, class
Svguses the raw clip bounds ratio for the image cache keys; however, when rendering the cached images, the_getImagemethod obviously creates integer-sized images. This results in cache thrashing (particularly with the default cache size of just10slots) when anSvginstance is used by severalSvgComponentobjects all using different scale/rotation values. Due to floating-point rounding errors, the_getImagemethod is creating multiple cache entries having the same integral size (hence producing the same output fromPictureRecorder).Proposed changes
The
Svgconstructor and the staticloadandloadFromStringmethods, as well as theSvgLoaderextension on classGameadding theloadSvgmethod, now accept 3 new named parameters:bool integralSize = falsebool fixedRatio = falseint cacheSize = Svg.defaultCacheSize(defaults to 10)The
integralSizeparameter, whentrue, enforces integer values for the image cache keys, thus preventing useless stalls in the pipeline. Honestly, I don't think this parameter should ever befalse... I don't see how it would be useful to use keys that depend on floating-point rounding errors. I would recommend removing this parameter entirely, always behaving as if it weretrue.The
fixedRatioparameter, whentrue, ensures that only the actual Svg image size are used for the cache keys, thus ensuring that the image cache always contains a single entry. It may be useful in all situations where a given Svg is only ever scaled down, as in the testbed linked below.The
cacheSizeparameter may be fine-tuned where the amount of cache entries, generated by different rotation/scale values, is known or may be estimated in advance.The new parameters are also available as read-write properties: the related accessors empty the current cache as a side-effect. The defaults ensure that the changes do not break any existing client of class
Svg.Testing
A complete testbed for the changes is available — this displays 200+1
SvgComponentobjects all with different rotation/scale values. For comparison purposes, the testbed starts with the default implementation; the Mode and Size buttons cycle through several combinations of the new parameters.Notes
I understand that having read-write properties for the new parameters might not adhere to the coding conventions; they were necessary to demonstrate the issue in the testbed.
Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Related Issues