mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
fe2a164d30
The only remaining use of the cache is mapping handles to textures. Using a concrete type for the key avoids the allocation caused by convT. If we need more caches again in the future we can copy the type, or make it generic. Instead of updating the benchmark, we removed it outright. It suffered from several flaws: - The amount of work for each iteration of b.N wasn't constant, because the same cache was reused, growing ever larger in size. - It only tested the cost of insertions. The comment "half are the same and half updated" wasn't true, as calling 'put' with the same key twice would've resulted in a panic. - It didn't simulate any particular workload or cache size, making the benchmark useless for comparing different cache implementations. The cost of insertions isn't particularly interesting. Signed-off-by: Dominik Honnef <dominik@honnef.co>
154 lines
2.7 KiB
Go
154 lines
2.7 KiB
Go
// SPDX-License-Identifier: Unlicense OR MIT
|
|
|
|
package gpu
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gioui.org/internal/f32"
|
|
)
|
|
|
|
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 f32.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
|
|
}
|