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