webgpu.h: Add subgroupMinSize and subgroupMaxSize to AdapterInfo

Spec PR: https://github.com/webgpu-native/webgpu-headers/pull/509

Change-Id: I5510a054304d802dfbcbfe1a03ef8f2e6db36032
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/223876
Reviewed-by: Alan Baker <alanbaker@google.com>
Commit-Queue: Fr <beaufort.francois@gmail.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 99561d5..cffc024 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -181,6 +181,8 @@
             {"name": "adapter type", "type": "adapter type"},
             {"name": "vendor ID", "type": "uint32_t"},
             {"name": "device ID", "type": "uint32_t"},
+            {"name": "subgroup min size", "type": "uint32_t"},
+            {"name": "subgroup max size", "type": "uint32_t"},
             {"name": "compatibility mode", "type": "bool", "default": "false", "tags": ["dawn", "emscripten"]}
         ]
     },
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp
index 811c44c..48e5162 100644
--- a/src/dawn/native/Adapter.cpp
+++ b/src/dawn/native/Adapter.cpp
@@ -235,8 +235,15 @@
     info->adapterType = mPhysicalDevice->GetAdapterType();
     info->vendorID = mPhysicalDevice->GetVendorId();
     info->deviceID = mPhysicalDevice->GetDeviceId();
+    info->subgroupMinSize = mPhysicalDevice->GetSubgroupMinSize();
+    info->subgroupMaxSize = mPhysicalDevice->GetSubgroupMaxSize();
     info->compatibilityMode = mFeatureLevel == wgpu::FeatureLevel::Compatibility;
 
+    if (mPhysicalDevice->GetBackendType() == wgpu::BackendType::D3D12 &&
+        mTogglesState.IsEnabled(Toggle::D3D12RelaxMinSubgroupSizeTo8)) {
+        info->subgroupMinSize = std::min(info->subgroupMinSize, 8u);
+    }
+
     return wgpu::Status::Success;
 }
 
diff --git a/src/dawn/native/PhysicalDevice.cpp b/src/dawn/native/PhysicalDevice.cpp
index b0d3935..ba4a937 100644
--- a/src/dawn/native/PhysicalDevice.cpp
+++ b/src/dawn/native/PhysicalDevice.cpp
@@ -118,6 +118,14 @@
     return mBackend;
 }
 
+uint32_t PhysicalDeviceBase::GetSubgroupMinSize() const {
+    return mSubgroupMinSize;
+}
+
+uint32_t PhysicalDeviceBase::GetSubgroupMaxSize() const {
+    return mSubgroupMaxSize;
+}
+
 bool PhysicalDeviceBase::IsFeatureSupportedWithToggles(wgpu::FeatureName feature,
                                                        const TogglesState& toggles) const {
     return ValidateFeatureSupportedWithToggles(feature, toggles).success;
diff --git a/src/dawn/native/PhysicalDevice.h b/src/dawn/native/PhysicalDevice.h
index 89c36f7..38d2a62 100644
--- a/src/dawn/native/PhysicalDevice.h
+++ b/src/dawn/native/PhysicalDevice.h
@@ -88,6 +88,8 @@
     const std::string& GetDriverDescription() const;
     wgpu::AdapterType GetAdapterType() const;
     wgpu::BackendType GetBackendType() const;
+    uint32_t GetSubgroupMinSize() const;
+    uint32_t GetSubgroupMaxSize() const;
 
     MaybeError ResetInternalDeviceForTesting();
 
@@ -139,6 +141,8 @@
     wgpu::AdapterType mAdapterType = wgpu::AdapterType::Unknown;
     gpu_info::DriverVersion mDriverVersion;
     std::string mDriverDescription;
+    uint32_t mSubgroupMinSize = 4;
+    uint32_t mSubgroupMaxSize = 128;
 
     // Juat a wrapper of ValidateFeatureSupportedWithToggles, return true if a feature is supported
     // by this adapter AND suitable with given toggles.
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
index 2fab350..69527ad 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -102,6 +102,13 @@
     if (mAdapterType == wgpu::AdapterType::DiscreteGPU && mDeviceInfo.isUMA) {
         mAdapterType = wgpu::AdapterType::IntegratedGPU;
     }
+
+    mSubgroupMinSize = mDeviceInfo.waveLaneCountMin;
+    // Currently the WaveLaneCountMax queried from D3D12 API is not reliable and the meaning is
+    // unclear. Use 128 instead, which is the largest possible size. Reference:
+    // https://github.com/Microsoft/DirectXShaderCompiler/wiki/Wave-Intrinsics#:~:text=UINT%20WaveLaneCountMax
+    mSubgroupMaxSize = 128u;
+
     return {};
 }
 
diff --git a/src/dawn/native/metal/PhysicalDeviceMTL.mm b/src/dawn/native/metal/PhysicalDeviceMTL.mm
index 3649b2e..6014f19 100644
--- a/src/dawn/native/metal/PhysicalDeviceMTL.mm
+++ b/src/dawn/native/metal/PhysicalDeviceMTL.mm
@@ -314,6 +314,9 @@
 
     NSString* osVersion = [[NSProcessInfo processInfo] operatingSystemVersionString];
     mDriverDescription = "Metal driver on " + std::string(systemName) + [osVersion UTF8String];
+
+    mSubgroupMinSize = 4;   // The 4 comes from the minimum derivative group.
+    mSubgroupMaxSize = 64;  // In MSL, a ballot is a uint64, so the max subgroup size is 64.
 }
 
 bool PhysicalDevice::IsMetalValidationEnabled() const {
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index 5e357e9..488c76c 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -165,6 +165,9 @@
             break;
     }
 
+    mSubgroupMinSize = mDeviceInfo.subgroupSizeControlProperties.minSubgroupSize;
+    mSubgroupMaxSize = mDeviceInfo.subgroupSizeControlProperties.maxSubgroupSize;
+
     // Check for essential Vulkan extensions and features
     // Needed for viewport Y-flip.
     if (!mDeviceInfo.HasExt(DeviceExt::Maintenance1)) {
diff --git a/src/dawn/tests/end2end/SubgroupsTests.cpp b/src/dawn/tests/end2end/SubgroupsTests.cpp
index 494e471..620f320 100644
--- a/src/dawn/tests/end2end/SubgroupsTests.cpp
+++ b/src/dawn/tests/end2end/SubgroupsTests.cpp
@@ -55,10 +55,10 @@
     return o;
 }
 
-DAWN_TEST_PARAM_STRUCT(SubgroupsPropertiesTestsParams, RequestSubgroups);
+DAWN_TEST_PARAM_STRUCT(SubgroupsAdapterInfoParams, RequestSubgroups);
 
 template <class Params>
-class SubgroupsPropertiesTestBase : public DawnTestWithParams<Params> {
+class SubgroupsAdapterInfoTestBase : public DawnTestWithParams<Params> {
   public:
     using DawnTestWithParams<Params>::GetParam;
     using DawnTestWithParams<Params>::SupportsFeatures;
@@ -85,8 +85,9 @@
     }
 };
 
-using SubgroupsPropertiesTests = SubgroupsPropertiesTestBase<SubgroupsPropertiesTestsParams>;
+using SubgroupsPropertiesTests = SubgroupsAdapterInfoTestBase<SubgroupsAdapterInfoParams>;
 
+// Test that subgroupMinSize and subgroupMaxSize in wgpu::AdapterPropertiesSubgroups are valid.
 TEST_P(SubgroupsPropertiesTests, FromAdapter) {
     wgpu::AdapterPropertiesSubgroups subgroup_properties;
 
@@ -106,6 +107,7 @@
     CheckValidSizes(subgroup_properties.subgroupMinSize, subgroup_properties.subgroupMaxSize);
 }
 
+// Test that subgroupMinSize and subgroupMaxSize in wgpu::AdapterPropertiesSubgroups are valid.
 TEST_P(SubgroupsPropertiesTests, FromDevice) {
     wgpu::AdapterPropertiesSubgroups subgroup_properties;
     wgpu::AdapterInfo info;
@@ -116,6 +118,8 @@
     CheckValidSizes(subgroup_properties.subgroupMinSize, subgroup_properties.subgroupMaxSize);
 }
 
+// Test that subgroupMinSize and subgroupMaxSize in wgpu::AdapterPropertiesSubgroups are the same
+// between adapter and device.
 TEST_P(SubgroupsPropertiesTests, DeviceAndAdapterAgree) {
     wgpu::AdapterPropertiesSubgroups adapter_subgroup_properties;
     wgpu::AdapterInfo adapter_info;
@@ -138,6 +142,42 @@
                          VulkanBackend()},
                         {RequestSubgroups::WhenAvailable, RequestSubgroups::Never});
 
+using SubgroupsAdapterInfoTests = SubgroupsAdapterInfoTestBase<SubgroupsAdapterInfoParams>;
+
+// Test that subgroupMinSize and subgroupMaxSize in wgpu::AdapterInfo are valid.
+TEST_P(SubgroupsAdapterInfoTests, FromAdapter) {
+    wgpu::AdapterInfo info;
+    adapter.GetInfo(&info);
+
+    CheckValidSizes(info.subgroupMinSize, info.subgroupMaxSize);
+}
+
+// Test that subgroupMinSize and subgroupMaxSize in wgpu::AdapterInfo are valid.
+TEST_P(SubgroupsAdapterInfoTests, FromDevice) {
+    wgpu::AdapterInfo info;
+    device.GetAdapterInfo(&info);
+
+    CheckValidSizes(info.subgroupMinSize, info.subgroupMaxSize);
+}
+
+// Test that subgroupMinSize and subgroupMaxSize in wgpu::AdapterInfo are the same between adapter
+// and device.
+TEST_P(SubgroupsAdapterInfoTests, DeviceAndAdapterAgree) {
+    wgpu::AdapterInfo adapter_info;
+    adapter.GetInfo(&adapter_info);
+
+    wgpu::AdapterInfo device_info;
+    device.GetAdapterInfo(&device_info);
+
+    EXPECT_EQ(device_info.subgroupMinSize, adapter_info.subgroupMinSize);
+    EXPECT_EQ(device_info.subgroupMaxSize, adapter_info.subgroupMaxSize);
+}
+
+DAWN_INSTANTIATE_TEST_P(SubgroupsAdapterInfoTests,
+                        {D3D12Backend(), D3D12Backend({}, {"use_dxc"}), MetalBackend(),
+                         VulkanBackend()},
+                        {RequestSubgroups::WhenAvailable, RequestSubgroups::Never});
+
 template <class Params>
 class SubgroupsTestsBase : public DawnTestWithParams<Params> {
   public:
diff --git a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
index f1a2738..cd17ea7 100644
--- a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
@@ -127,6 +127,8 @@
     fakeInfo.adapterType = WGPUAdapterType_IntegratedGPU;
     fakeInfo.vendorID = 0x134;
     fakeInfo.deviceID = 0x918;
+    fakeInfo.subgroupMinSize = 4;
+    fakeInfo.subgroupMaxSize = 128;
 
     wgpu::SupportedLimits fakeLimits = {};
     fakeLimits.limits.maxTextureDimension1D = 433;
@@ -186,6 +188,8 @@
                 EXPECT_EQ(info.adapterType, fakeInfo.adapterType);
                 EXPECT_EQ(info.vendorID, fakeInfo.vendorID);
                 EXPECT_EQ(info.deviceID, fakeInfo.deviceID);
+                EXPECT_EQ(info.subgroupMinSize, fakeInfo.subgroupMinSize);
+                EXPECT_EQ(info.subgroupMaxSize, fakeInfo.subgroupMaxSize);
 
                 wgpu::SupportedLimits limits = {};
                 EXPECT_EQ(adapter.GetLimits(&limits), wgpu::Status::Success);