Skip to content

Commit

Permalink
Test non-filterable textures can't be used with filtering sampler. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
greggman authored Nov 5, 2024
1 parent d2bd876 commit 8a80203
Showing 1 changed file with 126 additions and 0 deletions.
126 changes: 126 additions & 0 deletions src/webgpu/api/validation/non_filterable_texture.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
export const description = `
Tests that non-filterable textures used with filtering samplers generate a validation error.
`;

import { makeTestGroup } from '../../../common/framework/test_group.js';
import { keysOf } from '../../../common/util/data_tables.js';

import { ValidationTest } from './validation_test.js';

const kNonFilterableCaseInfo: Record<GPUTextureSampleType, { type: string; component: string }> = {
sint: { type: 'i32', component: '0,' },
uint: { type: 'u32', component: '0,' },
float: { type: 'f32', component: '0,' }, // no error for f32
'unfilterable-float': { type: 'f32', component: '0,' }, // no error for f32
depth: { type: 'depth', component: '' },
};
const kNonFilterableCases = keysOf(kNonFilterableCaseInfo);

export const g = makeTestGroup(ValidationTest);

g.test('non_filterable_texture_with_filtering_sampler')
.desc(
'test that createXXXPipeline generates a validation error if a depth/u32/i32 texture binding is used with a filtering sampler binding'
)
.params(u =>
u
.combine('pipeline', ['compute', 'render'])
.combine('async', [true, false] as const)
.combine('sampleType', kNonFilterableCases)
.combine('viewDimension', ['2d', '2d-array', 'cube', 'cube-array'] as const)
.combine('sameGroup', [true, false] as const)
)
.beforeAllSubcases(t => t.skipIfTextureViewDimensionNotSupported(t.params.viewDimension))
.fn(t => {
const { device } = t;
const { pipeline, async, sampleType, viewDimension, sameGroup } = t.params;
const { type, component } = kNonFilterableCaseInfo[sampleType];

const coord = viewDimension.startsWith('2d') ? 'vec2f(0)' : 'vec3f(0)';
const dimensionSuffix = viewDimension.replace('-', '_');
const textureType =
type === 'depth' ? `texture_depth_${dimensionSuffix}` : `texture_${dimensionSuffix}<${type}>`;
const layer = viewDimension.endsWith('-array') ? ', 0' : '';

const groupNdx = sameGroup ? 0 : 1;

const module = device.createShaderModule({
code: `
@group(0) @binding(0) var t: ${textureType};
@group(${groupNdx}) @binding(1) var s: sampler;
fn test() {
_ = textureGather(${component} t, s, ${coord}${layer});
}
@compute @workgroup_size(1) fn cs() {
test();
}
@vertex fn vs() -> @builtin(position) vec4f {
return vec4f(0);
}
@fragment fn fs() -> @location(0) vec4f {
test();
return vec4f(0);
}
`,
});

const bindGroup0LayoutEntries: GPUBindGroupLayoutEntry[] = [
{
binding: 0,
visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT,
texture: {
sampleType,
viewDimension,
multisampled: false,
},
},
];

const samplerBGLEntry: GPUBindGroupLayoutEntry = {
binding: 1,
visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT,
sampler: {
type: 'filtering',
},
};

if (sameGroup) {
bindGroup0LayoutEntries.push(samplerBGLEntry);
}

const bindGroupLayout0 = device.createBindGroupLayout({
entries: bindGroup0LayoutEntries,
});

const pipelineLayoutDesc = {
bindGroupLayouts: [bindGroupLayout0],
};

if (!sameGroup) {
const bindGroupLayout1 = device.createBindGroupLayout({
entries: [samplerBGLEntry],
});
pipelineLayoutDesc.bindGroupLayouts.push(bindGroupLayout1);
}

const layout = device.createPipelineLayout(pipelineLayoutDesc);

const success = sampleType === 'float';

if (pipeline === 'compute') {
t.doCreateComputePipelineTest(async, success, {
layout,
compute: { module },
});
} else {
t.doCreateRenderPipelineTest(async, success, {
layout,
vertex: { module },
fragment: { module, targets: [{ format: 'rgba8unorm' }] },
});
}
});

0 comments on commit 8a80203

Please sign in to comment.