mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 09:25:38 +00:00
ui/app/internal/gpu: add specialized path cache to avoid key allocations
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
|||||||
|
package gpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gioui.org/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type resourceCache struct {
|
||||||
|
res map[interface{}]resource
|
||||||
|
newRes map[interface{}]resource
|
||||||
|
}
|
||||||
|
|
||||||
|
// opCache is like a resourceCache using the concrete OpKey
|
||||||
|
// key type to avoid allocations.
|
||||||
|
type opCache struct {
|
||||||
|
res map[ui.OpKey]resource
|
||||||
|
newRes map[ui.OpKey]resource
|
||||||
|
}
|
||||||
|
|
||||||
|
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(ctx *context) {
|
||||||
|
for k, v := range r.res {
|
||||||
|
if _, exists := r.newRes[k]; !exists {
|
||||||
|
delete(r.res, k)
|
||||||
|
v.release(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range r.newRes {
|
||||||
|
delete(r.newRes, k)
|
||||||
|
r.res[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *resourceCache) release(ctx *context) {
|
||||||
|
for _, v := range r.newRes {
|
||||||
|
v.release(ctx)
|
||||||
|
}
|
||||||
|
r.newRes = nil
|
||||||
|
r.res = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOpCache() *opCache {
|
||||||
|
return &opCache{
|
||||||
|
res: make(map[ui.OpKey]resource),
|
||||||
|
newRes: make(map[ui.OpKey]resource),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *opCache) get(key ui.OpKey) (resource, bool) {
|
||||||
|
v, exists := r.res[key]
|
||||||
|
if exists {
|
||||||
|
r.newRes[key] = v
|
||||||
|
}
|
||||||
|
return v, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *opCache) put(key ui.OpKey, 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 *opCache) frame(ctx *context) {
|
||||||
|
for k, v := range r.res {
|
||||||
|
if _, exists := r.newRes[k]; !exists {
|
||||||
|
delete(r.res, k)
|
||||||
|
v.release(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range r.newRes {
|
||||||
|
delete(r.newRes, k)
|
||||||
|
r.res[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *opCache) release(ctx *context) {
|
||||||
|
for _, v := range r.newRes {
|
||||||
|
v.release(ctx)
|
||||||
|
}
|
||||||
|
r.newRes = nil
|
||||||
|
r.res = nil
|
||||||
|
}
|
||||||
@@ -25,7 +25,8 @@ type GPU struct {
|
|||||||
summary string
|
summary string
|
||||||
err error
|
err error
|
||||||
|
|
||||||
cache *resourceCache
|
pathCache *opCache
|
||||||
|
cache *resourceCache
|
||||||
|
|
||||||
frames chan frame
|
frames chan frame
|
||||||
results chan frameResult
|
results chan frameResult
|
||||||
@@ -142,11 +143,6 @@ func (op *opClip) decode(data []byte) {
|
|||||||
|
|
||||||
type clipType uint8
|
type clipType uint8
|
||||||
|
|
||||||
type resourceCache struct {
|
|
||||||
res map[interface{}]resource
|
|
||||||
newRes map[interface{}]resource
|
|
||||||
}
|
|
||||||
|
|
||||||
type resource interface {
|
type resource interface {
|
||||||
release(ctx *context)
|
release(ctx *context)
|
||||||
}
|
}
|
||||||
@@ -196,6 +192,7 @@ func NewGPU(ctx gl.Context) (*GPU, error) {
|
|||||||
refreshErr: make(chan error),
|
refreshErr: make(chan error),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
stopped: make(chan struct{}),
|
stopped: make(chan struct{}),
|
||||||
|
pathCache: newOpCache(),
|
||||||
cache: newResourceCache(),
|
cache: newResourceCache(),
|
||||||
}
|
}
|
||||||
if err := g.renderLoop(ctx); err != nil {
|
if err := g.renderLoop(ctx); err != nil {
|
||||||
@@ -224,6 +221,7 @@ func (g *GPU) renderLoop(glctx gl.Context) error {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer g.cache.release(ctx)
|
defer g.cache.release(ctx)
|
||||||
|
defer g.pathCache.release(ctx)
|
||||||
r := newRenderer(ctx)
|
r := newRenderer(ctx)
|
||||||
defer r.release()
|
defer r.release()
|
||||||
var timers *timers
|
var timers *timers
|
||||||
@@ -263,7 +261,7 @@ func (g *GPU) renderLoop(glctx gl.Context) error {
|
|||||||
stencilTimer.begin()
|
stencilTimer.begin()
|
||||||
ctx.Enable(gl.BLEND)
|
ctx.Enable(gl.BLEND)
|
||||||
r.packStencils(&ops.pathOps)
|
r.packStencils(&ops.pathOps)
|
||||||
r.stencilClips(g.cache, ops.pathOps)
|
r.stencilClips(g.pathCache, ops.pathOps)
|
||||||
r.packIntersections(ops.imageOps)
|
r.packIntersections(ops.imageOps)
|
||||||
r.intersect(ops.imageOps)
|
r.intersect(ops.imageOps)
|
||||||
stencilTimer.end()
|
stencilTimer.end()
|
||||||
@@ -276,6 +274,7 @@ func (g *GPU) renderLoop(glctx gl.Context) error {
|
|||||||
err := glctx.Present()
|
err := glctx.Present()
|
||||||
cleanupTimer.begin()
|
cleanupTimer.begin()
|
||||||
g.cache.frame(ctx)
|
g.cache.frame(ctx)
|
||||||
|
g.pathCache.frame(ctx)
|
||||||
cleanupTimer.end()
|
cleanupTimer.end()
|
||||||
var res frameResult
|
var res frameResult
|
||||||
if frame.collectStats && timers.ready() {
|
if frame.collectStats && timers.ready() {
|
||||||
@@ -380,50 +379,6 @@ func (r *renderer) release() {
|
|||||||
r.blitter.release()
|
r.blitter.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
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(ctx *context) {
|
|
||||||
for k, v := range r.res {
|
|
||||||
if _, exists := r.newRes[k]; !exists {
|
|
||||||
delete(r.res, k)
|
|
||||||
v.release(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k, v := range r.newRes {
|
|
||||||
delete(r.newRes, k)
|
|
||||||
r.res[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *resourceCache) release(ctx *context) {
|
|
||||||
for _, v := range r.newRes {
|
|
||||||
v.release(ctx)
|
|
||||||
}
|
|
||||||
r.newRes = nil
|
|
||||||
r.res = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBlitter(ctx *context) *blitter {
|
func newBlitter(ctx *context) *blitter {
|
||||||
prog, err := createColorPrograms(ctx, blitVSrc, blitFSrc)
|
prog, err := createColorPrograms(ctx, blitVSrc, blitFSrc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -498,7 +453,7 @@ uniform vec4 color;
|
|||||||
return prog, nil
|
return prog, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *renderer) stencilClips(cache *resourceCache, ops []*pathOp) {
|
func (r *renderer) stencilClips(pathCache *opCache, ops []*pathOp) {
|
||||||
if len(r.packer.sizes) == 0 {
|
if len(r.packer.sizes) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -511,10 +466,10 @@ func (r *renderer) stencilClips(cache *resourceCache, ops []*pathOp) {
|
|||||||
bindFramebuffer(r.ctx, f.fbo)
|
bindFramebuffer(r.ctx, f.fbo)
|
||||||
r.ctx.Clear(gl.COLOR_BUFFER_BIT)
|
r.ctx.Clear(gl.COLOR_BUFFER_BIT)
|
||||||
}
|
}
|
||||||
data, exists := cache.get(p.pathKey)
|
data, exists := pathCache.get(p.pathKey)
|
||||||
if !exists {
|
if !exists {
|
||||||
data = buildPath(r.ctx, p.pathVerts)
|
data = buildPath(r.ctx, p.pathVerts)
|
||||||
cache.put(p.pathKey, data)
|
pathCache.put(p.pathKey, data)
|
||||||
}
|
}
|
||||||
r.pather.stencilPath(p.clip, p.off, p.place.Pos, data.(*pathData))
|
r.pather.stencilPath(p.clip, p.off, p.place.Pos, data.(*pathData))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user