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  }