Skip to content

Commit

Permalink
Compat: adjust for 0 vert/frag storage buffers/textures (#4088)
Browse files Browse the repository at this point in the history
Compat does allows supporting 0 storage buffers and storage textures
in fragment shaders. Update some test for this situation.
  • Loading branch information
greggman authored Dec 12, 2024
1 parent 5b26e0e commit 64eb522
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
const kExtraLimits: LimitsRequest = {
maxBindingsPerBindGroup: 'adapterLimit',
maxBindGroups: 'adapterLimit',
maxStorageBuffersInFragmentStage: 'adapterLimit',
maxStorageBuffersInVertexStage: 'adapterLimit',
};

const limit = 'maxStorageBuffersPerShaderStage';
Expand Down Expand Up @@ -165,6 +167,24 @@ g.test('createPipeline,at_over')
`can not test ${testValue} bindings in same group because maxBindingsPerBindGroup = ${device.limits.maxBindingsPerBindGroup}`
);

if (t.isCompatibility) {
t.skipIf(
(bindingCombination === 'fragment' ||
bindingCombination === 'vertexAndFragmentWithPossibleVertexStageOverflow' ||
bindingCombination === 'vertexAndFragmentWithPossibleFragmentStageOverflow') &&
testValue > device.limits.maxStorageBuffersInFragmentStage!,
`can not test ${testValue} bindings as it is more than maxStorageBuffersInFragmentStage(${device.limits.maxStorageBuffersInFragmentStage})`
);

t.skipIf(
(bindingCombination === 'vertex' ||
bindingCombination === 'vertexAndFragmentWithPossibleVertexStageOverflow' ||
bindingCombination === 'vertexAndFragmentWithPossibleFragmentStageOverflow') &&
testValue > device.limits.maxStorageBuffersInVertexStage!,
`can not test ${testValue} bindings as it is more than maxStorageBuffersInVertexStage(${device.limits.maxStorageBuffersInVertexStage})`
);
}

const code = getPerStageWGSLForBindingCombination(
bindingCombination,
order,
Expand Down
43 changes: 42 additions & 1 deletion src/webgpu/api/validation/layout_shader_compat.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ValidBindableResource,
} from '../../capability_info.js';
import { GPUConst } from '../../constants.js';
import { MaxLimitsTestMixin } from '../../gpu_test.js';

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

Expand Down Expand Up @@ -156,7 +157,7 @@ const BindingResourceCompatibleWithShaderStages = function (
return true;
};

export const g = makeTestGroup(F);
export const g = makeTestGroup(MaxLimitsTestMixin(F));

g.test('pipeline_layout_shader_exact_match')
.desc(
Expand Down Expand Up @@ -195,6 +196,46 @@ g.test('pipeline_layout_shader_exact_match')
isBindingStaticallyUsed,
} = t.params;

if (t.isCompatibility) {
const bindingUsedWithVertexStage =
(shaderStageWithBinding & GPUShaderStage.VERTEX) !== 0 ||
(pipelineLayoutVisibility & GPUShaderStage.VERTEX) !== 0;
const bindingUsedWithFragmentStage =
(shaderStageWithBinding & GPUShaderStage.FRAGMENT) !== 0 ||
(pipelineLayoutVisibility & GPUShaderStage.FRAGMENT) !== 0;
const bindingIsStorageBuffer =
bindingInPipelineLayout === 'readonlyStorageBuf' ||
bindingInPipelineLayout === 'storageBuf';
const bindingIsStorageTexture =
bindingInPipelineLayout === 'readonlyStorageTex' ||
bindingInPipelineLayout === 'readwriteStorageTex' ||
bindingInPipelineLayout === 'writeonlyStorageTex';
t.skipIf(
bindingUsedWithVertexStage &&
bindingIsStorageBuffer &&
t.device.limits.maxStorageBuffersInVertexStage === 0,
'Storage buffers can not be used in vertex shaders because maxStorageBuffersInVertexStage === 0'
);
t.skipIf(
bindingUsedWithVertexStage &&
bindingIsStorageTexture &&
t.device.limits.maxStorageTexturesInVertexStage === 0,
'Storage textures can not be used in vertex shaders because maxStorageTexturesInVertexStage === 0'
);
t.skipIf(
bindingUsedWithFragmentStage &&
bindingIsStorageBuffer &&
t.device.limits.maxStorageBuffersInFragmentStage === 0,
'Storage buffers can not be used in fragment shaders because maxStorageBuffersInFragmentStage === 0'
);
t.skipIf(
bindingUsedWithFragmentStage &&
bindingIsStorageTexture &&
t.device.limits.maxStorageTexturesInFragmentStage === 0,
'Storage textures can not be used in fragment shaders because maxStorageTexturesInFragmentStage === 0'
);
}

const layout = t.createPipelineLayout(bindingInPipelineLayout, pipelineLayoutVisibility);
const bindResourceDeclaration = `@group(0) @binding(0) ${t.GetBindableResourceShaderDeclaration(
bindingInShader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Tests for resource compatibility between pipeline layout and shader modules

import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { keysOf } from '../../../../common/util/data_tables.js';
import { MaxLimitsTestMixin } from '../../../gpu_test.js';
import {
kAPIResources,
getWGSLShaderForResource,
Expand All @@ -13,7 +14,7 @@ import {

import { CreateRenderPipelineValidationTest } from './common.js';

export const g = makeTestGroup(CreateRenderPipelineValidationTest);
export const g = makeTestGroup(MaxLimitsTestMixin(CreateRenderPipelineValidationTest));

g.test('resource_compatibility')
.desc(
Expand Down Expand Up @@ -53,8 +54,36 @@ g.test('resource_compatibility')
((wgslResource.buffer !== undefined && wgslResource.buffer.type === 'storage') ||
(wgslResource.storageTexture !== undefined &&
wgslResource.storageTexture.access !== 'read-only')),
'Storage buffers and textures cannot be used in vertex shaders'
'Read-Write Storage buffers and textures cannot be used in vertex shaders'
);
if (t.isCompatibility) {
t.skipIf(
t.params.stage === 'vertex' &&
(apiResource.buffer?.type === 'storage' ||
apiResource.buffer?.type === 'read-only-storage') &&
t.device.limits.maxStorageBuffersInVertexStage === 0,
'Storage buffers can not be used in vertex shaders because maxStorageBuffersInVertexStage === 0'
);
t.skipIf(
t.params.stage === 'vertex' &&
apiResource.storageTexture !== undefined &&
t.device.limits.maxStorageTexturesInVertexStage === 0,
'Storage textures can not be used in vertex shaders because maxStorageTexturesInVertexStage === 0'
);
t.skipIf(
t.params.stage === 'fragment' &&
(apiResource.buffer?.type === 'storage' ||
apiResource.buffer?.type === 'read-only-storage') &&
t.device.limits.maxStorageBuffersInFragmentStage === 0,
'Storage buffers can not be used in fragment shaders because maxStorageBuffersInFragmentStage === 0'
);
t.skipIf(
t.params.stage === 'fragment' &&
apiResource.storageTexture !== undefined &&
t.device.limits.maxStorageTexturesInFragmentStage === 0,
'Storage textures can not be used in fragment shaders because maxStorageTexturesInFragmentStage === 0'
);
}
t.skipIfTextureViewDimensionNotSupported(wgslResource.texture?.viewDimension);
const emptyVS = `
@vertex
Expand Down
11 changes: 11 additions & 0 deletions src/webgpu/gpu_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ import {
import { createTextureFromTexelViews } from './util/texture.js';
import { reifyExtent3D, reifyOrigin3D } from './util/unions.js';

// Declarations for WebGPU items we want tests for that are not yet officially part of the spec.
declare global {
// MAINTENANCE_TODO: remove once added to @webgpu/types
interface GPUSupportedLimits {
readonly maxStorageBuffersInFragmentStage?: number;
readonly maxStorageTexturesInFragmentStage?: number;
readonly maxStorageBuffersInVertexStage?: number;
readonly maxStorageTexturesInVertexStage?: number;
}
}

const devicePool = new DevicePool();

// MAINTENANCE_TODO: When DevicePool becomes able to provide multiple devices at once, use the
Expand Down

0 comments on commit 64eb522

Please sign in to comment.