caches.go 2.7 KB

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