diff --git a/dawn.json b/dawn.json index 59f307a0dc..7d419bb29f 100644 --- a/dawn.json +++ b/dawn.json @@ -53,7 +53,8 @@ "members": [ {"name": "compatible surface", "type": "surface", "optional": true}, {"name": "power preference", "type": "power preference", "default": "undefined"}, - {"name": "force fallback adapter", "type": "bool", "default": "false"} + {"name": "force fallback adapter", "type": "bool", "default": "false"}, + {"name": "compatibility mode", "type": "bool", "default": "false"} ] }, "request adapter status": { @@ -140,7 +141,8 @@ {"name": "name", "type": "char", "annotation": "const*", "length": "strlen"}, {"name": "driver description", "type": "char", "annotation": "const*", "length": "strlen"}, {"name": "adapter type", "type": "adapter type"}, - {"name": "backend type", "type": "backend type"} + {"name": "backend type", "type": "backend type"}, + {"name": "compatibility mode", "type": "bool", "default": "false"} ] }, "adapter type": { diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp index 0e9aa04044..22c40c9ab0 100644 --- a/src/dawn/native/Adapter.cpp +++ b/src/dawn/native/Adapter.cpp @@ -20,8 +20,10 @@ namespace dawn::native { -AdapterBase::AdapterBase(const Ref& physicalDevice) - : mPhysicalDevice(std::move(physicalDevice)) {} +AdapterBase::AdapterBase(const Ref& physicalDevice, FeatureLevel featureLevel) + : mPhysicalDevice(std::move(physicalDevice)), mFeatureLevel(featureLevel) { + ASSERT(physicalDevice->SupportsFeatureLevel(featureLevel)); +} AdapterBase::~AdapterBase() = default; @@ -39,6 +41,7 @@ bool AdapterBase::APIGetLimits(SupportedLimits* limits) const { void AdapterBase::APIGetProperties(AdapterProperties* properties) const { mPhysicalDevice->APIGetProperties(properties); + properties->compatibilityMode = mFeatureLevel == FeatureLevel::Compatibility; } bool AdapterBase::APIHasFeature(wgpu::FeatureName feature) const { @@ -68,4 +71,8 @@ bool AdapterBase::AllowUnsafeAPIs() const { !GetTogglesState().IsEnabled(Toggle::DisallowUnsafeAPIs); } +FeatureLevel AdapterBase::GetFeatureLevel() const { + return mFeatureLevel; +} + } // namespace dawn::native diff --git a/src/dawn/native/Adapter.h b/src/dawn/native/Adapter.h index f56e4b2393..722896ac75 100644 --- a/src/dawn/native/Adapter.h +++ b/src/dawn/native/Adapter.h @@ -18,6 +18,7 @@ #include "dawn/native/DawnNative.h" #include "dawn/common/RefCounted.h" +#include "dawn/native/PhysicalDevice.h" #include "dawn/native/dawn_platform.h" namespace dawn::native { @@ -28,7 +29,7 @@ struct SupportedLimits; class AdapterBase : public RefCounted { public: - explicit AdapterBase(const Ref& physicalDevice); + AdapterBase(const Ref& physicalDevice, FeatureLevel featureLevel); ~AdapterBase() override; // WebGPU API @@ -53,8 +54,11 @@ class AdapterBase : public RefCounted { // TODO(dawn:1685): Remove wrapper once DisallowUnsafeAPIs is fully removed. bool AllowUnsafeAPIs() const; + FeatureLevel GetFeatureLevel() const; + private: Ref mPhysicalDevice; + FeatureLevel mFeatureLevel; }; } // namespace dawn::native diff --git a/src/dawn/native/Instance.cpp b/src/dawn/native/Instance.cpp index d6a899ef05..bac6dd35b6 100644 --- a/src/dawn/native/Instance.cpp +++ b/src/dawn/native/Instance.cpp @@ -255,6 +255,10 @@ ResultOrError> InstanceBase::RequestAdapterInternal( AdapterProperties properties; mAdapters[i]->APIGetProperties(&properties); + bool isCompatibility = mAdapters[i]->GetFeatureLevel() == FeatureLevel::Compatibility; + if (options->compatibilityMode != isCompatibility) { + continue; + } if (options->forceFallbackAdapter) { if (!gpu_info::IsGoogleSwiftshader(properties.vendorID, properties.deviceID)) { continue; @@ -320,7 +324,12 @@ void InstanceBase::DiscoverDefaultAdapters() { for (Ref& physicalDevice : physicalDevices) { ASSERT(physicalDevice->GetBackendType() == backend->GetType()); ASSERT(physicalDevice->GetInstance() == this); - mAdapters.push_back(AcquireRef(new AdapterBase(std::move(physicalDevice)))); + for (auto featureLevel : {FeatureLevel::Compatibility, FeatureLevel::Core}) { + if (physicalDevice->SupportsFeatureLevel(featureLevel)) { + mAdapters.push_back( + AcquireRef(new AdapterBase(std::move(physicalDevice), featureLevel))); + } + } } } @@ -454,7 +463,12 @@ MaybeError InstanceBase::DiscoverAdaptersInternal(const AdapterDiscoveryOptionsB for (Ref& physicalDevice : newPhysicalDevices) { ASSERT(physicalDevice->GetBackendType() == backend->GetType()); ASSERT(physicalDevice->GetInstance() == this); - mAdapters.push_back(AcquireRef(new AdapterBase(std::move(physicalDevice)))); + for (auto featureLevel : {FeatureLevel::Compatibility, FeatureLevel::Core}) { + if (physicalDevice->SupportsFeatureLevel(featureLevel)) { + mAdapters.push_back( + AcquireRef(new AdapterBase(std::move(physicalDevice), featureLevel))); + } + } } } diff --git a/src/dawn/native/PhysicalDevice.h b/src/dawn/native/PhysicalDevice.h index 1d9af42d53..5647a46919 100644 --- a/src/dawn/native/PhysicalDevice.h +++ b/src/dawn/native/PhysicalDevice.h @@ -33,6 +33,8 @@ namespace dawn::native { class DeviceBase; +enum class FeatureLevel { Compatibility, Core }; + class PhysicalDeviceBase : public RefCounted { public: PhysicalDeviceBase(InstanceBase* instance, @@ -78,6 +80,8 @@ class PhysicalDeviceBase : public RefCounted { virtual bool SupportsExternalImages() const = 0; + virtual bool SupportsFeatureLevel(FeatureLevel featureLevel) const = 0; + protected: uint32_t mVendorId = 0xFFFFFFFF; std::string mVendorName; diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp index 1235d393dd..37adc7863d 100644 --- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp +++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp @@ -73,6 +73,10 @@ bool PhysicalDevice::SupportsExternalImages() const { return false; } +bool PhysicalDevice::SupportsFeatureLevel(FeatureLevel featureLevel) const { + return featureLevel == FeatureLevel::Compatibility; +} + const DeviceInfo& PhysicalDevice::GetDeviceInfo() const { return mDeviceInfo; } diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h index 356d4bdd7f..8c8c91227f 100644 --- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h +++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h @@ -34,6 +34,8 @@ class PhysicalDevice : public d3d::PhysicalDevice { // PhysicalDeviceBase Implementation bool SupportsExternalImages() const override; + bool SupportsFeatureLevel(FeatureLevel featureLevel) const override; + const DeviceInfo& GetDeviceInfo() const; ResultOrError> CreateD3D11Device(); diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp index 18304834d3..287fba0d6b 100644 --- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp +++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp @@ -43,6 +43,10 @@ bool PhysicalDevice::SupportsExternalImages() const { return true; } +bool PhysicalDevice::SupportsFeatureLevel(FeatureLevel) const { + return true; +} + const D3D12DeviceInfo& PhysicalDevice::GetDeviceInfo() const { return mDeviceInfo; } diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.h b/src/dawn/native/d3d12/PhysicalDeviceD3D12.h index 611c85e69d..cb737217cc 100644 --- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.h +++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.h @@ -34,6 +34,7 @@ class PhysicalDevice : public d3d::PhysicalDevice { // PhysicalDeviceBase Implementation bool SupportsExternalImages() const override; + bool SupportsFeatureLevel(FeatureLevel featureLevel) const override; const D3D12DeviceInfo& GetDeviceInfo() const; Backend* GetBackend() const; diff --git a/src/dawn/native/metal/BackendMTL.mm b/src/dawn/native/metal/BackendMTL.mm index a21254be3b..589a782b7e 100644 --- a/src/dawn/native/metal/BackendMTL.mm +++ b/src/dawn/native/metal/BackendMTL.mm @@ -292,6 +292,8 @@ class PhysicalDevice : public PhysicalDeviceBase { return true; } + bool SupportsFeatureLevel(FeatureLevel) const override { return true; } + private: ResultOrError> CreateDeviceImpl(AdapterBase* adapter, const DeviceDescriptor* descriptor, diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp index cb2c5fa591..7a1bdece10 100644 --- a/src/dawn/native/null/DeviceNull.cpp +++ b/src/dawn/native/null/DeviceNull.cpp @@ -51,6 +51,10 @@ bool PhysicalDevice::SupportsExternalImages() const { return false; } +bool PhysicalDevice::SupportsFeatureLevel(FeatureLevel) const { + return true; +} + MaybeError PhysicalDevice::InitializeImpl() { return {}; } diff --git a/src/dawn/native/null/DeviceNull.h b/src/dawn/native/null/DeviceNull.h index abdad48d7d..95cbfa675c 100644 --- a/src/dawn/native/null/DeviceNull.h +++ b/src/dawn/native/null/DeviceNull.h @@ -181,6 +181,8 @@ class PhysicalDevice : public PhysicalDeviceBase { // PhysicalDeviceBase Implementation bool SupportsExternalImages() const override; + bool SupportsFeatureLevel(FeatureLevel featureLevel) const override; + // Used for the tests that intend to use an adapter without all features enabled. using PhysicalDeviceBase::SetSupportedFeaturesForTesting; diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.cpp b/src/dawn/native/opengl/PhysicalDeviceGL.cpp index 9222058589..6674cc1a11 100644 --- a/src/dawn/native/opengl/PhysicalDeviceGL.cpp +++ b/src/dawn/native/opengl/PhysicalDeviceGL.cpp @@ -227,6 +227,10 @@ ResultOrError> PhysicalDevice::CreateDeviceImpl(AdapterBase* ada return Device::Create(adapter, descriptor, mFunctions, std::move(context), deviceToggles); } +bool PhysicalDevice::SupportsFeatureLevel(FeatureLevel featureLevel) const { + return featureLevel == FeatureLevel::Compatibility; +} + MaybeError PhysicalDevice::ValidateFeatureSupportedWithTogglesImpl( wgpu::FeatureName feature, const TogglesState& toggles) const { diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.h b/src/dawn/native/opengl/PhysicalDeviceGL.h index d53f39e243..64e5167b86 100644 --- a/src/dawn/native/opengl/PhysicalDeviceGL.h +++ b/src/dawn/native/opengl/PhysicalDeviceGL.h @@ -33,6 +33,7 @@ class PhysicalDevice : public PhysicalDeviceBase { // PhysicalDeviceBase Implementation bool SupportsExternalImages() const override; + bool SupportsFeatureLevel(FeatureLevel featureLevel) const override; private: MaybeError InitializeImpl() override; diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp index 07feed89f7..affb18240a 100644 --- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp +++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp @@ -429,6 +429,10 @@ bool PhysicalDevice::SupportsExternalImages() const { mVulkanInstance->GetFunctions()); } +bool PhysicalDevice::SupportsFeatureLevel(FeatureLevel) const { + return true; +} + void PhysicalDevice::SetupBackendDeviceToggles(TogglesState* deviceToggles) const { // TODO(crbug.com/dawn/857): tighten this workaround when this issue is fixed in both // Vulkan SPEC and drivers. diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.h b/src/dawn/native/vulkan/PhysicalDeviceVk.h index 5c420725a2..ee2b1463f0 100644 --- a/src/dawn/native/vulkan/PhysicalDeviceVk.h +++ b/src/dawn/native/vulkan/PhysicalDeviceVk.h @@ -35,6 +35,7 @@ class PhysicalDevice : public PhysicalDeviceBase { // PhysicalDeviceBase Implementation bool SupportsExternalImages() const override; + bool SupportsFeatureLevel(FeatureLevel featureLevel) const override; const VulkanDeviceInfo& GetDeviceInfo() const; VkPhysicalDevice GetVkPhysicalDevice() const; diff --git a/src/dawn/tests/end2end/AdapterDiscoveryTests.cpp b/src/dawn/tests/end2end/AdapterDiscoveryTests.cpp index f9bf442c7e..53dcb40de1 100644 --- a/src/dawn/tests/end2end/AdapterDiscoveryTests.cpp +++ b/src/dawn/tests/end2end/AdapterDiscoveryTests.cpp @@ -65,7 +65,7 @@ TEST(AdapterDiscoveryTests, OnlySwiftShader) { instance.DiscoverAdapters(&options); const auto& adapters = instance.GetAdapters(); - EXPECT_LE(adapters.size(), 1u); // 0 or 1 SwiftShader adapters. + EXPECT_LE(adapters.size(), 2u); // 0 or 2 SwiftShader adapters. for (const auto& adapter : adapters) { wgpu::AdapterProperties properties; adapter.GetProperties(&properties); @@ -260,6 +260,9 @@ class AdapterCreationTest : public ::testing::Test { wgpu::AdapterProperties properties; nativeAdapter.GetProperties(&properties); + if (properties.compatibilityMode) { + continue; + } swiftShaderAvailable = swiftShaderAvailable || gpu_info::IsGoogleSwiftshader(properties.vendorID, properties.deviceID); @@ -387,6 +390,45 @@ TEST_F(AdapterCreationTest, PreferLowPower) { } } +// Test that requesting a Compatibility adapter is supported. +TEST_F(AdapterCreationTest, Compatibility) { + wgpu::RequestAdapterOptions options = {}; + options.compatibilityMode = true; + + MockCallback cb; + + WGPUAdapter cAdapter = nullptr; + EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this)) + .WillOnce(SaveArg<1>(&cAdapter)); + instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this)); + + wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter); + EXPECT_EQ(adapter != nullptr, anyAdapterAvailable); + + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + EXPECT_TRUE(properties.compatibilityMode); +} + +// Test that requesting a Non-Compatibility adapter is supported and is default. +TEST_F(AdapterCreationTest, NonCompatibility) { + wgpu::RequestAdapterOptions options = {}; + + MockCallback cb; + + WGPUAdapter cAdapter = nullptr; + EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this)) + .WillOnce(SaveArg<1>(&cAdapter)); + instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this)); + + wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter); + EXPECT_EQ(adapter != nullptr, anyAdapterAvailable); + + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + EXPECT_FALSE(properties.compatibilityMode); +} + // Test that GetInstance() returns the correct Instance. TEST_F(AdapterCreationTest, GetInstance) { wgpu::RequestAdapterOptions options = {}; diff --git a/src/dawn/tests/unittests/FeatureTests.cpp b/src/dawn/tests/unittests/FeatureTests.cpp index ce954dbc7a..dc531f1efc 100644 --- a/src/dawn/tests/unittests/FeatureTests.cpp +++ b/src/dawn/tests/unittests/FeatureTests.cpp @@ -34,9 +34,10 @@ class FeatureTests : public testing::Test { mInstanceBase.Get(), dawn::native::TogglesState(dawn::native::ToggleStage::Adapter) .SetForTesting(dawn::native::Toggle::AllowUnsafeAPIs, true, true)), - mAdapterBase(&mPhysicalDevice), - mUnsafeAdapterBaseDisallow(&mUnsafePhysicalDeviceDisallow), - mUnsafeAdapterBase(&mUnsafePhysicalDevice) {} + mAdapterBase(&mPhysicalDevice, dawn::native::FeatureLevel::Core), + mUnsafeAdapterBaseDisallow(&mUnsafePhysicalDeviceDisallow, + dawn::native::FeatureLevel::Core), + mUnsafeAdapterBase(&mUnsafePhysicalDevice, dawn::native::FeatureLevel::Core) {} std::vector GetAllFeatureNames() { std::vector allFeatureNames(kTotalFeaturesCount); diff --git a/src/dawn/tests/unittests/GetProcAddressTests.cpp b/src/dawn/tests/unittests/GetProcAddressTests.cpp index 0893ff46ef..2641a3cc24 100644 --- a/src/dawn/tests/unittests/GetProcAddressTests.cpp +++ b/src/dawn/tests/unittests/GetProcAddressTests.cpp @@ -56,7 +56,8 @@ class GetProcAddressTests : public testing::TestWithParam { GetProcAddressTests() : testing::TestWithParam(), mNativeInstance(dawn::native::InstanceBase::Create()), - mAdapterBase(AcquireRef(new dawn::native::null::PhysicalDevice(mNativeInstance.Get()))) {} + mAdapterBase(AcquireRef(new dawn::native::null::PhysicalDevice(mNativeInstance.Get())), + dawn::native::FeatureLevel::Core) {} void SetUp() override { switch (GetParam()) { diff --git a/src/dawn/tests/unittests/PerThreadProcTests.cpp b/src/dawn/tests/unittests/PerThreadProcTests.cpp index d9bafdf208..839c72516f 100644 --- a/src/dawn/tests/unittests/PerThreadProcTests.cpp +++ b/src/dawn/tests/unittests/PerThreadProcTests.cpp @@ -27,7 +27,8 @@ class PerThreadProcTests : public testing::Test { public: PerThreadProcTests() : mNativeInstance(dawn::native::InstanceBase::Create()), - mAdapterBase(AcquireRef(new dawn::native::null::PhysicalDevice(mNativeInstance.Get()))) {} + mAdapterBase(AcquireRef(new dawn::native::null::PhysicalDevice(mNativeInstance.Get())), + dawn::native::FeatureLevel::Core) {} ~PerThreadProcTests() override = default; protected: