github.com/utopiagio/gio@v0.0.8/gpu/caches.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package gpu 4 5 import ( 6 "fmt" 7 8 "github.com/utopiagio/gio/internal/f32" 9 ) 10 11 type textureCacheKey struct { 12 filter byte 13 handle any 14 } 15 16 type textureCache struct { 17 res map[textureCacheKey]resourceCacheValue 18 } 19 20 type resourceCacheValue struct { 21 used bool 22 resource resource 23 } 24 25 // opCache is like a resourceCache but using concrete types and a 26 // freelist instead of two maps to avoid runtime.mapaccess2 calls 27 // since benchmarking showed them as a bottleneck. 28 type opCache struct { 29 // store the index + 1 in cache this key is stored in 30 index map[opKey]int 31 // list of indexes in cache that are free and can be used 32 freelist []int 33 cache []opCacheValue 34 } 35 36 type opCacheValue struct { 37 data pathData 38 39 bounds f32.Rectangle 40 // the fields below are handled by opCache 41 key opKey 42 keep bool 43 } 44 45 func newTextureCache() *textureCache { 46 return &textureCache{ 47 res: make(map[textureCacheKey]resourceCacheValue), 48 } 49 } 50 51 func (r *textureCache) get(key textureCacheKey) (resource, bool) { 52 v, exists := r.res[key] 53 if !exists { 54 return nil, false 55 } 56 if !v.used { 57 v.used = true 58 r.res[key] = v 59 } 60 return v.resource, exists 61 } 62 63 func (r *textureCache) put(key textureCacheKey, val resource) { 64 v, exists := r.res[key] 65 if exists && v.used { 66 panic(fmt.Errorf("key exists, %v", key)) 67 } 68 v.used = true 69 v.resource = val 70 r.res[key] = v 71 } 72 73 func (r *textureCache) frame() { 74 for k, v := range r.res { 75 if v.used { 76 v.used = false 77 r.res[k] = v 78 } else { 79 delete(r.res, k) 80 v.resource.release() 81 } 82 } 83 } 84 85 func (r *textureCache) release() { 86 for _, v := range r.res { 87 v.resource.release() 88 } 89 r.res = nil 90 } 91 92 func newOpCache() *opCache { 93 return &opCache{ 94 index: make(map[opKey]int), 95 freelist: make([]int, 0), 96 cache: make([]opCacheValue, 0), 97 } 98 } 99 100 func (r *opCache) get(key opKey) (o opCacheValue, exist bool) { 101 v := r.index[key] 102 if v == 0 { 103 return 104 } 105 r.cache[v-1].keep = true 106 return r.cache[v-1], true 107 } 108 109 func (r *opCache) put(key opKey, val opCacheValue) { 110 v := r.index[key] 111 val.keep = true 112 val.key = key 113 if v == 0 { 114 // not in cache 115 i := len(r.cache) 116 if len(r.freelist) > 0 { 117 i = r.freelist[len(r.freelist)-1] 118 r.freelist = r.freelist[:len(r.freelist)-1] 119 r.cache[i] = val 120 } else { 121 r.cache = append(r.cache, val) 122 } 123 r.index[key] = i + 1 124 } else { 125 r.cache[v-1] = val 126 } 127 } 128 129 func (r *opCache) frame() { 130 r.freelist = r.freelist[:0] 131 for i, v := range r.cache { 132 r.cache[i].keep = false 133 if v.keep { 134 continue 135 } 136 if v.data.data != nil { 137 v.data.release() 138 r.cache[i].data.data = nil 139 } 140 delete(r.index, v.key) 141 r.freelist = append(r.freelist, i) 142 } 143 } 144 145 func (r *opCache) release() { 146 for i := range r.cache { 147 r.cache[i].keep = false 148 } 149 r.frame() 150 r.index = nil 151 r.freelist = nil 152 r.cache = nil 153 }