Files
gio/gpu/caches.go
T
Viktor f11a656426 gpu: exploit pathCache in collectOps
Previously the cache was only filled during gpu-buffer creation,
resulting in extra work on the CPU to transform vertices if the same
shape was used multiple times in the same frame. Cases such as font
rendering was cached already before this change as it is drawn in it's
own op.Ops that is never reset - and thus re-used from one frame
to the next.

Since we are now calling put() twice per frame an update should no
longer panic.

Signed-off-by: Viktor <viktor.ogeman@gmail.com>
2020-06-21 11:20:36 +02:00

112 lines
1.9 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package gpu
import (
"fmt"
"gioui.org/f32"
"gioui.org/internal/ops"
)
type resourceCache struct {
res map[interface{}]resource
newRes map[interface{}]resource
}
// opCache is like a resourceCache but using concrete types.
type opCache struct {
res map[ops.Key]opCacheValue
newRes map[ops.Key]opCacheValue
}
type opCacheValue struct {
data *pathData
bounds f32.Rectangle
}
func newResourceCache() *resourceCache {
return &resourceCache{
res: make(map[interface{}]resource),
newRes: make(map[interface{}]resource),
}
}
func (r *resourceCache) get(key interface{}) (resource, bool) {
v, exists := r.res[key]
if exists {
r.newRes[key] = v
}
return v, exists
}
func (r *resourceCache) put(key interface{}, val resource) {
if _, exists := r.newRes[key]; exists {
panic(fmt.Errorf("key exists, %p", key))
}
r.res[key] = val
r.newRes[key] = val
}
func (r *resourceCache) frame() {
for k, v := range r.res {
if _, exists := r.newRes[k]; !exists {
delete(r.res, k)
v.release()
}
}
for k, v := range r.newRes {
delete(r.newRes, k)
r.res[k] = v
}
}
func (r *resourceCache) release() {
for _, v := range r.newRes {
v.release()
}
r.newRes = nil
r.res = nil
}
func newOpCache() *opCache {
return &opCache{
res: make(map[ops.Key]opCacheValue),
newRes: make(map[ops.Key]opCacheValue),
}
}
func (r *opCache) get(key ops.Key) (opCacheValue, bool) {
v, exists := r.res[key]
if exists {
r.newRes[key] = v
}
return v, exists
}
func (r *opCache) put(key ops.Key, val opCacheValue) {
r.res[key] = val
r.newRes[key] = val
}
func (r *opCache) frame() {
for k, v := range r.res {
if _, exists := r.newRes[k]; !exists {
delete(r.res, k)
v.data.release()
}
}
for k, v := range r.newRes {
delete(r.newRes, k)
r.res[k] = v
}
}
func (r *opCache) release() {
for _, v := range r.newRes {
v.data.release()
}
r.newRes = nil
r.res = nil
}