From 824ea20e657b8a04a570f359507e499ed9dbf9b6 Mon Sep 17 00:00:00 2001 From: Shrek Shao Date: Tue, 14 Jan 2025 16:14:34 -0800 Subject: [PATCH 1/3] Compat: fix float16(32)-renderable tests --- .../api/operation/render_pass/storeOp.spec.ts | 1 + .../render_pipeline/overrides.spec.ts | 6 ++++- .../pipeline_output_targets.spec.ts | 1 + .../rendering/color_target_state.spec.ts | 15 +++++++++-- .../resource_init/texture_zero.spec.ts | 6 ++++- .../operation/sampling/filter_mode.spec.ts | 5 ++++ src/webgpu/format_info.ts | 4 +++ src/webgpu/gpu_test.ts | 26 +++++++++++++++++++ .../web_platform/canvas/configure.spec.ts | 6 ++--- 9 files changed, 63 insertions(+), 7 deletions(-) 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 4ba256669d60..867ea6533598 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'; @@ -279,6 +281,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 69e058d8d1a3..6d1f9404adb9 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({ @@ -224,7 +224,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); @@ -343,7 +343,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); From 149a20b895142f7c86c3d0438b163f1dc1701ec7 Mon Sep 17 00:00:00 2001 From: Shrek Shao Date: Wed, 15 Jan 2025 09:05:31 -0800 Subject: [PATCH 2/3] revert configure change --- src/webgpu/web_platform/canvas/configure.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webgpu/web_platform/canvas/configure.spec.ts b/src/webgpu/web_platform/canvas/configure.spec.ts index 6d1f9404adb9..69e058d8d1a3 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({ @@ -224,7 +224,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); @@ -343,7 +343,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); From c02fc9099b54687d8d8a05d4942e215bd902c752 Mon Sep 17 00:00:00 2001 From: Shrek Shao Date: Thu, 16 Jan 2025 18:54:05 -0800 Subject: [PATCH 3/3] Fix after #4150 --- .../api/operation/render_pass/storeOp.spec.ts | 2 +- .../operation/render_pipeline/overrides.spec.ts | 2 +- .../pipeline_output_targets.spec.ts | 2 +- .../rendering/color_target_state.spec.ts | 13 ++++--------- .../operation/resource_init/texture_zero.spec.ts | 7 ++----- .../api/operation/sampling/filter_mode.spec.ts | 10 +++++----- src/webgpu/gpu_test.ts | 16 +++++++--------- 7 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/webgpu/api/operation/render_pass/storeOp.spec.ts b/src/webgpu/api/operation/render_pass/storeOp.spec.ts index d2c5c8b45c09..0e030f17be4a 100644 --- a/src/webgpu/api/operation/render_pass/storeOp.spec.ts +++ b/src/webgpu/api/operation/render_pass/storeOp.spec.ts @@ -152,7 +152,7 @@ g.test('render_pass_store_op,color_attachment_only') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.colorFormat); - t.skipIfFloatTextureFormatNotColorRenderable(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 d42796e95b68..b0ec9881dd68 100644 --- a/src/webgpu/api/operation/render_pipeline/overrides.spec.ts +++ b/src/webgpu/api/operation/render_pipeline/overrides.spec.ts @@ -192,7 +192,7 @@ g.test('precision') ]) ) .beforeAllSubcases(t => { - t.skipIfFloatTextureFormatNotColorRenderable(kPrecisionTestFormat); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(kPrecisionTestFormat); }) .fn(async t => { const format = kPrecisionTestFormat; 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 7e4c40ec5e23..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,7 +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.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 e95d9c7937d8..6a88d0fea192 100644 --- a/src/webgpu/api/operation/rendering/color_target_state.spec.ts +++ b/src/webgpu/api/operation/rendering/color_target_state.spec.ts @@ -203,18 +203,13 @@ g.test('blending,GPUBlendComponent') }) ) .beforeAllSubcases(t => { - const requiredFeatures = t.getFloatTextureFormatColorRenderableFeatures( - kBlendingGPUBlendComponentFormat - ); if ( IsDualSourceBlendingFactor(t.params.srcFactor) || IsDualSourceBlendingFactor(t.params.dstFactor) ) { - requiredFeatures.push('dual-source-blending'); - } - if (requiredFeatures.length > 0) { - t.selectDeviceOrSkipTestCase(requiredFeatures); + t.selectDeviceOrSkipTestCase('dual-source-blending'); } + t.selectDeviceForRenderableColorFormatOrSkipTestCase(kBlendingGPUBlendComponentFormat); }) .fn(t => { const textureFormat: GPUTextureFormat = kBlendingGPUBlendComponentFormat; @@ -400,7 +395,7 @@ g.test('blending,formats') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); }) .fn(t => { const { format } = t.params; @@ -806,7 +801,7 @@ g.test('blending,clamping') .combine('dstValue', [0.2, 0.4]) ) .beforeAllSubcases(t => { - t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); + 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 6cb3bbfdb1d8..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,11 +43,8 @@ g.test('uninitialized_texture_is_zero') .params(kTestParams) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - const requiredFeatures = [ - ...t.getFloatTextureFormatColorRenderableFeatures(t.params.format), - ...(kTextureFormatInfo[t.params.format].feature ?? []), - ] as GPUFeatureName[]; - t.selectDeviceOrSkipTestCase(requiredFeatures); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); + t.selectDeviceOrSkipTestCase(kTextureFormatInfo[t.params.format].feature); }) .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 1efc2c4a3782..ba9cb7d17a1a 100644 --- a/src/webgpu/api/operation/sampling/filter_mode.spec.ts +++ b/src/webgpu/api/operation/sampling/filter_mode.spec.ts @@ -481,7 +481,7 @@ g.test('magFilter,nearest') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -605,7 +605,7 @@ g.test('magFilter,linear') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -741,7 +741,7 @@ g.test('minFilter,nearest') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -875,7 +875,7 @@ g.test('minFilter,linear') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - t.skipIfFloatTextureFormatNotColorRenderable(t.params.format); + t.selectDeviceForRenderableColorFormatOrSkipTestCase(t.params.format); if (kTextureFormatInfo[t.params.format].color.type === 'unfilterable-float') { t.selectDeviceOrSkipTestCase('float32-filterable'); } @@ -972,7 +972,7 @@ g.test('mipmapFilter') ) .beforeAllSubcases(t => { t.skipIfTextureFormatNotSupported(t.params.format); - t.skipIfFloatTextureFormatNotColorRenderable(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/gpu_test.ts b/src/webgpu/gpu_test.ts index 867ea6533598..27a5b40321fe 100644 --- a/src/webgpu/gpu_test.ts +++ b/src/webgpu/gpu_test.ts @@ -229,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; @@ -296,15 +303,6 @@ export class GPUTestSubcaseBatchState extends SubcaseBatchState { 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) {