Skip to content

Commit

Permalink
Merge pull request #5190 from fyne-io/fix/textspeed1
Browse files Browse the repository at this point in the history
First stage in text speed improvements
  • Loading branch information
andydotxyz authored Oct 16, 2024
2 parents e76dfc5 + fe31121 commit 4875e35
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 8 deletions.
15 changes: 11 additions & 4 deletions internal/cache/text.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cache

import (
"image/color"
"sync"
"time"

Expand All @@ -19,10 +20,16 @@ type fontMetric struct {
}

type fontSizeEntry struct {
text string
size float32
style fyne.TextStyle
custom string
Text string
Size float32
Style fyne.TextStyle
Source string
}

type FontCacheEntry struct {
fontSizeEntry

Color color.Color
}

// GetFontMetrics looks up a calculated size and baseline required for the specified text parameters.
Expand Down
37 changes: 37 additions & 0 deletions internal/cache/texture_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,17 @@ func DeleteTexture(obj fyne.CanvasObject) {
textures.Delete(obj)
}

// GetTextTexture gets cached texture for a text run.
func GetTextTexture(ent FontCacheEntry) (TextureType, bool) {
return load(ent)
}

// GetTexture gets cached texture.
func GetTexture(obj fyne.CanvasObject) (TextureType, bool) {
return load(obj)
}

func load(obj any) (TextureType, bool) {
t, ok := textures.Load(obj)
if t == nil || !ok {
return NoTexture, false
Expand All @@ -31,6 +40,17 @@ func GetTexture(obj fyne.CanvasObject) (TextureType, bool) {
func RangeExpiredTexturesFor(canvas fyne.Canvas, f func(fyne.CanvasObject)) {
now := timeNow()
textures.Range(func(key, value any) bool {
if _, ok := key.(FontCacheEntry); ok {
tinfo := value.(*textureInfo)

// just free text directly when that string/style combo is done
if tinfo.isExpired(now) && tinfo.canvas == canvas {
textures.Delete(key)
tinfo.textFree()
}

return true
}
obj, tinfo := key.(fyne.CanvasObject), value.(*textureInfo)
if tinfo.isExpired(now) && tinfo.canvas == canvas {
f(obj)
Expand All @@ -40,11 +60,16 @@ func RangeExpiredTexturesFor(canvas fyne.Canvas, f func(fyne.CanvasObject)) {
}

// RangeTexturesFor range over the textures for the specified canvas.
// It will not return the texture for a `canvas.Text` as their render lifecycle is handled separately.
//
// Note: If this is used to free textures, then it should be called inside a current
// gl context to ensure textures are deleted from gl.
func RangeTexturesFor(canvas fyne.Canvas, f func(fyne.CanvasObject)) {
textures.Range(func(key, value any) bool {
if _, ok := key.(FontCacheEntry); ok {
return true // do nothing, text cache lives outside the scope of an object
}

obj, tinfo := key.(fyne.CanvasObject), value.(*textureInfo)
if tinfo.canvas == canvas {
f(obj)
Expand All @@ -53,9 +78,21 @@ func RangeTexturesFor(canvas fyne.Canvas, f func(fyne.CanvasObject)) {
})
}

// SetTextTexture sets cached texture for a text run.
func SetTextTexture(ent FontCacheEntry, texture TextureType, canvas fyne.Canvas, free func()) {
store(ent, texture, canvas, free)
}

// SetTexture sets cached texture.
func SetTexture(obj fyne.CanvasObject, texture TextureType, canvas fyne.Canvas) {
store(obj, texture, canvas, nil)
}

func store(obj any, texture TextureType, canvas fyne.Canvas, free func()) {
texInfo := &textureInfo{texture: texture}
if free != nil {
texInfo.textFree = free
}
texInfo.canvas = canvas
texInfo.setAlive()
textures.Store(obj, texInfo)
Expand Down
4 changes: 3 additions & 1 deletion internal/cache/texture_desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ var NoTexture = TextureType(0)

type textureInfo struct {
textureCacheBase
texture TextureType

texture TextureType
textFree func()
}

// IsValid will return true if the passed texture is potentially a texture
Expand Down
4 changes: 3 additions & 1 deletion internal/cache/texture_gomobile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ var NoTexture = gl.Texture{0}

type textureInfo struct {
textureCacheBase
texture TextureType

texture TextureType
textFree func()
}

// IsValid will return true if the passed texture is potentially a texture
Expand Down
6 changes: 4 additions & 2 deletions internal/cache/texture_goxjs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

package cache

import gl "github.com/fyne-io/gl-js"
import "github.com/fyne-io/gl-js"

// TextureType represents an uploaded GL texture
type TextureType = gl.Texture
Expand All @@ -11,7 +11,9 @@ var NoTexture = gl.NoTexture

type textureInfo struct {
textureCacheBase
texture TextureType

texture TextureType
textFree func()
}

// IsValid will return true if the passed texture is potentially a texture
Expand Down
24 changes: 24 additions & 0 deletions internal/painter/gl/texture.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ func (p *painter) freeTexture(obj fyne.CanvasObject) {
}

func (p *painter) getTexture(object fyne.CanvasObject, creator func(canvasObject fyne.CanvasObject) Texture) (Texture, error) {
if t, ok := object.(*canvas.Text); ok {
custom := ""
if t.FontSource != nil {
custom = t.FontSource.Name()
}
ent := cache.FontCacheEntry{Color: t.Color}
ent.Text = t.Text
ent.Size = t.TextSize
ent.Style = t.TextStyle
ent.Source = custom

texture, ok := cache.GetTextTexture(ent)

if !ok {
tex := creator(object)
texture = cache.TextureType(tex)
cache.SetTextTexture(ent, texture, p.canvas, func() {
p.ctx.DeleteTexture(tex)
})
}

return Texture(texture), nil
}

texture, ok := cache.GetTexture(object)

if !ok {
Expand Down

0 comments on commit 4875e35

Please sign in to comment.