From 24a858d12dc6fbd06d6421ed52370a181224e7bc Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Thu, 14 Mar 2024 14:06:44 -0700 Subject: [PATCH] WGSL Validation test for textureSampleCompareLevel --- src/webgpu/listing_meta.json | 5 + .../builtin/textureSampleCompareLevel.spec.ts | 252 ++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 src/webgpu/shader/validation/expression/call/builtin/textureSampleCompareLevel.spec.ts diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index 682d8283ba63..addd670ac444 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -1951,6 +1951,11 @@ "webgpu:shader,validation,expression,call,builtin,textureSampleCompare:offset_argument,non_const:*": { "subcaseMS": 1.720 }, "webgpu:shader,validation,expression,call,builtin,textureSampleCompare:offset_argument:*": { "subcaseMS": 1.540 }, "webgpu:shader,validation,expression,call,builtin,textureSampleCompare:only_in_fragment:*": { "subcaseMS": 1.121 }, + "webgpu:shader,validation,expression,call,builtin,textureSampleCompareLevel:array_index_argument:*": { "subcaseMS": 1.989 }, + "webgpu:shader,validation,expression,call,builtin,textureSampleCompareLevel:coords_argument:*": { "subcaseMS": 1.932 }, + "webgpu:shader,validation,expression,call,builtin,textureSampleCompareLevel:depth_ref_argument:*": { "subcaseMS": 1.578 }, + "webgpu:shader,validation,expression,call,builtin,textureSampleCompareLevel:offset_argument,non_const:*": { "subcaseMS": 1.347 }, + "webgpu:shader,validation,expression,call,builtin,textureSampleCompareLevel:offset_argument:*": { "subcaseMS": 1.619 }, "webgpu:shader,validation,expression,call,builtin,unpack4xI8:bad_args:*": { "subcaseMS": 121.263 }, "webgpu:shader,validation,expression,call,builtin,unpack4xI8:must_use:*": { "subcaseMS": 35.200 }, "webgpu:shader,validation,expression,call,builtin,unpack4xI8:supported:*": { "subcaseMS": 24.150 }, diff --git a/src/webgpu/shader/validation/expression/call/builtin/textureSampleCompareLevel.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/textureSampleCompareLevel.spec.ts new file mode 100644 index 000000000000..c94c4b5b713a --- /dev/null +++ b/src/webgpu/shader/validation/expression/call/builtin/textureSampleCompareLevel.spec.ts @@ -0,0 +1,252 @@ +const builtin = 'textureSampleCompareLevel'; +export const description = ` +Validation tests for the ${builtin}() builtin. + +* test textureSampleCompareLevel coords parameter must be correct type +* test textureSampleCompareLevel array_index parameter must be correct type +* test textureSampleCompareLevel depth_ref parameter must be correct type +* test textureSampleCompareLevel offset parameter must be correct type +* test textureSampleCompareLevel offset parameter must be a const-expression +* test textureSampleCompareLevel offset parameter must be between -8 and +7 inclusive +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; +import { + Type, + kAllScalarsAndVectors, + isConvertible, + ScalarType, + VectorType, + isUnsignedType, +} from '../../../../../util/conversion.js'; +import { ShaderValidationTest } from '../../../shader_validation_test.js'; + +type TextureSampleCompareLevelArguments = { + coordsArgType: ScalarType | VectorType; + hasArrayIndexArg?: boolean; + offsetArgType?: VectorType; +}; + +const kValidTextureSampleCompareLevelParameterTypes: { + [n: string]: TextureSampleCompareLevelArguments; +} = { + texture_depth_2d: { coordsArgType: Type.vec2f, offsetArgType: Type.vec2i }, + texture_depth_2d_array: { + coordsArgType: Type.vec2f, + hasArrayIndexArg: true, + offsetArgType: Type.vec2i, + }, + texture_depth_cube: { coordsArgType: Type.vec3f }, + texture_depth_cube_array: { coordsArgType: Type.vec3f, hasArrayIndexArg: true }, +} as const; + +const kTextureTypes = keysOf(kValidTextureSampleCompareLevelParameterTypes); +const kValuesTypes = objectsToRecord(kAllScalarsAndVectors); + +export const g = makeTestGroup(ShaderValidationTest); + +g.test('coords_argument') + .desc( + ` +Validates that only incorrect coords arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', keysOf(kValidTextureSampleCompareLevelParameterTypes)) + .combine('coordType', keysOf(kValuesTypes)) + .beginSubcases() + .combine('value', [-1, 0, 1] as const) + // filter out unsigned types with negative values + .filter(t => !isUnsignedType(kValuesTypes[t.coordType]) || t.value >= 0) + .expand('offset', ({ textureType }) => { + const offset = kValidTextureSampleCompareLevelParameterTypes[textureType].offsetArgType; + return offset ? [false, true] : [false]; + }) + ) + .fn(t => { + const { textureType, coordType, offset, value } = t.params; + const coordArgType = kValuesTypes[coordType]; + const { + offsetArgType, + coordsArgType: coordsRequiredType, + hasArrayIndexArg, + } = kValidTextureSampleCompareLevelParameterTypes[textureType]; + + const coordWGSL = coordArgType.create(value).wgsl(); + const arrayWGSL = hasArrayIndexArg ? ', 0' : ''; + const offsetWGSL = offset ? `, ${offsetArgType?.create(0).wgsl()}` : ''; + + const code = ` +@group(0) @binding(0) var s: sampler_comparison; +@group(0) @binding(1) var t: ${textureType}; +@fragment fn fs() -> @location(0) vec4f { + let v = textureSampleCompareLevel(t, s, ${coordWGSL}${arrayWGSL}, 0${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = isConvertible(coordArgType, coordsRequiredType); + t.expectCompileResult(expectSuccess, code); + }); + +g.test('array_index_argument') + .desc( + ` +Validates that only incorrect array_index arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', kTextureTypes) + // filter out types with no array_index + .filter(t => !!kValidTextureSampleCompareLevelParameterTypes[t.textureType].hasArrayIndexArg) + .combine('arrayIndexType', keysOf(kValuesTypes)) + .beginSubcases() + .combine('value', [-9, -8, 0, 7, 8]) + // filter out unsigned types with negative values + .filter(t => !isUnsignedType(kValuesTypes[t.arrayIndexType]) || t.value >= 0) + ) + .fn(t => { + const { textureType, arrayIndexType, value } = t.params; + const arrayIndexArgType = kValuesTypes[arrayIndexType]; + const args = [arrayIndexArgType.create(value)]; + const { coordsArgType, offsetArgType } = + kValidTextureSampleCompareLevelParameterTypes[textureType]; + + const coordWGSL = coordsArgType.create(0).wgsl(); + const arrayWGSL = args.map(arg => arg.wgsl()).join(', '); + const offsetWGSL = offsetArgType ? `, ${offsetArgType.create(0).wgsl()}` : ''; + + const code = ` +@group(0) @binding(0) var s: sampler_comparison; +@group(0) @binding(1) var t: ${textureType}; +@fragment fn fs() -> @location(0) vec4f { + let v = textureSampleCompareLevel(t, s, ${coordWGSL}, ${arrayWGSL}, 0${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = + isConvertible(arrayIndexArgType, Type.i32) || isConvertible(arrayIndexArgType, Type.u32); + t.expectCompileResult(expectSuccess, code); + }); + +g.test('depth_ref_argument') + .desc( + ` +Validates that only incorrect depth_ref arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', kTextureTypes) + .combine('depthRefType', keysOf(kValuesTypes)) + .beginSubcases() + .combine('value', [-1, 0, 1]) + // filter out unsigned types with negative values + .filter(t => !isUnsignedType(kValuesTypes[t.depthRefType]) || t.value >= 0) + ) + .fn(t => { + const { textureType, depthRefType, value } = t.params; + const depthRefArgType = kValuesTypes[depthRefType]; + const args = [depthRefArgType.create(value)]; + const { coordsArgType, hasArrayIndexArg, offsetArgType } = + kValidTextureSampleCompareLevelParameterTypes[textureType]; + + const coordWGSL = coordsArgType.create(0).wgsl(); + const arrayWGSL = hasArrayIndexArg ? ', 0' : ''; + const depthRefWGSL = args.map(arg => arg.wgsl()).join(', '); + const offsetWGSL = offsetArgType ? `, ${offsetArgType.create(0).wgsl()}` : ''; + + const code = ` +@group(0) @binding(0) var s: sampler_comparison; +@group(0) @binding(1) var t: ${textureType}; +@fragment fn fs() -> @location(0) vec4f { + let v = textureSampleCompareLevel(t, s, ${coordWGSL}${arrayWGSL}, ${depthRefWGSL}${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = isConvertible(depthRefArgType, Type.f32); + t.expectCompileResult(expectSuccess, code); + }); + +g.test('offset_argument') + .desc( + ` +Validates that only incorrect offset arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', kTextureTypes) + // filter out types with no offset + .filter(t => !!kValidTextureSampleCompareLevelParameterTypes[t.textureType].offsetArgType) + .combine('offsetType', keysOf(kValuesTypes)) + .beginSubcases() + .combine('value', [-9, -8, 0, 7, 8]) + // filter out unsigned types with negative values + .filter(t => !isUnsignedType(kValuesTypes[t.offsetType]) || t.value >= 0) + ) + .fn(t => { + const { textureType, offsetType, value } = t.params; + const offsetArgType = kValuesTypes[offsetType]; + const args = [offsetArgType.create(value)]; + const { + coordsArgType, + hasArrayIndexArg, + offsetArgType: offsetRequiredType, + } = kValidTextureSampleCompareLevelParameterTypes[textureType]; + + const coordWGSL = coordsArgType.create(0).wgsl(); + const arrayWGSL = hasArrayIndexArg ? ', 0' : ''; + const offsetWGSL = args.map(arg => arg.wgsl()).join(', '); + + const code = ` +@group(0) @binding(0) var s: sampler_comparison; +@group(0) @binding(1) var t: ${textureType}; +@fragment fn fs() -> @location(0) vec4f { + let v = textureSampleCompareLevel(t, s, ${coordWGSL}${arrayWGSL}, 0, ${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = + isConvertible(offsetArgType, offsetRequiredType!) && value >= -8 && value <= 7; + t.expectCompileResult(expectSuccess, code); + }); + +g.test('offset_argument,non_const') + .desc( + ` +Validates that only non-const offset arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', kTextureTypes) + .combine('varType', ['c', 'u', 'l']) + // filter out types with no offset + .filter(t => !!kValidTextureSampleCompareLevelParameterTypes[t.textureType].offsetArgType) + ) + .fn(t => { + const { textureType, varType } = t.params; + const { coordsArgType, hasArrayIndexArg, offsetArgType } = + kValidTextureSampleCompareLevelParameterTypes[textureType]; + + const coordWGSL = coordsArgType.create(0).wgsl(); + const arrayWGSL = hasArrayIndexArg ? ', 0' : ''; + const offsetWGSL = `${offsetArgType}(${varType})`; + + const code = ` +@group(0) @binding(0) var s: sampler_comparison; +@group(0) @binding(1) var t: ${textureType}; +@group(0) @binding(2) var u: ${offsetArgType}; +@fragment fn fs() -> @location(0) vec4f { + const c = 1; + let l = ${offsetArgType?.create(0).wgsl()}; + let v = textureSampleCompareLevel(t, s, ${coordWGSL}${arrayWGSL}, 0, ${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = varType === 'c'; + t.expectCompileResult(expectSuccess, code); + });