danprince / games Goto Github PK
View Code? Open in Web Editor NEW๐ฎ A personal library for building tiny 2D games.
License: The Unlicense
๐ฎ A personal library for building tiny 2D games.
License: The Unlicense
Noticed strange behaviour where text shadows would disappear after ~90s for no obvious reason. A bit of debugging showed that my benchmarking example was creating a new gradient fill every frame. The cache responsible for text was filling up (one new cached canvas per frame) and eventually it must have affected the rendering behaviour.
Can think of a couple of solutions here. The first would be to use a standard LRU cache with a fixed capacity. Frequently rendered text would stay in the cache with a guarantee that memory won't ever spiral out of control (even if I do something stupid, like recreating a gradient once per frame).
The other option would be to solve the leaking memory with a weak map. A cache built this way would automatically evict entries when there are no more references, whilst allowing the cache to hold as many active entries as necessary.
The tricky thing with weak maps here is that the cache keys are composite (a font, a text color/gradient/pattern, a shadow color/gradient/pattern, and the text itself). That means the cache would need be made of layered weak maps.
cache.get([font, color, shadow, text]);
// behind the scenes, every layer is a weak map
map.get(font)?.get(color)?.get(shadow)?.get(text)
// vs
cache.get(`${font.url}/${key(color)/${key(shadow)}/${text}`)
// behind the scenes it's a single lookup
object[`${font.url}/${key(color)/${key(shadow)}/${text}`]
export class WeakCompositeCache<Keys extends [], Value> {
private map = new WeakMap();
set(keys: Keys, value: Value) {
let cache = this.map;
for (let i = 0; i < keys.length - 1; i++) {
let key = keys[i];
let child = cache.get(key);
if (!child) {
child = new WeakMap();
cache.set(key, child);
}
cache = child;
}
let key = keys[keys.length - 1];
cache.set(key, value);
}
get(keys: Keys): Value | undefined {
let cache = this.map;
for (let i = 0; i < keys.length - 1; i++) {
let key = keys[i];
let child = cache.get(key);
if (!child) return undefined;
}
let key = keys[keys.length - 1];
return cache.get(key);
}
}
I suspect the LRU approach has better performance and stricter guarantees for memory leaks.
Noticing in benchmarks that even with caching in place, rendering text is still much slower than rendering sprites. Seems happy rendering ~6k sprites at 60FPS, but only around ~1k words (both pretty arbitrary measures depending on size etc).
This is almost certainly because it's more expensive to keep sending different textures to the GPU (each unique piece of text is rendered to a separate canvas then cached).
Could try maintaining a main cache texture and have the others drawn into it instead.
Packing sprites into the texture cache efficiently seems like a non-starter (immediately sacrificing the performance gains to calculate layout) and you'd have to recalculate the layout each time the cache changed.
Maybe simpler to work with a horizontal strip instead. Each time we add an item to the cache we'd expand the strip's width/height to accommodate for the new canvas, then add it to the end.
Sometimes useful to be able to manage the font inside a spritesheet rather than a separate file (consistent palette, colocated sprite editing etc).
Should make it possible to create a font from a sprite rectangle inside a sheet.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.