[emscripten] Implement subgroup matrix

Also:

- Add tests that print adapter/device features and adapter info
  (including subgroup matrix configs)

- Fix printing of test parameter names for readability:

  -SpotTests.DeviceFeatures/0
  +SpotTests.DeviceFeatures/MinCompat

Bug: 403607795
Change-Id: Ic4997914c630a647827408c2312d2b5db89ef8fc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/331255
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Shao, Jiawei <jiawei.shao@intel.com>
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 5ebbe2a..b36f24e 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -2553,7 +2553,7 @@
             {"value": 49, "name": "multi draw indirect", "tags": ["dawn", "emscripten"], "jsrepr": "'chromium-experimental-multi-draw-indirect'"},
             {"value": 50, "name": "dawn texel copy buffer row alignment", "tags": ["dawn"]},
             {"value": 51, "name": "flexible texture views", "tags": ["dawn"]},
-            {"value": 52, "name": "chromium experimental subgroup matrix", "tags": ["dawn"]},
+            {"value": 52, "name": "chromium experimental subgroup matrix", "tags": ["dawn", "emscripten"]},
             {"value": 53, "name": "shared fence EGL sync", "tags": ["dawn", "native"]},
             {"value": 54, "name": "dawn device allocator control", "tags": ["dawn"]},
             {"value": 55, "name": "adapter properties WGPU", "tags": ["dawn"]},
@@ -4164,7 +4164,7 @@
             {"value": 55, "name": "shared texture memory a hardware buffer properties", "tags": ["dawn", "native"]},
             {"value": 56, "name": "a hardware buffer properties", "tags": ["dawn", "native"]},
             {"value": 58, "name": "dawn texel copy buffer row alignment limits", "tags": ["dawn"]},
-            {"value": 59, "name": "adapter properties subgroup matrix configs", "tags": ["dawn"]},
+            {"value": 59, "name": "adapter properties subgroup matrix configs", "tags": ["dawn", "emscripten"]},
             {"value": 60, "name": "shared fence EGL sync descriptor", "tags": ["dawn", "native"]},
             {"value": 61, "name": "shared fence EGL sync export info", "tags": ["dawn", "native"]},
             {"value": 62, "name": "dawn injected invalid s type", "tags": ["dawn"]},
@@ -4887,20 +4887,19 @@
     },
     "subgroup matrix component type": {
         "category": "enum",
-        "emscripten_no_enum_table": true,
-        "tags": ["dawn"],
+        "tags": ["dawn", "emscripten"],
         "values": [
-            {"value": 1, "name": "f32"},
-            {"value": 2, "name": "f16"},
-            {"value": 3, "name": "u32"},
-            {"value": 4, "name": "i32"},
-            {"value": 5, "name": "u8"},
-            {"value": 6, "name": "i8"}
+            {"value": 1, "name": "f32", "jsrepr": "'f32'"},
+            {"value": 2, "name": "f16", "jsrepr": "'f16'"},
+            {"value": 3, "name": "u32", "jsrepr": "'u32'"},
+            {"value": 4, "name": "i32", "jsrepr": "'i32'"},
+            {"value": 5, "name": "u8", "jsrepr": "'u8'"},
+            {"value": 6, "name": "i8", "jsrepr": "'i8'"}
         ]
     },
     "subgroup matrix config": {
         "category": "structure",
-        "tags": ["dawn"],
+        "tags": ["dawn", "emscripten"],
         "members": [
             {"name": "component type", "type": "subgroup matrix component type"},
             {"name": "result component type", "type": "subgroup matrix component type"},
@@ -4913,7 +4912,7 @@
         "category": "structure",
         "chained": "out",
         "chain roots": ["adapter info"],
-        "tags": ["dawn"],
+        "tags": ["dawn", "emscripten"],
         "members": [
             {"name": "config count", "type": "size_t"},
             {"name": "configs", "type": "subgroup matrix config", "annotation": "const*", "length": "config count"}
diff --git a/src/emdawnwebgpu/tests/SpotTests.cpp b/src/emdawnwebgpu/tests/SpotTests.cpp
index a40f8e0..16415e2 100644
--- a/src/emdawnwebgpu/tests/SpotTests.cpp
+++ b/src/emdawnwebgpu/tests/SpotTests.cpp
@@ -144,7 +144,10 @@
     bool mGotCompatibilityMode = false;
 };
 
-INSTANTIATE_TEST_SUITE_P(, SpotTests, ::testing::ValuesIn({Mode::MinCompat, Mode::MaxCore}));
+INSTANTIATE_TEST_SUITE_P(,
+                         SpotTests,
+                         ::testing::ValuesIn({Mode::MinCompat, Mode::MaxCore}),
+                         ::testing::PrintToStringParamName());
 
 TEST_P(SpotTests, QuerySet) {
     // Spot test wgpuQuerySetGetType which uses indexOf on an int-to-string table.
@@ -220,10 +223,12 @@
     wgpu::SupportedWGSLLanguageFeatures f;
     mInstance.GetWGSLLanguageFeatures(&f);
     auto features = DAWN_UNSAFE_TODO(std::span(f.features, f.featureCount));
+    std::cout << "GetWGSLLanguageFeatures:\n";
     for (auto feature : features) {
         // GetWGSLLanguageFeatures should filter out any unknown features.
         EXPECT_NE(feature, wgpu::WGSLLanguageFeatureName{0});
         EXPECT_TRUE(mInstance.HasWGSLLanguageFeature(feature));
+        std::cout << "  - " << feature << "\n";
     }
 
     // Test a specific feature to make sure minification worked.
@@ -520,4 +525,41 @@
                                     : wgpu::TextureViewDimension::Undefined);
 }
 
+TEST_P(SpotTests, AdapterInfo) {
+    wgpu::AdapterPropertiesSubgroupMatrixConfigs extConfigs;
+    wgpu::AdapterInfo info;
+    info.nextInChain = &extConfigs;
+
+    mAdapter.GetInfo(&info);
+    std::cout << "AdapterInfo:\n  ";
+    std::cout << info.vendor << ", " << info.architecture << ", " << info.device << ", "
+              << info.description << ",\n  ";
+    std::cout << info.backendType << ", " << info.adapterType << ",\n  ";
+    std::cout << info.vendorID << ", " << info.deviceID << ",\n  ";
+    std::cout << info.subgroupMinSize << ", " << info.subgroupMaxSize << "\n";
+    std::cout << "AdapterPropertiesSubgroupMatrixConfigs:\n";
+    for (auto cfg : DAWN_UNSAFE_TODO(std::span(extConfigs.configs, extConfigs.configCount))) {
+        std::cout << "  - " << cfg.componentType << ", " << cfg.resultComponentType << ", " << cfg.M
+                  << ", " << cfg.N << ", " << cfg.K << "\n";
+    }
+}
+
+TEST_P(SpotTests, AdapterFeatures) {
+    wgpu::SupportedFeatures features;
+    mAdapter.GetFeatures(&features);
+    std::cout << "Adapter features:\n";
+    for (auto feature : DAWN_UNSAFE_TODO(std::span(features.features, features.featureCount))) {
+        std::cout << "  - " << feature << "\n";
+    }
+}
+
+TEST_P(SpotTests, DeviceFeatures) {
+    wgpu::SupportedFeatures features;
+    mDevice.GetFeatures(&features);
+    std::cout << "Device features:\n";
+    for (auto feature : DAWN_UNSAFE_TODO(std::span(features.features, features.featureCount))) {
+        std::cout << "  - " << feature << "\n";
+    }
+}
+
 }  // namespace
diff --git a/third_party/emdawnwebgpu/pkg/webgpu/src/library_webgpu.js b/third_party/emdawnwebgpu/pkg/webgpu/src/library_webgpu.js
index 2f6298b..11ee034 100644
--- a/third_party/emdawnwebgpu/pkg/webgpu/src/library_webgpu.js
+++ b/third_party/emdawnwebgpu/pkg/webgpu/src/library_webgpu.js
@@ -612,7 +612,7 @@
 
     fillAdapterInfoStruct__deps: ['$stringToNewUTF8', '$lengthBytesUTF8'],
     fillAdapterInfoStruct: (info, infoStruct) => {
-      {{{ gpu.makeCheckDescriptor('infoStruct') }}}
+      {{{ gpu.makeCheck('infoStruct') }}}
 
       // Populate subgroup limits.
       {{{ makeSetValue('infoStruct', C_STRUCTS.WGPUAdapterInfo.subgroupMinSize, 'info.subgroupMinSize', 'u32') }}};
@@ -643,6 +643,29 @@
       {{{ makeSetValue('infoStruct', C_STRUCTS.WGPUAdapterInfo.adapterType, 'adapterType', 'i32') }}};
       {{{ makeSetValue('infoStruct', C_STRUCTS.WGPUAdapterInfo.vendorID, '0', 'u32') }}};
       {{{ makeSetValue('infoStruct', C_STRUCTS.WGPUAdapterInfo.deviceID, '0', 'u32') }}};
+
+      WebGPU.iterateExtensions(infoStruct, {
+        {{{ gpu.SType.AdapterPropertiesSubgroupMatrixConfigs }}}: (ext) => {
+          let configCount = 0;
+          let configsPtr = {{{ gpu.NULLPTR }}};
+          if (info.subgroupMatrixConfigs) {
+            configCount = info.subgroupMatrixConfigs.length;
+            configsPtr = _malloc(configCount * {{{ C_STRUCTS.WGPUSubgroupMatrixConfig.__size__ }}});
+            for (const [i, cfg] of info.subgroupMatrixConfigs.entries()) {
+              const ptr = configsPtr + i * {{{ C_STRUCTS.WGPUSubgroupMatrixConfig.__size__ }}};
+              const componentType = WebGPU.SubgroupMatrixComponentType.indexOf(cfg.componentType);
+              const resultComponentType = WebGPU.SubgroupMatrixComponentType.indexOf(cfg.resultComponentType);
+              {{{ makeSetValue('ptr', C_STRUCTS.WGPUSubgroupMatrixConfig.componentType, 'componentType', 'i32') }}};
+              {{{ makeSetValue('ptr', C_STRUCTS.WGPUSubgroupMatrixConfig.resultComponentType, 'resultComponentType', 'i32') }}};
+              {{{ makeSetValue('ptr', C_STRUCTS.WGPUSubgroupMatrixConfig.M, 'cfg.M', 'u32') }}};
+              {{{ makeSetValue('ptr', C_STRUCTS.WGPUSubgroupMatrixConfig.N, 'cfg.N', 'u32') }}};
+              {{{ makeSetValue('ptr', C_STRUCTS.WGPUSubgroupMatrixConfig.K, 'cfg.K', 'u32') }}};
+            }
+          }
+          {{{ makeSetValue('ext', C_STRUCTS.WGPUAdapterPropertiesSubgroupMatrixConfigs.configs, 'configsPtr', '*') }}};
+          {{{ makeSetValue('ext', C_STRUCTS.WGPUAdapterPropertiesSubgroupMatrixConfigs.configCount, 'configCount', '*') }}};
+        },
+      });
     },
 
     // Maps from enum number to enum string.
diff --git a/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu-externs.js b/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu-externs.js
index 81ada6b..390efac 100644
--- a/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu-externs.js
+++ b/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu-externs.js
@@ -206,6 +206,21 @@
 GPUAdapterInfo.prototype.subgroupMinSize;
 /** @type {number} */
 GPUAdapterInfo.prototype.subgroupMaxSize;
+/** @type {Iterator<GPUSubgroupMatrixConfig>} */
+GPUAdapterInfo.prototype.subgroupMatrixConfigs;
+
+/** @constructor */
+function GPUSubgroupMatrixConfig() {}
+/** @type {string} */
+GPUSubgroupMatrixConfig.prototype.componentType;
+/** @type {string} */
+GPUSubgroupMatrixConfig.prototype.resultComponentType;
+/** @type {number} */
+GPUSubgroupMatrixConfig.prototype.M;
+/** @type {number} */
+GPUSubgroupMatrixConfig.prototype.N;
+/** @type {number} */
+GPUSubgroupMatrixConfig.prototype.K;
 
 /** @constructor */
 function GPU() {}
diff --git a/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp b/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp
index 37ca156..37a00e6 100644
--- a/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp
+++ b/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp
@@ -1813,6 +1813,11 @@
   free(const_cast<char*>(value.vendor.data));
 }
 
+void wgpuAdapterPropertiesSubgroupMatrixConfigsFreeMembers(
+    WGPUAdapterPropertiesSubgroupMatrixConfigs ext) {
+  free(const_cast<WGPUSubgroupMatrixConfig*>(ext.configs));
+}
+
 void wgpuSupportedFeaturesFreeMembers(WGPUSupportedFeatures value) {
   free(const_cast<WGPUFeatureName*>(value.features));
 }