Populate WGPUAdapterPropertiesSubgroups Including: In the wire Adapter, initializes subgroup properties so they can be read even if adapter acquisition fails. Bug: 354751907 Change-Id: I28733c7cf3165b84c6858415357b77c8be06b105 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/216117 Reviewed-by: Loko Kung <lokokung@google.com> Auto-Submit: David Neto <dneto@google.com> Commit-Queue: David Neto <dneto@google.com>
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp index ff41288..9e5d3bf 100644 --- a/src/dawn/native/Adapter.cpp +++ b/src/dawn/native/Adapter.cpp
@@ -191,6 +191,12 @@ if (auto* powerPreferenceDesc = unpacked.Get<DawnAdapterPropertiesPowerPreference>()) { powerPreferenceDesc->powerPreference = mPowerPreference; } + if (auto* subgroupsProperties = unpacked.Get<AdapterPropertiesSubgroups>()) { + // When the feature is *not* supported, these must be 4 and 128. + // Set those defaults now, but a backend may override this. + subgroupsProperties->subgroupMinSize = 4; + subgroupsProperties->subgroupMaxSize = 128; + } mPhysicalDevice->PopulateBackendProperties(unpacked);
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp index 34f436f..3918eaa 100644 --- a/src/dawn/native/Device.cpp +++ b/src/dawn/native/Device.cpp
@@ -1868,6 +1868,7 @@ limits->limits = mLimits.v1; + // TODO(354751907): Move this to AdapterInfo if (auto* subgroupLimits = unpacked.Get<DawnExperimentalSubgroupLimits>()) { wgpu::ChainedStructOut* originalChain = subgroupLimits->nextInChain; if (!HasFeature(Feature::Subgroups)) {
diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp index d072704..c5d1cba 100644 --- a/src/dawn/native/Toggles.cpp +++ b/src/dawn/native/Toggles.cpp
@@ -585,7 +585,7 @@ "crbug.com/372698905", ToggleStage::Device}}, {Toggle::D3D12RelaxMinSubgroupSizeTo8, {"d3d12_relax_min_subgroup_size_to_8", - "Relax the adapters and devices' minSubgroupSize to the minimium of D3D12 reported " + "Relax the adapters and devices' subgroupMinSize to the minimium of D3D12 reported " "minWaveLaneCount and 8. Some D3D12 drivers is possible to run fragment shader with wave " "count 8 while reporting minWaveLaneCount 16.", "https://crbug.com/381969450", ToggleStage::Adapter}},
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp index c46df96..5f6ea1a 100644 --- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp +++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -368,6 +368,7 @@ // - maxVertexBufferArrayStride // Experimental limits for subgroups + // TODO(crbug.com/354751907) Move this to AdapterInfo limits->experimentalSubgroupLimits.minSubgroupSize = 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: @@ -844,6 +845,13 @@ } void PhysicalDevice::PopulateBackendProperties(UnpackedPtr<AdapterInfo>& info) const { + if (auto* subgroupProperties = info.Get<AdapterPropertiesSubgroups>()) { + subgroupProperties->subgroupMinSize = 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 + subgroupProperties->subgroupMaxSize = 128u; + } if (auto* memoryHeapProperties = info.Get<AdapterPropertiesMemoryHeaps>()) { // https://microsoft.github.io/DirectX-Specs/d3d/D3D12GPUUploadHeaps.html describes // the properties of D3D12 Default/Upload/Readback heaps.
diff --git a/src/dawn/native/metal/PhysicalDeviceMTL.mm b/src/dawn/native/metal/PhysicalDeviceMTL.mm index d03ee34..b3cc059 100644 --- a/src/dawn/native/metal/PhysicalDeviceMTL.mm +++ b/src/dawn/native/metal/PhysicalDeviceMTL.mm
@@ -749,10 +749,13 @@ // explicitly use Xcode 13.3 and MacOS 12.3 version 21E226, so does not support // MTLGPUFamilyMetal3. // Note that supportsFamily: method requires macOS 10.15+ or iOS 13.0+ + // TODO(380326541): Check that reduction operations are supported in Apple6. The support + // table says Apple7. if (@available(macOS 10.15, iOS 13.0, *)) { if ([*mDevice supportsFamily:MTLGPUFamilyApple6] || [*mDevice supportsFamily:MTLGPUFamilyMac2]) { EnableFeature(Feature::Subgroups); + // TODO(crbug.com/380244620) remove SubgroupsF16 EnableFeature(Feature::SubgroupsF16); } } @@ -952,6 +955,7 @@ // - maxVertexBufferArrayStride // Experimental limits for subgroups + // TODO(354751907): Move to AdapterInfo limits->experimentalSubgroupLimits.minSubgroupSize = 4; limits->experimentalSubgroupLimits.maxSubgroupSize = 64; @@ -965,6 +969,10 @@ } void PhysicalDevice::PopulateBackendProperties(UnpackedPtr<AdapterInfo>& info) const { + if (auto* subgroupProperties = info.Get<AdapterPropertiesSubgroups>()) { + subgroupProperties->subgroupMinSize = 4; + subgroupProperties->subgroupMaxSize = 64; + } if (auto* memoryHeapProperties = info.Get<AdapterPropertiesMemoryHeaps>()) { if ([*mDevice hasUnifiedMemory]) { auto* heapInfo = new MemoryHeapInfo[1];
diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp index 3a2a120..c5173c6 100644 --- a/src/dawn/native/null/DeviceNull.cpp +++ b/src/dawn/native/null/DeviceNull.cpp
@@ -111,6 +111,10 @@ } void PhysicalDevice::PopulateBackendProperties(UnpackedPtr<AdapterInfo>& info) const { + if (auto* subgroupProperties = info.Get<AdapterPropertiesSubgroups>()) { + subgroupProperties->subgroupMinSize = 4; + subgroupProperties->subgroupMaxSize = 128; + } if (auto* memoryHeapProperties = info.Get<AdapterPropertiesMemoryHeaps>()) { auto* heapInfo = new MemoryHeapInfo[1]; memoryHeapProperties->heapCount = 1;
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp index 3306fb9..8470900 100644 --- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp +++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -639,6 +639,7 @@ } // Experimental limits for subgroups + // TODO(crbug.com/354751907) Move this to AdapterInfo limits->experimentalSubgroupLimits.minSubgroupSize = mDeviceInfo.subgroupSizeControlProperties.minSubgroupSize; limits->experimentalSubgroupLimits.maxSubgroupSize = @@ -1035,6 +1036,13 @@ } void PhysicalDevice::PopulateBackendProperties(UnpackedPtr<AdapterInfo>& info) const { + if (auto* subgroupProperties = info.Get<AdapterPropertiesSubgroups>()) { + // Subgroups are supported only if subgroup size control is supported. + subgroupProperties->subgroupMinSize = + mDeviceInfo.subgroupSizeControlProperties.minSubgroupSize; + subgroupProperties->subgroupMaxSize = + mDeviceInfo.subgroupSizeControlProperties.maxSubgroupSize; + } if (auto* memoryHeapProperties = info.Get<AdapterPropertiesMemoryHeaps>()) { size_t count = mDeviceInfo.memoryHeaps.size(); auto* heapInfo = new MemoryHeapInfo[count];
diff --git a/src/dawn/tests/end2end/SubgroupsTests.cpp b/src/dawn/tests/end2end/SubgroupsTests.cpp index eb7c4ba..494e471 100644 --- a/src/dawn/tests/end2end/SubgroupsTests.cpp +++ b/src/dawn/tests/end2end/SubgroupsTests.cpp
@@ -39,6 +39,105 @@ namespace dawn { namespace { +enum class RequestSubgroups { + WhenAvailable, + Never, +}; +std::ostream& operator<<(std::ostream& o, const RequestSubgroups& r) { + switch (r) { + case RequestSubgroups::WhenAvailable: + o << "when_supported"; + break; + case RequestSubgroups::Never: + o << "never"; + break; + } + return o; +} + +DAWN_TEST_PARAM_STRUCT(SubgroupsPropertiesTestsParams, RequestSubgroups); + +template <class Params> +class SubgroupsPropertiesTestBase : public DawnTestWithParams<Params> { + public: + using DawnTestWithParams<Params>::GetParam; + using DawnTestWithParams<Params>::SupportsFeatures; + + protected: + std::vector<wgpu::FeatureName> GetRequiredFeatures() override { + if (GetParam().mRequestSubgroups == RequestSubgroups::WhenAvailable && + SupportsFeatures({wgpu::FeatureName::Subgroups})) { + return {wgpu::FeatureName::Subgroups}; + } + return {}; + } + + // Checks valid values for min and max subgroup sizes, per spec. + void CheckValidSizes(uint32_t subgroupMinSize, uint32_t subgroupMaxSize) { + EXPECT_GE(subgroupMinSize, 4u) << subgroupMinSize; + EXPECT_TRUE(IsPowerOfTwo(subgroupMinSize)) << subgroupMinSize; + + EXPECT_LE(subgroupMaxSize, 128u) << subgroupMaxSize; + EXPECT_TRUE(IsPowerOfTwo(subgroupMaxSize)); + + EXPECT_LE(subgroupMinSize, subgroupMaxSize) + << subgroupMinSize << " should be less equal than " << subgroupMaxSize; + } +}; + +using SubgroupsPropertiesTests = SubgroupsPropertiesTestBase<SubgroupsPropertiesTestsParams>; + +TEST_P(SubgroupsPropertiesTests, FromAdapter) { + wgpu::AdapterPropertiesSubgroups subgroup_properties; + + // Write invalid values to start with, to make sure they are overwritten. + subgroup_properties.subgroupMinSize = 3; + subgroup_properties.subgroupMaxSize = 443; + + wgpu::AdapterInfo info; + info.nextInChain = &subgroup_properties; + + adapter.GetInfo(&info); + + // Check the integrity of the struct. + EXPECT_EQ(subgroup_properties.sType, wgpu::SType::AdapterPropertiesSubgroups); + EXPECT_EQ(subgroup_properties.nextInChain, nullptr); + + CheckValidSizes(subgroup_properties.subgroupMinSize, subgroup_properties.subgroupMaxSize); +} + +TEST_P(SubgroupsPropertiesTests, FromDevice) { + wgpu::AdapterPropertiesSubgroups subgroup_properties; + wgpu::AdapterInfo info; + info.nextInChain = &subgroup_properties; + + device.GetAdapterInfo(&info); + + CheckValidSizes(subgroup_properties.subgroupMinSize, subgroup_properties.subgroupMaxSize); +} + +TEST_P(SubgroupsPropertiesTests, DeviceAndAdapterAgree) { + wgpu::AdapterPropertiesSubgroups adapter_subgroup_properties; + wgpu::AdapterInfo adapter_info; + adapter_info.nextInChain = &adapter_subgroup_properties; + adapter.GetInfo(&adapter_info); + + wgpu::AdapterPropertiesSubgroups device_subgroup_properties; + wgpu::AdapterInfo device_info; + device_info.nextInChain = &device_subgroup_properties; + device.GetAdapterInfo(&device_info); + + EXPECT_EQ(device_subgroup_properties.subgroupMinSize, + adapter_subgroup_properties.subgroupMinSize); + EXPECT_EQ(device_subgroup_properties.subgroupMaxSize, + adapter_subgroup_properties.subgroupMaxSize); +} + +DAWN_INSTANTIATE_TEST_P(SubgroupsPropertiesTests, + {D3D12Backend(), D3D12Backend({}, {"use_dxc"}), MetalBackend(), + VulkanBackend()}, + {RequestSubgroups::WhenAvailable, RequestSubgroups::Never}); + template <class Params> class SubgroupsTestsBase : public DawnTestWithParams<Params> { public: @@ -389,8 +488,7 @@ constexpr int32_t SubgroupBroadcastConstantValueForInvocation0 = 1; constexpr int32_t SubgroupRegisterInitializer = 555; -class SubgroupsBroadcastTests - : public SubgroupsTestsBase<SubgroupsBroadcastTestsParams> { +class SubgroupsBroadcastTests : public SubgroupsTestsBase<SubgroupsBroadcastTestsParams> { protected: // Testing subgroup broadcasting. The shader declares a workgroup size of [workgroupSize, 1, 1], // in which each invocation hold a register initialized to SubgroupRegisterInitializer, then @@ -604,7 +702,6 @@ // SubgroupBroadcastValueOfInvocation0 ); - // Core functions that may be polyfilled enum class SubgroupIntrinsicOp : uint8_t { Add,
diff --git a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp index 480b55b..9b4d055 100644 --- a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp +++ b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
@@ -233,10 +233,16 @@ fakeVkProperties.chain.sType = WGPUSType_AdapterPropertiesVk; fakeVkProperties.driverVersion = 0x801F6000; + WGPUAdapterPropertiesSubgroups fakeSubgroupsProperties = {}; + fakeSubgroupsProperties.chain.sType = WGPUSType_AdapterPropertiesSubgroups; + fakeSubgroupsProperties.subgroupMinSize = 4; + fakeSubgroupsProperties.subgroupMaxSize = 128; + std::initializer_list<WGPUFeatureName> fakeFeaturesList = { WGPUFeatureName_AdapterPropertiesMemoryHeaps, WGPUFeatureName_AdapterPropertiesD3D, WGPUFeatureName_AdapterPropertiesVk, + WGPUFeatureName_Subgroups, }; // Expect the server to receive the message. Then, mock a fake reply. @@ -267,6 +273,10 @@ *reinterpret_cast<WGPUAdapterPropertiesVk*>(chain) = fakeVkProperties; break; + case WGPUSType_AdapterPropertiesSubgroups: + *reinterpret_cast<WGPUAdapterPropertiesSubgroups*>(chain) = + fakeSubgroupsProperties; + break; default: ADD_FAILURE() << "Unexpected chain"; return WGPUStatus_Error; @@ -327,6 +337,17 @@ adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info)); // Expect them to match. EXPECT_EQ(vkProperties.driverVersion, fakeVkProperties.driverVersion); + + // Get the Subgroups properties. + WGPUAdapterPropertiesSubgroups subgroupsProperties = {}; + subgroupsProperties.chain.sType = WGPUSType_AdapterPropertiesSubgroups; + info.nextInChain = &subgroupsProperties.chain; + adapter.GetInfo(reinterpret_cast<wgpu::AdapterInfo*>(&info)); + // Expect them to match. + EXPECT_EQ(subgroupsProperties.subgroupMinSize, + fakeSubgroupsProperties.subgroupMinSize); + EXPECT_EQ(subgroupsProperties.subgroupMaxSize, + fakeSubgroupsProperties.subgroupMaxSize); }))); FlushCallbacks();
diff --git a/src/dawn/wire/client/Adapter.cpp b/src/dawn/wire/client/Adapter.cpp index 2302b6d..3ed95ee 100644 --- a/src/dawn/wire/client/Adapter.cpp +++ b/src/dawn/wire/client/Adapter.cpp
@@ -200,6 +200,13 @@ mVkProperties.driverVersion = vkProperties->driverVersion; break; } + case WGPUSType_AdapterPropertiesSubgroups: { + auto* subgroupsProperties = + reinterpret_cast<WGPUAdapterPropertiesSubgroups*>(chain); + mSubgroupsProperties.subgroupMinSize = subgroupsProperties->subgroupMinSize; + mSubgroupsProperties.subgroupMaxSize = subgroupsProperties->subgroupMaxSize; + break; + } default: DAWN_UNREACHABLE(); break; @@ -235,6 +242,13 @@ vkProperties->driverVersion = mVkProperties.driverVersion; break; } + case WGPUSType_AdapterPropertiesSubgroups: { + auto* subgroupsProperties = + reinterpret_cast<WGPUAdapterPropertiesSubgroups*>(chain); + subgroupsProperties->subgroupMinSize = mSubgroupsProperties.subgroupMinSize; + subgroupsProperties->subgroupMaxSize = mSubgroupsProperties.subgroupMaxSize; + break; + } default: break; }
diff --git a/src/dawn/wire/client/Adapter.h b/src/dawn/wire/client/Adapter.h index cfdebfd..756b411 100644 --- a/src/dawn/wire/client/Adapter.h +++ b/src/dawn/wire/client/Adapter.h
@@ -76,6 +76,13 @@ std::vector<WGPUMemoryHeapInfo> mMemoryHeapInfo; WGPUAdapterPropertiesD3D mD3DProperties; WGPUAdapterPropertiesVk mVkProperties; + // Initialize subgroup properties so they can be read even if adapter + // acquisition fails. + WGPUAdapterPropertiesSubgroups mSubgroupsProperties = { + {nullptr, WGPUSType_AdapterPropertiesSubgroups}, + 4u, // subgroupMinSize + 128u // subgroupMaxSize + }; }; } // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/LimitsAndFeatures.cpp b/src/dawn/wire/client/LimitsAndFeatures.cpp index e5e4ce4..cd70277 100644 --- a/src/dawn/wire/client/LimitsAndFeatures.cpp +++ b/src/dawn/wire/client/LimitsAndFeatures.cpp
@@ -112,6 +112,7 @@ for (auto* chain = limits->nextInChain; chain; chain = chain->next) { switch (chain->sType) { case (WGPUSType_DawnExperimentalSubgroupLimits): { + // TODO(crbug.com/354751907) Remove this, as it is now in AdapterInfo. auto* experimentalSubgroupLimits = reinterpret_cast<WGPUDawnExperimentalSubgroupLimits*>(chain); mExperimentalSubgroupLimits = *experimentalSubgroupLimits;
diff --git a/src/dawn/wire/server/ServerAdapter.cpp b/src/dawn/wire/server/ServerAdapter.cpp index 992f6b0..60b4afd 100644 --- a/src/dawn/wire/server/ServerAdapter.cpp +++ b/src/dawn/wire/server/ServerAdapter.cpp
@@ -127,6 +127,7 @@ WGPUSupportedLimits limits = {}; // Chained DawnExperimentalSubgroupLimits. + // TODO(crbug.com/354751907) Remove this, as it is now in AdapterInfo. WGPUDawnExperimentalSubgroupLimits experimentalSubgroupLimits = {}; experimentalSubgroupLimits.chain.sType = WGPUSType_DawnExperimentalSubgroupLimits; limits.nextInChain = &experimentalSubgroupLimits.chain;
diff --git a/src/dawn/wire/server/ServerInstance.cpp b/src/dawn/wire/server/ServerInstance.cpp index 8c97bbe..e504950 100644 --- a/src/dawn/wire/server/ServerInstance.cpp +++ b/src/dawn/wire/server/ServerInstance.cpp
@@ -120,6 +120,14 @@ propertiesChain = &(*propertiesChain)->next; } + // Query AdapterPropertiesSubgroups if the feature is supported. + WGPUAdapterPropertiesSubgroups subgroupsProperties = {}; + subgroupsProperties.chain.sType = WGPUSType_AdapterPropertiesSubgroups; + if (mProcs.adapterHasFeature(adapter, WGPUFeatureName_Subgroups)) { + *propertiesChain = &subgroupsProperties.chain; + propertiesChain = &(*propertiesChain)->next; + } + mProcs.adapterGetInfo(adapter, &info); cmd.info = &info; @@ -127,6 +135,7 @@ // DawnExperimentalImmediateDataLimits, and DawnTexelCopyBufferRowAlignmentLimits. WGPUSupportedLimits limits = {}; + // TODO(crbug.com/354751907) Remove this, as it is now in AdapterInfo. WGPUDawnExperimentalSubgroupLimits experimentalSubgroupLimits = {}; experimentalSubgroupLimits.chain.sType = WGPUSType_DawnExperimentalSubgroupLimits; limits.nextInChain = &experimentalSubgroupLimits.chain;