Files
prevara/gio/gpu/caches.go
2025-11-30 16:45:22 +00:00

153 lines
2.7 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package gpu
import (
"fmt"
"image"
)
type textureCacheKey struct {
filter byte
handle any
}
type textureCache struct {
res map[textureCacheKey]resourceCacheValue
}
type resourceCacheValue struct {
used bool
resource resource
}
// opCache is like a resourceCache but using concrete types and a
// freelist instead of two maps to avoid runtime.mapaccess2 calls
// since benchmarking showed them as a bottleneck.
type opCache struct {
// store the index + 1 in cache this key is stored in
index map[opKey]int
// list of indexes in cache that are free and can be used
freelist []int
cache []opCacheValue
}
type opCacheValue struct {
data pathData
bounds image.Rectangle
// the fields below are handled by opCache
key opKey
keep bool
}
func newTextureCache() *textureCache {
return &textureCache{
res: make(map[textureCacheKey]resourceCacheValue),
}
}
func (r *textureCache) get(key textureCacheKey) (resource, bool) {
v, exists := r.res[key]
if !exists {
return nil, false
}
if !v.used {
v.used = true
r.res[key] = v
}
return v.resource, exists
}
func (r *textureCache) put(key textureCacheKey, val resource) {
v, exists := r.res[key]
if exists && v.used {
panic(fmt.Errorf("key exists, %v", key))
}
v.used = true
v.resource = val
r.res[key] = v
}
func (r *textureCache) frame() {
for k, v := range r.res {
if v.used {
v.used = false
r.res[k] = v
} else {
delete(r.res, k)
v.resource.release()
}
}
}
func (r *textureCache) release() {
for _, v := range r.res {
v.resource.release()
}
r.res = nil
}
func newOpCache() *opCache {
return &opCache{
index: make(map[opKey]int),
freelist: make([]int, 0),
cache: make([]opCacheValue, 0),
}
}
func (r *opCache) get(key opKey) (o opCacheValue, exist bool) {
v := r.index[key]
if v == 0 {
return
}
r.cache[v-1].keep = true
return r.cache[v-1], true
}
func (r *opCache) put(key opKey, val opCacheValue) {
v := r.index[key]
val.keep = true
val.key = key
if v == 0 {
// not in cache
i := len(r.cache)
if len(r.freelist) > 0 {
i = r.freelist[len(r.freelist)-1]
r.freelist = r.freelist[:len(r.freelist)-1]
r.cache[i] = val
} else {
r.cache = append(r.cache, val)
}
r.index[key] = i + 1
} else {
r.cache[v-1] = val
}
}
func (r *opCache) frame() {
r.freelist = r.freelist[:0]
for i, v := range r.cache {
r.cache[i].keep = false
if v.keep {
continue
}
if v.data.data != nil {
v.data.release()
r.cache[i].data.data = nil
}
delete(r.index, v.key)
r.freelist = append(r.freelist, i)
}
}
func (r *opCache) release() {
for i := range r.cache {
r.cache[i].keep = false
}
r.frame()
r.index = nil
r.freelist = nil
r.cache = nil
}