From b5c735a5d2fcff8c23a24fa985a69a23706fefb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Thu, 31 Oct 2024 08:23:24 +0100 Subject: [PATCH 1/7] Add tests for GPUDevice.adapterInfo --- src/webgpu/api/operation/device/info.spec.ts | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/webgpu/api/operation/device/info.spec.ts diff --git a/src/webgpu/api/operation/device/info.spec.ts b/src/webgpu/api/operation/device/info.spec.ts new file mode 100644 index 000000000000..aa40225450a5 --- /dev/null +++ b/src/webgpu/api/operation/device/info.spec.ts @@ -0,0 +1,34 @@ +export const description = ` +Tests GPUDevice.adapterInfo member. +`; + +import { Fixture } from '../../../../common/framework/fixture.js'; +import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { getGPU } from '../../../../common/util/navigator_gpu.js'; +import { assert, objectEquals } from '../../../../common/util/util.js'; + +export const g = makeTestGroup(Fixture); + +g.test('device_adapter_info') + .desc( + ` + Test that GPUDevice.adapterInfo matches GPUAdapter.info` + ) + .fn(async t => { + const gpu = getGPU(t.rec); + const adapter = await gpu.requestAdapter(); + assert(adapter !== null); + + const device = await t.requestDeviceTracked(adapter); + assert(device !== null); + + assert(device.adapterInfo instanceof GPUAdapterInfo); + assert(adapter.info instanceof GPUAdapterInfo); + + for (const k of Object.keys(GPUAdapterInfo.prototype)) { + t.expect( + objectEquals(device.adapterInfo[k], adapter.info[k]), + `device.adapterInfo.${k} is "${device.adapterInfo[k]}". Expected "${adapter.info[k]}"` + ); + } + }); From 5b2d7b46651b3fae689a854066487cf0018666fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Mon, 4 Nov 2024 12:57:55 +0100 Subject: [PATCH 2/7] Address feedback --- src/webgpu/api/operation/adapter/info.spec.ts | 28 +++++++++++++-- src/webgpu/api/operation/device/info.spec.ts | 34 ------------------- 2 files changed, 26 insertions(+), 36 deletions(-) delete mode 100644 src/webgpu/api/operation/device/info.spec.ts diff --git a/src/webgpu/api/operation/adapter/info.spec.ts b/src/webgpu/api/operation/adapter/info.spec.ts index ee5c4e86c57f..94048d050a90 100644 --- a/src/webgpu/api/operation/adapter/info.spec.ts +++ b/src/webgpu/api/operation/adapter/info.spec.ts @@ -1,11 +1,11 @@ export const description = ` -Tests GPUAdapter.info members formatting. +Tests for GPUAdapterInfo. `; import { Fixture } from '../../../../common/framework/fixture.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { getGPU } from '../../../../common/util/navigator_gpu.js'; -import { assert } from '../../../../common/util/util.js'; +import { assert, objectEquals } from '../../../../common/util/util.js'; export const g = makeTestGroup(Fixture); @@ -39,3 +39,27 @@ g.test('adapter_info') `adapterInfo.device should be a normalized identifier. But it's '${adapterInfo.device}'` ); }); + +g.test('device_matches_adapter') +.desc( + ` +Test that GPUDevice.adapterInfo matches GPUAdapter.info` +) +.fn(async t => { + const gpu = getGPU(t.rec); + const adapter = await gpu.requestAdapter(); + assert(adapter !== null); + + const device = await t.requestDeviceTracked(adapter); + assert(device !== null); + + assert(device.adapterInfo instanceof GPUAdapterInfo); + assert(adapter.info instanceof GPUAdapterInfo); + + for (const k of Object.keys(GPUAdapterInfo.prototype)) { + t.expect( + objectEquals(device.adapterInfo[k], adapter.info[k]), + `device.adapterInfo.${k} is "${device.adapterInfo[k]}". Expected "${adapter.info[k]}"` + ); + } +}); diff --git a/src/webgpu/api/operation/device/info.spec.ts b/src/webgpu/api/operation/device/info.spec.ts deleted file mode 100644 index aa40225450a5..000000000000 --- a/src/webgpu/api/operation/device/info.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -export const description = ` -Tests GPUDevice.adapterInfo member. -`; - -import { Fixture } from '../../../../common/framework/fixture.js'; -import { makeTestGroup } from '../../../../common/framework/test_group.js'; -import { getGPU } from '../../../../common/util/navigator_gpu.js'; -import { assert, objectEquals } from '../../../../common/util/util.js'; - -export const g = makeTestGroup(Fixture); - -g.test('device_adapter_info') - .desc( - ` - Test that GPUDevice.adapterInfo matches GPUAdapter.info` - ) - .fn(async t => { - const gpu = getGPU(t.rec); - const adapter = await gpu.requestAdapter(); - assert(adapter !== null); - - const device = await t.requestDeviceTracked(adapter); - assert(device !== null); - - assert(device.adapterInfo instanceof GPUAdapterInfo); - assert(adapter.info instanceof GPUAdapterInfo); - - for (const k of Object.keys(GPUAdapterInfo.prototype)) { - t.expect( - objectEquals(device.adapterInfo[k], adapter.info[k]), - `device.adapterInfo.${k} is "${device.adapterInfo[k]}". Expected "${adapter.info[k]}"` - ); - } - }); From 5a23afd91e395125ece1ae940f228929b1989438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Mon, 4 Nov 2024 18:14:12 +0100 Subject: [PATCH 3/7] Add same_object test --- src/webgpu/api/operation/adapter/info.spec.ts | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/webgpu/api/operation/adapter/info.spec.ts b/src/webgpu/api/operation/adapter/info.spec.ts index 94048d050a90..1758e0127e08 100644 --- a/src/webgpu/api/operation/adapter/info.spec.ts +++ b/src/webgpu/api/operation/adapter/info.spec.ts @@ -40,26 +40,41 @@ g.test('adapter_info') ); }); +g.test('same_object') + .desc( + ` +GPUAdapter.info provides the same object each time it's accessed` + ) + .fn(async t => { + const gpu = getGPU(t.rec); + const adapter = await gpu.requestAdapter(); + assert(adapter !== null); + + const adapterInfo1 = adapter.info; + const adapterInfo2 = adapter.info; + t.expect(adapterInfo1 === adapterInfo2); + }); + g.test('device_matches_adapter') -.desc( - ` + .desc( + ` Test that GPUDevice.adapterInfo matches GPUAdapter.info` -) -.fn(async t => { - const gpu = getGPU(t.rec); - const adapter = await gpu.requestAdapter(); - assert(adapter !== null); + ) + .fn(async t => { + const gpu = getGPU(t.rec); + const adapter = await gpu.requestAdapter(); + assert(adapter !== null); - const device = await t.requestDeviceTracked(adapter); - assert(device !== null); + const device = await t.requestDeviceTracked(adapter); + assert(device !== null); - assert(device.adapterInfo instanceof GPUAdapterInfo); - assert(adapter.info instanceof GPUAdapterInfo); + assert(device.adapterInfo instanceof GPUAdapterInfo); + assert(adapter.info instanceof GPUAdapterInfo); - for (const k of Object.keys(GPUAdapterInfo.prototype)) { - t.expect( - objectEquals(device.adapterInfo[k], adapter.info[k]), - `device.adapterInfo.${k} is "${device.adapterInfo[k]}". Expected "${adapter.info[k]}"` - ); - } -}); + for (const k of Object.keys(GPUAdapterInfo.prototype)) { + t.expect( + objectEquals(device.adapterInfo[k], adapter.info[k]), + `device.adapterInfo.${k} is "${device.adapterInfo[k]}". Expected "${adapter.info[k]}"` + ); + } + }); From d578f69b67012470892686a7bbb68732a667910e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Tue, 5 Nov 2024 18:52:32 +0100 Subject: [PATCH 4/7] Address last feedback --- package-lock.json | 17 ++--- package.json | 2 +- src/webgpu/api/operation/adapter/info.spec.ts | 64 ++++++++++++++++--- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index cc4e97a2ce64..79facbc94e90 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.49", + "@webgpu/types": "^0.1.51", "ansi-colors": "4.1.3", "babel-plugin-add-header-comment": "^1.0.3", "babel-plugin-const-enum": "^1.2.0", @@ -1539,10 +1539,11 @@ "dev": true }, "node_modules/@webgpu/types": { - "version": "0.1.49", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.49.tgz", - "integrity": "sha512-NMmS8/DofhH/IFeW+876XrHVWel+J/vdcFCHLDqeJgkH9x0DeiwjVd8LcBdaxdG/T7Rf8VUAYsA8X1efMzLjRQ==", - "dev": true + "version": "0.1.51", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.51.tgz", + "integrity": "sha512-ktR3u64NPjwIViNCck+z9QeyN0iPkQCUOQ07ZCV1RzlkfP+olLTeEZ95O1QHS+v4w9vJeY9xj/uJuSphsHy5rQ==", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/abbrev": { "version": "1.1.1", @@ -10076,9 +10077,9 @@ "dev": true }, "@webgpu/types": { - "version": "0.1.49", - "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.49.tgz", - "integrity": "sha512-NMmS8/DofhH/IFeW+876XrHVWel+J/vdcFCHLDqeJgkH9x0DeiwjVd8LcBdaxdG/T7Rf8VUAYsA8X1efMzLjRQ==", + "version": "0.1.51", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.51.tgz", + "integrity": "sha512-ktR3u64NPjwIViNCck+z9QeyN0iPkQCUOQ07ZCV1RzlkfP+olLTeEZ95O1QHS+v4w9vJeY9xj/uJuSphsHy5rQ==", "dev": true }, "abbrev": { diff --git a/package.json b/package.json index 3ef62315db25..cef3de27ed1d 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.49", + "@webgpu/types": "^0.1.51", "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/adapter/info.spec.ts b/src/webgpu/api/operation/adapter/info.spec.ts index 1758e0127e08..1b12fce471aa 100644 --- a/src/webgpu/api/operation/adapter/info.spec.ts +++ b/src/webgpu/api/operation/adapter/info.spec.ts @@ -43,7 +43,7 @@ g.test('adapter_info') g.test('same_object') .desc( ` -GPUAdapter.info provides the same object each time it's accessed` +GPUAdapter.info and GPUDevice.adapterInfo provide the same object each time it's accessed` ) .fn(async t => { const gpu = getGPU(t.rec); @@ -53,6 +53,15 @@ GPUAdapter.info provides the same object each time it's accessed` const adapterInfo1 = adapter.info; const adapterInfo2 = adapter.info; t.expect(adapterInfo1 === adapterInfo2); + + const device = await t.requestDeviceTracked(adapter); + assert(device !== null); + + const deviceAdapterInfo1 = device.adapterInfo; + const deviceAdapterInfo2 = device.adapterInfo; + t.expect(deviceAdapterInfo1 === deviceAdapterInfo2); + + t.expect(adapter.info !== device.adapterInfo); }); g.test('device_matches_adapter') @@ -60,7 +69,12 @@ g.test('device_matches_adapter') ` Test that GPUDevice.adapterInfo matches GPUAdapter.info` ) + .paramsSubcasesOnly(u => + u.combine('testDeviceFirst', [true, false]).combine('testMembersFirst', [true, false]) + ) .fn(async t => { + const { testDeviceFirst, testMembersFirst } = t.params; + const gpu = getGPU(t.rec); const adapter = await gpu.requestAdapter(); assert(adapter !== null); @@ -68,13 +82,47 @@ Test that GPUDevice.adapterInfo matches GPUAdapter.info` const device = await t.requestDeviceTracked(adapter); assert(device !== null); - assert(device.adapterInfo instanceof GPUAdapterInfo); - assert(adapter.info instanceof GPUAdapterInfo); + const deviceInfo: unknown[] = []; + const adapterInfo: unknown[] = []; - for (const k of Object.keys(GPUAdapterInfo.prototype)) { - t.expect( - objectEquals(device.adapterInfo[k], adapter.info[k]), - `device.adapterInfo.${k} is "${device.adapterInfo[k]}". Expected "${adapter.info[k]}"` - ); + type GPUAdapterInfoKey = 'vendor' | 'architecture' | 'device' | 'description'; + const GPUAdapterInfoKeys = Object.keys(GPUAdapterInfo.prototype) as GPUAdapterInfoKey[]; + if (testMembersFirst) { + if (testDeviceFirst) { + assert(device.adapterInfo instanceof GPUAdapterInfo); + for (const k of GPUAdapterInfoKeys) { + deviceInfo.push(device.adapterInfo[k]); + } + assert(adapter.info instanceof GPUAdapterInfo); + for (const k of GPUAdapterInfoKeys) { + adapterInfo.push(adapter.info[k]); + } + } else { + assert(adapter.info instanceof GPUAdapterInfo); + for (const k of GPUAdapterInfoKeys) { + adapterInfo.push(adapter.info[k]); + } + assert(device.adapterInfo instanceof GPUAdapterInfo); + for (const k of GPUAdapterInfoKeys) { + deviceInfo.push(device.adapterInfo[k]); + } + } + } else { + if (testDeviceFirst) { + assert(device.adapterInfo instanceof GPUAdapterInfo); + assert(adapter.info instanceof GPUAdapterInfo); + for (const k of GPUAdapterInfoKeys) { + deviceInfo.push(device.adapterInfo[k]); + adapterInfo.push(adapter.info[k]); + } + } else { + assert(adapter.info instanceof GPUAdapterInfo); + assert(device.adapterInfo instanceof GPUAdapterInfo); + for (const k of GPUAdapterInfoKeys) { + adapterInfo.push(adapter.info[k]); + deviceInfo.push(device.adapterInfo[k]); + } + } + t.expect(objectEquals(deviceInfo, adapterInfo)); } }); From 24a4f41b004f012e9a5fd76736d75d76c2081ce6 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Tue, 5 Nov 2024 14:13:05 -0800 Subject: [PATCH 5/7] Apply suggestions from code review --- src/webgpu/api/operation/adapter/info.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/webgpu/api/operation/adapter/info.spec.ts b/src/webgpu/api/operation/adapter/info.spec.ts index 1b12fce471aa..b4385c10ae28 100644 --- a/src/webgpu/api/operation/adapter/info.spec.ts +++ b/src/webgpu/api/operation/adapter/info.spec.ts @@ -43,7 +43,8 @@ g.test('adapter_info') g.test('same_object') .desc( ` -GPUAdapter.info and GPUDevice.adapterInfo provide the same object each time it's accessed` +GPUAdapter.info and GPUDevice.adapterInfo provide the same object each time they're accessed, +but different objects from one another.` ) .fn(async t => { const gpu = getGPU(t.rec); @@ -67,7 +68,8 @@ GPUAdapter.info and GPUDevice.adapterInfo provide the same object each time it's g.test('device_matches_adapter') .desc( ` -Test that GPUDevice.adapterInfo matches GPUAdapter.info` +Test that GPUDevice.adapterInfo matches GPUAdapter.info. Cases access the members in +different orders to make sure that they are consistent regardless of the access order.` ) .paramsSubcasesOnly(u => u.combine('testDeviceFirst', [true, false]).combine('testMembersFirst', [true, false]) From 90d9beb6332f8c445d703f3260e19b72c79ad919 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Tue, 5 Nov 2024 14:16:14 -0800 Subject: [PATCH 6/7] simplify using keysOf --- src/webgpu/api/operation/adapter/info.spec.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/webgpu/api/operation/adapter/info.spec.ts b/src/webgpu/api/operation/adapter/info.spec.ts index b4385c10ae28..a1c44ee4fa0e 100644 --- a/src/webgpu/api/operation/adapter/info.spec.ts +++ b/src/webgpu/api/operation/adapter/info.spec.ts @@ -4,6 +4,7 @@ Tests for GPUAdapterInfo. import { Fixture } from '../../../../common/framework/fixture.js'; import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { keysOf } from '../../../../common/util/data_tables.js'; import { getGPU } from '../../../../common/util/navigator_gpu.js'; import { assert, objectEquals } from '../../../../common/util/util.js'; @@ -87,25 +88,24 @@ different orders to make sure that they are consistent regardless of the access const deviceInfo: unknown[] = []; const adapterInfo: unknown[] = []; - type GPUAdapterInfoKey = 'vendor' | 'architecture' | 'device' | 'description'; - const GPUAdapterInfoKeys = Object.keys(GPUAdapterInfo.prototype) as GPUAdapterInfoKey[]; + const kGPUAdapterInfoKeys = keysOf(GPUAdapterInfo.prototype); if (testMembersFirst) { if (testDeviceFirst) { assert(device.adapterInfo instanceof GPUAdapterInfo); - for (const k of GPUAdapterInfoKeys) { + for (const k of kGPUAdapterInfoKeys) { deviceInfo.push(device.adapterInfo[k]); } assert(adapter.info instanceof GPUAdapterInfo); - for (const k of GPUAdapterInfoKeys) { + for (const k of kGPUAdapterInfoKeys) { adapterInfo.push(adapter.info[k]); } } else { assert(adapter.info instanceof GPUAdapterInfo); - for (const k of GPUAdapterInfoKeys) { + for (const k of kGPUAdapterInfoKeys) { adapterInfo.push(adapter.info[k]); } assert(device.adapterInfo instanceof GPUAdapterInfo); - for (const k of GPUAdapterInfoKeys) { + for (const k of kGPUAdapterInfoKeys) { deviceInfo.push(device.adapterInfo[k]); } } @@ -113,14 +113,14 @@ different orders to make sure that they are consistent regardless of the access if (testDeviceFirst) { assert(device.adapterInfo instanceof GPUAdapterInfo); assert(adapter.info instanceof GPUAdapterInfo); - for (const k of GPUAdapterInfoKeys) { + for (const k of kGPUAdapterInfoKeys) { deviceInfo.push(device.adapterInfo[k]); adapterInfo.push(adapter.info[k]); } } else { assert(adapter.info instanceof GPUAdapterInfo); assert(device.adapterInfo instanceof GPUAdapterInfo); - for (const k of GPUAdapterInfoKeys) { + for (const k of kGPUAdapterInfoKeys) { adapterInfo.push(adapter.info[k]); deviceInfo.push(device.adapterInfo[k]); } From 519ea907f517f7abddd07924ba8ac6ae83d9d377 Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Tue, 5 Nov 2024 14:18:23 -0800 Subject: [PATCH 7/7] add messages to expects --- src/webgpu/api/operation/adapter/info.spec.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/webgpu/api/operation/adapter/info.spec.ts b/src/webgpu/api/operation/adapter/info.spec.ts index a1c44ee4fa0e..89dbbaa621f2 100644 --- a/src/webgpu/api/operation/adapter/info.spec.ts +++ b/src/webgpu/api/operation/adapter/info.spec.ts @@ -54,16 +54,22 @@ but different objects from one another.` const adapterInfo1 = adapter.info; const adapterInfo2 = adapter.info; - t.expect(adapterInfo1 === adapterInfo2); + t.expect(adapterInfo1 === adapterInfo2, 'adapter.info should obey [SameObject]'); const device = await t.requestDeviceTracked(adapter); assert(device !== null); const deviceAdapterInfo1 = device.adapterInfo; const deviceAdapterInfo2 = device.adapterInfo; - t.expect(deviceAdapterInfo1 === deviceAdapterInfo2); + t.expect( + deviceAdapterInfo1 === deviceAdapterInfo2, + 'device.adapterInfo should obey [SameObject]' + ); - t.expect(adapter.info !== device.adapterInfo); + t.expect( + adapter.info !== device.adapterInfo, + 'adapter.info and device.adapterInfo should NOT return the same object' + ); }); g.test('device_matches_adapter')