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