text/v2: add glyphImageCache.atime

If many runes were added at the same time, GCing the current cache
did nothing and wasted time.
This commit is contained in:
Hajime Hoshi 2024-07-03 18:39:30 +09:00
parent c1315b3238
commit c5974390a8

View File

@ -44,6 +44,7 @@ type glyphImageCacheEntry struct {
type glyphImageCache[Key comparable] struct { type glyphImageCache[Key comparable] struct {
cache map[Key]*glyphImageCacheEntry cache map[Key]*glyphImageCacheEntry
atime int64
m sync.Mutex m sync.Mutex
} }
@ -51,9 +52,11 @@ func (g *glyphImageCache[Key]) getOrCreate(face Face, key Key, create func() *eb
g.m.Lock() g.m.Lock()
defer g.m.Unlock() defer g.m.Unlock()
n := now()
e, ok := g.cache[key] e, ok := g.cache[key]
if ok { if ok {
e.atime = now() e.atime = n
return e.image return e.image
} }
@ -66,7 +69,7 @@ func (g *glyphImageCache[Key]) getOrCreate(face Face, key Key, create func() *eb
image: img, image: img,
} }
if img != nil { if img != nil {
e.atime = now() e.atime = n
} else { } else {
// If the glyph image is nil, the entry doesn't have to be removed. // If the glyph image is nil, the entry doesn't have to be removed.
// Keep this until the face is GCed. // Keep this until the face is GCed.
@ -75,21 +78,24 @@ func (g *glyphImageCache[Key]) getOrCreate(face Face, key Key, create func() *eb
g.cache[key] = e g.cache[key] = e
// Clean up old entries. // Clean up old entries.
if g.atime < n {
// cacheSoftLimit indicates the soft limit of the number of glyphs in the cache. // cacheSoftLimit indicates the soft limit of the number of glyphs in the cache.
// If the number of glyphs exceeds this soft limits, old glyphs are removed. // If the number of glyphs exceeds this soft limits, old glyphs are removed.
// Even after cleaning up the cache, the number of glyphs might still exceed the soft limit, but // Even after cleaning up the cache, the number of glyphs might still exceed the soft limit, but
// this is fine. // this is fine.
cacheSoftLimit := 128 * glyphVariationCount(face) cacheSoftLimit := 128 * glyphVariationCount(face)
if len(g.cache) > cacheSoftLimit { if len(g.cache) > cacheSoftLimit {
for key, e := range g.cache { for key, e := range g.cache {
// 60 is an arbitrary number. // 60 is an arbitrary number.
if e.atime >= now()-60 { if e.atime >= now()-60 {
continue continue
}
delete(g.cache, key)
} }
delete(g.cache, key)
} }
} }
g.atime = n
return img return img
} }