diff --git a/src/webgpu/api/operation/render_pass/storeOp.spec.ts b/src/webgpu/api/operation/render_pass/storeOp.spec.ts index 84a920555a17..0e030f17be4a 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.selectDeviceForRenderableColorFormatOrSkipTestCase(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..b0ec9881dd68 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.selectDeviceForRenderableColorFormatOrSkipTestCase(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..9fc0f1640e6d 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.selectDeviceForRenderableColorFormatOrSkipTestCase(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..6a88d0fea192 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. @@ -208,9 +209,10 @@ g.test('blending,GPUBlendComponent') ) { t.selectDeviceOrSkipTestCase('dual-source-blending'); } + t.selectDeviceForRenderableColorFormatOrSkipTestCase(kBlendingGPUBlendComponentFormat); }) .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 +395,7 @@ g.test('blending,formats') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); }) .fn(t => { const { format } = t.params; @@ -797,6 +800,9 @@ g.test('blending,clamping') .combine('srcValue', [0.4, 0.6, 0.8, 1.0]) .combine('dstValue', [0.2, 0.4]) ) + .beforeAllSubcases(t => { + t.selectDeviceForRenderableColorFormatOrSkipTestCase(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..66aadcbf0346 100644 --- a/src/webgpu/api/operation/resource_init/texture_zero.spec.ts +++ b/src/webgpu/api/operation/resource_init/texture_zero.spec.ts @@ -43,6 +43,7 @@ g.test('uninitialized_texture_is_zero') .params(kTestParams) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); t.selectDeviceOrSkipTestCase(kTextureFormatInfo[t.params.format].feature); }) .fn(t => { diff --git a/src/webgpu/api/operation/sampling/filter_mode.spec.ts b/src/webgpu/api/operation/sampling/filter_mode.spec.ts index 8d32ae5e3289..ba9cb7d17a1a 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.selectDeviceForRenderableColorFormatOrSkipTestCase(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.selectDeviceForRenderableColorFormatOrSkipTestCase(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.selectDeviceForRenderableColorFormatOrSkipTestCase(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.selectDeviceForRenderableColorFormatOrSkipTestCase(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.selectDeviceForRenderableColorFormatOrSkipTestCase(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 4ba256669d60..27a5b40321fe 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'; @@ -227,6 +229,13 @@ export class GPUTestSubcaseBatchState extends SubcaseBatchState { this.selectDeviceOrSkipTestCase(features); } + /** Skips test if format is float16 or float32 and not color renderable based on device feature availability. */ + selectDeviceForRenderableColorFormatOrSkipTestCase(...formats: (GPUTextureFormat | undefined)[]) { + this.selectDeviceOrSkipTestCase({ + requiredFeatures: this.getFloatTextureFormatColorRenderableFeatures(...formats), + }); + } + /** @internal MAINTENANCE_TODO: Make this not visible to test code? */ acquireMismatchedProvider(): Promise | undefined { return this.mismatchedProvider; @@ -279,6 +288,21 @@ 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; + } + skipIfCopyTextureToTextureNotSupportedForFormat(...formats: (GPUTextureFormat | undefined)[]) { if (this.isCompatibility) { for (const format of formats) {