Skip to content

Refactor textureDimensions and textureLoad tests for texture formats #4199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/webgpu/format_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,13 @@ const kTextureFormatInfo_TypeCheck: {
readonly [F in GPUTextureFormat]: TextureFormatInfo_TypeCheck;
} = kTextureFormatInfo;

// Depth texture formats including formats that also support stencil
export const kDepthTextureFormats = kDepthStencilFormats.filter(v => kTextureFormatInfo[v].depth);
// Stencil texture formats including formats that also support depth
export const kStencilTextureFormats = kDepthStencilFormats.filter(
v => kTextureFormatInfo[v].stencil
);

// Texture formats that may possibly be used as a storage texture.
// Some may require certain features to be enabled.
export const kPossibleStorageTextureFormats = [
Expand Down Expand Up @@ -1917,6 +1924,23 @@ export function isTextureFormatPossiblyUsableAsRenderAttachment(format: GPUTextu
return format === 'rg11b10ufloat' || isDepthOrStencilTextureFormat(format) || !!info.colorRender;
}

/**
* Returns true if a texture can possibly be used multisampled.
* The texture may require certain features to be enabled.
*/
export function isTextureFormatPossiblyMultisampled(format: GPUTextureFormat) {
const info = kTextureFormatInfo[format];
return format === 'rg11b10ufloat' || info.multisample;
}

/**
* Returns true if a texture can possibly be used as a writable storage texture.
* The texture may require certain features to be enabled.
*/
export function isTextureFormatPossiblyStorageWritable(format: GPUTextureFormat) {
return kTextureFormatInfo[format].color?.readWriteStorage;
}

export function is16Float(format: GPUTextureFormat) {
return format === 'r16float' || format === 'rg16float' || format === 'rgba16float';
}
Expand Down
13 changes: 13 additions & 0 deletions src/webgpu/gpu_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,19 @@ export class GPUTestBase extends Fixture<GPUTestSubcaseBatchState> {
}
}

skipIfTextureLoadNotSupportedForTextureType(...types: (string | undefined | null)[]) {
if (this.isCompatibility) {
for (const type of types) {
switch (type) {
case 'texture_depth_2d':
case 'texture_depth_2d_array':
case 'texture_depth_multisampled_2d':
this.skip(`${type} is not supported by textureLoad in compatibility mode`);
}
}
}
}

skipIfTextureFormatNotUsableAsStorageTexture(...formats: (GPUTextureFormat | undefined)[]) {
for (const format of formats) {
if (format && !isTextureFormatUsableAsStorageFormat(this.device, format)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ If level is outside the range [0, textureNumLevels(t)) then any valid value for

import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import {
getBlockInfoForTextureFormat,
isDepthTextureFormat,
isStencilTextureFormat,
isTextureFormatPossiblyMultisampled,
isTextureFormatPossiblyStorageWritable,
kAllTextureFormats,
kColorTextureFormats,
kTextureFormatInfo,
kDepthTextureFormats,
kPossibleStorageTextureFormats,
sampleTypeForFormatAndAspect,
textureDimensionAndFormatCompatible,
} from '../../../../../format_info.js';
Expand Down Expand Up @@ -41,17 +46,15 @@ const kAllViewDimensions: readonly GPUTextureViewDimension[] = [

/** @returns the aspects to test for the given format */
function aspectsForFormat(format: GPUTextureFormat): readonly GPUTextureAspect[] {
const formatInfo = kTextureFormatInfo[format];
if (formatInfo.depth !== undefined && formatInfo.stencil !== undefined) {
if (isDepthTextureFormat(format) && isStencilTextureFormat(format)) {
return ['depth-only', 'stencil-only'];
}
return ['all'];
}

/** @returns the sample counts to test for the given format */
function samplesForFormat(format: GPUTextureFormat): readonly number[] {
const info = kTextureFormatInfo[format];
return info.multisample ? [1, kMaxSamplesForTest] : [1];
return isTextureFormatPossiblyMultisampled(format) ? [1, kMaxSamplesForTest] : [1];
}

/**
Expand Down Expand Up @@ -157,7 +160,7 @@ function testValues(params: {
const kMinLen = 1 << kMaxMipsForTest;
const kNumCubeFaces = 6;

const formatInfo = kTextureFormatInfo[params.format];
const formatInfo = getBlockInfoForTextureFormat(params.format);
const bw = formatInfo.blockWidth;
const bh = formatInfo.blockHeight;
let mip = params.baseMipLevel;
Expand Down Expand Up @@ -286,7 +289,6 @@ Parameters:
.params(u =>
u
.combine('format', kAllTextureFormats)
.unless(p => kTextureFormatInfo[p.format].color?.type === 'unfilterable-float')
.expand('aspect', u => aspectsForFormat(u.format))
.expand('samples', u => samplesForFormat(u.format))
.beginSubcases()
Expand All @@ -296,17 +298,12 @@ Parameters:
.expand('baseMipLevel', baseMipLevel)
.expand('textureDimensionsLevel', textureDimensionsLevel)
)
.beforeAllSubcases(t => {
const info = kTextureFormatInfo[t.params.format];
t.skipIfTextureFormatNotSupportedDeprecated(t.params.format);
.fn(t => {
t.skipIfTextureFormatNotSupported(t.params.format);
t.skipIfTextureViewDimensionNotSupported(t.params.dimensions);
if (t.params.samples > 1) {
// multisampled texture requires GPUTextureUsage.RENDER_ATTACHMENT usage
t.skipIfMultisampleNotSupportedForFormatDeprecated(t.params.format);
t.skipIfTextureFormatNotMultisampled(t.params.format);
}
t.selectDeviceOrSkipTestCase(info.feature);
})
.fn(t => {
t.skipIfTextureViewDimensionNotSupportedDeprecated(t.params.dimensions);
const values = testValues(t.params);
const texture = t.createTextureTracked({
size: values.size,
Expand All @@ -333,13 +330,12 @@ Parameters:
switch (sampleType) {
case 'depth':
case 'float':
case 'unfilterable-float':
return `${base}_${dimensions}<f32>`;
case 'uint':
return `${base}_${dimensions}<u32>`;
case 'sint':
return `${base}_${dimensions}<i32>`;
case 'unfilterable-float':
throw new Error(`'${t.params.format}' does not support sampling`);
}
}

Expand Down Expand Up @@ -377,8 +373,7 @@ Parameters:
)
.params(u =>
u
.combine('format', kAllTextureFormats)
.filter(p => !!kTextureFormatInfo[p.format].depth)
.combine('format', kDepthTextureFormats)
.expand('aspect', u => aspectsForFormat(u.format))
.unless(u => u.aspect === 'stencil-only')
.expand('samples', u => samplesForFormat(u.format))
Expand All @@ -389,13 +384,9 @@ Parameters:
.expand('baseMipLevel', baseMipLevel)
.expand('textureDimensionsLevel', textureDimensionsLevel)
)
.beforeAllSubcases(t => {
const info = kTextureFormatInfo[t.params.format];
t.skipIfTextureFormatNotSupportedDeprecated(t.params.format);
t.selectDeviceOrSkipTestCase(info.feature);
})
.fn(t => {
t.skipIfTextureViewDimensionNotSupportedDeprecated(t.params.dimensions);
t.skipIfTextureFormatNotSupported(t.params.format);
t.skipIfTextureViewDimensionNotSupported(t.params.dimensions);
const values = testValues(t.params);
const texture = t.createTextureTracked({
size: values.size,
Expand Down Expand Up @@ -465,31 +456,23 @@ Parameters:
)
.params(u =>
u
.combine('format', kColorTextureFormats)
.filter(p => kTextureFormatInfo[p.format].color?.storage === true)
.combine('format', kPossibleStorageTextureFormats)
.expand('aspect', u => aspectsForFormat(u.format))
.beginSubcases()
.combine('stage', kShaderStages)
.combine('access', ['read', 'write', 'read_write'] as const)
// vertex stage can not use writable storage.
.unless(t => t.stage === 'vertex' && t.access !== 'read')
// Only some formats support write
.unless(
t =>
kTextureFormatInfo[t.format].color.readWriteStorage === false && t.access === 'read_write'
)
.unless(t => !isTextureFormatPossiblyStorageWritable(t.format) && t.access === 'read_write')
.expand('dimensions', u => viewDimensions(u).filter(dimensionsValidForStorage))
.expand('textureMipCount', textureMipCount)
.expand('baseMipLevel', baseMipLevel)
)
.beforeAllSubcases(t => {
const info = kTextureFormatInfo[t.params.format];
t.skipIfTextureFormatNotSupportedDeprecated(t.params.format);
t.skipIfTextureFormatNotUsableAsStorageTextureDeprecated(t.params.format);
t.selectDeviceOrSkipTestCase(info.feature);
})
.fn(t => {
t.skipIfNoStorageTexturesInStage(t.params.stage);
t.skipIfTextureFormatNotSupported(t.params.format);
t.skipIfTextureFormatNotUsableAsStorageTexture(t.params.format);

const values = testValues(t.params);
const texture = t.createTextureTracked({
Expand Down
Loading