mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
text/v2: bug fix: StdFace was never released
StdFace was used as a cache key, then these are never released. This change fixes this issue by adding faceCacheKey and use it as a cache key. Updates #498
This commit is contained in:
parent
77f3b57d1f
commit
3f180b2165
@ -52,7 +52,7 @@ type glyphImageCacheEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type glyphImageCache struct {
|
type glyphImageCache struct {
|
||||||
cache map[Face]map[glyphImageCacheKey]*glyphImageCacheEntry
|
cache map[faceCacheKey]map[glyphImageCacheKey]*glyphImageCacheEntry
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,17 +62,18 @@ func (g *glyphImageCache) getOrCreate(face Face, key glyphImageCacheKey, create
|
|||||||
g.m.Lock()
|
g.m.Lock()
|
||||||
defer g.m.Unlock()
|
defer g.m.Unlock()
|
||||||
|
|
||||||
e, ok := g.cache[face][key]
|
e, ok := g.cache[face.faceCacheKey()][key]
|
||||||
if ok {
|
if ok {
|
||||||
e.atime = now()
|
e.atime = now()
|
||||||
return e.image
|
return e.image
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.cache == nil {
|
if g.cache == nil {
|
||||||
g.cache = map[Face]map[glyphImageCacheKey]*glyphImageCacheEntry{}
|
g.cache = map[faceCacheKey]map[glyphImageCacheKey]*glyphImageCacheEntry{}
|
||||||
}
|
}
|
||||||
if g.cache[face] == nil {
|
faceCacheKey := face.faceCacheKey()
|
||||||
g.cache[face] = map[glyphImageCacheKey]*glyphImageCacheEntry{}
|
if g.cache[faceCacheKey] == nil {
|
||||||
|
g.cache[faceCacheKey] = map[glyphImageCacheKey]*glyphImageCacheEntry{}
|
||||||
}
|
}
|
||||||
|
|
||||||
img := create()
|
img := create()
|
||||||
@ -86,7 +87,7 @@ func (g *glyphImageCache) getOrCreate(face Face, key glyphImageCacheKey, create
|
|||||||
// Keep this until the face is GCed.
|
// Keep this until the face is GCed.
|
||||||
e.atime = infTime
|
e.atime = infTime
|
||||||
}
|
}
|
||||||
g.cache[face][key] = e
|
g.cache[faceCacheKey][key] = e
|
||||||
|
|
||||||
// Clean up old entries.
|
// Clean up old entries.
|
||||||
|
|
||||||
@ -95,13 +96,13 @@ func (g *glyphImageCache) getOrCreate(face Face, key glyphImageCacheKey, create
|
|||||||
// 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.
|
||||||
const cacheSoftLimit = 512
|
const cacheSoftLimit = 512
|
||||||
if len(g.cache[face]) > cacheSoftLimit {
|
if len(g.cache[faceCacheKey]) > cacheSoftLimit {
|
||||||
for key, e := range g.cache[face] {
|
for key, e := range g.cache[faceCacheKey] {
|
||||||
// 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[face], key)
|
delete(g.cache[faceCacheKey], key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,5 +114,5 @@ func (g *glyphImageCache) clear(face Face) {
|
|||||||
|
|
||||||
g.m.Lock()
|
g.m.Lock()
|
||||||
defer g.m.Unlock()
|
defer g.m.Unlock()
|
||||||
delete(g.cache, face)
|
delete(g.cache, face.faceCacheKey())
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package text
|
|||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
"golang.org/x/image/math/fixed"
|
"golang.org/x/image/math/fixed"
|
||||||
@ -24,6 +25,12 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var currentStdFaceID uint64
|
||||||
|
|
||||||
|
func nextStdFaceID() uint64 {
|
||||||
|
return atomic.AddUint64(¤tStdFaceID, 1)
|
||||||
|
}
|
||||||
|
|
||||||
var _ Face = (*StdFace)(nil)
|
var _ Face = (*StdFace)(nil)
|
||||||
|
|
||||||
// StdFace is a Face implementation for a semi-standard font.Face (golang.org/x/image/font).
|
// StdFace is a Face implementation for a semi-standard font.Face (golang.org/x/image/font).
|
||||||
@ -32,6 +39,8 @@ var _ Face = (*StdFace)(nil)
|
|||||||
type StdFace struct {
|
type StdFace struct {
|
||||||
f *faceWithCache
|
f *faceWithCache
|
||||||
|
|
||||||
|
id uint64
|
||||||
|
|
||||||
addr *StdFace
|
addr *StdFace
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +50,7 @@ func NewStdFace(face font.Face) *StdFace {
|
|||||||
f: &faceWithCache{
|
f: &faceWithCache{
|
||||||
f: face,
|
f: face,
|
||||||
},
|
},
|
||||||
|
id: nextStdFaceID(),
|
||||||
}
|
}
|
||||||
s.addr = s
|
s.addr = s
|
||||||
runtime.SetFinalizer(s, theGlyphImageCache.clear)
|
runtime.SetFinalizer(s, theGlyphImageCache.clear)
|
||||||
@ -71,6 +81,11 @@ func (s *StdFace) UnsafeInternal() any {
|
|||||||
return s.f.f
|
return s.f.f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// faceCacheKey implements Face.
|
||||||
|
func (s *StdFace) faceCacheKey() faceCacheKey {
|
||||||
|
return faceCacheKey(s.id)
|
||||||
|
}
|
||||||
|
|
||||||
// advance implements Face.
|
// advance implements Face.
|
||||||
func (s *StdFace) advance(text string) float64 {
|
func (s *StdFace) advance(text string) float64 {
|
||||||
return fixed26_6ToFloat64(font.MeasureString(s.f, text))
|
return fixed26_6ToFloat64(font.MeasureString(s.f, text))
|
||||||
|
@ -26,6 +26,8 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type faceCacheKey uint64
|
||||||
|
|
||||||
// Face is an interface representing a font face. The implementations are only GoTextFace and StdFace.
|
// Face is an interface representing a font face. The implementations are only GoTextFace and StdFace.
|
||||||
type Face interface {
|
type Face interface {
|
||||||
// Metrics returns the metrics for this Face.
|
// Metrics returns the metrics for this Face.
|
||||||
@ -36,6 +38,8 @@ type Face interface {
|
|||||||
// This is unsafe since this might make internal cache states out of sync.
|
// This is unsafe since this might make internal cache states out of sync.
|
||||||
UnsafeInternal() any
|
UnsafeInternal() any
|
||||||
|
|
||||||
|
faceCacheKey() faceCacheKey
|
||||||
|
|
||||||
advance(text string) float64
|
advance(text string) float64
|
||||||
|
|
||||||
appendGlyphs(glyphs []Glyph, text string, originX, originY float64) []Glyph
|
appendGlyphs(glyphs []Glyph, text string, originX, originY float64) []Glyph
|
||||||
|
Loading…
Reference in New Issue
Block a user