Skip to content

Commit dcf8058

Browse files
committed
Refactor copyTextureToTexture test for texture formats
Also expanded the multisample depth test and add multisample stencil placeholder. Issue: gpuweb#4181
1 parent 6b56a20 commit dcf8058

File tree

3 files changed

+105
-63
lines changed

3 files changed

+105
-63
lines changed

src/webgpu/api/operation/command_buffer/copyTextureToTexture.spec.ts

+67-59
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,23 @@ import {
88
kTextureDimensions,
99
} from '../../../capability_info.js';
1010
import {
11-
kTextureFormatInfo,
12-
kRegularTextureFormats,
13-
kCompressedTextureFormats,
14-
kDepthStencilFormats,
15-
textureDimensionAndFormatCompatible,
16-
depthStencilFormatAspectSize,
17-
DepthStencilFormat,
1811
ColorTextureFormat,
12+
DepthStencilFormat,
13+
depthStencilFormatAspectSize,
14+
getBaseFormatForTextureFormat,
15+
getBlockInfoForColorTextureFormat,
1916
isCompressedTextureFormat,
20-
viewCompatibleDeprecated,
21-
RegularTextureFormat,
17+
isDepthTextureFormat,
2218
isRegularTextureFormat,
19+
isStencilTextureFormat,
20+
kCompressedTextureFormats,
21+
kDepthStencilFormats,
22+
kRegularTextureFormats,
23+
RegularTextureFormat,
24+
textureDimensionAndFormatCompatible,
25+
textureFormatsAreViewCompatible,
2326
} from '../../../format_info.js';
24-
import { GPUTest, TextureTestMixin } from '../../../gpu_test.js';
27+
import { AllFeaturesMaxLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js';
2528
import { checkElementsEqual } from '../../../util/check_contents.js';
2629
import { align } from '../../../util/math.js';
2730
import { physicalMipSize } from '../../../util/texture/base.js';
@@ -32,20 +35,17 @@ import { findFailedPixels } from '../../../util/texture/texture_ok.js';
3235

3336
const dataGenerator = new DataArrayGenerator();
3437

35-
class F extends TextureTestMixin(GPUTest) {
38+
class F extends TextureTestMixin(AllFeaturesMaxLimitsGPUTest) {
3639
GetInitialDataPerMipLevel(
3740
dimension: GPUTextureDimension,
3841
textureSize: Required<GPUExtent3DDict>,
3942
format: ColorTextureFormat,
4043
mipLevel: number
4144
): Uint8Array {
4245
const textureSizeAtLevel = physicalMipSize(textureSize, format, dimension, mipLevel);
43-
const bytesPerBlock = kTextureFormatInfo[format].color.bytes;
44-
const blockWidthInTexel = kTextureFormatInfo[format].blockWidth;
45-
const blockHeightInTexel = kTextureFormatInfo[format].blockHeight;
46+
const { bytesPerBlock, blockWidth, blockHeight } = getBlockInfoForColorTextureFormat(format);
4647
const blocksPerSubresource =
47-
(textureSizeAtLevel.width / blockWidthInTexel) *
48-
(textureSizeAtLevel.height / blockHeightInTexel);
48+
(textureSizeAtLevel.width / blockWidth) * (textureSizeAtLevel.height / blockHeight);
4949

5050
const byteSize = bytesPerBlock * blocksPerSubresource * textureSizeAtLevel.depthOrArrayLayers;
5151
return dataGenerator.generateView(byteSize);
@@ -121,9 +121,7 @@ class F extends TextureTestMixin(GPUTest) {
121121
dimension,
122122
srcCopyLevel
123123
);
124-
const bytesPerBlock = kTextureFormatInfo[srcFormat].color.bytes;
125-
const blockWidth = kTextureFormatInfo[srcFormat].blockWidth;
126-
const blockHeight = kTextureFormatInfo[srcFormat].blockHeight;
124+
const { bytesPerBlock, blockWidth, blockHeight } = getBlockInfoForColorTextureFormat(srcFormat);
127125
const srcBlocksPerRow = srcTextureSizeAtLevel.width / blockWidth;
128126
const srcBlockRowsPerImage = srcTextureSizeAtLevel.height / blockHeight;
129127
this.device.queue.writeTexture(
@@ -208,7 +206,7 @@ class F extends TextureTestMixin(GPUTest) {
208206
align(dstBlocksPerRow * bytesPerBlock, 4);
209207

210208
if (isCompressedTextureFormat(dstTexture.format) && this.isCompatibility) {
211-
assert(viewCompatibleDeprecated(this.isCompatibility, srcFormat, dstFormat));
209+
assert(textureFormatsAreViewCompatible(this.device, srcFormat, dstFormat));
212210
// compare by rendering. We need the expected texture to match
213211
// the dstTexture so we'll create a texture where we supply
214212
// all of the data in JavaScript.
@@ -576,7 +574,7 @@ class F extends TextureTestMixin(GPUTest) {
576574
});
577575
const bindGroup = this.GetBindGroupForT2TCopyWithDepthTests(bindGroupLayout, copySize[2]);
578576

579-
const hasStencil = kTextureFormatInfo[sourceTexture.format].stencil;
577+
const hasStencil = isStencilTextureFormat(sourceTexture.format);
580578
const encoder = this.device.createCommandEncoder();
581579
for (let srcCopyLayer = 0; srcCopyLayer < copySize[2]; ++srcCopyLayer) {
582580
const renderPass = encoder.beginRenderPass({
@@ -625,7 +623,7 @@ class F extends TextureTestMixin(GPUTest) {
625623
size: copySize,
626624
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
627625
});
628-
const hasStencil = kTextureFormatInfo[destinationTexture.format].stencil;
626+
const hasStencil = isStencilTextureFormat(destinationTexture.format);
629627
const encoder = this.device.createCommandEncoder();
630628
for (let dstCopyLayer = 0; dstCopyLayer < copySize[2]; ++dstCopyLayer) {
631629
// If the depth value is not expected, the color of outputColorTexture will remain Red after
@@ -790,8 +788,8 @@ g.test('color_textures,non_compressed,non_array')
790788
.combine('srcFormat', kRegularTextureFormats)
791789
.combine('dstFormat', kRegularTextureFormats)
792790
.filter(({ srcFormat, dstFormat }) => {
793-
const srcBaseFormat = kTextureFormatInfo[srcFormat].baseFormat;
794-
const dstBaseFormat = kTextureFormatInfo[dstFormat].baseFormat;
791+
const srcBaseFormat = getBaseFormatForTextureFormat(srcFormat);
792+
const dstBaseFormat = getBaseFormatForTextureFormat(dstFormat);
795793
return (
796794
srcFormat === dstFormat ||
797795
(srcBaseFormat !== undefined &&
@@ -885,8 +883,8 @@ g.test('color_textures,compressed,non_array')
885883
.combine('srcFormat', kCompressedTextureFormats)
886884
.combine('dstFormat', kCompressedTextureFormats)
887885
.filter(({ srcFormat, dstFormat }) => {
888-
const srcBaseFormat = kTextureFormatInfo[srcFormat].baseFormat;
889-
const dstBaseFormat = kTextureFormatInfo[dstFormat].baseFormat;
886+
const srcBaseFormat = getBaseFormatForTextureFormat(srcFormat);
887+
const dstBaseFormat = getBaseFormatForTextureFormat(dstFormat);
890888
return (
891889
srcFormat === dstFormat ||
892890
(srcBaseFormat !== undefined &&
@@ -924,10 +922,6 @@ g.test('color_textures,compressed,non_array')
924922
.beforeAllSubcases(t => {
925923
const { srcFormat, dstFormat } = t.params;
926924
t.skipIfCopyTextureToTextureNotSupportedForFormat(srcFormat, dstFormat);
927-
t.selectDeviceOrSkipTestCase([
928-
kTextureFormatInfo[srcFormat].feature,
929-
kTextureFormatInfo[dstFormat].feature,
930-
]);
931925
})
932926
.fn(t => {
933927
const {
@@ -939,10 +933,10 @@ g.test('color_textures,compressed,non_array')
939933
srcCopyLevel,
940934
dstCopyLevel,
941935
} = t.params;
942-
const srcBlockWidth = kTextureFormatInfo[srcFormat].blockWidth;
943-
const srcBlockHeight = kTextureFormatInfo[srcFormat].blockHeight;
944-
const dstBlockWidth = kTextureFormatInfo[dstFormat].blockWidth;
945-
const dstBlockHeight = kTextureFormatInfo[dstFormat].blockHeight;
936+
const { blockWidth: srcBlockWidth, blockHeight: srcBlockHeight } =
937+
getBlockInfoForColorTextureFormat(srcFormat);
938+
const { blockWidth: dstBlockWidth, blockHeight: dstBlockHeight } =
939+
getBlockInfoForColorTextureFormat(dstFormat);
946940

947941
t.DoCopyTextureToTextureTest(
948942
dimension,
@@ -977,8 +971,8 @@ g.test('color_textures,non_compressed,array')
977971
.combine('srcFormat', kRegularTextureFormats)
978972
.combine('dstFormat', kRegularTextureFormats)
979973
.filter(({ srcFormat, dstFormat }) => {
980-
const srcBaseFormat = kTextureFormatInfo[srcFormat].baseFormat;
981-
const dstBaseFormat = kTextureFormatInfo[dstFormat].baseFormat;
974+
const srcBaseFormat = getBaseFormatForTextureFormat(srcFormat);
975+
const dstBaseFormat = getBaseFormatForTextureFormat(dstFormat);
982976
return (
983977
srcFormat === dstFormat ||
984978
(srcBaseFormat !== undefined &&
@@ -1050,8 +1044,8 @@ g.test('color_textures,compressed,array')
10501044
.combine('srcFormat', kCompressedTextureFormats)
10511045
.combine('dstFormat', kCompressedTextureFormats)
10521046
.filter(({ srcFormat, dstFormat }) => {
1053-
const srcBaseFormat = kTextureFormatInfo[srcFormat].baseFormat;
1054-
const dstBaseFormat = kTextureFormatInfo[dstFormat].baseFormat;
1047+
const srcBaseFormat = getBaseFormatForTextureFormat(srcFormat);
1048+
const dstBaseFormat = getBaseFormatForTextureFormat(dstFormat);
10551049
return (
10561050
srcFormat === dstFormat ||
10571051
(srcBaseFormat !== undefined &&
@@ -1079,10 +1073,6 @@ g.test('color_textures,compressed,array')
10791073
.beforeAllSubcases(t => {
10801074
const { srcFormat, dstFormat } = t.params;
10811075
t.skipIfCopyTextureToTextureNotSupportedForFormat(srcFormat, dstFormat);
1082-
t.selectDeviceOrSkipTestCase([
1083-
kTextureFormatInfo[srcFormat].feature,
1084-
kTextureFormatInfo[dstFormat].feature,
1085-
]);
10861076
})
10871077
.fn(t => {
10881078
const {
@@ -1094,10 +1084,12 @@ g.test('color_textures,compressed,array')
10941084
srcCopyLevel,
10951085
dstCopyLevel,
10961086
} = t.params;
1097-
const srcBlockWidth = kTextureFormatInfo[srcFormat].blockWidth;
1098-
const srcBlockHeight = kTextureFormatInfo[srcFormat].blockHeight;
1099-
const dstBlockWidth = kTextureFormatInfo[dstFormat].blockWidth;
1100-
const dstBlockHeight = kTextureFormatInfo[dstFormat].blockHeight;
1087+
t.skipIfTextureFormatNotSupported(srcFormat, dstFormat);
1088+
1089+
const { blockWidth: srcBlockWidth, blockHeight: srcBlockHeight } =
1090+
getBlockInfoForColorTextureFormat(srcFormat);
1091+
const { blockWidth: dstBlockWidth, blockHeight: dstBlockHeight } =
1092+
getBlockInfoForColorTextureFormat(dstFormat);
11011093

11021094
t.DoCopyTextureToTextureTest(
11031095
dimension,
@@ -1260,10 +1252,6 @@ g.test('copy_depth_stencil')
12601252
);
12611253
})
12621254
)
1263-
.beforeAllSubcases(t => {
1264-
const { format } = t.params;
1265-
t.selectDeviceForTextureFormatOrSkipTestCase(format);
1266-
})
12671255
.fn(t => {
12681256
const {
12691257
format,
@@ -1273,6 +1261,7 @@ g.test('copy_depth_stencil')
12731261
srcCopyBaseArrayLayer,
12741262
dstCopyBaseArrayLayer,
12751263
} = t.params;
1264+
t.skipIfTextureFormatNotSupported(format);
12761265

12771266
const copySize: [number, number, number] = [
12781267
srcTextureSize.width >> srcCopyLevel,
@@ -1299,7 +1288,7 @@ g.test('copy_depth_stencil')
12991288
});
13001289

13011290
let initialStencilData: undefined | Uint8Array = undefined;
1302-
if (kTextureFormatInfo[format].stencil) {
1291+
if (isStencilTextureFormat(format)) {
13031292
initialStencilData = t.GetInitialStencilDataPerMipLevel(srcTextureSize, format, srcCopyLevel);
13041293
t.InitializeStencilAspect(
13051294
sourceTexture,
@@ -1309,7 +1298,7 @@ g.test('copy_depth_stencil')
13091298
copySize
13101299
);
13111300
}
1312-
if (kTextureFormatInfo[format].depth) {
1301+
if (isDepthTextureFormat(format)) {
13131302
t.InitializeDepthAspect(sourceTexture, format, srcCopyLevel, srcCopyBaseArrayLayer, copySize);
13141303
}
13151304

@@ -1329,7 +1318,7 @@ g.test('copy_depth_stencil')
13291318
);
13301319
t.queue.submit([encoder.finish()]);
13311320

1332-
if (kTextureFormatInfo[format].stencil) {
1321+
if (isStencilTextureFormat(format)) {
13331322
assert(initialStencilData !== undefined);
13341323
t.VerifyStencilAspect(
13351324
destinationTexture,
@@ -1339,7 +1328,7 @@ g.test('copy_depth_stencil')
13391328
copySize
13401329
);
13411330
}
1342-
if (kTextureFormatInfo[format].depth) {
1331+
if (isDepthTextureFormat(format)) {
13431332
t.VerifyDepthAspect(
13441333
destinationTexture,
13451334
format,
@@ -1552,22 +1541,25 @@ g.test('copy_multisampled_depth')
15521541
texture can only be 1.
15531542
`
15541543
)
1544+
.params(u =>
1545+
u.combine('format', kDepthStencilFormats).filter(t => isDepthTextureFormat(t.format))
1546+
)
15551547
.beforeAllSubcases(t => {
15561548
t.skipIf(t.isCompatibility, 'multisample textures are not copyable in compatibility mode');
15571549
})
15581550
.fn(t => {
1551+
const { format } = t.params;
15591552
const textureSize = [32, 16, 1] as const;
1560-
const kDepthFormat = 'depth24plus';
15611553
const kSampleCount = 4;
15621554

15631555
const sourceTexture = t.createTextureTracked({
1564-
format: kDepthFormat,
1556+
format,
15651557
size: textureSize,
15661558
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
15671559
sampleCount: kSampleCount,
15681560
});
15691561
const destinationTexture = t.createTextureTracked({
1570-
format: kDepthFormat,
1562+
format,
15711563
size: textureSize,
15721564
usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
15731565
sampleCount: kSampleCount,
@@ -1596,7 +1588,7 @@ g.test('copy_multisampled_depth')
15961588
layout: 'auto',
15971589
vertex: vertexState,
15981590
depthStencil: {
1599-
format: kDepthFormat,
1591+
format,
16001592
depthCompare: 'always',
16011593
depthWriteEnabled: true,
16021594
},
@@ -1613,6 +1605,10 @@ g.test('copy_multisampled_depth')
16131605
depthClearValue: 0.0,
16141606
depthLoadOp: 'clear',
16151607
depthStoreOp: 'store',
1608+
...(isStencilTextureFormat(format) && {
1609+
stencilLoadOp: 'clear',
1610+
stencilStoreOp: 'store',
1611+
}),
16161612
},
16171613
});
16181614
renderPassForInit.setPipeline(renderPipelineForInit);
@@ -1651,7 +1647,7 @@ g.test('copy_multisampled_depth')
16511647
targets: [{ format: kColorFormat }],
16521648
},
16531649
depthStencil: {
1654-
format: kDepthFormat,
1650+
format,
16551651
depthCompare: 'equal',
16561652
depthWriteEnabled: false,
16571653
},
@@ -1686,6 +1682,10 @@ g.test('copy_multisampled_depth')
16861682
view: destinationTexture.createView(),
16871683
depthLoadOp: 'load',
16881684
depthStoreOp: 'store',
1685+
...(isStencilTextureFormat(format) && {
1686+
stencilLoadOp: 'clear',
1687+
stencilStoreOp: 'store',
1688+
}),
16891689
},
16901690
});
16911691
renderPassForVerify.setPipeline(renderPipelineForVerify);
@@ -1698,3 +1698,11 @@ g.test('copy_multisampled_depth')
16981698
exp: { R: 0.0, G: 1.0, B: 0.0, A: 1.0 },
16991699
});
17001700
});
1701+
1702+
g.test('copy_multisampled_stencil')
1703+
.desc(
1704+
`
1705+
Validate the correctness of copyTextureToTexture() with multisampled stencil formats.
1706+
`
1707+
)
1708+
.unimplemented();

src/webgpu/format_info.ts

+26
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,32 @@ export function textureFormatsAreViewCompatible(
17721772
: a === b || a + '-srgb' === b || b + '-srgb' === a;
17731773
}
17741774

1775+
/**
1776+
* Gets the block width, height, and bytes per block for a color texture format.
1777+
*/
1778+
export function getBlockInfoForColorTextureFormat(format: ColorTextureFormat) {
1779+
const info = kTextureFormatInfo[format];
1780+
return {
1781+
blockWidth: info.blockWidth,
1782+
blockHeight: info.blockHeight,
1783+
bytesPerBlock: info.color.bytes,
1784+
};
1785+
}
1786+
1787+
/**
1788+
* Gets the baseFormat for a texture format.
1789+
*/
1790+
export function getBaseFormatForTextureFormat(format: GPUTextureFormat) {
1791+
return kTextureFormatInfo[format].baseFormat;
1792+
}
1793+
1794+
/**
1795+
* Gets the feature needed for a give texture format or undefined if none.
1796+
*/
1797+
export function getRequiredFeatureForTextureFormat(format: GPUTextureFormat) {
1798+
return kTextureFormatInfo[format].feature;
1799+
}
1800+
17751801
export function getFeaturesForFormats<T>(
17761802
formats: readonly (T & (GPUTextureFormat | undefined))[]
17771803
): readonly (GPUFeatureName | undefined)[] {

src/webgpu/gpu_test.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
EncodableTextureFormat,
3232
isCompressedTextureFormat,
3333
ColorTextureFormat,
34+
getRequiredFeatureForTextureFormat,
3435
isTextureFormatUsableAsStorageFormatDeprecated,
3536
isMultisampledTextureFormatDeprecated,
3637
isTextureFormatUsableAsStorageFormat,
@@ -526,11 +527,18 @@ export class GPUTestBase extends Fixture<GPUTestSubcaseBatchState> {
526527
* Skips test if any format is not supported.
527528
*/
528529
skipIfTextureFormatNotSupported(...formats: (GPUTextureFormat | undefined)[]) {
529-
if (isCompatibilityDevice(this.device)) {
530-
for (const format of formats) {
531-
if (format === 'bgra8unorm-srgb') {
532-
this.skip(`texture format '${format} is not supported`);
530+
for (const format of formats) {
531+
if (format) {
532+
if (isCompatibilityDevice(this.device)) {
533+
if (format === 'bgra8unorm-srgb') {
534+
this.skip(`texture format '${format} is not supported`);
535+
}
533536
}
537+
const feature = getRequiredFeatureForTextureFormat(format);
538+
this.skipIf(
539+
!!feature && !this.device.features.has(feature),
540+
`texture format '${format}' requires feature: '${feature}`
541+
);
534542
}
535543
}
536544
}

0 commit comments

Comments
 (0)