From c978e0ba8c72bb43ad556dbe7978b9e098c40c8b Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Sun, 26 Apr 2026 02:01:37 -0700 Subject: [PATCH 1/2] Test createTexture() with invalid usages or combinations of usages Per spec, TRANSIENT_ATTACHMENT cannot be used in any combination of usages other than RENDER_ATTACHMENT | TRANSIENT_ATTACHMENT. --- .../api/validation/createTexture.spec.ts | 35 +++++++++++++++++++ src/webgpu/capability_info.ts | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/webgpu/api/validation/createTexture.spec.ts b/src/webgpu/api/validation/createTexture.spec.ts index a87580fa5051..1e7ba7ba99de 100644 --- a/src/webgpu/api/validation/createTexture.spec.ts +++ b/src/webgpu/api/validation/createTexture.spec.ts @@ -8,6 +8,7 @@ import { kTextureUsages, isValidTextureUsageCombination, kValidCombinationsOfOneOrTwoTextureUsages, + kAllTextureUsages, } from '../../capability_info.js'; import { GPUConst } from '../../constants.js'; import { @@ -1098,6 +1099,40 @@ g.test('depthOrArrayLayers_and_mipLevelCount_for_transient_attachments') }, !success); }); +const kInvalidUsage = 0x8000; +assert((kInvalidUsage & kAllTextureUsages) === 0); +g.test('usage') + .desc('Test combinations of zero to two usage flags are validated to be valid.') + .params(u => + u + .combine('usage1', [0, ...kTextureUsages, kInvalidUsage]) + .combine('usage2', [0, ...kTextureUsages, kInvalidUsage]) + .filter(p => p.usage1 <= p.usage2) + ) + .fn(t => { + const { usage1, usage2 } = t.params; + const usage = usage1 | usage2; + + // MAINTENANCE_TODO(#4509): Remove this after all implementations have TRANSIENT_ATTACHMENT. + if ((usage & GPUConst.TextureUsage.TRANSIENT_ATTACHMENT) !== 0) { + t.skipIfTransientAttachmentNotSupported(); + } + + const isValid = + usage !== 0 && + (usage & ~kAllTextureUsages) === 0 && + ((usage & GPUTextureUsage.TRANSIENT_ATTACHMENT) === 0 || + usage === (GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TRANSIENT_ATTACHMENT)); + + t.expectGPUError( + 'validation', + () => { + t.createTextureTracked({ format: 'rgba8unorm', size: [1, 1], usage }); + }, + !isValid + ); + }); + g.test('viewFormats') .desc( `Test creating a texture with viewFormats list for all {texture format}x{view format}. Only compatible view formats should be valid.` diff --git a/src/webgpu/capability_info.ts b/src/webgpu/capability_info.ts index 46da76f7f9cc..d4a5ea7a53cd 100644 --- a/src/webgpu/capability_info.ts +++ b/src/webgpu/capability_info.ts @@ -225,7 +225,7 @@ const kTextureUsageInfo: { /** List of all GPUTextureUsage values. */ export const kTextureUsages = numericKeysOf(kTextureUsageInfo); /** Bitmask of all known texture usages. */ -const kAllTextureUsages = kTextureUsages.reduce((acc, usage) => acc | usage, 0); +export const kAllTextureUsages = kTextureUsages.reduce((acc, usage) => acc | usage, 0); /** An arbitrary invalid texture usage bit. */ export const kSomeBogusTextureUsage: GPUTextureUsageFlags = 0x4000_0000; From a2df9b2889795bb2ca390e01a9427aa3ce3a647e Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Tue, 28 Apr 2026 13:22:51 +0200 Subject: [PATCH 2/2] address comments --- src/webgpu/api/validation/buffer/create.spec.ts | 7 +++---- src/webgpu/api/validation/createTexture.spec.ts | 7 +++---- src/webgpu/capability_info.ts | 4 ++++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/webgpu/api/validation/buffer/create.spec.ts b/src/webgpu/api/validation/buffer/create.spec.ts index b014626225f3..ecc35edc2f4b 100644 --- a/src/webgpu/api/validation/buffer/create.spec.ts +++ b/src/webgpu/api/validation/buffer/create.spec.ts @@ -8,6 +8,7 @@ import { kAllBufferUsageBits, kBufferSizeAlignment, kBufferUsages, + kSomeBogusBufferUsage, } from '../../../capability_info.js'; import { GPUConst } from '../../../constants.js'; import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js'; @@ -53,14 +54,12 @@ g.test('limit') t.expectGPUError('validation', () => t.createBufferTracked({ size, usage }), !isValid); }); -const kInvalidUsage = 0x8000; -assert((kInvalidUsage & kAllBufferUsageBits) === 0); g.test('usage') .desc('Test combinations of zero to two usage flags are validated to be valid.') .params(u => u - .combine('usage1', [0, ...kBufferUsages, kInvalidUsage]) - .combine('usage2', [0, ...kBufferUsages, kInvalidUsage]) + .combine('usage1', [0, ...kBufferUsages, kSomeBogusBufferUsage]) + .combine('usage2', [0, ...kBufferUsages, kSomeBogusBufferUsage]) .beginSubcases() .combine('mappedAtCreation', [false, true]) ) diff --git a/src/webgpu/api/validation/createTexture.spec.ts b/src/webgpu/api/validation/createTexture.spec.ts index 1e7ba7ba99de..b87bc8007e02 100644 --- a/src/webgpu/api/validation/createTexture.spec.ts +++ b/src/webgpu/api/validation/createTexture.spec.ts @@ -9,6 +9,7 @@ import { isValidTextureUsageCombination, kValidCombinationsOfOneOrTwoTextureUsages, kAllTextureUsages, + kSomeBogusTextureUsage, } from '../../capability_info.js'; import { GPUConst } from '../../constants.js'; import { @@ -1099,14 +1100,12 @@ g.test('depthOrArrayLayers_and_mipLevelCount_for_transient_attachments') }, !success); }); -const kInvalidUsage = 0x8000; -assert((kInvalidUsage & kAllTextureUsages) === 0); g.test('usage') .desc('Test combinations of zero to two usage flags are validated to be valid.') .params(u => u - .combine('usage1', [0, ...kTextureUsages, kInvalidUsage]) - .combine('usage2', [0, ...kTextureUsages, kInvalidUsage]) + .combine('usage1', [0, ...kTextureUsages, kSomeBogusTextureUsage]) + .combine('usage2', [0, ...kTextureUsages, kSomeBogusTextureUsage]) .filter(p => p.usage1 <= p.usage2) ) .fn(t => { diff --git a/src/webgpu/capability_info.ts b/src/webgpu/capability_info.ts index d4a5ea7a53cd..3d7160bb894e 100644 --- a/src/webgpu/capability_info.ts +++ b/src/webgpu/capability_info.ts @@ -77,6 +77,10 @@ export const kAllBufferUsageBits = kBufferUsages.reduce( 0 ); +/** An arbitrary invalid buffer usage bit. */ +export const kSomeBogusBufferUsage: GPUBufferUsageFlags = 0x4000_0000; +assert((kSomeBogusBufferUsage & kAllBufferUsageBits) === 0); + // Errors /** Per-GPUErrorFilter info. */