Functions to free up (SDL2) texture memory

master
Noah 2022-04-09 14:25:56 -07:00
parent c1b8bc910b
commit df69b8e525
3 changed files with 81 additions and 1 deletions

View File

@ -79,6 +79,11 @@ func (t *Texture) Image() image.Image {
return nil return nil
} }
// Free the texture. Doesn't do anything in the Canvas engine currently.
func (t *Texture) Free() error {
return nil
}
// LoadTexture recalls a cached texture image. // LoadTexture recalls a cached texture image.
func (e *Engine) LoadTexture(name string) (render.Texturer, error) { func (e *Engine) LoadTexture(name string) (render.Texturer, error) {
if tex, ok := e.textures[name]; ok { if tex, ok := e.textures[name]; ok {
@ -94,5 +99,13 @@ func (e *Engine) Copy(t render.Texturer, src, dist render.Rect) {
// e.canvas.ctx2d.Call("drawImage", tex.image, dist.X, dist.Y) // e.canvas.ctx2d.Call("drawImage", tex.image, dist.X, dist.Y)
e.canvas.ctx2d.Call("drawImage", tex.canvas, dist.X, dist.Y) e.canvas.ctx2d.Call("drawImage", tex.canvas, dist.X, dist.Y)
}
// FreeTextures flushes the texture cache.
func (e *Engine) FreeTextures() int {
var len = len(e.textures)
for name := range e.textures {
delete(e.textures, name)
}
return len
} }

View File

@ -34,6 +34,10 @@ type Engine interface {
LoadTexture(name string) (Texturer, error) LoadTexture(name string) (Texturer, error)
Copy(t Texturer, src, dst Rect) Copy(t Texturer, src, dst Rect)
// Teardown and free memory for all textures, returning the number
// of textures that were freed.
FreeTextures() int
// Delay for a moment using the render engine's delay method, // Delay for a moment using the render engine's delay method,
// implemented by sdl.Delay(uint32) // implemented by sdl.Delay(uint32)
Delay(uint32) Delay(uint32)
@ -49,4 +53,5 @@ type Engine interface {
type Texturer interface { type Texturer interface {
Size() Rect Size() Rect
Image() image.Image Image() image.Image
Free() error // teardown and free memory
} }

View File

@ -23,6 +23,7 @@ func (r *Renderer) Copy(t render.Texturer, src, dst render.Rect) {
// Texture can hold on to SDL textures for caching and optimization. // Texture can hold on to SDL textures for caching and optimization.
type Texture struct { type Texture struct {
render *Renderer // backref to free them up thoroughly
tex *sdl.Texture tex *sdl.Texture
image image.Image image image.Image
width int32 width int32
@ -62,6 +63,7 @@ func (r *Renderer) StoreTexture(name string, img image.Image) (render.Texturer,
} }
tex := &Texture{ tex := &Texture{
render: r,
width: surface.W, width: surface.W,
height: surface.H, height: surface.H,
tex: texture, tex: texture,
@ -72,6 +74,32 @@ func (r *Renderer) StoreTexture(name string, img image.Image) (render.Texturer,
return tex, nil return tex, nil
} }
// CountTextures is a custom function for the SDL2 Engine only that returns the
// size of the engine texture cache.
//
// Returns the number of (Go) Texture objects (which hold cached image.Image
// and can garbage collect nicely) and the number of those which also have
// SDL2 Texture objects (which need to be freed manually).
func (r *Renderer) CountTextures() (bitmaps int, sdl2textures int) {
var withTex int // ones with active SDL2 Texture objects
for _, tex := range r.textures {
if tex.tex != nil {
withTex++
}
}
return len(r.textures), withTex
}
// ListTextures is a custom function to peek into the SDL2 texture cache names.
func (r *Renderer) ListTextures() []string {
var keys = []string{}
for key := range r.textures {
keys = append(keys, key)
}
return keys
}
// Size returns the dimensions of the texture. // Size returns the dimensions of the texture.
func (t *Texture) Size() render.Rect { func (t *Texture) Size() render.Rect {
return render.NewRect(int(t.width), int(t.height)) return render.NewRect(int(t.width), int(t.height))
@ -82,10 +110,44 @@ func (t *Texture) Image() image.Image {
return t.image return t.image
} }
// Free the SDL2 texture object.
func (t *Texture) Free() error {
var err error
if t.tex != nil {
err = t.tex.Destroy()
t.tex = nil
}
// Free up the cached texture too to garbage collect the image.Image cache etc.
for name, tex := range t.render.textures {
if tex == t {
delete(t.render.textures, name)
break
}
}
return err
}
// LoadTexture initializes a texture from a bitmap image. // LoadTexture initializes a texture from a bitmap image.
func (r *Renderer) LoadTexture(name string) (render.Texturer, error) { func (r *Renderer) LoadTexture(name string) (render.Texturer, error) {
if tex, ok := r.textures[name]; ok { if tex, ok := r.textures[name]; ok {
// If the SDL2 texture had been freed, recreate it.
if tex.tex == nil {
return r.StoreTexture(name, tex.image)
}
return tex, nil return tex, nil
} }
return nil, fmt.Errorf("LoadTexture(%s): not found in texture cache", name) return nil, fmt.Errorf("LoadTexture(%s): not found in texture cache", name)
} }
// FreeTextures flushes the internal cache of SDL2 textures and frees their memory.
func (r *Renderer) FreeTextures() int {
var num = len(r.textures)
for name, tex := range r.textures {
delete(r.textures, name)
tex.tex.Destroy()
}
return num
}