Skip to content

Commit

Permalink
Refactor render_pass_descriptor tests for texture formats.
Browse files Browse the repository at this point in the history
  • Loading branch information
greggman committed Feb 21, 2025
1 parent 1245e3f commit 13eb138
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 41 deletions.
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

0 comments on commit 13eb138

Please sign in to comment.