webgpuCacheSampler.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /* eslint-disable babylonjs/available */
  2. /* eslint-disable jsdoc/require-jsdoc */
  3. // eslint-disable-next-line @typescript-eslint/naming-convention
  4. import * as WebGPUConstants from "./webgpuConstants.js";
  5. const filterToBits = [
  6. 0 | (0 << 1) | (0 << 2),
  7. 0 | (0 << 1) | (0 << 2),
  8. 1 | (1 << 1) | (0 << 2),
  9. 1 | (1 << 1) | (1 << 2),
  10. 0 | (0 << 1) | (0 << 2),
  11. 0 | (1 << 1) | (0 << 2),
  12. 0 | (1 << 1) | (1 << 2),
  13. 0 | (1 << 1) | (0 << 2),
  14. 0 | (0 << 1) | (1 << 2),
  15. 1 | (0 << 1) | (0 << 2),
  16. 1 | (0 << 1) | (1 << 2),
  17. 1 | (1 << 1) | (0 << 2),
  18. 1 | (0 << 1) | (0 << 2), // TEXTURE_LINEAR_NEAREST
  19. ];
  20. // subtract 0x01FF from the comparison function value before indexing this array!
  21. const comparisonFunctionToBits = [
  22. (0 << 3) | (0 << 4) | (0 << 5) | (0 << 6),
  23. (0 << 3) | (0 << 4) | (0 << 5) | (1 << 6),
  24. (0 << 3) | (0 << 4) | (1 << 5) | (0 << 6),
  25. (0 << 3) | (0 << 4) | (1 << 5) | (1 << 6),
  26. (0 << 3) | (1 << 4) | (0 << 5) | (0 << 6),
  27. (0 << 3) | (1 << 4) | (0 << 5) | (1 << 6),
  28. (0 << 3) | (1 << 4) | (1 << 5) | (0 << 6),
  29. (0 << 3) | (1 << 4) | (1 << 5) | (1 << 6),
  30. (1 << 3) | (0 << 4) | (0 << 5) | (0 << 6), // ALWAYS
  31. ];
  32. const filterNoMipToBits = [
  33. 0 << 7,
  34. 1 << 7,
  35. 1 << 7,
  36. 0 << 7,
  37. 0 << 7,
  38. 0 << 7,
  39. 0 << 7,
  40. 1 << 7,
  41. 0 << 7,
  42. 0 << 7,
  43. 0 << 7,
  44. 0 << 7,
  45. 1 << 7, // TEXTURE_LINEAR_NEAREST
  46. ];
  47. /** @internal */
  48. export class WebGPUCacheSampler {
  49. constructor(device) {
  50. this._samplers = {};
  51. this._device = device;
  52. this.disabled = false;
  53. }
  54. static GetSamplerHashCode(sampler) {
  55. // The WebGPU spec currently only allows values 1 and 4 for anisotropy
  56. const anisotropy = sampler._cachedAnisotropicFilteringLevel && sampler._cachedAnisotropicFilteringLevel > 1 ? 4 : 1;
  57. const code = filterToBits[sampler.samplingMode] +
  58. comparisonFunctionToBits[(sampler._comparisonFunction || 0x0202) - 0x0200 + 1] +
  59. filterNoMipToBits[sampler.samplingMode] + // handle the lodMinClamp = lodMaxClamp = 0 case when no filter used for mip mapping
  60. ((sampler._cachedWrapU ?? 1) << 8) +
  61. ((sampler._cachedWrapV ?? 1) << 10) +
  62. ((sampler._cachedWrapR ?? 1) << 12) +
  63. ((sampler.useMipMaps ? 1 : 0) << 14) + // need to factor this in because _getSamplerFilterDescriptor depends on samplingMode AND useMipMaps!
  64. (anisotropy << 15);
  65. return code;
  66. }
  67. static _GetSamplerFilterDescriptor(sampler, anisotropy) {
  68. let magFilter, minFilter, mipmapFilter, lodMinClamp, lodMaxClamp;
  69. const useMipMaps = sampler.useMipMaps;
  70. switch (sampler.samplingMode) {
  71. case 11:
  72. magFilter = WebGPUConstants.FilterMode.Linear;
  73. minFilter = WebGPUConstants.FilterMode.Linear;
  74. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  75. if (!useMipMaps) {
  76. lodMinClamp = lodMaxClamp = 0;
  77. }
  78. break;
  79. case 3:
  80. case 3:
  81. magFilter = WebGPUConstants.FilterMode.Linear;
  82. minFilter = WebGPUConstants.FilterMode.Linear;
  83. if (!useMipMaps) {
  84. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  85. lodMinClamp = lodMaxClamp = 0;
  86. }
  87. else {
  88. mipmapFilter = WebGPUConstants.FilterMode.Linear;
  89. }
  90. break;
  91. case 8:
  92. magFilter = WebGPUConstants.FilterMode.Nearest;
  93. minFilter = WebGPUConstants.FilterMode.Nearest;
  94. if (!useMipMaps) {
  95. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  96. lodMinClamp = lodMaxClamp = 0;
  97. }
  98. else {
  99. mipmapFilter = WebGPUConstants.FilterMode.Linear;
  100. }
  101. break;
  102. case 4:
  103. magFilter = WebGPUConstants.FilterMode.Nearest;
  104. minFilter = WebGPUConstants.FilterMode.Nearest;
  105. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  106. if (!useMipMaps) {
  107. lodMinClamp = lodMaxClamp = 0;
  108. }
  109. break;
  110. case 5:
  111. magFilter = WebGPUConstants.FilterMode.Nearest;
  112. minFilter = WebGPUConstants.FilterMode.Linear;
  113. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  114. if (!useMipMaps) {
  115. lodMinClamp = lodMaxClamp = 0;
  116. }
  117. break;
  118. case 6:
  119. magFilter = WebGPUConstants.FilterMode.Nearest;
  120. minFilter = WebGPUConstants.FilterMode.Linear;
  121. if (!useMipMaps) {
  122. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  123. lodMinClamp = lodMaxClamp = 0;
  124. }
  125. else {
  126. mipmapFilter = WebGPUConstants.FilterMode.Linear;
  127. }
  128. break;
  129. case 7:
  130. magFilter = WebGPUConstants.FilterMode.Nearest;
  131. minFilter = WebGPUConstants.FilterMode.Linear;
  132. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  133. lodMinClamp = lodMaxClamp = 0;
  134. break;
  135. case 1:
  136. case 1:
  137. magFilter = WebGPUConstants.FilterMode.Nearest;
  138. minFilter = WebGPUConstants.FilterMode.Nearest;
  139. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  140. lodMinClamp = lodMaxClamp = 0;
  141. break;
  142. case 9:
  143. magFilter = WebGPUConstants.FilterMode.Linear;
  144. minFilter = WebGPUConstants.FilterMode.Nearest;
  145. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  146. if (!useMipMaps) {
  147. lodMinClamp = lodMaxClamp = 0;
  148. }
  149. break;
  150. case 10:
  151. magFilter = WebGPUConstants.FilterMode.Linear;
  152. minFilter = WebGPUConstants.FilterMode.Nearest;
  153. if (!useMipMaps) {
  154. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  155. lodMinClamp = lodMaxClamp = 0;
  156. }
  157. else {
  158. mipmapFilter = WebGPUConstants.FilterMode.Linear;
  159. }
  160. break;
  161. case 2:
  162. case 2:
  163. magFilter = WebGPUConstants.FilterMode.Linear;
  164. minFilter = WebGPUConstants.FilterMode.Linear;
  165. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  166. lodMinClamp = lodMaxClamp = 0;
  167. break;
  168. case 12:
  169. magFilter = WebGPUConstants.FilterMode.Linear;
  170. minFilter = WebGPUConstants.FilterMode.Nearest;
  171. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  172. lodMinClamp = lodMaxClamp = 0;
  173. break;
  174. default:
  175. magFilter = WebGPUConstants.FilterMode.Nearest;
  176. minFilter = WebGPUConstants.FilterMode.Nearest;
  177. mipmapFilter = WebGPUConstants.FilterMode.Nearest;
  178. lodMinClamp = lodMaxClamp = 0;
  179. break;
  180. }
  181. if (anisotropy > 1 && (lodMinClamp !== 0 || lodMaxClamp !== 0) && mipmapFilter !== WebGPUConstants.FilterMode.Nearest) {
  182. return {
  183. magFilter: WebGPUConstants.FilterMode.Linear,
  184. minFilter: WebGPUConstants.FilterMode.Linear,
  185. mipmapFilter: WebGPUConstants.FilterMode.Linear,
  186. anisotropyEnabled: true,
  187. };
  188. }
  189. return {
  190. magFilter,
  191. minFilter,
  192. mipmapFilter,
  193. lodMinClamp,
  194. lodMaxClamp,
  195. };
  196. }
  197. static _GetWrappingMode(mode) {
  198. switch (mode) {
  199. case 1:
  200. return WebGPUConstants.AddressMode.Repeat;
  201. case 0:
  202. return WebGPUConstants.AddressMode.ClampToEdge;
  203. case 2:
  204. return WebGPUConstants.AddressMode.MirrorRepeat;
  205. }
  206. return WebGPUConstants.AddressMode.Repeat;
  207. }
  208. static _GetSamplerWrappingDescriptor(sampler) {
  209. return {
  210. addressModeU: this._GetWrappingMode(sampler._cachedWrapU),
  211. addressModeV: this._GetWrappingMode(sampler._cachedWrapV),
  212. addressModeW: this._GetWrappingMode(sampler._cachedWrapR),
  213. };
  214. }
  215. static _GetSamplerDescriptor(sampler, label) {
  216. // The WebGPU spec currently only allows values 1 and 4 for anisotropy
  217. const anisotropy = sampler.useMipMaps && sampler._cachedAnisotropicFilteringLevel && sampler._cachedAnisotropicFilteringLevel > 1 ? 4 : 1;
  218. const filterDescriptor = this._GetSamplerFilterDescriptor(sampler, anisotropy);
  219. return {
  220. label,
  221. ...filterDescriptor,
  222. ...this._GetSamplerWrappingDescriptor(sampler),
  223. compare: sampler._comparisonFunction ? WebGPUCacheSampler.GetCompareFunction(sampler._comparisonFunction) : undefined,
  224. maxAnisotropy: filterDescriptor.anisotropyEnabled ? anisotropy : 1,
  225. };
  226. }
  227. static GetCompareFunction(compareFunction) {
  228. switch (compareFunction) {
  229. case 519:
  230. return WebGPUConstants.CompareFunction.Always;
  231. case 514:
  232. return WebGPUConstants.CompareFunction.Equal;
  233. case 516:
  234. return WebGPUConstants.CompareFunction.Greater;
  235. case 518:
  236. return WebGPUConstants.CompareFunction.GreaterEqual;
  237. case 513:
  238. return WebGPUConstants.CompareFunction.Less;
  239. case 515:
  240. return WebGPUConstants.CompareFunction.LessEqual;
  241. case 512:
  242. return WebGPUConstants.CompareFunction.Never;
  243. case 517:
  244. return WebGPUConstants.CompareFunction.NotEqual;
  245. default:
  246. return WebGPUConstants.CompareFunction.Less;
  247. }
  248. }
  249. getSampler(sampler, bypassCache = false, hash = 0, label) {
  250. if (this.disabled) {
  251. return this._device.createSampler(WebGPUCacheSampler._GetSamplerDescriptor(sampler, label));
  252. }
  253. if (bypassCache) {
  254. hash = 0;
  255. }
  256. else if (hash === 0) {
  257. hash = WebGPUCacheSampler.GetSamplerHashCode(sampler);
  258. }
  259. let gpuSampler = bypassCache ? undefined : this._samplers[hash];
  260. if (!gpuSampler) {
  261. gpuSampler = this._device.createSampler(WebGPUCacheSampler._GetSamplerDescriptor(sampler, label));
  262. if (!bypassCache) {
  263. this._samplers[hash] = gpuSampler;
  264. }
  265. }
  266. return gpuSampler;
  267. }
  268. }
  269. //# sourceMappingURL=webgpuCacheSampler.js.map