Skip to content

Commit 3fec95c

Browse files
authored
Merge branch 'main' into skip-hmtlve
2 parents e604df8 + 149e02a commit 3fec95c

File tree

4 files changed

+246
-7
lines changed

4 files changed

+246
-7
lines changed
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
export const description = `
2+
Tests that, in compat mode, the dimension of a view is compatible with a texture's textureBindingViewDimension.
3+
`;
4+
5+
import { makeTestGroup } from '../../../../common/framework/test_group.js';
6+
import { kTextureDimensions, kTextureViewDimensions } from '../../../capability_info.js';
7+
import {
8+
effectiveViewDimensionForTexture,
9+
getTextureDimensionFromView,
10+
} from '../../../util/texture/base.js';
11+
import { CompatibilityTest } from '../../compatibility_test.js';
12+
13+
export const g = makeTestGroup(CompatibilityTest);
14+
15+
function isTextureBindingViewDimensionCompatibleWithDimension(
16+
dimension: GPUTextureDimension = '2d',
17+
textureBindingViewDimension: GPUTextureViewDimension = '2d'
18+
) {
19+
return getTextureDimensionFromView(textureBindingViewDimension) === dimension;
20+
}
21+
22+
function isValidViewDimensionForDimension(
23+
dimension: GPUTextureDimension | undefined,
24+
depthOrArrayLayers: number,
25+
viewDimension: GPUTextureViewDimension | undefined
26+
) {
27+
if (viewDimension === undefined) {
28+
return true;
29+
}
30+
31+
switch (dimension) {
32+
case '1d':
33+
return viewDimension === '1d';
34+
case '2d':
35+
case undefined:
36+
switch (viewDimension) {
37+
case undefined:
38+
case '2d':
39+
case '2d-array':
40+
return true;
41+
case 'cube':
42+
return depthOrArrayLayers === 6;
43+
case 'cube-array':
44+
return depthOrArrayLayers % 6 === 0;
45+
default:
46+
return false;
47+
}
48+
break;
49+
case '3d':
50+
return viewDimension === '3d';
51+
}
52+
}
53+
54+
function isValidDimensionForDepthOrArrayLayers(
55+
dimension: GPUTextureDimension | undefined,
56+
depthOrArrayLayers: number
57+
) {
58+
switch (dimension) {
59+
case '1d':
60+
return depthOrArrayLayers === 1;
61+
default:
62+
return true;
63+
}
64+
}
65+
66+
function isValidViewDimensionForDepthOrArrayLayers(
67+
viewDimension: GPUTextureViewDimension | undefined,
68+
depthOrArrayLayers: number
69+
) {
70+
switch (viewDimension) {
71+
case 'cube':
72+
return depthOrArrayLayers === 6;
73+
case 'cube-array':
74+
return depthOrArrayLayers % 6 === 0;
75+
default:
76+
return true;
77+
}
78+
return viewDimension === 'cube';
79+
}
80+
81+
function getEffectiveTextureBindingViewDimension(
82+
dimension: GPUTextureDimension | undefined,
83+
depthOrArrayLayers: number,
84+
textureBindingViewDimension: GPUTextureViewDimension | undefined
85+
) {
86+
if (textureBindingViewDimension) {
87+
return textureBindingViewDimension;
88+
}
89+
90+
switch (dimension) {
91+
case '1d':
92+
return '1d';
93+
case '2d':
94+
case undefined:
95+
return depthOrArrayLayers > 1 ? '2d-array' : '2d';
96+
break;
97+
case '3d':
98+
return '3d';
99+
}
100+
}
101+
102+
g.test('viewDimension_matches_textureBindingViewDimension')
103+
.desc(
104+
`
105+
Tests that, in compat mode, the dimension of a view is compatible with a texture's textureBindingViewDimension
106+
when used as a TEXTURE_BINDING.
107+
`
108+
)
109+
.params(u =>
110+
u //
111+
.combine('dimension', [...kTextureDimensions, undefined])
112+
.combine('textureBindingViewDimension', [...kTextureViewDimensions, undefined])
113+
.combine('viewDimension', [...kTextureViewDimensions, undefined])
114+
.combine('depthOrArrayLayers', [1, 2, 6])
115+
.filter(
116+
({ dimension, textureBindingViewDimension, depthOrArrayLayers, viewDimension }) =>
117+
textureBindingViewDimension !== 'cube-array' &&
118+
viewDimension !== 'cube-array' &&
119+
isTextureBindingViewDimensionCompatibleWithDimension(
120+
dimension,
121+
textureBindingViewDimension
122+
) &&
123+
isValidViewDimensionForDimension(dimension, depthOrArrayLayers, viewDimension) &&
124+
isValidViewDimensionForDepthOrArrayLayers(
125+
textureBindingViewDimension,
126+
depthOrArrayLayers
127+
) &&
128+
isValidDimensionForDepthOrArrayLayers(dimension, depthOrArrayLayers)
129+
)
130+
)
131+
.fn(t => {
132+
const { dimension, textureBindingViewDimension, viewDimension, depthOrArrayLayers } = t.params;
133+
134+
const texture = t.device.createTexture({
135+
size: [1, 1, depthOrArrayLayers],
136+
format: 'rgba8unorm',
137+
usage: GPUTextureUsage.TEXTURE_BINDING,
138+
...(dimension && { dimension }),
139+
...(textureBindingViewDimension && { textureBindingViewDimension }),
140+
} as GPUTextureDescriptor); // MAINTENANCE_TODO: remove cast once textureBindingViewDimension is added to IDL
141+
t.trackForCleanup(texture);
142+
143+
const effectiveTextureBindingViewDimension = getEffectiveTextureBindingViewDimension(
144+
dimension,
145+
texture.depthOrArrayLayers,
146+
textureBindingViewDimension
147+
);
148+
149+
const effectiveViewDimension = getEffectiveTextureBindingViewDimension(
150+
dimension,
151+
texture.depthOrArrayLayers,
152+
viewDimension
153+
);
154+
155+
const layout = t.device.createBindGroupLayout({
156+
entries: [
157+
{
158+
binding: 0,
159+
visibility: GPUShaderStage.COMPUTE,
160+
texture: {
161+
viewDimension: effectiveViewDimensionForTexture(texture, viewDimension),
162+
},
163+
},
164+
],
165+
});
166+
167+
const resource = texture.createView({ dimension: viewDimension });
168+
const shouldError = effectiveTextureBindingViewDimension !== effectiveViewDimension;
169+
170+
t.expectValidationError(() => {
171+
t.device.createBindGroup({
172+
layout,
173+
entries: [{ binding: 0, resource }],
174+
});
175+
}, shouldError);
176+
});

src/webgpu/compat/api/validation/texture/createTexture.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
export const description = `
22
Tests that you can not use bgra8unorm-srgb in compat mode.
3+
Tests that textureBindingViewDimension must compatible with texture dimension
34
`;
45

56
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
7+
import { kTextureDimensions, kTextureViewDimensions } from '../../../../capability_info.js';
8+
import { getTextureDimensionFromView } from '../../../../util/texture/base.js';
69
import { CompatibilityTest } from '../../../compatibility_test.js';
710

811
export const g = makeTestGroup(CompatibilityTest);
@@ -39,3 +42,31 @@ g.test('unsupportedTextureViewFormats')
3942
true
4043
);
4144
});
45+
46+
g.test('invalidTextureBindingViewDimension')
47+
.desc(
48+
`Tests that you can not specify a textureBindingViewDimension that is incompatible with the texture's dimension.`
49+
)
50+
.params(u =>
51+
u //
52+
.combine('dimension', kTextureDimensions)
53+
.combine('textureBindingViewDimension', kTextureViewDimensions)
54+
)
55+
.fn(t => {
56+
const { dimension, textureBindingViewDimension } = t.params;
57+
const shouldError = getTextureDimensionFromView(textureBindingViewDimension) !== dimension;
58+
t.expectGPUError(
59+
'validation',
60+
() => {
61+
const texture = t.device.createTexture({
62+
size: [1, 1, dimension === '1d' ? 1 : 6],
63+
format: 'rgba8unorm',
64+
usage: GPUTextureUsage.TEXTURE_BINDING,
65+
dimension,
66+
textureBindingViewDimension,
67+
} as GPUTextureDescriptor); // MAINTENANCE_TODO: remove cast once textureBindingViewDimension is added to IDL
68+
t.trackForCleanup(texture);
69+
},
70+
shouldError
71+
);
72+
});

src/webgpu/listing_meta.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,7 @@
829829
"webgpu:api,validation,texture,rg11b10ufloat_renderable:begin_render_pass_single_sampled:*": { "subcaseMS": 1.200 },
830830
"webgpu:api,validation,texture,rg11b10ufloat_renderable:create_render_pipeline:*": { "subcaseMS": 2.400 },
831831
"webgpu:api,validation,texture,rg11b10ufloat_renderable:create_texture:*": { "subcaseMS": 12.700 },
832+
"webgpu:compat,api,validation,createBindGroup:viewDimension_matches_textureBindingViewDimension:*": { "subcaseMS": 6.523 },
832833
"webgpu:compat,api,validation,encoding,cmds,copyTextureToBuffer:compressed:*": { "subcaseMS": 202.929 },
833834
"webgpu:compat,api,validation,encoding,programmable,pipeline_bind_group_compat:twoDifferentTextureViews,compute_pass,unused:*": { "subcaseMS": 1.501 },
834835
"webgpu:compat,api,validation,encoding,programmable,pipeline_bind_group_compat:twoDifferentTextureViews,compute_pass,used:*": { "subcaseMS": 49.405 },
@@ -837,6 +838,7 @@
837838
"webgpu:compat,api,validation,render_pipeline,fragment_state:colorState:*": { "subcaseMS": 32.604 },
838839
"webgpu:compat,api,validation,render_pipeline,shader_module:sample_mask:*": { "subcaseMS": 14.801 },
839840
"webgpu:compat,api,validation,render_pipeline,vertex_state:maxVertexAttributesVertexIndexInstanceIndex:*": { "subcaseMS": 3.700 },
841+
"webgpu:compat,api,validation,texture,createTexture:invalidTextureBindingViewDimension:*": { "subcaseMS": 6.022 },
840842
"webgpu:compat,api,validation,texture,createTexture:unsupportedTextureFormats:*": { "subcaseMS": 0.700 },
841843
"webgpu:compat,api,validation,texture,createTexture:unsupportedTextureViewFormats:*": { "subcaseMS": 0.601 },
842844
"webgpu:compat,api,validation,texture,cubeArray:cube_array:*": { "subcaseMS": 13.701 },

src/webgpu/util/texture/base.ts

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,52 @@ export function viewDimensionsForTextureDimension(textureDimension: GPUTextureDi
157157
}
158158
}
159159

160-
/** Returns the default view dimension for a given texture descriptor. */
161-
export function defaultViewDimensionsForTexture(textureDescriptor: Readonly<GPUTextureDescriptor>) {
162-
switch (textureDescriptor.dimension) {
160+
/** Returns the effective view dimension for a given texture dimension and depthOrArrayLayers */
161+
export function effectiveViewDimensionForDimension(
162+
viewDimension: GPUTextureViewDimension | undefined,
163+
dimension: GPUTextureDimension | undefined,
164+
depthOrArrayLayers: number
165+
) {
166+
if (viewDimension) {
167+
return viewDimension;
168+
}
169+
170+
switch (dimension || '2d') {
163171
case '1d':
164172
return '1d';
165-
case '2d': {
166-
const sizeDict = reifyExtent3D(textureDescriptor.size);
167-
return sizeDict.depthOrArrayLayers > 1 ? '2d-array' : '2d';
168-
}
173+
case '2d':
174+
case undefined:
175+
return depthOrArrayLayers > 1 ? '2d-array' : '2d';
176+
break;
169177
case '3d':
170178
return '3d';
171179
default:
172180
unreachable();
173181
}
174182
}
175183

184+
/** Returns the effective view dimension for a given texture */
185+
export function effectiveViewDimensionForTexture(
186+
texture: GPUTexture,
187+
viewDimension: GPUTextureViewDimension | undefined
188+
) {
189+
return effectiveViewDimensionForDimension(
190+
viewDimension,
191+
texture.dimension,
192+
texture.depthOrArrayLayers
193+
);
194+
}
195+
196+
/** Returns the default view dimension for a given texture descriptor. */
197+
export function defaultViewDimensionsForTexture(textureDescriptor: Readonly<GPUTextureDescriptor>) {
198+
const sizeDict = reifyExtent3D(textureDescriptor.size);
199+
return effectiveViewDimensionForDimension(
200+
undefined,
201+
textureDescriptor.dimension,
202+
sizeDict.depthOrArrayLayers
203+
);
204+
}
205+
176206
/** Reifies the optional fields of `GPUTextureDescriptor`.
177207
* MAINTENANCE_TODO: viewFormats should not be omitted here, but it seems likely that the
178208
* @webgpu/types definition will have to change before we can include it again.

0 commit comments

Comments
 (0)