feat: add LRU-backed render context with cache metrics#9
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
RenderContextabstraction threaded throughRasterComponent::renderandTimeline::build, plus a concreteCachingRenderContextthat memoizesRasterImageoutputs keyed by component content hash. Lets time-invariant subtrees (e.g. aDropShadow's static blur) skip re-rendering across frames.tellur-core::dyn_compare(new):DynEq/DynHashsuper-traits with blanket impls overPartialEq + Hash + 'static, plus ahash_f32bit-pattern helper. Wires upimpl PartialEq + Hash for dyn RasterComponent / dyn VectorComponentsoBox<dyn _>andVec<Box<dyn _>>get structural equality and hashing through the standard library blanket impls.tellur-core::render_context(new):RenderContexttrait (fn render(&mut self, c: &dyn RasterComponent, size, target) -> RasterImage) and aPassThroughcache-less implementation.RasterComponent::renderandTimeline::buildnow take&mut dyn RenderContext.Vec2/Color/Transform/Anchor/EdgeInsets/TimelineTime/LocalTimeget hand-rolledHash(bits viaf32::to_bits);Path/Group/Paint/Fill/StrokegetPartialEq + Hash; layout containers (Padding/Sized/Place/Frame/Stack/DecoratedBox, plusDropShadow) get hand-writtenPartialEq + Hashbecausederivecan't see throughBox<dyn _>fields.tellur-macros:#[raster_component]/#[vector_component]now emitPartialEq(derived) and a hand-rolledHashimpl that routes rawf32/f64fields through the bit-pattern hasher, so user-defined component bodies are cache-compatible out of the box.tellur-renderer::render_context(new):CachingRenderContextwith a byte-bounded LRU (default 8 GiB) and a system-memory-pressure guard (skips admission / sheds entries above 90% utilization viasysinfo). Keys are(TypeId, content_hash, size_bits, target). Pixel data isbytes::Bytes(Arc-backed) so cache hits are essentially free.CacheMetrics+TypeStats: per-type hits / misses / inclusive vs self time, plus aggregate hit rate / bytes-cached / bytes-evicted / pressure-skips / oversize-skips.Displayimpl sorts byself_timedescending so the actual bottleneck floats to the top.FfmpegEncoderalso prints a loop-phase breakdown (buildvsffmpeg-writevsother) at the end of an export.DropShadow::renderandcomposite_childrenroute child renders throughctx.render(&*child, ...)instead of callingchild.render(...)directly, so oneRenderContextinstance can observe every level of the tree.tellur-renderer/examples/memoization_benchmark.rs(new): renders thetimeline_to_mp4scene twice (PassThrough vs CachingRenderContext) without ffmpeg in the loop. On 1920×1080, 5s @ 60fps the cache saves ~6.5% of wall-clock time (DropShadow's 3-pass blur drops from 1200 invocations to 1); the remaining cost is dominated by per-pixel alpha compositing incomposite_at, which memoization can't reach.