From 9e617625fe363b1cf7b67fa1df4c2f7befad2a4d Mon Sep 17 00:00:00 2001 From: Popov72 <github@evpopov.com> Date: Mon, 21 Oct 2024 20:01:13 +0200 Subject: [PATCH] WebGPU: Fix collisions in bind group cache (#15722) * Fix anisotropy value used in the sampler hash code calculation * Fix collisions in the bind group cache --- .../src/Engines/WebGPU/webgpuCacheBindGroups.ts | 17 +++++++++++++++-- .../src/Engines/WebGPU/webgpuCacheSampler.ts | 5 ++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/dev/core/src/Engines/WebGPU/webgpuCacheBindGroups.ts b/packages/dev/core/src/Engines/WebGPU/webgpuCacheBindGroups.ts index 63735bff65a..e981c228446 100644 --- a/packages/dev/core/src/Engines/WebGPU/webgpuCacheBindGroups.ts +++ b/packages/dev/core/src/Engines/WebGPU/webgpuCacheBindGroups.ts @@ -10,6 +10,19 @@ import type { InternalTexture } from "../../Materials/Textures/internalTexture"; import type { ExternalTexture } from "../../Materials/Textures/externalTexture"; import type { WebGPUDrawContext } from "./webgpuDrawContext"; +/** + * Sampler hash codes are 19 bits long, so using a start value of 2^20 for buffer ids will ensure we can't have any collision with the sampler hash codes + */ +const bufferIdStart = 1 << 20; + +/** + * textureIdStart is added to texture ids to ensure we can't have any collision with the buffer ids / sampler hash codes. + * 2^35 for textureIdStart means we can have: + * - 2^(35-20) = 2^15 = 32768 possible buffer ids + * - 2^(53-35) = 2^18 = 524288 possible texture ids + */ +const textureIdStart = 2 ** 35; + class WebGPUBindGroupCacheNode { public values: { [id: number]: WebGPUBindGroupCacheNode }; public bindGroups: GPUBindGroup[]; @@ -94,7 +107,7 @@ export class WebGPUCacheBindGroups { } for (const bufferName of webgpuPipelineContext.shaderProcessingContext.bufferNames) { - const uboId = drawContext.buffers[bufferName]?.uniqueId ?? 0; + const uboId = (drawContext.buffers[bufferName]?.uniqueId ?? 0) + bufferIdStart; let nextNode = node.values[uboId]; if (!nextNode) { nextNode = new WebGPUBindGroupCacheNode(); @@ -114,7 +127,7 @@ export class WebGPUCacheBindGroups { } for (const textureName of webgpuPipelineContext.shaderProcessingContext.textureNames) { - const textureId = materialContext.textures[textureName]?.texture?.uniqueId ?? 0; + const textureId = (materialContext.textures[textureName]?.texture?.uniqueId ?? 0) + textureIdStart; let nextNode = node.values[textureId]; if (!nextNode) { nextNode = new WebGPUBindGroupCacheNode(); diff --git a/packages/dev/core/src/Engines/WebGPU/webgpuCacheSampler.ts b/packages/dev/core/src/Engines/WebGPU/webgpuCacheSampler.ts index 2236a95c75a..5d02a39a71d 100644 --- a/packages/dev/core/src/Engines/WebGPU/webgpuCacheSampler.ts +++ b/packages/dev/core/src/Engines/WebGPU/webgpuCacheSampler.ts @@ -65,7 +65,7 @@ export class WebGPUCacheSampler { public static GetSamplerHashCode(sampler: TextureSampler): number { // The WebGPU spec currently only allows values 1 and 4 for anisotropy - const anisotropy = sampler._cachedAnisotropicFilteringLevel && sampler._cachedAnisotropicFilteringLevel > 1 ? 4 : 1; + const anisotropy = sampler._cachedAnisotropicFilteringLevel ? sampler._cachedAnisotropicFilteringLevel : 1; const code = filterToBits[sampler.samplingMode] + comparisonFunctionToBits[(sampler._comparisonFunction || 0x0202) - 0x0200 + 1] + @@ -243,8 +243,7 @@ export class WebGPUCacheSampler { } private static _GetSamplerDescriptor(sampler: TextureSampler, label?: string): GPUSamplerDescriptor { - // The WebGPU spec currently only allows values 1 and 4 for anisotropy - const anisotropy = sampler.useMipMaps && sampler._cachedAnisotropicFilteringLevel && sampler._cachedAnisotropicFilteringLevel > 1 ? 4 : 1; + const anisotropy = sampler.useMipMaps && sampler._cachedAnisotropicFilteringLevel ? sampler._cachedAnisotropicFilteringLevel : 1; const filterDescriptor = this._GetSamplerFilterDescriptor(sampler, anisotropy); return { label,