From 6e93a5f4496841b787f82c6926ecc113fe966525 Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Tue, 25 Feb 2025 16:53:19 -0800 Subject: [PATCH] Refactor src/webpgu/api/validation/encoding and a few extra Issue #4181 Issue #4178 Note: For copyTextureToTexture:texture_format_compatibility it was not at all clear to me why it was choosing textures with features. AFAICT that was testing almost nothing. Refactored it. --- .../encoding/beginComputePass.spec.ts | 18 ++-- .../encoding/beginRenderPass.spec.ts | 6 +- .../encoding/cmds/clearBuffer.spec.ts | 4 +- .../encoding/cmds/compute_pass.spec.ts | 4 +- .../encoding/cmds/copyBufferToBuffer.spec.ts | 4 +- .../cmds/copyTextureToTexture.spec.ts | 90 +++++++++---------- .../validation/encoding/cmds/debug.spec.ts | 4 +- .../encoding/cmds/index_access.spec.ts | 4 +- .../encoding/cmds/render/draw.spec.ts | 8 +- .../cmds/render/dynamic_state.spec.ts | 4 +- .../cmds/render/indirect_draw.spec.ts | 4 +- .../cmds/render/indirect_multi_draw.spec.ts | 27 ++---- .../cmds/render/setIndexBuffer.spec.ts | 4 +- .../encoding/cmds/render/setPipeline.spec.ts | 4 +- .../cmds/render/setVertexBuffer.spec.ts | 4 +- .../cmds/render/state_tracking.spec.ts | 4 +- .../encoding/cmds/render_pass.spec.ts | 4 +- .../encoding/cmds/setBindGroup.spec.ts | 4 +- .../createRenderBundleEncoder.spec.ts | 32 +++---- .../encoding/encoder_open_state.spec.ts | 25 +++--- .../validation/encoding/render_bundle.spec.ts | 13 +-- 21 files changed, 113 insertions(+), 158 deletions(-) diff --git a/src/webgpu/api/validation/encoding/beginComputePass.spec.ts b/src/webgpu/api/validation/encoding/beginComputePass.spec.ts index 4922a9016719..01c60e14b58c 100644 --- a/src/webgpu/api/validation/encoding/beginComputePass.spec.ts +++ b/src/webgpu/api/validation/encoding/beginComputePass.spec.ts @@ -4,9 +4,9 @@ Tests for validation in beginComputePass and GPUComputePassDescriptor as its opt import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { kQueryTypes } from '../../../capability_info.js'; -import { ValidationTest } from '../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { tryComputePass(success: boolean, descriptor: GPUComputePassDescriptor): void { const encoder = this.device.createCommandEncoder(); const computePass = encoder.beginComputePass(descriptor); @@ -31,11 +31,9 @@ g.test('timestampWrites,query_set_type') u // .combine('queryType', kQueryTypes) ) - .beforeAllSubcases(t => { - t.selectDeviceForQueryTypeOrSkipTestCase(['timestamp', t.params.queryType]); - }) .fn(t => { const { queryType } = t.params; + t.skipIfDeviceDoesNotSupportQueryType(queryType); const isValid = queryType === 'timestamp'; @@ -55,10 +53,8 @@ g.test('timestampWrites,query_set_type') g.test('timestampWrites,invalid_query_set') .desc(`Tests that timestampWrite that has an invalid query set generates a validation error.`) .params(u => u.combine('querySetState', ['valid', 'invalid'] as const)) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase(['timestamp-query']); - }) .fn(t => { + t.skipIfDeviceDoesNotSupportQueryType('timestamp'); const { querySetState } = t.params; const querySet = t.createQuerySetWithState(querySetState, { @@ -88,10 +84,8 @@ g.test('timestampWrites,query_index') .combine('beginningOfPassWriteIndex', [undefined, 0, 1, 2, 3] as const) .combine('endOfPassWriteIndex', [undefined, 0, 1, 2, 3] as const) ) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase(['timestamp-query']); - }) .fn(t => { + t.skipIfDeviceDoesNotSupportQueryType('timestamp'); const { beginningOfPassWriteIndex, endOfPassWriteIndex } = t.params; const querySetCount = 2; @@ -122,10 +116,10 @@ g.test('timestamp_query_set,device_mismatch') ) .paramsSubcasesOnly(u => u.combine('mismatched', [true, false])) .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase(['timestamp-query']); t.selectMismatchedDeviceOrSkipTestCase('timestamp-query'); }) .fn(t => { + t.skipIfDeviceDoesNotSupportQueryType('timestamp'); const { mismatched } = t.params; const sourceDevice = mismatched ? t.mismatchedDevice : t.device; diff --git a/src/webgpu/api/validation/encoding/beginRenderPass.spec.ts b/src/webgpu/api/validation/encoding/beginRenderPass.spec.ts index 98164559d68f..923aec3374eb 100644 --- a/src/webgpu/api/validation/encoding/beginRenderPass.spec.ts +++ b/src/webgpu/api/validation/encoding/beginRenderPass.spec.ts @@ -22,9 +22,9 @@ Notes: `; import { makeTestGroup } from '../../../../common/framework/test_group.js'; -import { ValidationTest } from '../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); g.test('color_attachments,device_mismatch') .desc( @@ -176,10 +176,10 @@ g.test('timestamp_query_set,device_mismatch') ) .paramsSubcasesOnly(u => u.combine('mismatched', [true, false])) .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase(['timestamp-query']); t.selectMismatchedDeviceOrSkipTestCase('timestamp-query'); }) .fn(t => { + t.skipIfDeviceDoesNotSupportQueryType('timestamp'); const { mismatched } = t.params; const sourceDevice = mismatched ? t.mismatchedDevice : t.device; diff --git a/src/webgpu/api/validation/encoding/cmds/clearBuffer.spec.ts b/src/webgpu/api/validation/encoding/cmds/clearBuffer.spec.ts index a903528ea756..6367097ab530 100644 --- a/src/webgpu/api/validation/encoding/cmds/clearBuffer.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/clearBuffer.spec.ts @@ -6,9 +6,9 @@ import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { kBufferUsages } from '../../../../capability_info.js'; import { kResourceStates } from '../../../../gpu_test.js'; import { kMaxSafeMultipleOf8 } from '../../../../util/math.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { TestClearBuffer(options: { buffer: GPUBuffer; offset: number | undefined; diff --git a/src/webgpu/api/validation/encoding/cmds/compute_pass.spec.ts b/src/webgpu/api/validation/encoding/cmds/compute_pass.spec.ts index b32b4a632b4f..173d81a952be 100644 --- a/src/webgpu/api/validation/encoding/cmds/compute_pass.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/compute_pass.spec.ts @@ -9,9 +9,9 @@ import { makeValueTestVariant } from '../../../../../common/util/util.js'; import { kBufferUsages } from '../../../../capability_info.js'; import { GPUConst } from '../../../../constants.js'; import { kResourceStates, ResourceState } from '../../../../gpu_test.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { createComputePipeline(state: 'valid' | 'invalid'): GPUComputePipeline { if (state === 'valid') { return this.createNoOpComputePipeline(); diff --git a/src/webgpu/api/validation/encoding/cmds/copyBufferToBuffer.spec.ts b/src/webgpu/api/validation/encoding/cmds/copyBufferToBuffer.spec.ts index e20518838dd1..b98bc03736af 100644 --- a/src/webgpu/api/validation/encoding/cmds/copyBufferToBuffer.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/copyBufferToBuffer.spec.ts @@ -27,9 +27,9 @@ import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { kBufferUsages } from '../../../../capability_info.js'; import { kResourceStates } from '../../../../gpu_test.js'; import { kMaxSafeMultipleOf8 } from '../../../../util/math.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { TestCopyBufferToBuffer(options: { srcBuffer: GPUBuffer; srcOffset: number; diff --git a/src/webgpu/api/validation/encoding/cmds/copyTextureToTexture.spec.ts b/src/webgpu/api/validation/encoding/cmds/copyTextureToTexture.spec.ts index aaf70ac10d4f..4eabbccbb25d 100644 --- a/src/webgpu/api/validation/encoding/cmds/copyTextureToTexture.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/copyTextureToTexture.spec.ts @@ -5,19 +5,21 @@ copyTextureToTexture tests. import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { kTextureUsages, kTextureDimensions } from '../../../../capability_info.js'; import { - kTextureFormatInfo, kAllTextureFormats, kCompressedTextureFormats, kDepthStencilFormats, - kFeaturesForFormats, - filterFormatsByFeature, textureDimensionAndFormatCompatible, + getBlockInfoForTextureFormat, + getBaseFormatForTextureFormat, + canCopyFromAllAspectsOfTextureFormat, + canCopyToAllAspectsOfTextureFormat, + ColorTextureFormat, } from '../../../../format_info.js'; import { kResourceStates } from '../../../../gpu_test.js'; import { align, lcm } from '../../../../util/math.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { TestCopyTextureToTexture( source: GPUTexelCopyTextureInfo, destination: GPUTexelCopyTextureInfo, @@ -45,13 +47,11 @@ class F extends ValidationTest { format: GPUTextureFormat, mipLevel: number ): Required { + const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(format); const virtualWidthAtLevel = Math.max(textureSize.width >> mipLevel, 1); const virtualHeightAtLevel = Math.max(textureSize.height >> mipLevel, 1); - const physicalWidthAtLevel = align(virtualWidthAtLevel, kTextureFormatInfo[format].blockWidth); - const physicalHeightAtLevel = align( - virtualHeightAtLevel, - kTextureFormatInfo[format].blockHeight - ); + const physicalWidthAtLevel = align(virtualWidthAtLevel, blockWidth); + const physicalHeightAtLevel = align(virtualHeightAtLevel, blockHeight); switch (dimension) { case '1d': @@ -358,28 +358,26 @@ Test the formats of textures in copyTextureToTexture must be copy-compatible. ) .params(u => u - .combine('srcFormatFeature', kFeaturesForFormats) - .combine('dstFormatFeature', kFeaturesForFormats) - .beginSubcases() - .expand('srcFormat', ({ srcFormatFeature }) => - filterFormatsByFeature(srcFormatFeature, kAllTextureFormats) - ) - .expand('dstFormat', ({ dstFormatFeature }) => - filterFormatsByFeature(dstFormatFeature, kAllTextureFormats) - ) + .combine('srcFormat', kAllTextureFormats) + .filter(t => canCopyFromAllAspectsOfTextureFormat(t.srcFormat)) + .combine('dstFormat', kAllTextureFormats) + .filter(t => canCopyToAllAspectsOfTextureFormat(t.dstFormat)) + .filter(t => { + const srcInfo = getBlockInfoForTextureFormat(t.srcFormat); + const dstInfo = getBlockInfoForTextureFormat(t.dstFormat); + return ( + srcInfo.blockWidth === dstInfo.blockWidth && srcInfo.blockHeight === dstInfo.blockHeight + ); + }) ) - .beforeAllSubcases(t => { - const { srcFormatFeature, dstFormatFeature } = t.params; - t.selectDeviceOrSkipTestCase([srcFormatFeature, dstFormatFeature]); - }) .fn(t => { const { srcFormat, dstFormat } = t.params; - t.skipIfTextureFormatNotSupportedDeprecated(srcFormat, dstFormat); - t.skipIfCopyTextureToTextureNotSupportedForFormatDeprecated(srcFormat, dstFormat); + t.skipIfTextureFormatNotSupported(srcFormat, dstFormat); + t.skipIfCopyTextureToTextureNotSupportedForFormat(srcFormat, dstFormat); - const srcFormatInfo = kTextureFormatInfo[srcFormat]; - const dstFormatInfo = kTextureFormatInfo[dstFormat]; + const srcFormatInfo = getBlockInfoForTextureFormat(srcFormat); + const dstFormatInfo = getBlockInfoForTextureFormat(dstFormat); const textureSize = { width: lcm(srcFormatInfo.blockWidth, dstFormatInfo.blockWidth), @@ -400,8 +398,10 @@ Test the formats of textures in copyTextureToTexture must be copy-compatible. }); // Allow copy between compatible format textures. - const srcBaseFormat = kTextureFormatInfo[srcFormat].baseFormat ?? srcFormat; - const dstBaseFormat = kTextureFormatInfo[dstFormat].baseFormat ?? dstFormat; + const srcBaseFormat = + getBaseFormatForTextureFormat(srcFormat as ColorTextureFormat) ?? srcFormat; + const dstBaseFormat = + getBaseFormatForTextureFormat(dstFormat as ColorTextureFormat) ?? dstFormat; const isSuccess = srcBaseFormat === dstBaseFormat; t.TestCopyTextureToTexture( @@ -448,13 +448,10 @@ Note: this is only tested for 2D textures as it is the only dimension compatible .combine('srcCopyLevel', [1, 2]) .combine('dstCopyLevel', [0, 1]) ) - .beforeAllSubcases(t => { - const { format } = t.params; - t.selectDeviceOrSkipTestCase(kTextureFormatInfo[format].feature); - }) .fn(t => { const { format, copyBoxOffsets, srcTextureSize, dstTextureSize, srcCopyLevel, dstCopyLevel } = t.params; + t.skipIfTextureFormatNotSupported(format); const kMipLevelCount = 3; const srcTexture = t.createTextureTracked({ @@ -704,12 +701,9 @@ Test the validations on the member 'aspect' of GPUTexelCopyTextureInfo in CopyTe .combine('sourceAspect', ['all', 'depth-only', 'stencil-only'] as const) .combine('destinationAspect', ['all', 'depth-only', 'stencil-only'] as const) ) - .beforeAllSubcases(t => { - const { format } = t.params; - t.selectDeviceOrSkipTestCase(kTextureFormatInfo[format].feature); - }) .fn(t => { const { format, sourceAspect, destinationAspect } = t.params; + t.skipIfTextureFormatNotSupported(format); const kTextureSize = { width: 16, height: 8, depthOrArrayLayers: 1 }; @@ -783,14 +777,13 @@ TODO: Express the offsets in "block size" so as to be able to test non-4x4 compr .combine('srcCopyLevel', [0, 1, 2]) .combine('dstCopyLevel', [0, 1, 2]) ) - .beforeAllSubcases(t => { - const { format } = t.params; - t.selectDeviceOrSkipTestCase(kTextureFormatInfo[format].feature); - t.skipIfCopyTextureToTextureNotSupportedForFormat(format); - }) .fn(t => { const { format, dimension, copyBoxOffsets, srcCopyLevel, dstCopyLevel } = t.params; - const { blockWidth, blockHeight } = kTextureFormatInfo[format]; + + t.skipIfTextureFormatNotSupported(format); + t.skipIfCopyTextureToTextureNotSupportedForFormat(format); + + const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(format); const kTextureSize = { width: 15 * blockWidth, @@ -840,14 +833,11 @@ TODO: Express the offsets in "block size" so as to be able to test non-4x4 compr const copyDepth = kTextureSize.depthOrArrayLayers + copyBoxOffsets.depthOrArrayLayers - copyOrigin.z; - const texelBlockWidth = kTextureFormatInfo[format].blockWidth; - const texelBlockHeight = kTextureFormatInfo[format].blockHeight; - const isSuccessForCompressedFormats = - copyOrigin.x % texelBlockWidth === 0 && - copyOrigin.y % texelBlockHeight === 0 && - copyWidth % texelBlockWidth === 0 && - copyHeight % texelBlockHeight === 0; + copyOrigin.x % blockWidth === 0 && + copyOrigin.y % blockHeight === 0 && + copyWidth % blockWidth === 0 && + copyHeight % blockHeight === 0; { const isSuccess = diff --git a/src/webgpu/api/validation/encoding/cmds/debug.spec.ts b/src/webgpu/api/validation/encoding/cmds/debug.spec.ts index 6032364dc2bb..7e5dad0dd639 100644 --- a/src/webgpu/api/validation/encoding/cmds/debug.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/debug.spec.ts @@ -15,9 +15,9 @@ Test Coverage: import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { kEncoderTypes } from '../../../../util/command_buffer_maker.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); g.test('debug_group_balanced') .params(u => diff --git a/src/webgpu/api/validation/encoding/cmds/index_access.spec.ts b/src/webgpu/api/validation/encoding/cmds/index_access.spec.ts index 00dc4e3042fe..090e01f3f944 100644 --- a/src/webgpu/api/validation/encoding/cmds/index_access.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/index_access.spec.ts @@ -3,9 +3,9 @@ Validation tests for indexed draws accessing the index buffer. `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { createIndexBuffer(indexData: Iterable): GPUBuffer { return this.makeBufferWithContents(new Uint32Array(indexData), GPUBufferUsage.INDEX); } diff --git a/src/webgpu/api/validation/encoding/cmds/render/draw.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/draw.spec.ts index 3dd52de47dc9..dda498a80c61 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/draw.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/draw.spec.ts @@ -7,7 +7,7 @@ and parameters as expect. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { kVertexFormatInfo } from '../../../../../capability_info.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; type VertexAttrib = A & { shaderLocation: number }; type VertexBuffer = V & { @@ -98,7 +98,7 @@ function callDraw( } function makeTestPipeline( - test: ValidationTest, + test: AllFeaturesMaxLimitsValidationTest, buffers: VertexState< { stepMode: GPUVertexStepMode; arrayStride: number }, { @@ -133,7 +133,7 @@ function makeTestPipeline( } function makeTestPipelineWithVertexAndInstanceBuffer( - test: ValidationTest, + test: AllFeaturesMaxLimitsValidationTest, arrayStride: number, attributeFormat: GPUVertexFormat, attributeOffset: number = 0 @@ -190,7 +190,7 @@ const kDefaultParameterForIndexedDraw = { indexBufferSize: 2 * 200, // exact required bound size for index buffer }; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); g.test(`unused_buffer_bound`) .desc( diff --git a/src/webgpu/api/validation/encoding/cmds/render/dynamic_state.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/dynamic_state.spec.ts index 7a85be7f0b69..c7e1c18e7b1a 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/dynamic_state.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/dynamic_state.spec.ts @@ -25,7 +25,7 @@ TODO: ensure existing tests cover these notes. Note many of these may be operati import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { MaxLimitsTestMixin } from '../../../../../gpu_test.js'; import { nextAfterF32 } from '../../../../../util/math.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; interface ViewportCall { x: number; @@ -43,7 +43,7 @@ interface ScissorCall { h: number; } -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { testViewportCall( success: boolean, v: ViewportCall, diff --git a/src/webgpu/api/validation/encoding/cmds/render/indirect_draw.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/indirect_draw.spec.ts index d60bf9431667..d0865a3c1f37 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/indirect_draw.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/indirect_draw.spec.ts @@ -5,13 +5,13 @@ Validation tests for drawIndirect/drawIndexedIndirect on render pass and render import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUConst } from '../../../../../constants.js'; import { kResourceStates } from '../../../../../gpu_test.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import { kRenderEncodeTypeParams } from './render.js'; const kIndirectDrawTestParams = kRenderEncodeTypeParams.combine('indexed', [true, false] as const); -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { makeIndexBuffer(): GPUBuffer { return this.createBufferTracked({ size: 16, diff --git a/src/webgpu/api/validation/encoding/cmds/render/indirect_multi_draw.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/indirect_multi_draw.spec.ts index f2ad688f8938..9b20ed1e797a 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/indirect_multi_draw.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/indirect_multi_draw.spec.ts @@ -10,13 +10,13 @@ import { kMaxUnsignedLongLongValue, } from '../../../../../constants.js'; import { kResourceStates } from '../../../../../gpu_test.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; const kIndirectMultiDrawTestParams = kUnitCaseParamsBuilder .combine('indexed', [true, false] as const) .combine('useDrawCountBuffer', [true, false] as const); -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { makeIndexBuffer(): GPUBuffer { return this.createBufferTracked({ size: 16, @@ -33,10 +33,6 @@ g.test('buffers_state') Tests indirect and draw count buffers must be valid. ` ) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase('chromium-experimental-multi-draw-indirect' as GPUFeatureName); - }) - .paramsSubcasesOnly( kIndirectMultiDrawTestParams .combine('indirectState', kResourceStates) @@ -52,6 +48,7 @@ Tests indirect and draw count buffers must be valid. ) ) .fn(t => { + t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName); const { indexed, indirectState, useDrawCountBuffer, drawCountState } = t.params; const indirectBuffer = t.createBufferWithState(indirectState, { size: 256, @@ -97,10 +94,10 @@ g.test('buffers,device_mismatch') .filter(p => p.useDrawCountBuffer || !p.drawCountMismatched) ) .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase('chromium-experimental-multi-draw-indirect' as GPUFeatureName); t.selectMismatchedDeviceOrSkipTestCase(undefined); }) .fn(t => { + t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName); const { indexed, useDrawCountBuffer, indirectMismatched, drawCountMismatched } = t.params; const indirectDevice = indirectMismatched ? t.mismatchedDevice : t.device; @@ -140,9 +137,6 @@ g.test('indirect_buffer_usage') Tests indirect and draw count buffers must have 'Indirect' usage. ` ) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase('chromium-experimental-multi-draw-indirect' as GPUFeatureName); - }) .paramsSubcasesOnly( kIndirectMultiDrawTestParams .combine('indirectUsage', [ @@ -157,6 +151,7 @@ Tests indirect and draw count buffers must have 'Indirect' usage. ] as const) ) .fn(t => { + t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName); const { indexed, indirectUsage, useDrawCountBuffer, drawCountUsage } = t.params; const indirectBuffer = t.createBufferTracked({ @@ -192,9 +187,6 @@ g.test('offsets_alignment') Tests indirect and draw count offsets must be a multiple of 4. ` ) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase('chromium-experimental-multi-draw-indirect' as GPUFeatureName); - }) .paramsSubcasesOnly( kIndirectMultiDrawTestParams.combineWithParams([ // Valid @@ -209,6 +201,7 @@ Tests indirect and draw count offsets must be a multiple of 4. ] as const) ) .fn(t => { + t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName); const { indexed, indirectOffset, useDrawCountBuffer, drawCountOffset } = t.params; const indirectBuffer = t.createBufferTracked({ @@ -287,10 +280,8 @@ Tests multi indirect draw calls with various indirect offsets and buffer sizes w yield { offset: 0, maxDrawCount: kMaxUnsignedLongValue, bufferSize: 1024 }; }) ) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase('chromium-experimental-multi-draw-indirect' as GPUFeatureName); - }) .fn(t => { + t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName); const { indexed, offset, maxDrawCount, bufferSize } = t.params; const indirectBuffer = t.createBufferTracked({ @@ -336,10 +327,8 @@ Tests multi indirect draw calls with various draw count offsets, and draw count { offset: kMaxUnsignedLongLongValue, bufferSize: 1024 }, ]) ) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase('chromium-experimental-multi-draw-indirect' as GPUFeatureName); - }) .fn(t => { + t.skipIfDeviceDoesNotHaveFeature('chromium-experimental-multi-draw-indirect' as GPUFeatureName); const { indexed, bufferSize, offset } = t.params; const indirectBuffer = t.createBufferTracked({ diff --git a/src/webgpu/api/validation/encoding/cmds/render/setIndexBuffer.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/setIndexBuffer.spec.ts index 829fe402ee50..f4a34c6f897d 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/setIndexBuffer.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/setIndexBuffer.spec.ts @@ -5,11 +5,11 @@ Validation tests for setIndexBuffer on render pass and render bundle. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUConst } from '../../../../../constants.js'; import { kResourceStates } from '../../../../../gpu_test.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import { kRenderEncodeTypeParams, buildBufferOffsetAndSizeOOBTestParams } from './render.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); g.test('index_buffer_state') .desc( diff --git a/src/webgpu/api/validation/encoding/cmds/render/setPipeline.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/setPipeline.spec.ts index 00624c069098..82e891c19c5e 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/setPipeline.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/setPipeline.spec.ts @@ -4,11 +4,11 @@ Validation tests for setPipeline on render pass and render bundle. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { kRenderEncodeTypes } from '../../../../../util/command_buffer_maker.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import { kRenderEncodeTypeParams } from './render.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); g.test('invalid_pipeline') .desc( diff --git a/src/webgpu/api/validation/encoding/cmds/render/setVertexBuffer.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/setVertexBuffer.spec.ts index be6ce7fe4d85..55fba5961559 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/setVertexBuffer.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/setVertexBuffer.spec.ts @@ -6,11 +6,11 @@ import { makeTestGroup } from '../../../../../../common/framework/test_group.js' import { makeValueTestVariant } from '../../../../../../common/util/util.js'; import { GPUConst } from '../../../../../constants.js'; import { kResourceStates } from '../../../../../gpu_test.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; import { kRenderEncodeTypeParams, buildBufferOffsetAndSizeOOBTestParams } from './render.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); g.test('slot') .desc( diff --git a/src/webgpu/api/validation/encoding/cmds/render/state_tracking.spec.ts b/src/webgpu/api/validation/encoding/cmds/render/state_tracking.spec.ts index 7cf229fca4d9..c2be676f09cf 100644 --- a/src/webgpu/api/validation/encoding/cmds/render/state_tracking.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render/state_tracking.spec.ts @@ -4,9 +4,9 @@ Validation tests for setVertexBuffer/setIndexBuffer state (not validation). See import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { range } from '../../../../../../common/util/util.js'; -import { ValidationTest } from '../../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { getVertexBuffer(): GPUBuffer { return this.createBufferTracked({ size: 256, diff --git a/src/webgpu/api/validation/encoding/cmds/render_pass.spec.ts b/src/webgpu/api/validation/encoding/cmds/render_pass.spec.ts index e3e881e01d1f..0d32236e2c78 100644 --- a/src/webgpu/api/validation/encoding/cmds/render_pass.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/render_pass.spec.ts @@ -9,6 +9,6 @@ TODO: `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); diff --git a/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts b/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts index e392b718825e..635e2d0b31e6 100644 --- a/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts @@ -22,9 +22,9 @@ import { kProgrammableEncoderTypes, ProgrammableEncoderType, } from '../../../../util/command_buffer_maker.js'; -import { ValidationTest } from '../../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../../validation_test.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { encoderTypeToStageFlag(encoderType: ProgrammableEncoderType): GPUShaderStageFlags { switch (encoderType) { case 'compute pass': diff --git a/src/webgpu/api/validation/encoding/createRenderBundleEncoder.spec.ts b/src/webgpu/api/validation/encoding/createRenderBundleEncoder.spec.ts index 598f2a258e9b..b5f9f4b70e76 100644 --- a/src/webgpu/api/validation/encoding/createRenderBundleEncoder.spec.ts +++ b/src/webgpu/api/validation/encoding/createRenderBundleEncoder.spec.ts @@ -9,19 +9,21 @@ import { range } from '../../../../common/util/util.js'; import { getDefaultLimits } from '../../../capability_info.js'; import { computeBytesPerSampleFromFormats, + getColorRenderByteCost, + isDepthOrStencilTextureFormat, + isTextureFormatColorRenderable, kAllTextureFormats, kDepthStencilFormats, - kTextureFormatInfo, kRenderableColorTextureFormats, } from '../../../format_info.js'; import { MaxLimitsTestMixin } from '../../../gpu_test.js'; -import { ValidationTest } from '../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; // MAINTENANCE_TODO: This should be changed to kMaxColorAttachmentsToTest // when this is made a MaxLimitTest (see above). const kMaxColorAttachments = getDefaultLimits('core').maxColorAttachments.default; -export const g = makeTestGroup(MaxLimitsTestMixin(ValidationTest)); +export const g = makeTestGroup(MaxLimitsTestMixin(AllFeaturesMaxLimitsValidationTest)); g.test('attachment_state,limits,maxColorAttachments') .desc(`Tests that attachment state must have <= device.limits.maxColorAttachments.`) @@ -62,20 +64,17 @@ g.test('attachment_state,limits,maxColorAttachmentBytesPerSample,aligned') range(kMaxColorAttachments, i => i + 1) ) ) - .beforeAllSubcases(t => { - t.skipIfTextureFormatNotSupportedDeprecated(t.params.format); - }) .fn(t => { const { format, colorFormatCount } = t.params; + t.skipIfTextureFormatNotSupported(format); const maxColorAttachments = t.device.limits.maxColorAttachments; t.skipIf( colorFormatCount > maxColorAttachments, `${colorFormatCount} > maxColorAttachments: ${maxColorAttachments}` ); - const info = kTextureFormatInfo[format]; const shouldError = - !info.colorRender || - info.colorRender.byteCost * colorFormatCount > + !isTextureFormatColorRenderable(t.device, format) || + getColorRenderByteCost(format) * colorFormatCount > t.device.limits.maxColorAttachmentBytesPerSample; t.expectValidationError(() => { @@ -166,16 +165,12 @@ g.test('valid_texture_formats') .beginSubcases() .combine('attachment', ['color', 'depthStencil']) ) - .beforeAllSubcases(t => { - const { format } = t.params; - t.selectDeviceForTextureFormatOrSkipTestCase(format); - }) .fn(t => { const { format, attachment } = t.params; + t.skipIfTextureFormatNotSupported(format); - const colorRenderable = kTextureFormatInfo[format].colorRender; - - const depthStencil = kTextureFormatInfo[format].depth || kTextureFormatInfo[format].stencil; + const colorRenderable = isTextureFormatColorRenderable(t.device, format); + const depthStencil = isDepthOrStencilTextureFormat(format); switch (attachment) { case 'color': { @@ -213,12 +208,9 @@ g.test('depth_stencil_readonly') .combine('depthReadOnly', [false, true]) .combine('stencilReadOnly', [false, true]) ) - .beforeAllSubcases(t => { - const { depthStencilFormat } = t.params; - t.selectDeviceForTextureFormatOrSkipTestCase(depthStencilFormat); - }) .fn(t => { const { depthStencilFormat, depthReadOnly, stencilReadOnly } = t.params; + t.skipIfTextureFormatNotSupported(depthStencilFormat); t.device.createRenderBundleEncoder({ colorFormats: [], depthStencilFormat, diff --git a/src/webgpu/api/validation/encoding/encoder_open_state.spec.ts b/src/webgpu/api/validation/encoding/encoder_open_state.spec.ts index 7e22ca5de888..e7d80fcbb76f 100644 --- a/src/webgpu/api/validation/encoding/encoder_open_state.spec.ts +++ b/src/webgpu/api/validation/encoding/encoder_open_state.spec.ts @@ -6,11 +6,11 @@ GPURenderPassEncoder when the encoder is not finished. import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { keysOf } from '../../../../common/util/data_tables.js'; import { unreachable } from '../../../../common/util/util.js'; -import { ValidationTest } from '../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; import { beginRenderPassWithQuerySet } from './queries/common.js'; -class F extends ValidationTest { +class F extends AllFeaturesMaxLimitsValidationTest { createRenderPipelineForTest(): GPURenderPipeline { return this.device.createRenderPipeline({ layout: 'auto', @@ -165,15 +165,11 @@ g.test('non_pass_commands') .beginSubcases() .combine('finishBeforeCommand', [false, true]) ) - .beforeAllSubcases(t => { - switch (t.params.command) { - case 'writeTimestamp': - t.selectDeviceOrSkipTestCase('timestamp-query'); - break; - } - }) .fn(t => { const { command, finishBeforeCommand } = t.params; + if (command === 'writeTimestamp') { + t.skipIfDeviceDoesNotSupportQueryType('timestamp'); + } const srcBuffer = t.createBufferTracked({ size: 16, @@ -304,14 +300,13 @@ g.test('render_pass_commands') .beginSubcases() .combine('finishBeforeCommand', [false, true]) ) - .beforeAllSubcases(t => { - const { command } = t.params; - if (command === 'multiDrawIndirect' || command === 'multiDrawIndexedIndirect') { - t.selectDeviceOrSkipTestCase('chromium-experimental-multi-draw-indirect' as GPUFeatureName); - } - }) .fn(t => { const { command, finishBeforeCommand } = t.params; + if (command === 'multiDrawIndirect' || command === 'multiDrawIndexedIndirect') { + t.skipIfDeviceDoesNotHaveFeature( + 'chromium-experimental-multi-draw-indirect' as GPUFeatureName + ); + } const querySet = t.createQuerySetTracked({ type: 'occlusion', count: 1 }); const encoder = t.device.createCommandEncoder(); diff --git a/src/webgpu/api/validation/encoding/render_bundle.spec.ts b/src/webgpu/api/validation/encoding/render_bundle.spec.ts index 35bdc9958388..49939c48b50f 100644 --- a/src/webgpu/api/validation/encoding/render_bundle.spec.ts +++ b/src/webgpu/api/validation/encoding/render_bundle.spec.ts @@ -4,9 +4,9 @@ Tests execution of render bundles. import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { kDepthStencilFormats } from '../../../format_info.js'; -import { ValidationTest } from '../validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from '../validation_test.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); g.test('empty_bundle_list') .desc( @@ -130,12 +130,9 @@ g.test('depth_stencil_formats_mismatch') { bundleFormat: 'stencil8', passFormat: 'depth24plus-stencil8' }, ] as const) ) - .beforeAllSubcases(t => { - const { bundleFormat, passFormat } = t.params; - t.selectDeviceForTextureFormatOrSkipTestCase([bundleFormat, passFormat]); - }) .fn(t => { const { bundleFormat, passFormat } = t.params; + t.skipIfTextureFormatNotSupported(bundleFormat, passFormat); const compatible = bundleFormat === passFormat; const bundleEncoder = t.device.createRenderBundleEncoder({ @@ -171,9 +168,6 @@ g.test('depth_stencil_readonly_mismatch') .combine('passDepthReadOnly', [false, true]) .combine('passStencilReadOnly', [false, true]) ) - .beforeAllSubcases(t => { - t.selectDeviceForTextureFormatOrSkipTestCase(t.params.depthStencilFormat); - }) .fn(t => { const { depthStencilFormat, @@ -182,6 +176,7 @@ g.test('depth_stencil_readonly_mismatch') passDepthReadOnly, passStencilReadOnly, } = t.params; + t.skipIfTextureFormatNotSupported(depthStencilFormat); const compatible = (!passDepthReadOnly || bundleDepthReadOnly === passDepthReadOnly) &&