Adds CTS test coverage for the `snorm10-10-10-2` vertex format. (#4695)
* This PR adds CTS test coverage for the `snorm10-10-10-2` vertex format.
* Adds `snorm10-10-10-2` to `kVertexFormatInfo` in `capability_info.ts` (with an explicit cast until `@webgpu/types` is updated).
* Adds signed 10-10-10-2 bit-packing (`makeRgb10a2Signed`) and normalization (`normalizeRgb10a2Signed`) test helpers.
* Adds packed format test data in `correctness.spec.ts` to verify conversion from raw vertex data to `vec4<f32>` in the vertex shader.
Issue: https://github.com/gpuweb/gpuweb/issues/6292
<hr>
**Requirements for PR author:**
- [x] All missing test coverage is tracked with "TODO" or `.unimplemented()`.
- [x] New helpers are `/** documented */` and new helper files are found in `helper_index.txt`.
- [x] Test behaves as expected in a WebGPU implementation. (If not passing, explain above.)
- [x] Test have be tested with compatibility mode validation enabled and behave as expected. (If not passing, explain above.)
**Requirements for [reviewer sign-off](https://github.com/gpuweb/cts/blob/main/docs/reviews.md):**
- [ ] Tests are properly located.
- [ ] [Test descriptions](https://github.com/gpuweb/cts/blob/main/docs/intro/plans.md) are accurate and complete.
- [ ] Tests provide complete coverage (including validation control cases). **Missing coverage MUST be covered by TODOs.**
- [ ] Tests avoid [over-parameterization](https://github.com/gpuweb/cts/blob/main/docs/organization.md#parameterization) (see case count report).
When landing this PR, be sure to make any necessary issue status updates.
* Roll @webgpu/types to 0.1.72
* Address review comments on makeRgb10a2Signed
---------
Co-authored-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/package-lock.json b/package-lock.json
index fb65120..d61298a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,7 +24,7 @@
"@types/w3c-image-capture": "^1.0.10",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
- "@webgpu/types": "^0.1.71",
+ "@webgpu/types": "^0.1.72",
"ansi-colors": "4.1.3",
"babel-plugin-add-header-comment": "^1.0.3",
"babel-plugin-const-enum": "^1.2.0",
@@ -148,7 +148,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
"integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
"dev": true,
- "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.22.13",
@@ -1042,7 +1041,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz",
"integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==",
"dev": true,
- "peer": true,
"dependencies": {
"undici-types": "~5.26.4"
}
@@ -1218,7 +1216,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz",
"integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==",
"dev": true,
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "6.9.1",
"@typescript-eslint/types": "6.9.1",
@@ -1542,11 +1539,10 @@
"dev": true
},
"node_modules/@webgpu/types": {
- "version": "0.1.71",
- "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.71.tgz",
- "integrity": "sha512-mMy8/ODcKhab808co15eW+yN+HgXoQxRQHTiBV9Mrvl1r0ufnid7YOcI+gi4eUWSWl9ezD6TW2KXccrL8HCh2A==",
- "dev": true,
- "license": "BSD-3-Clause"
+ "version": "0.1.72",
+ "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.72.tgz",
+ "integrity": "sha512-0cF7RFM2edNoiIS1ODJp0/Gzv4/xSXhwoR0YCza+OWpJWtn4wmo9DvK91aLlH9+uUnwIriP7ZiC3WitmyhuzBw==",
+ "dev": true
},
"node_modules/abbrev": {
"version": "1.1.1",
@@ -1572,7 +1568,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
"dev": true,
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2042,7 +2037,6 @@
"url": "https://github.com/sponsors/ai"
}
],
- "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001541",
"electron-to-chromium": "^1.4.535",
@@ -2903,7 +2897,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz",
"integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==",
"dev": true,
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -4356,7 +4349,6 @@
"resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz",
"integrity": "sha512-/ABUy3gYWu5iBmrUSRBP97JLpQUm0GgVveDCp6t3yRNIoltIYw7rEj3g5y1o2PGPR2vfTRGa7WC/LZHLTXnEzA==",
"dev": true,
- "peer": true,
"dependencies": {
"dateformat": "~4.6.2",
"eventemitter2": "~0.4.13",
@@ -4834,7 +4826,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"dev": true,
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
@@ -5042,7 +5033,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz",
"integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==",
"dev": true,
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -7220,7 +7210,6 @@
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
"integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
"dev": true,
- "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -8645,7 +8634,6 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
"dev": true,
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -9054,7 +9042,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
"integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
"dev": true,
- "peer": true,
"requires": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.22.13",
@@ -9760,7 +9747,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz",
"integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==",
"dev": true,
- "peer": true,
"requires": {
"undici-types": "~5.26.4"
}
@@ -9901,7 +9887,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz",
"integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==",
"dev": true,
- "peer": true,
"requires": {
"@typescript-eslint/scope-manager": "6.9.1",
"@typescript-eslint/types": "6.9.1",
@@ -10091,9 +10076,9 @@
"dev": true
},
"@webgpu/types": {
- "version": "0.1.71",
- "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.71.tgz",
- "integrity": "sha512-mMy8/ODcKhab808co15eW+yN+HgXoQxRQHTiBV9Mrvl1r0ufnid7YOcI+gi4eUWSWl9ezD6TW2KXccrL8HCh2A==",
+ "version": "0.1.72",
+ "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.72.tgz",
+ "integrity": "sha512-0cF7RFM2edNoiIS1ODJp0/Gzv4/xSXhwoR0YCza+OWpJWtn4wmo9DvK91aLlH9+uUnwIriP7ZiC3WitmyhuzBw==",
"dev": true
},
"abbrev": {
@@ -10116,8 +10101,7 @@
"version": "8.11.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
"integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
- "dev": true,
- "peer": true
+ "dev": true
},
"acorn-jsx": {
"version": "5.3.2",
@@ -10463,7 +10447,6 @@
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
"integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==",
"dev": true,
- "peer": true,
"requires": {
"caniuse-lite": "^1.0.30001541",
"electron-to-chromium": "^1.4.535",
@@ -11092,7 +11075,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz",
"integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==",
"dev": true,
- "peer": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -12160,7 +12142,6 @@
"resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz",
"integrity": "sha512-/ABUy3gYWu5iBmrUSRBP97JLpQUm0GgVveDCp6t3yRNIoltIYw7rEj3g5y1o2PGPR2vfTRGa7WC/LZHLTXnEzA==",
"dev": true,
- "peer": true,
"requires": {
"dateformat": "~4.6.2",
"eventemitter2": "~0.4.13",
@@ -12513,7 +12494,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"dev": true,
- "peer": true,
"requires": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
@@ -12641,7 +12621,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz",
"integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==",
"dev": true,
- "peer": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -14230,8 +14209,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
"integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
- "dev": true,
- "peer": true
+ "dev": true
},
"prettier-linter-helpers": {
"version": "1.0.0",
@@ -15307,8 +15285,7 @@
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
- "dev": true,
- "peer": true
+ "dev": true
},
"unbox-primitive": {
"version": "1.0.2",
diff --git a/package.json b/package.json
index 7493b84..ec9e302 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
"@types/w3c-image-capture": "^1.0.10",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
- "@webgpu/types": "^0.1.71",
+ "@webgpu/types": "^0.1.72",
"ansi-colors": "4.1.3",
"babel-plugin-add-header-comment": "^1.0.3",
"babel-plugin-const-enum": "^1.2.0",
diff --git a/src/webgpu/api/operation/vertex_state/correctness.spec.ts b/src/webgpu/api/operation/vertex_state/correctness.spec.ts
index 8ddeaa4..44baebd 100644
--- a/src/webgpu/api/operation/vertex_state/correctness.spec.ts
+++ b/src/webgpu/api/operation/vertex_state/correctness.spec.ts
@@ -71,6 +71,26 @@
return rgba / normalizationFactor;
}
+function makeRgb10a2Signed(rgba: Array<number>): number {
+ const [r, g, b, a] = rgba;
+ // Check the input fits in i32, then check it's in range for i10 or i2.
+ assert((r | 0) === r && r >= -512 && r <= 511);
+ assert((g | 0) === g && g >= -512 && g <= 511);
+ assert((b | 0) === b && b >= -512 && b <= 511);
+ assert((a | 0) === a && a >= -2 && a <= 1);
+ const r_bits = r & 0x3ff;
+ const g_bits = g & 0x3ff;
+ const b_bits = b & 0x3ff;
+ const a_bits = a & 0x3;
+ return r_bits | (g_bits << 10) | (b_bits << 20) | (a_bits << 30);
+}
+
+function normalizeRgb10a2Signed(val: number, index: number): number {
+ const isAlpha = index % 4 === 3;
+ const maxVal = isAlpha ? 1 : 511;
+ return Math.max(val / maxVal, -1.0);
+}
+
type TestData = {
shaderBaseType: string;
floatTolerance?: number;
@@ -379,6 +399,32 @@
}
case 'snorm': {
+ if (formatInfo.bytesPerComponent === 'packed') {
+ assert(bitSize === 0);
+ switch (format as string) {
+ case 'snorm10-10-10-2': {
+ /* prettier-ignore */
+ const data = [
+ [ 0, 0, 0, 0],
+ [ 511, 511, 511, 1],
+ [-512, -512, -512, -2],
+ [ 243, -123, 342, -1],
+ ];
+ const vertexData = new Uint32Array(data.map(makeRgb10a2Signed)).buffer;
+ const expectedData = new Float32Array(data.flat().map(normalizeRgb10a2Signed)).buffer;
+
+ return {
+ shaderBaseType: 'f32',
+ testComponentCount: data.flat().length,
+ expectedData,
+ vertexData,
+ floatTolerance: 0.1 / 511,
+ };
+ }
+ default:
+ unreachable();
+ }
+ }
/* prettier-ignore */
const data = [
42,
diff --git a/src/webgpu/capability_info.ts b/src/webgpu/capability_info.ts
index b13e310..017227c 100644
--- a/src/webgpu/capability_info.ts
+++ b/src/webgpu/capability_info.ts
@@ -371,6 +371,7 @@
// 32 bit packed
'unorm10-10-10-2': [ 'packed', 'unorm', 4, 4, 'vec4<f32>'],
'unorm8x4-bgra': [ 'packed', 'unorm', 4, 4, 'vec4<f32>'],
+ 'snorm10-10-10-2': [ 'packed', 'snorm', 4, 4, 'vec4<f32>'],
} as const);
/** List of all GPUVertexFormat values. */
export const kVertexFormats = keysOf(kVertexFormatInfo);