Skip to content

Refactor render_pass_descriptor tests for texture formats. #4197

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 1 commit into from
Feb 21, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ import { GPUConst } from '../../../constants.js';
import {
computeBytesPerSampleFromFormats,
kDepthStencilFormats,
kRenderableColorTextureFormats,
kTextureFormatInfo,
kPossiblyRenderableColorTextureFormats,
isTextureFormatColorRenderable,
isDepthTextureFormat,
isStencilTextureFormat,
isTextureFormatResolvable,
} from '../../../format_info.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;

class F extends ValidationTest {
class F extends AllFeaturesMaxLimitsValidationTest {
createTestTexture(
options: {
format?: GPUTextureFormat;
Expand Down Expand Up @@ -202,20 +205,18 @@ g.test('color_attachments,limits,maxColorAttachmentBytesPerSample,aligned')
)
.params(u =>
u
.combine('format', kRenderableColorTextureFormats)
.combine('format', kPossiblyRenderableColorTextureFormats)
.beginSubcases()
.combine(
'attachmentCount',
range(kMaxColorAttachments, i => i + 1)
)
)
.beforeAllSubcases(t => {
t.skipIfTextureFormatNotSupportedDeprecated(t.params.format);
})
.fn(t => {
const { format, attachmentCount } = t.params;
const info = kTextureFormatInfo[format];

t.skipIfTextureFormatNotSupported(format);
t.skipIfTextureFormatNotUsableAsRenderAttachment(format);
t.skipIf(
attachmentCount > t.device.limits.maxColorAttachments,
`attachmentCount: ${attachmentCount} > maxColorAttachments: ${t.device.limits.maxColorAttachments}`
Expand All @@ -227,7 +228,7 @@ g.test('color_attachments,limits,maxColorAttachmentBytesPerSample,aligned')
colorAttachments.push(t.getColorAttachment(colorTexture));
}
const shouldError =
info.colorRender === undefined ||
!isTextureFormatColorRenderable(t.device, format) ||
computeBytesPerSampleFromFormats(range(attachmentCount, () => format)) >
t.device.limits.maxColorAttachmentBytesPerSample;

Expand Down Expand Up @@ -1049,10 +1050,6 @@ g.test('depth_stencil_attachment,loadOp_storeOp_match_depthReadOnly_stencilReadO
.combine('stencilLoadOp', [undefined, 'clear', 'load'] as GPULoadOp[])
.combine('stencilStoreOp', [undefined, 'discard', 'store'] as GPUStoreOp[])
)
.beforeAllSubcases(t => {
const info = kTextureFormatInfo[t.params.format as GPUTextureFormat];
t.selectDeviceOrSkipTestCase(info.feature);
})
.fn(t => {
const {
format,
Expand All @@ -1064,6 +1061,8 @@ g.test('depth_stencil_attachment,loadOp_storeOp_match_depthReadOnly_stencilReadO
stencilStoreOp,
} = t.params;

t.skipIfTextureFormatNotSupported(format);

const depthAttachment = t.createTextureTracked({
format,
size: { width: 1, height: 1, depthOrArrayLayers: 1 },
Expand Down Expand Up @@ -1092,11 +1091,10 @@ g.test('depth_stencil_attachment,loadOp_storeOp_match_depthReadOnly_stencilReadO
const pass = encoder.beginRenderPass(renderPassDescriptor);
pass.end();

const info = kTextureFormatInfo[format];
const hasDepthSettings = !!depthLoadOp && !!depthStoreOp && !depthReadOnly;
const hasStencilSettings = !!stencilLoadOp && !!stencilStoreOp && !stencilReadOnly;
const hasDepth = info.depth;
const hasStencil = info.stencil;
const hasDepth = isDepthTextureFormat(format);
const hasStencil = isStencilTextureFormat(format);

const goodAspectSettingsPresent =
(hasDepthSettings ? hasDepth : true) && (hasStencilSettings ? hasStencil : true);
Expand Down Expand Up @@ -1162,27 +1160,19 @@ g.test('resolveTarget,format_supports_resolve')
if and only if they support 'resolve'.
`
)
.params(u =>
u
.combine('format', kRenderableColorTextureFormats)
.filter(t => kTextureFormatInfo[t.format].multisample)
)
.beforeAllSubcases(t => {
const { format } = t.params;
t.skipIfTextureFormatNotSupportedDeprecated(format);
t.skipIfMultisampleNotSupportedForFormatDeprecated(format);
})
.params(u => u.combine('format', kPossiblyRenderableColorTextureFormats))
.fn(t => {
const { format } = t.params;
const info = kTextureFormatInfo[format];
t.skipIfTextureFormatNotSupported(format);
t.skipIfMultisampleNotSupportedForFormat(format);

const multisampledColorTexture = t.createTestTexture({ format, sampleCount: 4 });
const resolveTarget = t.createTestTexture({ format });

const colorAttachment = t.getColorAttachment(multisampledColorTexture);
colorAttachment.resolveTarget = resolveTarget.createView();

t.tryRenderPass(!!info.colorRender?.resolve, {
t.tryRenderPass(isTextureFormatResolvable(t.device, format), {
colorAttachments: [colorAttachment],
});
});
Expand All @@ -1198,10 +1188,8 @@ g.test('timestampWrites,query_set_type')
u //
.combine('queryType', kQueryTypes)
)
.beforeAllSubcases(t => {
t.selectDeviceOrSkipTestCase(['timestamp-query']);
})
.fn(t => {
t.skipIfDeviceDoesNotSupportQueryType('timestamp');
const { queryType } = t.params;

const timestampWrites = {
Expand Down Expand Up @@ -1231,10 +1219,8 @@ g.test('timestampWrite,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 @@ -1262,13 +1248,9 @@ g.test('timestampWrite,query_index')
g.test('occlusionQuerySet,query_set_type')
.desc(`Test that occlusionQuerySet must have type 'occlusion'.`)
.params(u => u.combine('queryType', kQueryTypes))
.beforeAllSubcases(t => {
if (t.params.queryType === 'timestamp') {
t.selectDeviceOrSkipTestCase(['timestamp-query']);
}
})
.fn(t => {
const { queryType } = t.params;
t.skipIfDeviceDoesNotSupportQueryType(queryType);

const querySet = t.createQuerySetTracked({
type: queryType,
Expand Down
18 changes: 17 additions & 1 deletion src/webgpu/format_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1438,10 +1438,19 @@ const kASTCTextureFormatInfo = formatTableWithDefaults({
/* prettier-ignore */ export const kAllTextureFormats: readonly GPUTextureFormat[] = keysOf( kAllTextureFormatInfo);

// CompressedTextureFormat are unrenderable so filter from RegularTextureFormats for color targets is enough
// @deprecated
export const kRenderableColorTextureFormats = kRegularTextureFormats.filter(
v => kColorTextureFormatInfo[v].colorRender
);

// Color formats that are possibly renderable. Some may require features to be enabled.
// MAINTENANCE_TODO: remove 'rg11b10ufloat` once colorRender is added to its info.
// See: computeBytesPerSampleFromFormats
export const kPossiblyRenderableColorTextureFormats = [
...kRegularTextureFormats.filter(v => kColorTextureFormatInfo[v].colorRender),
'rg11b10ufloat',
] as const;

/** Per-GPUTextureFormat-per-aspect info. */
interface TextureFormatAspectInfo {
/** Whether the aspect can be used as `COPY_SRC`. */
Expand Down Expand Up @@ -2042,7 +2051,14 @@ export const kFeaturesForFormats = getFeaturesForFormats(kAllTextureFormats);
export function computeBytesPerSampleFromFormats(formats: readonly GPUTextureFormat[]) {
let bytesPerSample = 0;
for (const format of formats) {
const info = kTextureFormatInfo[format];
// MAINTENANCE_TODO: Add colorRender to rg11b10ufloat format in kTextureFormatInfo
// The issue is if we add it now lots of tests will break as they'll think they can
// render to the format but are not enabling 'rg11b10ufloat-renderable'. Once we
// get the CTS refactored (see issue 4181), then fix this.
const info =
format === 'rg11b10ufloat'
? { colorRender: { alignment: 4, byteCost: 8 } }
: kTextureFormatInfo[format];
const alignedBytesPerSample = align(bytesPerSample, info.colorRender!.alignment);
bytesPerSample = alignedBytesPerSample + info.colorRender!.byteCost;
}
Expand Down
30 changes: 30 additions & 0 deletions src/webgpu/gpu_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
isMultisampledTextureFormatDeprecated,
isTextureFormatUsableAsStorageFormat,
isTextureFormatUsableAsRenderAttachment,
isTextureFormatMultisampled,
} from './format_info.js';
import { checkElementsEqual, checkElementsBetween } from './util/check_contents.js';
import { CommandBufferMaker, EncoderType } from './util/command_buffer_maker.js';
Expand Down Expand Up @@ -524,6 +525,26 @@ export class GPUTestBase extends Fixture<GPUTestSubcaseBatchState> {
}
}

/**
* Skips test if device does not have feature.
* Note: Try to use one of the more specific skipIf tests if possible.
*/
skipIfDeviceDoesNotHaveFeature(feature: GPUFeatureName) {
this.skipIf(!this.device.features.has(feature), `device does not have feature: '${feature}'`);
}

/**
* Skips test if device des not support query type.
*/
skipIfDeviceDoesNotSupportQueryType(...types: GPUQueryType[]) {
for (const type of types) {
const feature = kQueryTypeInfo[type].feature;
if (feature) {
this.skipIfDeviceDoesNotHaveFeature(feature);
}
}
}

/**
* Skips test if any format is not supported.
*/
Expand All @@ -545,6 +566,15 @@ export class GPUTestBase extends Fixture<GPUTestSubcaseBatchState> {
}
}

skipIfMultisampleNotSupportedForFormat(...formats: (GPUTextureFormat | undefined)[]) {
for (const format of formats) {
if (format === undefined) continue;
if (!isTextureFormatMultisampled(this.device, format)) {
this.skip(`texture format '${format}' is not supported to be multisampled`);
}
}
}

/** @deprecated */
skipIfTextureViewDimensionNotSupportedDeprecated(
...dimensions: (GPUTextureViewDimension | undefined)[]
Expand Down