Skip to content

Commit c623e2b

Browse files
authored
WGSL builtin textureLoad for texture_2d tests (#3852)
* WGSL builtin textureLoad for texture_2d tests
1 parent 7229430 commit c623e2b

File tree

5 files changed

+619
-90
lines changed

5 files changed

+619
-90
lines changed

src/webgpu/format_info.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,18 @@ export function isCompressedTextureFormat(format: GPUTextureFormat) {
17731773
return format in kCompressedTextureFormatInfo;
17741774
}
17751775

1776+
export function isDepthTextureFormat(format: GPUTextureFormat) {
1777+
return !!kTextureFormatInfo[format].depth;
1778+
}
1779+
1780+
export function isStencilTextureFormat(format: GPUTextureFormat) {
1781+
return !!kTextureFormatInfo[format].stencil;
1782+
}
1783+
1784+
export function isDepthOrStencilTextureFormat(format: GPUTextureFormat) {
1785+
return isDepthTextureFormat(format) || isStencilTextureFormat(format);
1786+
}
1787+
17761788
export const kCompatModeUnsupportedStorageTextureFormats: readonly GPUTextureFormat[] = [
17771789
'rg32float',
17781790
'rg32sint',
@@ -1796,6 +1808,13 @@ export function isRegularTextureFormat(format: GPUTextureFormat) {
17961808
return format in kRegularTextureFormatInfo;
17971809
}
17981810

1811+
/**
1812+
* Returns true of format is both compressed and a float format, for example 'bc6h-rgb-ufloat'.
1813+
*/
1814+
export function isCompressedFloatTextureFormat(format: GPUTextureFormat) {
1815+
return isCompressedTextureFormat(format) && format.includes('float');
1816+
}
1817+
17991818
export const kFeaturesForFormats = getFeaturesForFormats(kAllTextureFormats);
18001819

18011820
/**

src/webgpu/shader/execution/expression/call/builtin/textureLoad.spec.ts

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,18 @@ If an out of bounds access occurs, the built-in function returns one of:
1414
* The data for some texel within bounds of the texture
1515
* A vector (0,0,0,0) or (0,0,0,1) of the appropriate type for non-depth textures
1616
* 0.0 for depth textures
17+
18+
TODO: Test textureLoad with depth textures as texture_2d, etc...
1719
`;
1820

1921
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
2022
import { unreachable, iterRange } from '../../../../../../common/util/util.js';
23+
import {
24+
isCompressedFloatTextureFormat,
25+
isDepthTextureFormat,
26+
kCompressedTextureFormats,
27+
kEncodableTextureFormats,
28+
} from '../../../../../format_info.js';
2129
import { GPUTest } from '../../../../../gpu_test.js';
2230
import {
2331
kFloat32Format,
@@ -28,7 +36,38 @@ import {
2836
} from '../../../../../util/conversion.js';
2937
import { TexelFormats } from '../../../../types.js';
3038

31-
import { generateCoordBoundaries } from './utils.js';
39+
import {
40+
TextureCall,
41+
checkCallResults,
42+
chooseTextureSize,
43+
createTextureWithRandomDataAndGetTexels,
44+
doTextureCalls,
45+
appendComponentTypeForFormatToTextureType,
46+
vec2,
47+
} from './texture_utils.js';
48+
import {
49+
Boundary,
50+
LevelSpec,
51+
generateCoordBoundaries,
52+
getCoordinateForBoundaries,
53+
getMipLevelFromLevelSpec,
54+
isBoundaryNegative,
55+
isLevelSpecNegative,
56+
} from './utils.js';
57+
58+
const kTestableColorFormats = [...kEncodableTextureFormats, ...kCompressedTextureFormats] as const;
59+
60+
function filterOutDepthAndCompressedFloatTextureFormats({ format }: { format: GPUTextureFormat }) {
61+
return !isDepthTextureFormat(format) && !isCompressedFloatTextureFormat(format);
62+
}
63+
64+
function filterOutU32WithNegativeValues(t: {
65+
C: 'i32' | 'u32';
66+
level: LevelSpec;
67+
coordsBoundary: Boundary;
68+
}) {
69+
return t.C === 'i32' || (!isLevelSpecNegative(t.level) && !isBoundaryNegative(t.coordsBoundary));
70+
}
3271

3372
export const g = makeTestGroup(GPUTest);
3473

@@ -59,8 +98,9 @@ g.test('sampled_2d')
5998
.desc(
6099
`
61100
C is i32 or u32
101+
L is i32 or u32
62102
63-
fn textureLoad(t: texture_2d<T>, coords: vec2<C>, level: C) -> vec4<T>
103+
fn textureLoad(t: texture_2d<T>, coords: vec2<C>, level: L) -> vec4<T>
64104
65105
Parameters:
66106
* t: The sampled texture to read from
@@ -70,11 +110,58 @@ Parameters:
70110
)
71111
.params(u =>
72112
u
113+
.combine('format', kTestableColorFormats)
114+
.filter(filterOutDepthAndCompressedFloatTextureFormats)
115+
.beginSubcases()
73116
.combine('C', ['i32', 'u32'] as const)
74-
.combine('coords', generateCoordBoundaries(2))
75-
.combine('level', [-1, 0, `numlevels-1`, `numlevels`] as const)
117+
.combine('L', ['i32', 'u32'] as const)
118+
.combine('coordsBoundary', generateCoordBoundaries(2))
119+
.combine('level', [-1, 0, `numLevels-1`, `numLevels`] as const)
120+
.filter(filterOutU32WithNegativeValues)
76121
)
77-
.unimplemented();
122+
.beforeAllSubcases(t => {
123+
const { format } = t.params;
124+
t.skipIfTextureFormatNotSupported(format);
125+
t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format);
126+
})
127+
.fn(async t => {
128+
const { format, C, L, coordsBoundary, level } = t.params;
129+
130+
// We want at least 4 blocks or something wide enough for 3 mip levels.
131+
const [width, height] = chooseTextureSize({ minSize: 8, minBlocks: 4, format });
132+
133+
const descriptor: GPUTextureDescriptor = {
134+
format,
135+
size: { width, height },
136+
usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING,
137+
};
138+
const { texels, texture } = await createTextureWithRandomDataAndGetTexels(t, descriptor);
139+
const mipLevel = getMipLevelFromLevelSpec(texture.mipLevelCount, level);
140+
const coords = getCoordinateForBoundaries<vec2>(texture, mipLevel, coordsBoundary);
141+
142+
const calls: TextureCall<vec2>[] = [
143+
{
144+
builtin: 'textureLoad',
145+
coordType: C === 'i32' ? 'i' : 'u',
146+
levelType: L === 'i32' ? 'i' : 'u',
147+
mipLevel,
148+
coords,
149+
},
150+
];
151+
const textureType = appendComponentTypeForFormatToTextureType('texture_2d', texture.format);
152+
const viewDescriptor = {};
153+
const sampler = undefined;
154+
const results = await doTextureCalls(t, texture, viewDescriptor, textureType, sampler, calls);
155+
const res = await checkCallResults(
156+
t,
157+
{ texels, descriptor, viewDescriptor },
158+
textureType,
159+
sampler,
160+
calls,
161+
results
162+
);
163+
t.expectOK(res);
164+
});
78165

79166
g.test('sampled_3d')
80167
.specURL('https://www.w3.org/TR/WGSL/#textureload')
@@ -94,7 +181,7 @@ Parameters:
94181
u
95182
.combine('C', ['i32', 'u32'] as const)
96183
.combine('coords', generateCoordBoundaries(3))
97-
.combine('level', [-1, 0, `numlevels-1`, `numlevels`] as const)
184+
.combine('level', [-1, 0, `numLevels-1`, `numLevels`] as const)
98185
)
99186
.unimplemented();
100187

@@ -144,7 +231,7 @@ Parameters:
144231
u
145232
.combine('C', ['i32', 'u32'] as const)
146233
.combine('coords', generateCoordBoundaries(2))
147-
.combine('level', [-1, 0, `numlevels-1`, `numlevels`] as const)
234+
.combine('level', [-1, 0, `numLevels-1`, `numLevels`] as const)
148235
)
149236
.unimplemented();
150237

@@ -189,7 +276,7 @@ Parameters:
189276
.combine('C', ['i32', 'u32'] as const)
190277
.combine('coords', generateCoordBoundaries(2))
191278
.combine('array_index', [-1, 0, `numlayers-1`, `numlayers`] as const)
192-
.combine('level', [-1, 0, `numlevels-1`, `numlevels`] as const)
279+
.combine('level', [-1, 0, `numLevels-1`, `numLevels`] as const)
193280
)
194281
.unimplemented();
195282

0 commit comments

Comments
 (0)