Skip to content

Commit 2127eae

Browse files
committed
Add immediate size validation cases for pipeline creation
Add cases to validate immediate size checks during both compute and render pipeline creation.
1 parent 0ca53dd commit 2127eae

5 files changed

Lines changed: 279 additions & 110 deletions

File tree

src/common/util/util.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,23 @@ export function combinationsOfOneOrTwoUsages(usages: readonly number[]) {
518518
}
519519
return combinations;
520520
}
521+
522+
/**
523+
* Checks if the browser supports immediate data (experimental).
524+
*
525+
* Checks for:
526+
* - `setImmediates` method on `GPURenderPassEncoder`, `GPUComputePassEncoder`, or `GPURenderBundleEncoder` prototypes.
527+
* - `maxImmediateSize` property on `GPUSupportedLimits` prototype.
528+
* - `immediate_address_space` feature in `gpu.wgslLanguageFeatures`.
529+
*
530+
* This helper is used to skip tests when the environment does not support immediate data functionality.
531+
*/
532+
export function supportsImmediateData(gpu: GPU): boolean {
533+
return (
534+
'setImmediates' in GPURenderPassEncoder.prototype ||
535+
'setImmediates' in GPUComputePassEncoder.prototype ||
536+
'setImmediates' in GPURenderBundleEncoder.prototype ||
537+
'maxImmediateSize' in GPUSupportedLimits.prototype ||
538+
gpu.wgslLanguageFeatures.has('immediate_address_space')
539+
);
540+
}

src/resources/cache/hashes.json

Lines changed: 110 additions & 110 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 Bytes
Binary file not shown.

src/webgpu/api/validation/compute_pipeline.spec.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Note: entry point matching tests are in shader_module/entry_point.spec.ts
77
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
88
import { makeTestGroup } from '../../../common/framework/test_group.js';
99
import { keysOf } from '../../../common/util/data_tables.js';
10+
import { getGPU } from '../../../common/util/navigator_gpu.js';
11+
import { supportsImmediateData } from '../../../common/util/util.js';
1012
import {
1113
isTextureFormatUsableWithStorageAccessMode,
1214
kPossibleStorageTextureFormats,
@@ -811,3 +813,71 @@ generates a validation error at createComputePipeline(Async)
811813
};
812814
vtu.doCreateComputePipelineTest(t, isAsync, success, descriptor);
813815
});
816+
817+
g.test('pipeline_creation_immediate_size_mismatch')
818+
.desc(
819+
`
820+
Validate that creating a pipeline fails if the shader uses immediate data
821+
larger than the immediateSize specified in the pipeline layout, or larger than
822+
maxImmediateSize if layout is 'auto'.
823+
Also validates that using less or equal size is allowed.
824+
`
825+
)
826+
.params(u =>
827+
u.combine('isAsync', [true, false]).combineWithParams([
828+
{ shaderSize: 16, layoutSize: 16 }, // Equal
829+
{ shaderSize: 12, layoutSize: 16 }, // Shader smaller
830+
{ shaderSize: 20, layoutSize: 16 }, // Shader larger (small diff)
831+
{ shaderSize: 32, layoutSize: 16 }, // Shader larger
832+
{ shaderSize: 'max', layoutSize: 'auto' }, // Shader equal to limit (auto layout)
833+
{ shaderSize: 'max+4', layoutSize: 'auto' }, // Shader larger than limit (auto layout)
834+
] as const)
835+
)
836+
.fn(t => {
837+
if (!supportsImmediateData(getGPU(t.rec))) {
838+
t.skip('Immediate data not supported');
839+
}
840+
841+
const { isAsync, shaderSize, layoutSize } = t.params;
842+
843+
const maxImmediateSize = t.device.limits.maxImmediateSize!;
844+
845+
let actualLayout: GPUPipelineLayout | 'auto';
846+
let validSize: number;
847+
848+
if (layoutSize === 'auto') {
849+
actualLayout = 'auto';
850+
// checked above
851+
validSize = maxImmediateSize!;
852+
} else {
853+
actualLayout = t.device.createPipelineLayout({
854+
bindGroupLayouts: [],
855+
immediateSize: layoutSize as number,
856+
});
857+
validSize = layoutSize as number;
858+
}
859+
860+
let actualShaderSize: number;
861+
if (shaderSize === 'max') {
862+
actualShaderSize = validSize;
863+
} else if (shaderSize === 'max+4') {
864+
actualShaderSize = validSize + 4;
865+
} else {
866+
actualShaderSize = shaderSize as number;
867+
}
868+
869+
const code = `
870+
var<immediate> data: array<u32, ${actualShaderSize / 4}>;
871+
fn use() { _ = data[0]; }
872+
@compute @workgroup_size(1) fn main_compute() { use(); }
873+
`;
874+
875+
const shouldError = actualShaderSize > validSize;
876+
877+
vtu.doCreateComputePipelineTest(t, isAsync, !shouldError, {
878+
layout: actualLayout,
879+
compute: {
880+
module: t.device.createShaderModule({ code }),
881+
},
882+
});
883+
});

0 commit comments

Comments
 (0)