Skip to content

Commit 28d4903

Browse files
committed
refactor textureLoad for texture formats
1 parent cc96807 commit 28d4903

File tree

3 files changed

+103
-77
lines changed

3 files changed

+103
-77
lines changed

src/webgpu/gpu_test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,19 @@ export class GPUTestBase extends Fixture<GPUTestSubcaseBatchState> {
631631
}
632632
}
633633

634+
skipIfTextureLoadNotSupportedForTextureType(...types: (string | undefined | null)[]) {
635+
if (this.isCompatibility) {
636+
for (const type of types) {
637+
switch (type) {
638+
case 'texture_depth_2d':
639+
case 'texture_depth_2d_array':
640+
case 'texture_depth_multisampled_2d':
641+
this.skip(`${type} is not supported by textureLoad in compatibility mode`);
642+
}
643+
}
644+
}
645+
}
646+
634647
skipIfTextureFormatNotUsableAsStorageTexture(...formats: (GPUTextureFormat | undefined)[]) {
635648
for (const format of formats) {
636649
if (format && !isTextureFormatUsableAsStorageFormat(this.device, format)) {

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

Lines changed: 38 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,15 @@ import { makeTestGroup } from '../../../../../../common/framework/test_group.js'
2121
import {
2222
isCompressedFloatTextureFormat,
2323
isDepthTextureFormat,
24-
isMultisampledTextureFormatDeprecated,
25-
isStencilTextureFormat,
26-
kDepthStencilFormats,
2724
kAllTextureFormats,
28-
kTextureFormatInfo,
2925
textureDimensionAndFormatCompatible,
26+
isCompressedTextureFormat,
27+
kPossibleMultisampledTextureFormats,
28+
kDepthTextureFormats,
29+
kPossibleStorageTextureFormats,
3030
} from '../../../../../format_info.js';
3131
import { AllFeaturesMaxLimitsGPUTest, GPUTest } from '../../../../../gpu_test.js';
3232
import { maxMipLevelCount, virtualMipSize } from '../../../../../util/texture/base.js';
33-
import { TexelFormats } from '../../../../types.js';
3433

3534
import {
3635
TextureCall,
@@ -101,19 +100,15 @@ Parameters:
101100
.combine('format', kAllTextureFormats)
102101
.filter(t => textureDimensionAndFormatCompatible('1d', t.format))
103102
// 1d textures can't have a height !== 1
104-
.filter(t => kTextureFormatInfo[t.format].blockHeight === 1)
103+
.filter(t => !isCompressedTextureFormat(t.format))
105104
.beginSubcases()
106105
.combine('samplePoints', kSamplePointMethods)
107106
.combine('C', ['i32', 'u32'] as const)
108107
.combine('L', ['i32', 'u32'] as const)
109108
)
110-
.beforeAllSubcases(t => {
111-
const { format } = t.params;
112-
t.skipIfTextureFormatNotSupportedDeprecated(format);
113-
t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format);
114-
})
115109
.fn(async t => {
116110
const { format, stage, C, L, samplePoints } = t.params;
111+
t.skipIfTextureFormatNotSupported(format);
117112

118113
// We want at least 4 blocks or something wide enough for 3 mip levels.
119114
const [width] = chooseTextureSize({ minSize: 8, minBlocks: 4, format });
@@ -192,13 +187,9 @@ Parameters:
192187
.combine('C', ['i32', 'u32'] as const)
193188
.combine('L', ['i32', 'u32'] as const)
194189
)
195-
.beforeAllSubcases(t => {
196-
const { format } = t.params;
197-
t.skipIfTextureFormatNotSupportedDeprecated(format);
198-
t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format);
199-
})
200190
.fn(async t => {
201191
const { format, stage, samplePoints, C, L } = t.params;
192+
t.skipIfTextureFormatNotSupported(format);
202193

203194
// We want at least 4 blocks or something wide enough for 3 mip levels.
204195
const size = chooseTextureSize({ minSize: 8, minBlocks: 4, format });
@@ -275,13 +266,9 @@ Parameters:
275266
.combine('C', ['i32', 'u32'] as const)
276267
.combine('L', ['i32', 'u32'] as const)
277268
)
278-
.beforeAllSubcases(t => {
279-
const { format } = t.params;
280-
t.skipIfTextureFormatNotSupportedDeprecated(format);
281-
t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format);
282-
})
283269
.fn(async t => {
284270
const { format, stage, samplePoints, C, L } = t.params;
271+
t.skipIfTextureFormatNotSupported(format);
285272

286273
// We want at least 4 blocks or something wide enough for 3 mip levels.
287274
const size = chooseTextureSize({ minSize: 8, minBlocks: 4, format, viewDimension: '3d' });
@@ -358,9 +345,7 @@ Parameters:
358345
'texture_multisampled_2d',
359346
'texture_depth_multisampled_2d',
360347
] as const)
361-
.combine('format', kAllTextureFormats)
362-
.filter(t => isMultisampledTextureFormatDeprecated(t.format, false))
363-
.filter(t => !isStencilTextureFormat(t.format))
348+
.combine('format', kPossibleMultisampledTextureFormats)
364349
// Filter out texture_depth_multisampled_2d with non-depth formats
365350
.filter(
366351
t =>
@@ -371,14 +356,11 @@ Parameters:
371356
.combine('C', ['i32', 'u32'] as const)
372357
.combine('S', ['i32', 'u32'] as const)
373358
)
374-
.beforeAllSubcases(t => {
375-
const { format, texture_type } = t.params;
376-
t.skipIfTextureFormatNotSupportedDeprecated(format);
377-
t.skipIfTextureLoadNotSupportedForTextureTypeDeprecated(texture_type);
378-
t.skipIfMultisampleNotSupportedForFormatDeprecated(format);
379-
})
380359
.fn(async t => {
381360
const { texture_type, format, stage, samplePoints, C, S } = t.params;
361+
t.skipIfTextureFormatNotSupported(format);
362+
t.skipIfTextureLoadNotSupportedForTextureType(texture_type);
363+
t.skipIfTextureFormatNotMultisampled(format);
382364

383365
const sampleCount = 4;
384366
const descriptor: GPUTextureDescriptor = {
@@ -446,20 +428,16 @@ Parameters:
446428
.params(u =>
447429
u
448430
.combine('stage', kShortShaderStages)
449-
.combine('format', kDepthStencilFormats)
450-
// filter out stencil only formats
451-
.filter(t => isDepthTextureFormat(t.format))
431+
.combine('format', kDepthTextureFormats)
452432
.beginSubcases()
453433
.combine('samplePoints', kSamplePointMethods)
454434
.combine('C', ['i32', 'u32'] as const)
455435
.combine('L', ['i32', 'u32'] as const)
456436
)
457-
.beforeAllSubcases(t => {
458-
t.skipIfTextureLoadNotSupportedForTextureTypeDeprecated('texture_depth_2d');
459-
t.selectDeviceForTextureFormatOrSkipTestCase(t.params.format);
460-
})
461437
.fn(async t => {
462438
const { format, stage, samplePoints, C, L } = t.params;
439+
t.skipIfTextureFormatNotSupported(format);
440+
t.skipIfTextureLoadNotSupportedForTextureType('texture_depth_2d');
463441

464442
// We want at least 4 blocks or something wide enough for 3 mip levels.
465443
const size = chooseTextureSize({ minSize: 8, minBlocks: 4, format });
@@ -623,14 +601,10 @@ Parameters:
623601
] as const)
624602
.combine('depthOrArrayLayers', [1, 8] as const)
625603
)
626-
.beforeAllSubcases(t => {
627-
const { format, texture_type } = t.params;
628-
t.skipIfTextureFormatNotSupportedDeprecated(format);
629-
t.skipIfTextureLoadNotSupportedForTextureTypeDeprecated(texture_type);
630-
t.selectDeviceForTextureFormatOrSkipTestCase(format);
631-
})
632604
.fn(async t => {
633605
const { texture_type, format, stage, samplePoints, C, A, L, depthOrArrayLayers } = t.params;
606+
t.skipIfTextureFormatNotSupported(format);
607+
t.skipIfTextureLoadNotSupportedForTextureType(texture_type);
634608

635609
// We want at least 4 blocks or something wide enough for 3 mip levels.
636610
const [width, height] = chooseTextureSize({ minSize: 8, minBlocks: 4, format });
@@ -702,22 +676,18 @@ Parameters:
702676
.params(u =>
703677
u
704678
.combine('stage', kShortShaderStages)
705-
.combineWithParams([...TexelFormats, { format: 'bgra8unorm' }] as const)
679+
.combine('format', kPossibleStorageTextureFormats)
706680
.beginSubcases()
707681
.combine('samplePoints', kSamplePointMethods)
708682
.combine('C', ['i32', 'u32'] as const)
709683
)
710-
.beforeAllSubcases(t => {
711-
t.skipIf(!t.hasLanguageFeature('readonly_and_readwrite_storage_textures'));
712-
if (t.params.format === 'bgra8unorm') {
713-
t.selectDeviceOrSkipTestCase('bgra8unorm-storage');
714-
} else {
715-
t.skipIfTextureFormatNotUsableAsStorageTextureDeprecated(t.params.format as GPUTextureFormat);
716-
}
717-
})
684+
.beforeAllSubcases(t =>
685+
t.skipIfLanguageFeatureNotSupported('readonly_and_readwrite_storage_textures')
686+
)
718687
.fn(async t => {
719688
const { format, stage, samplePoints, C } = t.params;
720689

690+
t.skipIfTextureFormatNotUsableAsStorageTexture(format);
721691
skipIfStorageTexturesNotSupportedInStage(t, stage);
722692

723693
// We want at least 3 blocks or something wide enough for 3 mip levels.
@@ -783,22 +753,19 @@ Parameters:
783753
.params(u =>
784754
u
785755
.combine('stage', kShortShaderStages)
786-
.combineWithParams([...TexelFormats, { format: 'bgra8unorm' }] as const)
756+
.combine('format', kPossibleStorageTextureFormats)
787757
.beginSubcases()
788758
.combine('samplePoints', kSamplePointMethods)
789759
.combine('C', ['i32', 'u32'] as const)
790760
)
791-
.beforeAllSubcases(t => {
792-
t.skipIf(!t.hasLanguageFeature('readonly_and_readwrite_storage_textures'));
793-
if (t.params.format === 'bgra8unorm') {
794-
t.selectDeviceOrSkipTestCase('bgra8unorm-storage');
795-
} else {
796-
t.skipIfTextureFormatNotUsableAsStorageTextureDeprecated(t.params.format as GPUTextureFormat);
797-
}
798-
})
761+
.beforeAllSubcases(t =>
762+
t.skipIfLanguageFeatureNotSupported('readonly_and_readwrite_storage_textures')
763+
)
799764
.fn(async t => {
800765
const { format, stage, samplePoints, C } = t.params;
801766

767+
t.skipIfTextureFormatNotSupported(format);
768+
t.skipIfTextureFormatNotUsableAsStorageTexture(format);
802769
skipIfStorageTexturesNotSupportedInStage(t, stage);
803770

804771
// We want at least 3 blocks or something wide enough for 3 mip levels.
@@ -864,24 +831,21 @@ Parameters:
864831
.params(u =>
865832
u
866833
.combine('stage', kShortShaderStages)
867-
.combineWithParams([...TexelFormats, { format: 'bgra8unorm' }] as const)
834+
.combine('format', kPossibleStorageTextureFormats)
868835
.beginSubcases()
869836
.combine('samplePoints', kSamplePointMethods)
870837
.combine('C', ['i32', 'u32'] as const)
871838
.combine('A', ['i32', 'u32'] as const)
872839
.combine('depthOrArrayLayers', [1, 8] as const)
873840
)
874-
.beforeAllSubcases(t => {
875-
t.skipIf(!t.hasLanguageFeature('readonly_and_readwrite_storage_textures'));
876-
if (t.params.format === 'bgra8unorm') {
877-
t.selectDeviceOrSkipTestCase('bgra8unorm-storage');
878-
} else {
879-
t.skipIfTextureFormatNotUsableAsStorageTextureDeprecated(t.params.format as GPUTextureFormat);
880-
}
881-
})
841+
.beforeAllSubcases(t =>
842+
t.skipIfLanguageFeatureNotSupported('readonly_and_readwrite_storage_textures')
843+
)
882844
.fn(async t => {
883845
const { format, stage, samplePoints, C, A, depthOrArrayLayers } = t.params;
884846

847+
t.skipIfTextureFormatNotSupported(format);
848+
t.skipIfTextureFormatNotUsableAsStorageTexture(format);
885849
skipIfStorageTexturesNotSupportedInStage(t, stage);
886850

887851
// We want at least 3 blocks or something wide enough for 3 mip levels.
@@ -952,22 +916,19 @@ Parameters:
952916
.params(u =>
953917
u
954918
.combine('stage', kShortShaderStages)
955-
.combineWithParams([...TexelFormats, { format: 'bgra8unorm' }] as const)
919+
.combine('format', kPossibleStorageTextureFormats)
956920
.beginSubcases()
957921
.combine('samplePoints', kSamplePointMethods)
958922
.combine('C', ['i32', 'u32'] as const)
959923
)
960924
.beforeAllSubcases(t => {
961-
t.skipIf(!t.hasLanguageFeature('readonly_and_readwrite_storage_textures'));
962-
if (t.params.format === 'bgra8unorm') {
963-
t.selectDeviceOrSkipTestCase('bgra8unorm-storage');
964-
} else {
965-
t.skipIfTextureFormatNotUsableAsStorageTextureDeprecated(t.params.format as GPUTextureFormat);
966-
}
925+
t.skipIfLanguageFeatureNotSupported('readonly_and_readwrite_storage_textures');
967926
})
968927
.fn(async t => {
969928
const { format, stage, samplePoints, C } = t.params;
970929

930+
t.skipIfTextureFormatNotSupported(format);
931+
t.skipIfTextureFormatNotUsableAsStorageTexture(format);
971932
skipIfStorageTexturesNotSupportedInStage(t, stage);
972933

973934
// We want at least 3 blocks or something wide enough for 3 mip levels.

src/webgpu/util/texture.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ const kLoadValueFromStorageInfo: Partial<{
114114
texelType: 'vec4i',
115115
unpackWGSL: 'return unpack4xI8(getSrc(byteOffset / 4))',
116116
},
117+
rg11b10ufloat: {
118+
storageType: 'u32',
119+
texelType: 'vec4f',
120+
unpackWGSL: `return unpackRG11B10UFloat(getSrc(byteOffset / 4))`,
121+
},
117122
r16float: {
118123
storageType: 'u32',
119124
texelType: 'vec4f',
@@ -308,6 +313,53 @@ function getCopyBufferToTextureViaRenderCode(
308313
return textureLoad(src, vec2u(x, y), 0).r;
309314
}
310315
316+
const kFloat32FormatMantissaBits = 23;
317+
const kFloat32FormatBias = 127;
318+
fn floatBitsToNumber(
319+
rawBits: u32,
320+
bitOffset: u32,
321+
exponentBits: u32,
322+
mantissaBits: u32,
323+
bias: u32,
324+
signed: bool) -> f32 {
325+
let nonSignBits = exponentBits + mantissaBits;
326+
let allBits = nonSignBits + select(0u, 1u, signed);
327+
let allMask = (1u << allBits) - 1u;
328+
let bits = (rawBits >> bitOffset) & allMask;
329+
let nonSignBitsMask = (1u << nonSignBits) - 1u;
330+
let exponentAndMantissaBits = bits & nonSignBitsMask;
331+
let exponentMask = ((1u << exponentBits) - 1u) << mantissaBits;
332+
let infinityOrNaN = (bits & exponentMask) == exponentMask;
333+
if (infinityOrNaN) {
334+
let mantissaMask = (1u << mantissaBits) - 1;
335+
let signBit = 1u << nonSignBits;
336+
let isNegative = (bits & signBit) != 0;
337+
if ((bits & mantissaMask) != 0u) {
338+
return 0.0; // NaN (does not exist in WGSL)
339+
}
340+
if (isNegative) {
341+
return f32(-2e38); // NEGATIVE_INFINITY (does not exist in WGSL)
342+
} else {
343+
return f32(2e38); // POSITIVE_INFINITY (does not exist in WGSL)
344+
}
345+
}
346+
var f32BitsWithWrongBias =
347+
exponentAndMantissaBits << (kFloat32FormatMantissaBits - mantissaBits);
348+
// add in the sign
349+
f32BitsWithWrongBias |= (bits << (31u - nonSignBits)) & 0x80000000u;
350+
let numberWithWrongBias = bitcast<f32>(f32BitsWithWrongBias);
351+
return numberWithWrongBias * pow(2.0f, f32(kFloat32FormatBias - bias));
352+
}
353+
354+
fn unpackRG11B10UFloat(v: u32) -> vec4f {
355+
return vec4f(
356+
floatBitsToNumber(v, 0, 5, 6, 15, false),
357+
floatBitsToNumber(v, 11, 5, 6, 15, false),
358+
floatBitsToNumber(v, 22, 5, 5, 15, false),
359+
1
360+
);
361+
}
362+
311363
fn unpack(byteOffset: u32) -> ${texelType} {
312364
${unpackWGSL};
313365
}

0 commit comments

Comments
 (0)