diff --git a/src/webgpu/api/operation/render_pass/storeOp.spec.ts b/src/webgpu/api/operation/render_pass/storeOp.spec.ts index 84a920555a17..d2c5c8b45c09 100644 --- a/src/webgpu/api/operation/render_pass/storeOp.spec.ts +++ b/src/webgpu/api/operation/render_pass/storeOp.spec.ts @@ -152,6 +152,7 @@ g.test('render_pass_store_op,color_attachment_only') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.colorFormat); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.colorFormat); }) .fn(t => { const colorAttachment = t.createTextureTracked({ diff --git a/src/webgpu/api/operation/render_pipeline/overrides.spec.ts b/src/webgpu/api/operation/render_pipeline/overrides.spec.ts index 61e2801d74e1..d42796e95b68 100644 --- a/src/webgpu/api/operation/render_pipeline/overrides.spec.ts +++ b/src/webgpu/api/operation/render_pipeline/overrides.spec.ts @@ -171,6 +171,7 @@ g.test('basic') ); }); +const kPrecisionTestFormat = 'rgba32float'; g.test('precision') .desc(`Test that the float number precision is preserved for constants`) .params(u => @@ -190,8 +191,11 @@ g.test('precision') }, ]) ) + .beforeAllSubcases(t => { + t.skipIfFloatTextureFormatNotColorRenderable(kPrecisionTestFormat); + }) .fn(async t => { - const format = 'rgba32float'; + const format = kPrecisionTestFormat; await t.ExpectShaderOutputWithConstants( t.params.isAsync, format, diff --git a/src/webgpu/api/operation/render_pipeline/pipeline_output_targets.spec.ts b/src/webgpu/api/operation/render_pipeline/pipeline_output_targets.spec.ts index fda018a7312e..7e4c40ec5e23 100644 --- a/src/webgpu/api/operation/render_pipeline/pipeline_output_targets.spec.ts +++ b/src/webgpu/api/operation/render_pipeline/pipeline_output_targets.spec.ts @@ -58,6 +58,7 @@ g.test('color,attachments') .beforeAllSubcases(t => { const info = kTextureFormatInfo[t.params.format]; t.skipIfTextureFormatNotSupported(t.params.format); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); t.selectDeviceOrSkipTestCase(info.feature); }) .fn(t => { diff --git a/src/webgpu/api/operation/rendering/color_target_state.spec.ts b/src/webgpu/api/operation/rendering/color_target_state.spec.ts index 5923cc1b063d..e95d9c7937d8 100644 --- a/src/webgpu/api/operation/rendering/color_target_state.spec.ts +++ b/src/webgpu/api/operation/rendering/color_target_state.spec.ts @@ -159,6 +159,7 @@ function computeBlendOperation( } } +const kBlendingGPUBlendComponentFormat = 'rgba16float'; g.test('blending,GPUBlendComponent') .desc( `Test all combinations of parameters for GPUBlendComponent. @@ -202,15 +203,21 @@ g.test('blending,GPUBlendComponent') }) ) .beforeAllSubcases(t => { + const requiredFeatures = t.getFloatTextureFormatColorRenderableFeatures( + kBlendingGPUBlendComponentFormat + ); if ( IsDualSourceBlendingFactor(t.params.srcFactor) || IsDualSourceBlendingFactor(t.params.dstFactor) ) { - t.selectDeviceOrSkipTestCase('dual-source-blending'); + requiredFeatures.push('dual-source-blending'); + } + if (requiredFeatures.length > 0) { + t.selectDeviceOrSkipTestCase(requiredFeatures); } }) .fn(t => { - const textureFormat: GPUTextureFormat = 'rgba16float'; + const textureFormat: GPUTextureFormat = kBlendingGPUBlendComponentFormat; const srcColor = t.params.srcColor; const srcColor1 = t.params.srcColor1; const dstColor = t.params.dstColor; @@ -393,6 +400,7 @@ g.test('blending,formats') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); }) .fn(t => { const { format } = t.params; @@ -797,6 +805,9 @@ g.test('blending,clamping') .combine('srcValue', [0.4, 0.6, 0.8, 1.0]) .combine('dstValue', [0.2, 0.4]) ) + .beforeAllSubcases(t => { + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); + }) .fn(t => { const { format, srcValue, dstValue } = t.params; diff --git a/src/webgpu/api/operation/resource_init/texture_zero.spec.ts b/src/webgpu/api/operation/resource_init/texture_zero.spec.ts index 95faa5c1837d..6cb3bbfdb1d8 100644 --- a/src/webgpu/api/operation/resource_init/texture_zero.spec.ts +++ b/src/webgpu/api/operation/resource_init/texture_zero.spec.ts @@ -43,7 +43,11 @@ g.test('uninitialized_texture_is_zero') .params(kTestParams) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - t.selectDeviceOrSkipTestCase(kTextureFormatInfo[t.params.format].feature); + const requiredFeatures = [ + ...t.getFloatTextureFormatColorRenderableFeatures(t.params.format), + ...(kTextureFormatInfo[t.params.format].feature ?? []), + ] as GPUFeatureName[]; + t.selectDeviceOrSkipTestCase(requiredFeatures); }) .fn(t => { const usage = getRequiredTextureUsage( diff --git a/src/webgpu/api/operation/sampling/filter_mode.spec.ts b/src/webgpu/api/operation/sampling/filter_mode.spec.ts index 8d32ae5e3289..1efc2c4a3782 100644 --- a/src/webgpu/api/operation/sampling/filter_mode.spec.ts +++ b/src/webgpu/api/operation/sampling/filter_mode.spec.ts @@ -481,6 +481,7 @@ g.test('magFilter,nearest') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -604,6 +605,7 @@ g.test('magFilter,linear') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -739,6 +741,7 @@ g.test('minFilter,nearest') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -872,6 +875,7 @@ g.test('minFilter,linear') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -968,6 +972,7 @@ g.test('mipmapFilter') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } diff --git a/src/webgpu/format_info.ts b/src/webgpu/format_info.ts index e65838fd2a10..8c1e9b7d7d04 100644 --- a/src/webgpu/format_info.ts +++ b/src/webgpu/format_info.ts @@ -1793,6 +1793,10 @@ export function canUseAsRenderTarget(format: GPUTextureFormat) { return kTextureFormatInfo[format].colorRender || isDepthOrStencilTextureFormat(format); } +export function is16Float(format: GPUTextureFormat) { + return format === 'r16float' || format === 'rg16float' || format === 'rgba16float'; +} + export function is32Float(format: GPUTextureFormat) { return format === 'r32float' || format === 'rg32float' || format === 'rgba32float'; } diff --git a/src/webgpu/gpu_test.ts b/src/webgpu/gpu_test.ts index 9c63f5d15d2c..259d0273aa42 100644 --- a/src/webgpu/gpu_test.ts +++ b/src/webgpu/gpu_test.ts @@ -32,6 +32,8 @@ import { isCompressedTextureFormat, ColorTextureFormat, isTextureFormatUsableAsStorageFormat, + is32Float, + is16Float, } from './format_info.js'; import { checkElementsEqual, checkElementsBetween } from './util/check_contents.js'; import { CommandBufferMaker, EncoderType } from './util/command_buffer_maker.js'; @@ -246,6 +248,30 @@ export class GPUTestSubcaseBatchState extends SubcaseBatchState { } } + getFloatTextureFormatColorRenderableFeatures(...formats: (GPUTextureFormat | undefined)[]) { + const requiredFeatures: GPUFeatureName[] = []; + if (this.isCompatibility) { + for (const format of formats) { + if (format === undefined) continue; + if (is32Float(format)) { + requiredFeatures.push('float32-renderable' as GPUFeatureName); + } else if (is16Float(format)) { + requiredFeatures.push('float16-renderable' as GPUFeatureName); + } + } + } + return requiredFeatures; + } + + /** Skips test if format is float16 or float32 and not color renderable based on device feature availability. */ + skipIfFloatTextureFormatNotColorRenderable(...formats: (GPUTextureFormat | undefined)[]) { + if (this.isCompatibility) { + this.selectDeviceOrSkipTestCase({ + requiredFeatures: this.getFloatTextureFormatColorRenderableFeatures(...formats), + }); + } + } + skipIfCopyTextureToTextureNotSupportedForFormat(...formats: (GPUTextureFormat | undefined)[]) { if (this.isCompatibility) { for (const format of formats) { diff --git a/src/webgpu/web_platform/canvas/configure.spec.ts b/src/webgpu/web_platform/canvas/configure.spec.ts index 3e9905dd5bd8..472bc008ef3f 100644 --- a/src/webgpu/web_platform/canvas/configure.spec.ts +++ b/src/webgpu/web_platform/canvas/configure.spec.ts @@ -179,7 +179,7 @@ g.test('format') format, }); const configuration = ctx.getConfiguration(); - t.expect(configuration!.format === format); + t.expect(configuration.format === format); } else { t.shouldThrow('TypeError', () => { ctx.configure({ @@ -223,7 +223,7 @@ g.test('usage') }); const configuration = ctx.getConfiguration(); - t.expect(configuration!.usage === usage); + t.expect(configuration.usage === usage); const currentTexture = ctx.getCurrentTexture(); t.expect(currentTexture instanceof GPUTexture); @@ -336,7 +336,7 @@ g.test('alpha_mode') }); const configuration = ctx.getConfiguration(); - t.expect(configuration!.alphaMode === alphaMode); + t.expect(configuration.alphaMode === alphaMode); const currentTexture = ctx.getCurrentTexture(); t.expect(currentTexture instanceof GPUTexture);