Skip to content

Commit

Permalink
Refactor src/webpgu/api/validation/encoding and a few extra
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
greggman committed Feb 26, 2025
1 parent c34b24e commit 9a40a97
Show file tree
Hide file tree
Showing 21 changed files with 113 additions and 158 deletions.
18 changes: 6 additions & 12 deletions src/webgpu/api/validation/encoding/beginComputePass.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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';

Expand All @@ -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, {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
6 changes: 3 additions & 3 deletions src/webgpu/api/validation/encoding/beginRenderPass.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions src/webgpu/api/validation/encoding/cmds/clearBuffer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/webgpu/api/validation/encoding/cmds/compute_pass.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -45,13 +47,11 @@ class F extends ValidationTest {
format: GPUTextureFormat,
mipLevel: number
): Required<GPUExtent3DDict> {
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':
Expand Down Expand Up @@ -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),
Expand All @@ -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(
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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 };

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 =
Expand Down
4 changes: 2 additions & 2 deletions src/webgpu/api/validation/encoding/cmds/debug.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
Expand Down
4 changes: 2 additions & 2 deletions src/webgpu/api/validation/encoding/cmds/index_access.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<number>): GPUBuffer {
return this.makeBufferWithContents(new Uint32Array(indexData), GPUBufferUsage.INDEX);
}
Expand Down
8 changes: 4 additions & 4 deletions src/webgpu/api/validation/encoding/cmds/render/draw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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> = A & { shaderLocation: number };
type VertexBuffer<V, A> = V & {
Expand Down Expand Up @@ -98,7 +98,7 @@ function callDraw(
}

function makeTestPipeline(
test: ValidationTest,
test: AllFeaturesMaxLimitsValidationTest,
buffers: VertexState<
{ stepMode: GPUVertexStepMode; arrayStride: number },
{
Expand Down Expand Up @@ -133,7 +133,7 @@ function makeTestPipeline(
}

function makeTestPipelineWithVertexAndInstanceBuffer(
test: ValidationTest,
test: AllFeaturesMaxLimitsValidationTest,
arrayStride: number,
attributeFormat: GPUVertexFormat,
attributeOffset: number = 0
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -43,7 +43,7 @@ interface ScissorCall {
h: number;
}

class F extends ValidationTest {
class F extends AllFeaturesMaxLimitsValidationTest {
testViewportCall(
success: boolean,
v: ViewportCall,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 9a40a97

Please sign in to comment.