From 91a2cfe45c9aad06995bc6e75b2f1cc5e5639c76 Mon Sep 17 00:00:00 2001 From: Greggman Date: Thu, 21 Nov 2024 11:27:57 -0800 Subject: [PATCH] Add warning in checkCallResults for compressed textures (#4053) We sample a compressed texture on the GPU and compare that to expected. If they don't match we try to identify which texels were sampled. This is done by doing a binary search, creating textures with some pixels white and some black and then sampling the texture to see if those white pixels contributed to the sample values. We can't do this for compressed textures because we can not easily create a compressed texture with white and black pixels exactly where we want them to appear. So, for compressed textures we just use rgba8unorm when identifying sample points. That can be useful to help find major bugs either in the CTS itself or in the GPU that are true for all texture formats. Unfortunately, if the bug is specificially with compressed textures this doesn't help. So, print out a warning that the sample points might not match. Also, change the diagram to show blocks. Eexample when blockWidth = 2, blockHeight = 2 ``` +===+===+===+===+ # a | # | # +---+---+---+---+ # | # | # +===+===+===+===+ # | # | # +---+---+---+---+ # | # | b # +===+===+===+===+ ``` --- .../expression/call/builtin/texture_utils.ts | 88 ++++++++++--------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/src/webgpu/shader/execution/expression/call/builtin/texture_utils.ts b/src/webgpu/shader/execution/expression/call/builtin/texture_utils.ts index b70630fdd07e..29259f5d32a3 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/texture_utils.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/texture_utils.ts @@ -2582,6 +2582,21 @@ export async function checkCallResults( const callForSamplePoints = checkInfo.calls[callIdx]; + // We're going to create textures with black and white texels + // but if it's a compressed texture we use an encodable texture. + // It's not perfect but we already know it failed. We're just hoping + // to get sample points. + const useTexelFormatForGPUTexture = isCompressedTextureFormat(texture.descriptor.format); + + if (useTexelFormatForGPUTexture) { + errs.push(` +### WARNING: sample points are derived from un-compressed textures and may not match the +actual GPU results of sampling a compressed texture. The test itself failed at this point +(see expected: and got: above). We're only trying to determine what the GPU sampled, but +we can not do that easily with compressed textures. ### +`); + } + const expectedSamplePoints = [ 'expected:', ...(await identifySamplePoints( @@ -2616,12 +2631,8 @@ export async function checkCallResults( call, gpuTexels, async (texels: TexelView[]) => { - // We're trying to create a texture with black and white texels - // but if it's a compressed texture we use an encodable texture. - // It's not perfect but we already know it failed. We're just hoping - // to get sample points. const descriptor = { ...texture.descriptor }; - if (isCompressedTextureFormat(descriptor.format)) { + if (useTexelFormatForGPUTexture) { descriptor.format = texels[0].format; } const gpuTexture = createTextureFromTexelViewsLocal(t, texels, descriptor); @@ -3401,19 +3412,29 @@ async function identifySamplePoints( layerEntries.set(xyId, weight); } - // +---+---+---+---+ - // | a | | | | - // +---+---+---+---+ - // | | | | | - // +---+---+---+---+ - // | | | | | - // +---+---+---+---+ - // | | | | b | - // +---+---+---+---+ + // example when blockWidth = 2, blockHeight = 2 + // + // 0 1 2 3 + // +===+===+===+===+ + // 0 # a | # | # + // +---+---+---+---+ + // 1 # | # | # + // +===+===+===+===+ + // 2 # | # | # + // +---+---+---+---+ + // 3 # | # | b # + // +===+===+===+===+ + const lines: string[] = []; const letter = (idx: number) => String.fromCodePoint(idx < 30 ? 97 + idx : idx + 9600 - 30); // 97: 'a' let idCount = 0; + const { blockWidth, blockHeight } = kTextureFormatInfo[texture.descriptor.format]; + const [blockHChar, blockVChar] = Math.max(blockWidth, blockHeight) > 1 ? ['=', '#'] : ['-', '|']; + const blockHCell = '+'.padStart(4, blockHChar); // generates ---+ or ===+ + // range + concatenate results. + const rangeCat = (num: number, fn: (i: number) => T) => range(num, fn).join(''); + for (let mipLevel = 0; mipLevel < mipLevelCount; ++mipLevel) { const level = levels[mipLevel]; if (!level) { @@ -3442,50 +3463,31 @@ async function identifySamplePoints( continue; } - { - let line = ' '; - for (let x = 0; x < width; x++) { - line += ` ${x.toString().padEnd(2)}`; - } - lines.push(line); - } - { - let line = ' +'; - for (let x = 0; x < width; x++) { - line += x === width - 1 ? '---+' : '---+'; - } - lines.push(line); - } + lines.push(` ${rangeCat(width, x => ` ${x.toString().padEnd(2)}`)}`); + lines.push(` +${rangeCat(width, () => blockHCell)}`); for (let y = 0; y < height; y++) { { - let line = `${y.toString().padEnd(2)}|`; + let line = `${y.toString().padStart(2)} ${blockVChar}`; for (let x = 0; x < width; x++) { + const colChar = (x + 1) % blockWidth === 0 ? blockVChar : '|'; const texelIdx = x + y * texelsPerRow; const weight = layerEntries.get(texelIdx); if (weight !== undefined) { - line += ` ${letter(idCount + orderedTexelIndices.length)} |`; + line += ` ${letter(idCount + orderedTexelIndices.length)} ${colChar}`; orderedTexelIndices.push(texelIdx); } else { - line += ' |'; + line += ` ${colChar}`; } } lines.push(line); } if (y < height - 1) { - let line = ' +'; - for (let x = 0; x < width; x++) { - line += x === width - 1 ? '---+' : '---+'; - } - lines.push(line); - } - } - { - let line = ' +'; - for (let x = 0; x < width; x++) { - line += x === width - 1 ? '---+' : '---+'; + lines.push( + ` +${rangeCat(width, () => ((y + 1) % blockHeight === 0 ? blockHCell : '---+'))}` + ); } - lines.push(line); } + lines.push(` +${range(width, () => blockHCell).join('')}`); const pad2 = (n: number) => n.toString().padStart(2); const pad3 = (n: number) => n.toString().padStart(3);