From b959c309e74c6758d6cd5dd578e58dcadae76acd Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Thu, 20 Feb 2025 13:38:39 -0800 Subject: [PATCH] Refactor createView test for texture formats. Issue #4181 --- src/webgpu/api/validation/createView.spec.ts | 77 ++++++++------------ src/webgpu/format_info.ts | 22 ++++++ src/webgpu/gpu_test.ts | 24 ++++++ 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/webgpu/api/validation/createView.spec.ts b/src/webgpu/api/validation/createView.spec.ts index 3d43342df6b..a46e64db197 100644 --- a/src/webgpu/api/validation/createView.spec.ts +++ b/src/webgpu/api/validation/createView.spec.ts @@ -11,11 +11,14 @@ import { } from '../../capability_info.js'; import { GPUConst } from '../../constants.js'; import { - kTextureFormatInfo, kAllTextureFormats, kFeaturesForFormats, filterFormatsByFeature, - viewCompatibleDeprecated, + textureFormatsAreViewCompatible, + isDepthTextureFormat, + isStencilTextureFormat, + getBlockInfoForTextureFormat, + isTextureFormatPossiblyUsableAsRenderAttachment, } from '../../format_info.js'; import { kResourceStates } from '../../gpu_test.js'; import { @@ -25,9 +28,9 @@ import { } from '../../util/texture/base.js'; import { reifyExtent3D } from '../../util/unions.js'; -import { ValidationTest } from './validation_test.js'; +import { AllFeaturesMaxLimitsValidationTest } from './validation_test.js'; -export const g = makeTestGroup(ValidationTest); +export const g = makeTestGroup(AllFeaturesMaxLimitsValidationTest); const kLevels = 6; @@ -48,19 +51,15 @@ g.test('format') ) .combine('useViewFormatList', [false, true]) ) - .beforeAllSubcases(t => { - const { textureFormatFeature, viewFormatFeature } = t.params; - t.selectDeviceOrSkipTestCase([textureFormatFeature, viewFormatFeature]); - }) .fn(t => { const { textureFormat, viewFormat, useViewFormatList } = t.params; - const { blockWidth, blockHeight } = kTextureFormatInfo[textureFormat]; + const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(textureFormat); - t.skipIfTextureFormatNotSupportedDeprecated(textureFormat, viewFormat); + t.skipIfTextureFormatNotSupported(textureFormat, viewFormat); const compatible = viewFormat === undefined || - viewCompatibleDeprecated(t.isCompatibility, textureFormat, viewFormat); + textureFormatsAreViewCompatible(t.device, textureFormat, viewFormat); const texture = t.createTextureTracked({ format: textureFormat, @@ -94,11 +93,9 @@ g.test('dimension') .combine('textureDimension', kTextureDimensions) .combine('viewDimension', [...kTextureViewDimensions, undefined]) ) - .beforeAllSubcases(t => { - t.skipIfTextureViewDimensionNotSupportedDeprecated(t.params.viewDimension); - }) .fn(t => { const { textureDimension, viewDimension } = t.params; + t.skipIfTextureViewDimensionNotSupported(t.params.viewDimension); const size = textureDimension === '1d' ? [4] : [4, 4, 6]; const textureDescriptor = { @@ -130,24 +127,22 @@ g.test('aspect') .combine('format', kAllTextureFormats) .combine('aspect', kTextureAspects) ) - .beforeAllSubcases(t => { - const { format } = t.params; - t.selectDeviceForTextureFormatOrSkipTestCase(format); - }) .fn(t => { const { format, aspect } = t.params; - const info = kTextureFormatInfo[format]; + const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(format); + + t.skipIfTextureFormatNotSupported(format); const texture = t.createTextureTracked({ format, - size: [info.blockWidth, info.blockHeight, 1], + size: [blockWidth, blockHeight, 1], usage: GPUTextureUsage.TEXTURE_BINDING, }); const success = aspect === 'all' || - (aspect === 'depth-only' && info.depth) || - (aspect === 'stencil-only' && info.stencil); + (aspect === 'depth-only' && isDepthTextureFormat(format)) || + (aspect === 'stencil-only' && isStencilTextureFormat(format)); t.expectValidationError(() => { texture.createView({ aspect }); }, !success); @@ -277,7 +272,7 @@ g.test('mip_levels') const { textureDimension, viewDimension, textureLevels, baseMipLevel, mipLevelCount } = t.params; - t.skipIfTextureViewDimensionNotSupportedDeprecated(viewDimension); + t.skipIfTextureViewDimensionNotSupported(viewDimension); const textureDescriptor: GPUTextureDescriptor = { format: 'rgba8unorm', @@ -317,7 +312,7 @@ g.test('cube_faces_square') .fn(t => { const { dimension, size } = t.params; - t.skipIfTextureViewDimensionNotSupportedDeprecated(dimension); + t.skipIfTextureViewDimensionNotSupported(dimension); const texture = t.createTextureTracked({ format: 'rgba8unorm', @@ -352,43 +347,31 @@ g.test('texture_view_usage') .combine('format', kAllTextureFormats) .combine('textureUsage0', kTextureUsages) .combine('textureUsage1', kTextureUsages) - .filter(({ format, textureUsage0, textureUsage1 }) => { - const info = kTextureFormatInfo[format]; + .unless(({ format, textureUsage0, textureUsage1 }) => { const textureUsage = textureUsage0 | textureUsage1; - - if ( + return ( (textureUsage & GPUConst.TextureUsage.RENDER_ATTACHMENT) !== 0 && - info.color && - !info.colorRender - ) { - return false; - } - - return true; + !isTextureFormatPossiblyUsableAsRenderAttachment(format) + ); }) .beginSubcases() .combine('textureViewUsage0', [0, ...kTextureUsages]) .combine('textureViewUsage1', [0, ...kTextureUsages]) ) - .beforeAllSubcases(t => { - const { format, textureUsage0, textureUsage1 } = t.params; - const info = kTextureFormatInfo[format]; - const textureUsage = textureUsage0 | textureUsage1; - t.skipIfTextureFormatNotSupportedDeprecated(format); - t.selectDeviceOrSkipTestCase(info.feature); - if (textureUsage & GPUTextureUsage.STORAGE_BINDING) { - t.skipIfTextureFormatNotUsableAsStorageTextureDeprecated(format); - } - }) .fn(t => { const { format, textureUsage0, textureUsage1, textureViewUsage0, textureViewUsage1 } = t.params; - const info = kTextureFormatInfo[format]; - const size = [info.blockWidth, info.blockHeight, 1]; + t.skipIfTextureFormatNotSupported(format); + + const { blockWidth, blockHeight } = getBlockInfoForTextureFormat(format); + + const size = [blockWidth, blockHeight, 1]; const dimension = '2d'; const mipLevelCount = 1; const usage = textureUsage0 | textureUsage1; + t.skipIfTextureFormatDoesNotSupportUsage(usage, format); + const textureDescriptor: GPUTextureDescriptor = { size, mipLevelCount, diff --git a/src/webgpu/format_info.ts b/src/webgpu/format_info.ts index 739a4ec093a..f5f072e597d 100644 --- a/src/webgpu/format_info.ts +++ b/src/webgpu/format_info.ts @@ -1784,6 +1784,19 @@ export function getBlockInfoForColorTextureFormat(format: ColorTextureFormat) { }; } +/** + * Gets the block width, height, and bytes per block for a color texture format. + * Note that bytesPerBlock will be undefined if format's size is undefined. + */ +export function getBlockInfoForTextureFormat(format: GPUTextureFormat) { + const info = kTextureFormatInfo[format]; + return { + blockWidth: info.blockWidth, + blockHeight: info.blockHeight, + bytesPerBlock: info.color?.bytes ?? info.depth?.bytes ?? info.stencil?.bytes, + }; +} + /** * Gets the baseFormat for a texture format. */ @@ -1863,6 +1876,15 @@ export function isTextureFormatColorRenderable( return !!kAllTextureFormatInfo[format].colorRender; } +/** + * Returns true of a texture can possibly be used as a render attachment. + * The texture may require certain features to be enabled. + */ +export function isTextureFormatPossiblyUsableAsRenderAttachment(format: GPUTextureFormat) { + const info = kTextureFormatInfo[format]; + return format === 'rg11b10ufloat' || isDepthOrStencilTextureFormat(format) || !!info.colorRender; +} + export function is16Float(format: GPUTextureFormat) { return format === 'r16float' || format === 'rg16float' || format === 'rgba16float'; } diff --git a/src/webgpu/gpu_test.ts b/src/webgpu/gpu_test.ts index 4046510730d..dbbab91fbed 100644 --- a/src/webgpu/gpu_test.ts +++ b/src/webgpu/gpu_test.ts @@ -35,6 +35,7 @@ import { isTextureFormatUsableAsStorageFormatDeprecated, isMultisampledTextureFormatDeprecated, isTextureFormatUsableAsStorageFormat, + isTextureFormatUsableAsRenderAttachment, } from './format_info.js'; import { checkElementsEqual, checkElementsBetween } from './util/check_contents.js'; import { CommandBufferMaker, EncoderType } from './util/command_buffer_maker.js'; @@ -613,6 +614,29 @@ export class GPUTestBase extends Fixture { } } + skipIfTextureFormatNotUsableAsRenderAttachment(...formats: (GPUTextureFormat | undefined)[]) { + for (const format of formats) { + if (format && !isTextureFormatUsableAsRenderAttachment(this.device, format)) { + this.skip(`Texture with ${format} is not usable as a render attachment`); + } + } + } + + skipIfTextureFormatDoesNotSupportUsage( + usage: GPUTextureUsageFlags, + ...formats: (GPUTextureFormat | undefined)[] + ) { + for (const format of formats) { + if (!format) continue; + if (usage & GPUTextureUsage.RENDER_ATTACHMENT) { + this.skipIfTextureFormatNotUsableAsRenderAttachment(format); + } + if (usage & GPUTextureUsage.STORAGE_BINDING) { + this.skipIfTextureFormatNotUsableAsStorageTexture(format); + } + } + } + /** Skips this test case if the `langFeature` is *not* supported. */ skipIfLanguageFeatureNotSupported(langFeature: WGSLLanguageFeature) { if (!this.hasLanguageFeature(langFeature)) {