diff --git a/dawn.json b/dawn.json index c842e7959a..d168b052bd 100644 --- a/dawn.json +++ b/dawn.json @@ -1384,6 +1384,7 @@ {"value": 6, "name": "texture compression ETC2"}, {"value": 7, "name": "texture compression ASTC"}, {"value": 8, "name": "indirect first instance"}, + {"value": 9, "name": "shader f16"}, {"value": 1001, "name": "dawn shader float 16", "tags": ["dawn"]}, {"value": 1002, "name": "dawn internal usages", "tags": ["dawn"]}, {"value": 1003, "name": "dawn multi planar formats", "tags": ["dawn"]}, diff --git a/include/dawn/native/DawnNative.h b/include/dawn/native/DawnNative.h index 1d7bf42116..b2ffa5ca7f 100644 --- a/include/dawn/native/DawnNative.h +++ b/include/dawn/native/DawnNative.h @@ -61,7 +61,15 @@ struct ToggleInfo { // A struct to record the information of a feature. A feature is a GPU feature that is not // required to be supported by all Dawn backends and can only be used when it is enabled on the // creation of device. -using FeatureInfo = ToggleInfo; +struct FeatureInfo { + const char* name; + const char* description; + const char* url; + // The enum of feature state, could be stable or experimental. Using an experimental feature + // requires DisallowUnsafeAPIs toggle being disabled. + enum class FeatureState { Stable = 0, Experimental }; + FeatureState featureState; +}; // An adapter is an object that represent on possibility of creating devices in the system. // Most of the time it will represent a combination of a physical GPU and an API. Not that the diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp index 741531281b..0234e2c094 100644 --- a/src/dawn/native/Adapter.cpp +++ b/src/dawn/native/Adapter.cpp @@ -19,6 +19,7 @@ #include "dawn/common/Constants.h" #include "dawn/common/GPUInfo.h" +#include "dawn/native/ChainUtils_autogen.h" #include "dawn/native/Device.h" #include "dawn/native/Instance.h" #include "dawn/native/ValidationUtils_autogen.h" @@ -189,15 +190,40 @@ bool AdapterBase::GetLimits(SupportedLimits* limits) const { return true; } +MaybeError AdapterBase::ValidateFeatureSupportedWithToggles( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) { + DAWN_TRY(ValidateFeatureName(feature)); + DAWN_INVALID_IF(!mSupportedFeatures.IsEnabled(feature), + "Requested feature %s is not supported.", feature); + + const FeatureInfo* featureInfo = GetInstance()->GetFeatureInfo(feature); + // Experimental features are guarded by toggle DisallowUnsafeAPIs. + if (featureInfo->featureState == FeatureInfo::FeatureState::Experimental) { + DAWN_INVALID_IF(!userProvidedToggles.IsDisabled(Toggle::DisallowUnsafeAPIs), + "Feature %s is guarded by toggle disallow_unsafe_apis.", featureInfo->name); + } + + // Do backend-specific validation. + return ValidateFeatureSupportedWithTogglesImpl(feature, userProvidedToggles); +} + ResultOrError> AdapterBase::CreateDeviceInternal( const DeviceDescriptor* descriptor) { ASSERT(descriptor != nullptr); + // Check overriden toggles before creating device, as some device features may be guarded by + // toggles, and requiring such features without using corresponding toggles should fails the + // device creating. + const DawnTogglesDeviceDescriptor* togglesDesc = nullptr; + FindInChain(descriptor->nextInChain, &togglesDesc); + TripleStateTogglesSet userProvidedToggles = + TripleStateTogglesSet::CreateFromTogglesDeviceDescriptor(togglesDesc); + + // Validate all required features are supported by the adapter and suitable under given toggles. for (uint32_t i = 0; i < descriptor->requiredFeaturesCount; ++i) { - wgpu::FeatureName f = descriptor->requiredFeatures[i]; - DAWN_TRY(ValidateFeatureName(f)); - DAWN_INVALID_IF(!mSupportedFeatures.IsEnabled(f), "Requested feature %s is not supported.", - f); + wgpu::FeatureName feature = descriptor->requiredFeatures[i]; + DAWN_TRY(ValidateFeatureSupportedWithToggles(feature, userProvidedToggles)); } if (descriptor->requiredLimits != nullptr) { @@ -208,7 +234,7 @@ ResultOrError> AdapterBase::CreateDeviceInternal( DAWN_INVALID_IF(descriptor->requiredLimits->nextInChain != nullptr, "nextInChain is not nullptr."); } - return CreateDeviceImpl(descriptor); + return CreateDeviceImpl(descriptor, userProvidedToggles); } void AdapterBase::SetUseTieredLimits(bool useTieredLimits) { diff --git a/src/dawn/native/Adapter.h b/src/dawn/native/Adapter.h index 6b6448f956..8bef32146e 100644 --- a/src/dawn/native/Adapter.h +++ b/src/dawn/native/Adapter.h @@ -24,6 +24,7 @@ #include "dawn/native/Error.h" #include "dawn/native/Features.h" #include "dawn/native/Limits.h" +#include "dawn/native/Toggles.h" #include "dawn/native/dawn_platform.h" namespace dawn::native { @@ -72,14 +73,24 @@ class AdapterBase : public RefCounted { std::string mName; wgpu::AdapterType mAdapterType = wgpu::AdapterType::Unknown; std::string mDriverDescription; + + // Features set that CAN be supported by devices of this adapter. Some features in this set may + // be guarded by toggles, and creating a device with these features required may result in a + // validation error if proper toggles are not enabled/disabled. FeaturesSet mSupportedFeatures; + // Check if a feature os supported by this adapter AND suitable with given toggles. + MaybeError ValidateFeatureSupportedWithToggles( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles); private: - virtual ResultOrError> CreateDeviceImpl(const DeviceDescriptor* descriptor) = 0; + virtual ResultOrError> CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) = 0; virtual MaybeError InitializeImpl() = 0; - // Check base WebGPU features and discover supported featurees. + // Check base WebGPU features and discover supported features. virtual MaybeError InitializeSupportedFeaturesImpl() = 0; // Check base WebGPU limits and populate supported limits. @@ -87,6 +98,10 @@ class AdapterBase : public RefCounted { virtual void InitializeVendorArchitectureImpl(); + virtual MaybeError ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) = 0; + ResultOrError> CreateDeviceInternal(const DeviceDescriptor* descriptor); virtual MaybeError ResetInternalDeviceForTestingImpl(); diff --git a/src/dawn/native/CopyTextureForBrowserHelper.cpp b/src/dawn/native/CopyTextureForBrowserHelper.cpp index d7890ed7d8..6f89842ef7 100644 --- a/src/dawn/native/CopyTextureForBrowserHelper.cpp +++ b/src/dawn/native/CopyTextureForBrowserHelper.cpp @@ -364,7 +364,7 @@ MaybeError ValidateCopyTextureForBrowser(DeviceBase* device, source->texture->GetSampleCount(), destination->texture->GetSampleCount()); DAWN_INVALID_IF( - options->internalUsage && !device->IsFeatureEnabled(Feature::DawnInternalUsages), + options->internalUsage && !device->HasFeature(Feature::DawnInternalUsages), "The internalUsage is true while the dawn-internal-usages feature is not enabled."); UsageValidationMode mode = options->internalUsage ? UsageValidationMode::Internal : UsageValidationMode::Default; diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp index 65e79c1e59..8112f64c5d 100644 --- a/src/dawn/native/Device.cpp +++ b/src/dawn/native/Device.cpp @@ -170,20 +170,19 @@ ResultOrError> ValidateLayoutAndGetRenderPipelineDescrip // DeviceBase -DeviceBase::DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor) - : mAdapter(adapter), mNextPipelineCompatibilityToken(1) { +DeviceBase::DeviceBase(AdapterBase* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) + : mAdapter(adapter), + mEnabledToggles(userProvidedToggles.providedTogglesEnabled), + mOverridenToggles(userProvidedToggles.togglesIsProvided), + mNextPipelineCompatibilityToken(1) { mAdapter->GetInstance()->IncrementDeviceCountForTesting(); ASSERT(descriptor != nullptr); AdapterProperties adapterProperties; adapter->APIGetProperties(&adapterProperties); - const DawnTogglesDeviceDescriptor* togglesDesc = nullptr; - FindInChain(descriptor->nextInChain, &togglesDesc); - if (togglesDesc != nullptr) { - ApplyToggleOverrides(togglesDesc); - } - SetDefaultToggles(); ApplyFeatures(descriptor); @@ -1323,17 +1322,19 @@ void DeviceBase::ApplyFeatures(const DeviceDescriptor* deviceDescriptor) { } } -bool DeviceBase::IsFeatureEnabled(Feature feature) const { +bool DeviceBase::HasFeature(Feature feature) const { return mEnabledFeatures.IsEnabled(feature); } void DeviceBase::SetWGSLExtensionAllowList() { // Set the WGSL extensions allow list based on device's enabled features and other - // propority. For example: - // mWGSLExtensionAllowList.insert("InternalExtensionForTesting"); - if (IsFeatureEnabled(Feature::ChromiumExperimentalDp4a)) { + // propority. + if (mEnabledFeatures.IsEnabled(Feature::ChromiumExperimentalDp4a)) { mWGSLExtensionAllowList.insert("chromium_experimental_dp4a"); } + if (mEnabledFeatures.IsEnabled(Feature::ShaderF16)) { + mWGSLExtensionAllowList.insert("f16"); + } } WGSLExtensionSet DeviceBase::GetWGSLExtensionAllowList() const { @@ -1800,27 +1801,6 @@ void DeviceBase::SetDefaultToggles() { SetToggle(Toggle::DisallowUnsafeAPIs, true); } -void DeviceBase::ApplyToggleOverrides(const DawnTogglesDeviceDescriptor* togglesDescriptor) { - ASSERT(togglesDescriptor != nullptr); - - for (uint32_t i = 0; i < togglesDescriptor->forceEnabledTogglesCount; ++i) { - Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum( - togglesDescriptor->forceEnabledToggles[i]); - if (toggle != Toggle::InvalidEnum) { - mEnabledToggles.Set(toggle, true); - mOverridenToggles.Set(toggle, true); - } - } - for (uint32_t i = 0; i < togglesDescriptor->forceDisabledTogglesCount; ++i) { - Toggle toggle = GetAdapter()->GetInstance()->ToggleNameToEnum( - togglesDescriptor->forceDisabledToggles[i]); - if (toggle != Toggle::InvalidEnum) { - mEnabledToggles.Set(toggle, false); - mOverridenToggles.Set(toggle, true); - } - } -} - void DeviceBase::FlushCallbackTaskQueue() { if (!mCallbackTaskManager->IsEmpty()) { // If a user calls Queue::Submit inside the callback, then the device will be ticked, diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h index 42bc77bc69..4fbe874a10 100644 --- a/src/dawn/native/Device.h +++ b/src/dawn/native/Device.h @@ -62,7 +62,9 @@ using WGSLExtensionSet = std::unordered_set; class DeviceBase : public RefCountedWithExternalCount { public: - DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor); + DeviceBase(AdapterBase* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles); ~DeviceBase() override; // Handles the error, causing a device loss if applicable. Almost always when a device loss @@ -279,11 +281,7 @@ class DeviceBase : public RefCountedWithExternalCount { QueueBase* APIGetQueue(); bool APIGetLimits(SupportedLimits* limits) const; - // Note that we should not use this function to query the features which can only be enabled - // behind toggles (use IsFeatureEnabled() instead). bool APIHasFeature(wgpu::FeatureName feature) const; - // Note that we should not use this function to query the features which can only be enabled - // behind toggles (use IsFeatureEnabled() instead). size_t APIEnumerateFeatures(wgpu::FeatureName* features) const; void APIInjectError(wgpu::ErrorType type, const char* message); bool APITick(); @@ -381,9 +379,7 @@ class DeviceBase : public RefCountedWithExternalCount { virtual bool ShouldDuplicateParametersForDrawIndirect( const RenderPipelineBase* renderPipelineBase) const; - // TODO(crbug.com/dawn/1434): Make this function non-overridable when we support requesting - // Adapter with toggles. - virtual bool IsFeatureEnabled(Feature feature) const; + bool HasFeature(Feature feature) const; const CombinedLimits& GetLimits() const; @@ -482,7 +478,6 @@ class DeviceBase : public RefCountedWithExternalCount { WGPUCreateRenderPipelineAsyncCallback callback, void* userdata); - void ApplyToggleOverrides(const DawnTogglesDeviceDescriptor* togglesDescriptor); void ApplyFeatures(const DeviceDescriptor* deviceDescriptor); void SetDefaultToggles(); diff --git a/src/dawn/native/Features.cpp b/src/dawn/native/Features.cpp index d375b2072e..4589f1c6ba 100644 --- a/src/dawn/native/Features.cpp +++ b/src/dawn/native/Features.cpp @@ -34,58 +34,64 @@ using FeatureEnumAndInfoList = static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {{ {Feature::TextureCompressionBC, {"texture-compression-bc", "Support Block Compressed (BC) texture formats", - "https://bugs.chromium.org/p/dawn/issues/detail?id=42"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=42", FeatureInfo::FeatureState::Stable}}, {Feature::TextureCompressionETC2, {"texture-compression-etc2", "Support Ericsson Texture Compressed (ETC2/EAC) texture " "formats", - "https://bugs.chromium.org/p/dawn/issues/detail?id=955"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=955", FeatureInfo::FeatureState::Stable}}, {Feature::TextureCompressionASTC, {"texture-compression-astc", "Support Adaptable Scalable Texture Compressed (ASTC) " "texture formats", - "https://bugs.chromium.org/p/dawn/issues/detail?id=955"}}, - {Feature::ShaderFloat16, - {"shader-float16", - "Support 16bit float arithmetic and declarations in uniform and storage buffers", - "https://bugs.chromium.org/p/dawn/issues/detail?id=426"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=955", FeatureInfo::FeatureState::Stable}}, {Feature::PipelineStatisticsQuery, {"pipeline-statistics-query", "Support Pipeline Statistics Query", - "https://bugs.chromium.org/p/dawn/issues/detail?id=434"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=434", FeatureInfo::FeatureState::Stable}}, {Feature::TimestampQuery, {"timestamp-query", "Support Timestamp Query", - "https://bugs.chromium.org/p/dawn/issues/detail?id=434"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=434", FeatureInfo::FeatureState::Stable}}, {Feature::DepthClipControl, {"depth-clip-control", "Disable depth clipping of primitives to the clip volume", - "https://bugs.chromium.org/p/dawn/issues/detail?id=1178"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=1178", FeatureInfo::FeatureState::Stable}}, {Feature::Depth32FloatStencil8, {"depth32float-stencil8", "Support depth32float-stencil8 texture format", - "https://bugs.chromium.org/p/dawn/issues/detail?id=690"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=690", FeatureInfo::FeatureState::Stable}}, {Feature::ChromiumExperimentalDp4a, {"chromium-experimental-dp4a", "Support experimental DP4a instructions in WGSL", - "https://bugs.chromium.org/p/tint/issues/detail?id=1497"}}, + "https://bugs.chromium.org/p/tint/issues/detail?id=1497", + FeatureInfo::FeatureState::Experimental}}, {Feature::IndirectFirstInstance, {"indirect-first-instance", "Support non-zero first instance values on indirect draw calls", - "https://bugs.chromium.org/p/dawn/issues/detail?id=1197"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=1197", FeatureInfo::FeatureState::Stable}}, + {Feature::ShaderF16, + {"shader-f16", "Supports the \"enable f16;\" directive in WGSL", + "https://bugs.chromium.org/p/dawn/issues/detail?id=1510", + FeatureInfo::FeatureState::Experimental}}, {Feature::DawnInternalUsages, {"dawn-internal-usages", "Add internal usages to resources to affect how the texture is allocated, but not " "frontend validation. Other internal commands may access this usage.", "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/" - "dawn_internal_usages.md"}}, + "dawn_internal_usages.md", + FeatureInfo::FeatureState::Stable}}, {Feature::MultiPlanarFormats, {"multiplanar-formats", "Import and use multi-planar texture formats with per plane views", - "https://bugs.chromium.org/p/dawn/issues/detail?id=551"}}, + "https://bugs.chromium.org/p/dawn/issues/detail?id=551", FeatureInfo::FeatureState::Stable}}, {Feature::DawnNative, {"dawn-native", "WebGPU is running on top of dawn_native.", "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/" - "dawn_native.md"}}, + "dawn_native.md", + FeatureInfo::FeatureState::Stable}}, }}; Feature FromAPIFeature(wgpu::FeatureName feature) { switch (feature) { case wgpu::FeatureName::Undefined: return Feature::InvalidEnum; + case wgpu::FeatureName::DawnShaderFloat16: + // Deprecated. + return Feature::InvalidEnum; case wgpu::FeatureName::TimestampQuery: return Feature::TimestampQuery; @@ -103,8 +109,6 @@ Feature FromAPIFeature(wgpu::FeatureName feature) { return Feature::Depth32FloatStencil8; case wgpu::FeatureName::IndirectFirstInstance: return Feature::IndirectFirstInstance; - case wgpu::FeatureName::DawnShaderFloat16: - return Feature::ShaderFloat16; case wgpu::FeatureName::DawnInternalUsages: return Feature::DawnInternalUsages; case wgpu::FeatureName::DawnMultiPlanarFormats: @@ -113,6 +117,8 @@ Feature FromAPIFeature(wgpu::FeatureName feature) { return Feature::DawnNative; case wgpu::FeatureName::ChromiumExperimentalDp4a: return Feature::ChromiumExperimentalDp4a; + case wgpu::FeatureName::ShaderF16: + return Feature::ShaderF16; } return Feature::InvalidEnum; } @@ -135,8 +141,6 @@ wgpu::FeatureName ToAPIFeature(Feature feature) { return wgpu::FeatureName::Depth32FloatStencil8; case Feature::IndirectFirstInstance: return wgpu::FeatureName::IndirectFirstInstance; - case Feature::ShaderFloat16: - return wgpu::FeatureName::DawnShaderFloat16; case Feature::DawnInternalUsages: return wgpu::FeatureName::DawnInternalUsages; case Feature::MultiPlanarFormats: @@ -145,6 +149,8 @@ wgpu::FeatureName ToAPIFeature(Feature feature) { return wgpu::FeatureName::DawnNative; case Feature::ChromiumExperimentalDp4a: return wgpu::FeatureName::ChromiumExperimentalDp4a; + case Feature::ShaderF16: + return wgpu::FeatureName::ShaderF16; case Feature::EnumCount: break; diff --git a/src/dawn/native/Features.h b/src/dawn/native/Features.h index f97fd9df67..9413da62a2 100644 --- a/src/dawn/native/Features.h +++ b/src/dawn/native/Features.h @@ -30,13 +30,13 @@ enum class Feature { TextureCompressionBC, TextureCompressionETC2, TextureCompressionASTC, - ShaderFloat16, PipelineStatisticsQuery, TimestampQuery, DepthClipControl, Depth32FloatStencil8, ChromiumExperimentalDp4a, IndirectFirstInstance, + ShaderF16, // Dawn-specific DawnInternalUsages, diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp index 11de9acabe..ef9a7d24bc 100644 --- a/src/dawn/native/Format.cpp +++ b/src/dawn/native/Format.cpp @@ -389,12 +389,12 @@ FormatTable BuildFormatTable(const DeviceBase* device) { AddMultiAspectFormat(wgpu::TextureFormat::Depth24PlusStencil8, Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, true, true, 2); AddDepthFormat(wgpu::TextureFormat::Depth32Float, 4, true); - bool isD32S8Supported = device->IsFeatureEnabled(Feature::Depth32FloatStencil8); + bool isD32S8Supported = device->HasFeature(Feature::Depth32FloatStencil8); AddMultiAspectFormat(wgpu::TextureFormat::Depth32FloatStencil8, Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth32Float, wgpu::TextureFormat::Stencil8, true, isD32S8Supported, true, 2); // BC compressed formats - bool isBCFormatSupported = device->IsFeatureEnabled(Feature::TextureCompressionBC); + bool isBCFormatSupported = device->HasFeature(Feature::TextureCompressionBC); AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnorm, 8, 4, 4, isBCFormatSupported, 4); AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4, isBCFormatSupported, 4, wgpu::TextureFormat::BC1RGBAUnorm); AddCompressedFormat(wgpu::TextureFormat::BC4RSnorm, 8, 4, 4, isBCFormatSupported, 1); @@ -411,7 +411,7 @@ FormatTable BuildFormatTable(const DeviceBase* device) { AddCompressedFormat(wgpu::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported, 4, wgpu::TextureFormat::BC7RGBAUnorm); // ETC2/EAC compressed formats - bool isETC2FormatSupported = device->IsFeatureEnabled(Feature::TextureCompressionETC2); + bool isETC2FormatSupported = device->HasFeature(Feature::TextureCompressionETC2); AddCompressedFormat(wgpu::TextureFormat::ETC2RGB8Unorm, 8, 4, 4, isETC2FormatSupported, 3); AddCompressedFormat(wgpu::TextureFormat::ETC2RGB8UnormSrgb, 8, 4, 4, isETC2FormatSupported, 3, wgpu::TextureFormat::ETC2RGB8Unorm); AddCompressedFormat(wgpu::TextureFormat::ETC2RGB8A1Unorm, 8, 4, 4, isETC2FormatSupported, 4); @@ -424,7 +424,7 @@ FormatTable BuildFormatTable(const DeviceBase* device) { AddCompressedFormat(wgpu::TextureFormat::EACRG11Snorm, 16, 4, 4, isETC2FormatSupported, 2); // ASTC compressed formats - bool isASTCFormatSupported = device->IsFeatureEnabled(Feature::TextureCompressionASTC); + bool isASTCFormatSupported = device->HasFeature(Feature::TextureCompressionASTC); AddCompressedFormat(wgpu::TextureFormat::ASTC4x4Unorm, 16, 4, 4, isASTCFormatSupported, 4); AddCompressedFormat(wgpu::TextureFormat::ASTC4x4UnormSrgb, 16, 4, 4, isASTCFormatSupported, 4, wgpu::TextureFormat::ASTC4x4Unorm); AddCompressedFormat(wgpu::TextureFormat::ASTC5x4Unorm, 16, 5, 4, isASTCFormatSupported, 4); @@ -455,7 +455,7 @@ FormatTable BuildFormatTable(const DeviceBase* device) { AddCompressedFormat(wgpu::TextureFormat::ASTC12x12UnormSrgb, 16, 12, 12, isASTCFormatSupported, 4, wgpu::TextureFormat::ASTC12x12Unorm); // multi-planar formats - const bool isMultiPlanarFormatSupported = device->IsFeatureEnabled(Feature::MultiPlanarFormats); + const bool isMultiPlanarFormatSupported = device->HasFeature(Feature::MultiPlanarFormats); AddMultiAspectFormat(wgpu::TextureFormat::R8BG8Biplanar420Unorm, Aspect::Plane0 | Aspect::Plane1, wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::RG8Unorm, false, isMultiPlanarFormatSupported, false, 3); diff --git a/src/dawn/native/IndirectDrawValidationEncoder.cpp b/src/dawn/native/IndirectDrawValidationEncoder.cpp index abd09cd112..db940e798b 100644 --- a/src/dawn/native/IndirectDrawValidationEncoder.cpp +++ b/src/dawn/native/IndirectDrawValidationEncoder.cpp @@ -338,7 +338,7 @@ MaybeError EncodeIndirectDrawValidationCommands(DeviceBase* device, if (device->IsValidationEnabled()) { newPass.flags |= kValidationEnabled; } - if (device->IsFeatureEnabled(Feature::IndirectFirstInstance)) { + if (device->HasFeature(Feature::IndirectFirstInstance)) { newPass.flags |= kIndirectFirstInstanceEnabled; } passes.push_back(std::move(newPass)); diff --git a/src/dawn/native/QuerySet.cpp b/src/dawn/native/QuerySet.cpp index a5031659c6..ad75bedebc 100644 --- a/src/dawn/native/QuerySet.cpp +++ b/src/dawn/native/QuerySet.cpp @@ -60,7 +60,7 @@ MaybeError ValidateQuerySetDescriptor(DeviceBase* device, const QuerySetDescript "fully implemented"); DAWN_INVALID_IF( - !device->IsFeatureEnabled(Feature::PipelineStatisticsQuery), + !device->HasFeature(Feature::PipelineStatisticsQuery), "Pipeline statistics query set created without the feature being enabled."); DAWN_INVALID_IF(descriptor->pipelineStatisticsCount == 0, @@ -82,7 +82,7 @@ MaybeError ValidateQuerySetDescriptor(DeviceBase* device, const QuerySetDescript "Timestamp queries are disallowed because they may expose precise " "timing information."); - DAWN_INVALID_IF(!device->IsFeatureEnabled(Feature::TimestampQuery), + DAWN_INVALID_IF(!device->HasFeature(Feature::TimestampQuery), "Timestamp query set created without the feature being enabled."); DAWN_INVALID_IF(descriptor->pipelineStatisticsCount != 0, diff --git a/src/dawn/native/RenderPipeline.cpp b/src/dawn/native/RenderPipeline.cpp index 8a3d82a6bd..03b90bb69c 100644 --- a/src/dawn/native/RenderPipeline.cpp +++ b/src/dawn/native/RenderPipeline.cpp @@ -156,7 +156,7 @@ MaybeError ValidatePrimitiveState(const DeviceBase* device, const PrimitiveState DAWN_TRY(ValidateSingleSType(descriptor->nextInChain, wgpu::SType::PrimitiveDepthClipControl)); const PrimitiveDepthClipControl* depthClipControl = nullptr; FindInChain(descriptor->nextInChain, &depthClipControl); - DAWN_INVALID_IF(depthClipControl && !device->IsFeatureEnabled(Feature::DepthClipControl), + DAWN_INVALID_IF(depthClipControl && !device->HasFeature(Feature::DepthClipControl), "%s is not supported", wgpu::FeatureName::DepthClipControl); DAWN_TRY(ValidatePrimitiveTopology(descriptor->topology)); DAWN_TRY(ValidateIndexFormat(descriptor->stripIndexFormat)); diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp index 7efbbf802a..5ddbbc3674 100644 --- a/src/dawn/native/Texture.cpp +++ b/src/dawn/native/Texture.cpp @@ -339,7 +339,7 @@ MaybeError ValidateTextureDescriptor(const DeviceBase* device, FindInChain(descriptor->nextInChain, &internalUsageDesc); DAWN_INVALID_IF( - internalUsageDesc != nullptr && !device->IsFeatureEnabled(Feature::DawnInternalUsages), + internalUsageDesc != nullptr && !device->HasFeature(Feature::DawnInternalUsages), "The internalUsageDesc is not empty while the dawn-internal-usages feature is not enabled"); const Format* format; diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp index 8fbf0e3e81..3816f20a57 100644 --- a/src/dawn/native/Toggles.cpp +++ b/src/dawn/native/Toggles.cpp @@ -17,6 +17,7 @@ #include "dawn/common/Assert.h" #include "dawn/common/BitSetIterator.h" #include "dawn/native/Toggles.h" +#include "dawn/native/dawn_platform.h" namespace dawn::native { namespace { @@ -334,6 +335,81 @@ std::vector TogglesSet::GetContainedToggleNames() const { return togglesNameInUse; } +TripleStateTogglesSet TripleStateTogglesSet::CreateFromTogglesDeviceDescriptor( + const DawnTogglesDeviceDescriptor* togglesDesc) { + TripleStateTogglesSet userToggles; + if (togglesDesc != nullptr) { + TogglesInfo togglesInfo; + for (uint32_t i = 0; i < togglesDesc->forceEnabledTogglesCount; ++i) { + Toggle toggle = togglesInfo.ToggleNameToEnum(togglesDesc->forceEnabledToggles[i]); + if (toggle != Toggle::InvalidEnum) { + userToggles.togglesIsProvided.Set(toggle, true); + userToggles.providedTogglesEnabled.Set(toggle, true); + } + } + for (uint32_t i = 0; i < togglesDesc->forceDisabledTogglesCount; ++i) { + Toggle toggle = togglesInfo.ToggleNameToEnum(togglesDesc->forceDisabledToggles[i]); + if (toggle != Toggle::InvalidEnum) { + userToggles.togglesIsProvided.Set(toggle, true); + userToggles.providedTogglesEnabled.Set(toggle, false); + } + } + } + return userToggles; +} + +void TripleStateTogglesSet::Set(Toggle toggle, bool enabled) { + ASSERT(toggle != Toggle::InvalidEnum); + togglesIsProvided.Set(toggle, true); + providedTogglesEnabled.Set(toggle, enabled); +} + +bool TripleStateTogglesSet::IsProvided(Toggle toggle) const { + return togglesIsProvided.Has(toggle); +} +// Return true if the toggle is provided in enable list, and false otherwise. +bool TripleStateTogglesSet::IsEnabled(Toggle toggle) const { + return togglesIsProvided.Has(toggle) && providedTogglesEnabled.Has(toggle); +} +// Return true if the toggle is provided in disable list, and false otherwise. +bool TripleStateTogglesSet::IsDisabled(Toggle toggle) const { + return togglesIsProvided.Has(toggle) && !providedTogglesEnabled.Has(toggle); +} + +std::vector TripleStateTogglesSet::GetEnabledToggleNames() const { + std::vector enabledTogglesName(providedTogglesEnabled.toggleBitset.count()); + + uint32_t index = 0; + for (uint32_t i : IterateBitSet(providedTogglesEnabled.toggleBitset)) { + const Toggle& toggle = static_cast(i); + // All enabled toggles must be provided. + ASSERT(togglesIsProvided.Has(toggle)); + const char* toggleName = ToggleEnumToName(toggle); + enabledTogglesName[index] = toggleName; + ++index; + } + + return enabledTogglesName; +} + +std::vector TripleStateTogglesSet::GetDisabledToggleNames() const { + std::vector enabledTogglesName(togglesIsProvided.toggleBitset.count() - + providedTogglesEnabled.toggleBitset.count()); + + uint32_t index = 0; + for (uint32_t i : IterateBitSet(togglesIsProvided.toggleBitset)) { + const Toggle& toggle = static_cast(i); + // Disabled toggles are those provided but not enabled. + if (!providedTogglesEnabled.Has(toggle)) { + const char* toggleName = ToggleEnumToName(toggle); + enabledTogglesName[index] = toggleName; + ++index; + } + } + + return enabledTogglesName; +} + const char* ToggleEnumToName(Toggle toggle) { ASSERT(toggle != Toggle::InvalidEnum); diff --git a/src/dawn/native/Toggles.h b/src/dawn/native/Toggles.h index 5e000f9f6e..981aa94e0c 100644 --- a/src/dawn/native/Toggles.h +++ b/src/dawn/native/Toggles.h @@ -24,6 +24,8 @@ namespace dawn::native { +struct DawnTogglesDeviceDescriptor; + enum class Toggle { EmulateStoreAndMSAAResolve, NonzeroClearResourcesOnCreationForTesting, @@ -92,6 +94,27 @@ struct TogglesSet { std::vector GetContainedToggleNames() const; }; +// TripleStateTogglesSet track each toggle with three posible states, i.e. "Not provided" (default), +// "Provided as enabled", and "Provided as disabled". This struct can be used to record the +// user-provided toggles, where some toggles are explicitly enabled or disabled while the other +// toggles are left as default. +struct TripleStateTogglesSet { + TogglesSet togglesIsProvided; + TogglesSet providedTogglesEnabled; + + static TripleStateTogglesSet CreateFromTogglesDeviceDescriptor( + const DawnTogglesDeviceDescriptor* togglesDesc); + // Provide a single toggle with given state. + void Set(Toggle toggle, bool enabled); + bool IsProvided(Toggle toggle) const; + // Return true if the toggle is provided in enable list, and false otherwise. + bool IsEnabled(Toggle toggle) const; + // Return true if the toggle is provided in disable list, and false otherwise. + bool IsDisabled(Toggle toggle) const; + std::vector GetEnabledToggleNames() const; + std::vector GetDisabledToggleNames() const; +}; + const char* ToggleEnumToName(Toggle toggle); class TogglesInfo { diff --git a/src/dawn/native/d3d12/AdapterD3D12.cpp b/src/dawn/native/d3d12/AdapterD3D12.cpp index e23830e899..bcd40fcb80 100644 --- a/src/dawn/native/d3d12/AdapterD3D12.cpp +++ b/src/dawn/native/d3d12/AdapterD3D12.cpp @@ -147,6 +147,9 @@ MaybeError Adapter::InitializeSupportedFeaturesImpl() { dxcVersion >= MakeDXCVersion(kLeastMajorVersionForDP4a, kLeastMinorVersionForDP4a)) { mSupportedFeatures.EnableFeature(Feature::ChromiumExperimentalDp4a); } + if (mDeviceInfo.supportsShaderF16) { + mSupportedFeatures.EnableFeature(Feature::ShaderF16); + } } return {}; @@ -312,6 +315,20 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) { return {}; } +MaybeError Adapter::ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) { + // shader-f16 feature and chromium-experimental-dp4a feature require DXC for D3D12. + if (feature == wgpu::FeatureName::ShaderF16 || + feature == wgpu::FeatureName::ChromiumExperimentalDp4a) { + DAWN_INVALID_IF(!(userProvidedToggles.IsEnabled(Toggle::UseDXC) && + mBackend->GetFunctions()->IsDXCAvailable()), + "Feature %s requires DXC for D3D12.", + GetInstance()->GetFeatureInfo(feature)->name); + } + return {}; +} + MaybeError Adapter::InitializeDebugLayerFilters() { if (!GetInstance()->IsBackendValidationEnabled()) { return {}; @@ -418,8 +435,10 @@ void Adapter::CleanUpDebugLayerFilters() { infoQueue->PopStorageFilter(); } -ResultOrError> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { - return Device::Create(this, descriptor); +ResultOrError> Adapter::CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { + return Device::Create(this, descriptor, userProvidedToggles); } // Resets the backend device and creates a new one. If any D3D12 objects belonging to the diff --git a/src/dawn/native/d3d12/AdapterD3D12.h b/src/dawn/native/d3d12/AdapterD3D12.h index 035e291a4c..2c8a377643 100644 --- a/src/dawn/native/d3d12/AdapterD3D12.h +++ b/src/dawn/native/d3d12/AdapterD3D12.h @@ -40,7 +40,9 @@ class Adapter : public AdapterBase { const gpu_info::D3DDriverVersion& GetDriverVersion() const; private: - ResultOrError> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + ResultOrError> CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) override; MaybeError ResetInternalDeviceForTestingImpl() override; bool AreTimestampQueriesSupported() const; @@ -49,6 +51,10 @@ class Adapter : public AdapterBase { MaybeError InitializeSupportedFeaturesImpl() override; MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override; + MaybeError ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) override; + MaybeError InitializeDebugLayerFilters(); void CleanUpDebugLayerFilters(); diff --git a/src/dawn/native/d3d12/D3D12Info.cpp b/src/dawn/native/d3d12/D3D12Info.cpp index 3d3470c173..d6d8dde71a 100644 --- a/src/dawn/native/d3d12/D3D12Info.cpp +++ b/src/dawn/native/d3d12/D3D12Info.cpp @@ -121,7 +121,7 @@ ResultOrError GatherDeviceInfo(const Adapter& adapter) { info.shaderProfiles[SingleShaderStage::Fragment] = L"p" + profileSuffix; info.shaderProfiles[SingleShaderStage::Compute] = L"c" + profileSuffix; - info.supportsShaderFloat16 = + info.supportsShaderF16 = driverShaderModel >= D3D_SHADER_MODEL_6_2 && featureOptions4.Native16BitShaderOpsSupported; info.supportsDP4a = driverShaderModel >= D3D_SHADER_MODEL_6_4; diff --git a/src/dawn/native/d3d12/D3D12Info.h b/src/dawn/native/d3d12/D3D12Info.h index f81e28de11..af0b6331c9 100644 --- a/src/dawn/native/d3d12/D3D12Info.h +++ b/src/dawn/native/d3d12/D3D12Info.h @@ -27,7 +27,7 @@ struct D3D12DeviceInfo { bool isUMA; uint32_t resourceHeapTier; bool supportsRenderPass; - bool supportsShaderFloat16; + bool supportsShaderF16; // shaderModel indicates the maximum supported shader model, for example, the value 62 // indicates that current driver supports the maximum shader model is shader model 6.2. uint32_t shaderModel; diff --git a/src/dawn/native/d3d12/DeviceD3D12.cpp b/src/dawn/native/d3d12/DeviceD3D12.cpp index 2a6c97f18e..4a6a1bddae 100644 --- a/src/dawn/native/d3d12/DeviceD3D12.cpp +++ b/src/dawn/native/d3d12/DeviceD3D12.cpp @@ -63,8 +63,10 @@ static constexpr uint64_t kZeroBufferSize = 1024 * 1024 * 4; // 4 Mb static constexpr uint64_t kMaxDebugMessagesToPrint = 5; // static -ResultOrError> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) { - Ref device = AcquireRef(new Device(adapter, descriptor)); +ResultOrError> Device::Create(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { + Ref device = AcquireRef(new Device(adapter, descriptor, userProvidedToggles)); DAWN_TRY(device->Initialize(descriptor)); return device; } @@ -84,7 +86,7 @@ MaybeError Device::Initialize(const DeviceDescriptor* descriptor) { CheckHRESULT(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)), "D3D12 create command queue")); - if (IsFeatureEnabled(Feature::TimestampQuery) && + if (HasFeature(Feature::TimestampQuery) && !IsToggleEnabled(Toggle::DisableTimestampQueryConversion)) { // Get GPU timestamp counter frequency (in ticks/second). This fails if the specified // command queue doesn't support timestamps. D3D12_COMMAND_LIST_TYPE_DIRECT queues @@ -876,17 +878,6 @@ bool Device::ShouldDuplicateNumWorkgroupsForDispatchIndirect( return ToBackend(computePipeline)->UsesNumWorkgroups(); } -bool Device::IsFeatureEnabled(Feature feature) const { - // Currently we can only use DXC to compile HLSL shaders using float16, and - // ChromiumExperimentalDp4a is an experimental feature which can only be enabled with toggle - // "use_dxc". - if ((feature == Feature::ChromiumExperimentalDp4a || feature == Feature::ShaderFloat16) && - !IsToggleEnabled(Toggle::UseDXC)) { - return false; - } - return DeviceBase::IsFeatureEnabled(feature); -} - void Device::SetLabelImpl() { SetDebugName(this, mD3d12Device.Get(), "Dawn_Device", GetLabel()); } diff --git a/src/dawn/native/d3d12/DeviceD3D12.h b/src/dawn/native/d3d12/DeviceD3D12.h index 49bc3014b1..6b56d1a59f 100644 --- a/src/dawn/native/d3d12/DeviceD3D12.h +++ b/src/dawn/native/d3d12/DeviceD3D12.h @@ -46,7 +46,9 @@ class StagingDescriptorAllocator; // Definition of backend types class Device final : public DeviceBase { public: - static ResultOrError> Create(Adapter* adapter, const DeviceDescriptor* descriptor); + static ResultOrError> Create(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles); ~Device() override; MaybeError Initialize(const DeviceDescriptor* descriptor); @@ -160,8 +162,6 @@ class Device final : public DeviceBase { bool ShouldDuplicateParametersForDrawIndirect( const RenderPipelineBase* renderPipelineBase) const override; - bool IsFeatureEnabled(Feature feature) const override; - uint64_t GetBufferCopyOffsetAlignmentForDepthStencil() const override; // Dawn APIs diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp index bb0077aa29..f67167e91d 100644 --- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp +++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp @@ -97,7 +97,7 @@ enum class Compiler { FXC, DXC }; X(bool, dumpShaders) #define D3D_BYTECODE_COMPILATION_REQUEST_MEMBERS(X) \ - X(bool, hasShaderFloat16Feature) \ + X(bool, hasShaderF16Feature) \ X(uint32_t, compileFlags) \ X(Compiler, compiler) \ X(uint64_t, compilerVersion) \ @@ -186,8 +186,7 @@ ResultOrError> CompileShaderDXC(const D3DBytecodeCompilationReq std::wstring entryPointW; DAWN_TRY_ASSIGN(entryPointW, ConvertStringToWstring(entryPointName)); - std::vector arguments = - GetDXCArguments(r.compileFlags, r.hasShaderFloat16Feature); + std::vector arguments = GetDXCArguments(r.compileFlags, r.hasShaderF16Feature); ComPtr result; DAWN_TRY(CheckHRESULT(r.dxcCompiler->Compile(sourceBlob.Get(), nullptr, entryPointW.c_str(), @@ -475,7 +474,7 @@ ResultOrError ShaderModule::Compile(const ProgrammableStage& pro req.hlsl.disableWorkgroupInit = device->IsToggleEnabled(Toggle::DisableWorkgroupInit); req.hlsl.dumpShaders = device->IsToggleEnabled(Toggle::DumpShaders); - req.bytecode.hasShaderFloat16Feature = device->IsFeatureEnabled(Feature::ShaderFloat16); + req.bytecode.hasShaderF16Feature = device->HasFeature(Feature::ShaderF16); req.bytecode.compileFlags = compileFlags; if (device->IsToggleEnabled(Toggle::UseDXC)) { diff --git a/src/dawn/native/metal/BackendMTL.mm b/src/dawn/native/metal/BackendMTL.mm index acba1a935c..3ef6f3f1e7 100644 --- a/src/dawn/native/metal/BackendMTL.mm +++ b/src/dawn/native/metal/BackendMTL.mm @@ -299,8 +299,10 @@ class Adapter : public AdapterBase { } private: - ResultOrError> CreateDeviceImpl(const DeviceDescriptor* descriptor) override { - return Device::Create(this, mDevice, descriptor); + ResultOrError> CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) override { + return Device::Create(this, mDevice, descriptor, userProvidedToggles); } MaybeError InitializeImpl() override { return {}; } @@ -378,6 +380,8 @@ class Adapter : public AdapterBase { mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance); + mSupportedFeatures.EnableFeature(Feature::ShaderF16); + return {}; } @@ -620,6 +624,12 @@ class Adapter : public AdapterBase { return {}; } + MaybeError ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) override { + return {}; + } + NSPRef> mDevice; }; diff --git a/src/dawn/native/metal/DeviceMTL.h b/src/dawn/native/metal/DeviceMTL.h index 074140b89c..62d4f909ba 100644 --- a/src/dawn/native/metal/DeviceMTL.h +++ b/src/dawn/native/metal/DeviceMTL.h @@ -38,7 +38,8 @@ class Device final : public DeviceBase { public: static ResultOrError> Create(AdapterBase* adapter, NSPRef> mtlDevice, - const DeviceDescriptor* descriptor); + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles); ~Device() override; MaybeError Initialize(const DeviceDescriptor* descriptor); @@ -74,7 +75,8 @@ class Device final : public DeviceBase { private: Device(AdapterBase* adapter, NSPRef> mtlDevice, - const DeviceDescriptor* descriptor); + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles); ResultOrError> CreateBindGroupImpl( const BindGroupDescriptor* descriptor) override; diff --git a/src/dawn/native/metal/DeviceMTL.mm b/src/dawn/native/metal/DeviceMTL.mm index 4b589eab3e..a3fdac1e51 100644 --- a/src/dawn/native/metal/DeviceMTL.mm +++ b/src/dawn/native/metal/DeviceMTL.mm @@ -107,16 +107,21 @@ void API_AVAILABLE(macos(10.15), ios(14)) UpdateTimestampPeriod(id de // static ResultOrError> Device::Create(AdapterBase* adapter, NSPRef> mtlDevice, - const DeviceDescriptor* descriptor) { - Ref device = AcquireRef(new Device(adapter, std::move(mtlDevice), descriptor)); + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { + Ref device = + AcquireRef(new Device(adapter, std::move(mtlDevice), descriptor, userProvidedToggles)); DAWN_TRY(device->Initialize(descriptor)); return device; } Device::Device(AdapterBase* adapter, NSPRef> mtlDevice, - const DeviceDescriptor* descriptor) - : DeviceBase(adapter, descriptor), mMtlDevice(std::move(mtlDevice)), mCompletedSerial(0) {} + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) + : DeviceBase(adapter, descriptor, userProvidedToggles), + mMtlDevice(std::move(mtlDevice)), + mCompletedSerial(0) {} Device::~Device() { Destroy(); @@ -132,7 +137,7 @@ MaybeError Device::Initialize(const DeviceDescriptor* descriptor) { DAWN_TRY(mCommandContext.PrepareNextCommandBuffer(*mCommandQueue)); - if (IsFeatureEnabled(Feature::TimestampQuery) && + if (HasFeature(Feature::TimestampQuery) && !IsToggleEnabled(Toggle::DisableTimestampQueryConversion)) { // Make a best guess of timestamp period based on device vendor info, and converge it to // an accurate value by the following calculations. @@ -322,7 +327,7 @@ MaybeError Device::TickImpl() { DAWN_TRY(SubmitPendingCommandBuffer()); // Just run timestamp period calculation when timestamp feature is enabled. - if (IsFeatureEnabled(Feature::TimestampQuery)) { + if (HasFeature(Feature::TimestampQuery)) { if (@available(macos 10.15, iOS 14.0, *)) { UpdateTimestampPeriod(GetMTLDevice(), mKalmanInfo.get(), &mCpuTimestamp, &mGpuTimestamp, &mTimestampPeriod); diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp index a00515db1c..79d5f66e63 100644 --- a/src/dawn/native/null/DeviceNull.cpp +++ b/src/dawn/native/null/DeviceNull.cpp @@ -65,8 +65,16 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) { return {}; } -ResultOrError> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { - return Device::Create(this, descriptor); +ResultOrError> Adapter::CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { + return Device::Create(this, descriptor, userProvidedToggles); +} + +MaybeError Adapter::ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) { + return {}; } class Backend : public BackendConnection { @@ -103,8 +111,10 @@ struct CopyFromStagingToBufferOperation : PendingOperation { // Device // static -ResultOrError> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) { - Ref device = AcquireRef(new Device(adapter, descriptor)); +ResultOrError> Device::Create(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { + Ref device = AcquireRef(new Device(adapter, descriptor, userProvidedToggles)); DAWN_TRY(device->Initialize(descriptor)); return device; } diff --git a/src/dawn/native/null/DeviceNull.h b/src/dawn/native/null/DeviceNull.h index 74da890354..7c90c4ee6d 100644 --- a/src/dawn/native/null/DeviceNull.h +++ b/src/dawn/native/null/DeviceNull.h @@ -89,7 +89,9 @@ struct PendingOperation { class Device final : public DeviceBase { public: - static ResultOrError> Create(Adapter* adapter, const DeviceDescriptor* descriptor); + static ResultOrError> Create(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles); ~Device() override; MaybeError Initialize(const DeviceDescriptor* descriptor); @@ -182,7 +184,13 @@ class Adapter : public AdapterBase { MaybeError InitializeSupportedFeaturesImpl() override; MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override; - ResultOrError> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + ResultOrError> CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) override; + + MaybeError ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) override; }; // Helper class so |BindGroup| can allocate memory for its binding data, diff --git a/src/dawn/native/opengl/AdapterGL.cpp b/src/dawn/native/opengl/AdapterGL.cpp index 7a4f336078..f309c61c8e 100644 --- a/src/dawn/native/opengl/AdapterGL.cpp +++ b/src/dawn/native/opengl/AdapterGL.cpp @@ -141,6 +141,11 @@ MaybeError Adapter::InitializeSupportedFeaturesImpl() { mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance); } + // ShaderF16 + if (mFunctions.IsGLExtensionSupported("GL_AMD_gpu_shader_half_float")) { + mSupportedFeatures.EnableFeature(Feature::ShaderF16); + } + return {}; } @@ -149,12 +154,20 @@ MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) { return {}; } -ResultOrError> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { +ResultOrError> Adapter::CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { EGLenum api = GetBackendType() == wgpu::BackendType::OpenGL ? EGL_OPENGL_API : EGL_OPENGL_ES_API; std::unique_ptr context; DAWN_TRY_ASSIGN(context, ContextEGL::Create(mEGLFunctions, api)); - return Device::Create(this, descriptor, mFunctions, std::move(context)); + return Device::Create(this, descriptor, mFunctions, std::move(context), userProvidedToggles); +} + +MaybeError Adapter::ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) { + return {}; } } // namespace dawn::native::opengl diff --git a/src/dawn/native/opengl/AdapterGL.h b/src/dawn/native/opengl/AdapterGL.h index 6e354b2d03..4d6b0c1b68 100644 --- a/src/dawn/native/opengl/AdapterGL.h +++ b/src/dawn/native/opengl/AdapterGL.h @@ -36,7 +36,13 @@ class Adapter : public AdapterBase { MaybeError InitializeImpl() override; MaybeError InitializeSupportedFeaturesImpl() override; MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override; - ResultOrError> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + ResultOrError> CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) override; + + MaybeError ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) override; OpenGLFunctions mFunctions; EGLFunctions mEGLFunctions; diff --git a/src/dawn/native/opengl/DeviceGL.cpp b/src/dawn/native/opengl/DeviceGL.cpp index 4246d5ff56..8297573e2d 100644 --- a/src/dawn/native/opengl/DeviceGL.cpp +++ b/src/dawn/native/opengl/DeviceGL.cpp @@ -108,8 +108,10 @@ namespace dawn::native::opengl { ResultOrError> Device::Create(AdapterBase* adapter, const DeviceDescriptor* descriptor, const OpenGLFunctions& functions, - std::unique_ptr context) { - Ref device = AcquireRef(new Device(adapter, descriptor, functions, std::move(context))); + std::unique_ptr context, + const TripleStateTogglesSet& userProvidedToggles) { + Ref device = AcquireRef( + new Device(adapter, descriptor, functions, std::move(context), userProvidedToggles)); DAWN_TRY(device->Initialize(descriptor)); return device; } @@ -117,8 +119,11 @@ ResultOrError> Device::Create(AdapterBase* adapter, Device::Device(AdapterBase* adapter, const DeviceDescriptor* descriptor, const OpenGLFunctions& functions, - std::unique_ptr context) - : DeviceBase(adapter, descriptor), mGL(functions), mContext(std::move(context)) {} + std::unique_ptr context, + const TripleStateTogglesSet& userProvidedToggles) + : DeviceBase(adapter, descriptor, userProvidedToggles), + mGL(functions), + mContext(std::move(context)) {} Device::~Device() { Destroy(); diff --git a/src/dawn/native/opengl/DeviceGL.h b/src/dawn/native/opengl/DeviceGL.h index 78abf1147a..08c776b762 100644 --- a/src/dawn/native/opengl/DeviceGL.h +++ b/src/dawn/native/opengl/DeviceGL.h @@ -43,7 +43,8 @@ class Device final : public DeviceBase { static ResultOrError> Create(AdapterBase* adapter, const DeviceDescriptor* descriptor, const OpenGLFunctions& functions, - std::unique_ptr context); + std::unique_ptr context, + const TripleStateTogglesSet& userProvidedToggles); ~Device() override; MaybeError Initialize(const DeviceDescriptor* descriptor); @@ -93,7 +94,8 @@ class Device final : public DeviceBase { Device(AdapterBase* adapter, const DeviceDescriptor* descriptor, const OpenGLFunctions& functions, - std::unique_ptr context); + std::unique_ptr context, + const TripleStateTogglesSet& userProvidedToggles); ResultOrError> CreateBindGroupImpl( const BindGroupDescriptor* descriptor) override; diff --git a/src/dawn/native/vulkan/AdapterVk.cpp b/src/dawn/native/vulkan/AdapterVk.cpp index 9ccc4d6514..ab0342bdc3 100644 --- a/src/dawn/native/vulkan/AdapterVk.cpp +++ b/src/dawn/native/vulkan/AdapterVk.cpp @@ -159,6 +159,15 @@ MaybeError Adapter::InitializeSupportedFeaturesImpl() { mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance); } + if (mDeviceInfo.HasExt(DeviceExt::ShaderFloat16Int8) && + mDeviceInfo.HasExt(DeviceExt::_16BitStorage) && + mDeviceInfo.shaderFloat16Int8Features.shaderFloat16 == VK_TRUE && + mDeviceInfo._16BitStorageFeatures.storageBuffer16BitAccess == VK_TRUE && + mDeviceInfo._16BitStorageFeatures.storageInputOutput16 == VK_TRUE && + mDeviceInfo._16BitStorageFeatures.uniformAndStorageBuffer16BitAccess == VK_TRUE) { + mSupportedFeatures.EnableFeature(Feature::ShaderF16); + } + if (mDeviceInfo.HasExt(DeviceExt::ShaderIntegerDotProduct) && mDeviceInfo.shaderIntegerDotProductProperties .integerDotProduct4x8BitPackedSignedAccelerated == VK_TRUE && @@ -354,8 +363,16 @@ bool Adapter::SupportsExternalImages() const { mVulkanInstance->GetFunctions()); } -ResultOrError> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { - return Device::Create(this, descriptor); +ResultOrError> Adapter::CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { + return Device::Create(this, descriptor, userProvidedToggles); +} + +MaybeError Adapter::ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) { + return {}; } } // namespace dawn::native::vulkan diff --git a/src/dawn/native/vulkan/AdapterVk.h b/src/dawn/native/vulkan/AdapterVk.h index 9cb5234a65..a7232fb3ed 100644 --- a/src/dawn/native/vulkan/AdapterVk.h +++ b/src/dawn/native/vulkan/AdapterVk.h @@ -46,7 +46,13 @@ class Adapter : public AdapterBase { MaybeError InitializeSupportedFeaturesImpl() override; MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override; - ResultOrError> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + ResultOrError> CreateDeviceImpl( + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) override; + + MaybeError ValidateFeatureSupportedWithTogglesImpl( + wgpu::FeatureName feature, + const TripleStateTogglesSet& userProvidedToggles) override; VkPhysicalDevice mPhysicalDevice; Ref mVulkanInstance; diff --git a/src/dawn/native/vulkan/DeviceVk.cpp b/src/dawn/native/vulkan/DeviceVk.cpp index 662fa5a1cd..b9902ab10b 100644 --- a/src/dawn/native/vulkan/DeviceVk.cpp +++ b/src/dawn/native/vulkan/DeviceVk.cpp @@ -78,14 +78,19 @@ class ScopedSignalSemaphore : public NonMovable { } // namespace // static -ResultOrError> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) { - Ref device = AcquireRef(new Device(adapter, descriptor)); +ResultOrError> Device::Create(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) { + Ref device = AcquireRef(new Device(adapter, descriptor, userProvidedToggles)); DAWN_TRY(device->Initialize(descriptor)); return device; } -Device::Device(Adapter* adapter, const DeviceDescriptor* descriptor) - : DeviceBase(adapter, descriptor), mDebugPrefix(GetNextDeviceDebugPrefix()) { +Device::Device(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles) + : DeviceBase(adapter, descriptor, userProvidedToggles), + mDebugPrefix(GetNextDeviceDebugPrefix()) { InitTogglesFromDriver(); } @@ -449,29 +454,29 @@ ResultOrError Device::CreateDevice(VkPhysicalDevice physicalD usedKnobs.features.samplerAnisotropy = VK_TRUE; } - if (IsFeatureEnabled(Feature::TextureCompressionBC)) { + if (HasFeature(Feature::TextureCompressionBC)) { ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionBC == VK_TRUE); usedKnobs.features.textureCompressionBC = VK_TRUE; } - if (IsFeatureEnabled(Feature::TextureCompressionETC2)) { + if (HasFeature(Feature::TextureCompressionETC2)) { ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionETC2 == VK_TRUE); usedKnobs.features.textureCompressionETC2 = VK_TRUE; } - if (IsFeatureEnabled(Feature::TextureCompressionASTC)) { + if (HasFeature(Feature::TextureCompressionASTC)) { ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionASTC_LDR == VK_TRUE); usedKnobs.features.textureCompressionASTC_LDR = VK_TRUE; } - if (IsFeatureEnabled(Feature::PipelineStatisticsQuery)) { + if (HasFeature(Feature::PipelineStatisticsQuery)) { ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.pipelineStatisticsQuery == VK_TRUE); usedKnobs.features.pipelineStatisticsQuery = VK_TRUE; } - if (IsFeatureEnabled(Feature::DepthClipControl)) { + if (HasFeature(Feature::DepthClipControl)) { const VulkanDeviceInfo& deviceInfo = ToBackend(GetAdapter())->GetDeviceInfo(); ASSERT(deviceInfo.HasExt(DeviceExt::DepthClipEnable) && deviceInfo.depthClipEnableFeatures.depthClipEnable == VK_TRUE); @@ -481,16 +486,20 @@ ResultOrError Device::CreateDevice(VkPhysicalDevice physicalD VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT); } - if (IsFeatureEnabled(Feature::ShaderFloat16)) { + // TODO(dawn:1510, tint:1473): After implementing a transform to handle the pipeline input / + // output if necessary, relax the requirement of storageInputOutput16. + if (HasFeature(Feature::ShaderF16)) { const VulkanDeviceInfo& deviceInfo = ToBackend(GetAdapter())->GetDeviceInfo(); ASSERT(deviceInfo.HasExt(DeviceExt::ShaderFloat16Int8) && deviceInfo.shaderFloat16Int8Features.shaderFloat16 == VK_TRUE && deviceInfo.HasExt(DeviceExt::_16BitStorage) && deviceInfo._16BitStorageFeatures.storageBuffer16BitAccess == VK_TRUE && + deviceInfo._16BitStorageFeatures.storageInputOutput16 == VK_TRUE && deviceInfo._16BitStorageFeatures.uniformAndStorageBuffer16BitAccess == VK_TRUE); usedKnobs.shaderFloat16Int8Features.shaderFloat16 = VK_TRUE; usedKnobs._16BitStorageFeatures.storageBuffer16BitAccess = VK_TRUE; + usedKnobs._16BitStorageFeatures.storageInputOutput16 = VK_TRUE; usedKnobs._16BitStorageFeatures.uniformAndStorageBuffer16BitAccess = VK_TRUE; featuresChain.Add(&usedKnobs.shaderFloat16Int8Features, diff --git a/src/dawn/native/vulkan/DeviceVk.h b/src/dawn/native/vulkan/DeviceVk.h index 6e88d4cf86..fa27f82fd1 100644 --- a/src/dawn/native/vulkan/DeviceVk.h +++ b/src/dawn/native/vulkan/DeviceVk.h @@ -43,7 +43,9 @@ class ResourceMemoryAllocator; class Device final : public DeviceBase { public: - static ResultOrError> Create(Adapter* adapter, const DeviceDescriptor* descriptor); + static ResultOrError> Create(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles); ~Device() override; MaybeError Initialize(const DeviceDescriptor* descriptor); @@ -113,7 +115,9 @@ class Device final : public DeviceBase { const char* GetDebugPrefix() { return mDebugPrefix.c_str(); } private: - Device(Adapter* adapter, const DeviceDescriptor* descriptor); + Device(Adapter* adapter, + const DeviceDescriptor* descriptor, + const TripleStateTogglesSet& userProvidedToggles); ResultOrError> CreateBindGroupImpl( const BindGroupDescriptor* descriptor) override; diff --git a/src/dawn/native/vulkan/RenderPipelineVk.cpp b/src/dawn/native/vulkan/RenderPipelineVk.cpp index 830e012437..df61ac77b3 100644 --- a/src/dawn/native/vulkan/RenderPipelineVk.cpp +++ b/src/dawn/native/vulkan/RenderPipelineVk.cpp @@ -436,7 +436,7 @@ MaybeError RenderPipeline::Initialize() { PNextChainBuilder rasterizationChain(&rasterization); VkPipelineRasterizationDepthClipStateCreateInfoEXT depthClipState; if (HasUnclippedDepth()) { - ASSERT(device->IsFeatureEnabled(Feature::DepthClipControl)); + ASSERT(device->HasFeature(Feature::DepthClipControl)); depthClipState.pNext = nullptr; depthClipState.depthClipEnable = VK_FALSE; depthClipState.flags = 0; diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn index 2955a8b94a..6f5ba74209 100644 --- a/src/dawn/tests/BUILD.gn +++ b/src/dawn/tests/BUILD.gn @@ -488,7 +488,7 @@ source_set("end2end_tests_sources") { "end2end/SamplerFilterAnisotropicTests.cpp", "end2end/SamplerTests.cpp", "end2end/ScissorTests.cpp", - "end2end/ShaderFloat16Tests.cpp", + "end2end/ShaderF16Tests.cpp", "end2end/ShaderTests.cpp", "end2end/ShaderValidationTests.cpp", "end2end/StorageTextureTests.cpp", diff --git a/src/dawn/tests/end2end/ExperimentalDP4aTests.cpp b/src/dawn/tests/end2end/ExperimentalDP4aTests.cpp index e6ecf3aabd..d77de5bffc 100644 --- a/src/dawn/tests/end2end/ExperimentalDP4aTests.cpp +++ b/src/dawn/tests/end2end/ExperimentalDP4aTests.cpp @@ -31,7 +31,18 @@ class ExperimentalDP4aTests : public DawnTestWithParams + +#include "dawn/tests/DawnTest.h" +#include "dawn/utils/ComboRenderPipelineDescriptor.h" +#include "dawn/utils/WGPUHelpers.h" + +namespace { +using RequireShaderF16Feature = bool; +DAWN_TEST_PARAM_STRUCT(ShaderF16TestsParams, RequireShaderF16Feature); + +} // anonymous namespace + +class ShaderF16Tests : public DawnTestWithParams { + protected: + std::vector GetRequiredFeatures() override { + mIsShaderF16SupportedOnAdapter = SupportsFeatures({wgpu::FeatureName::ShaderF16}); + if (!mIsShaderF16SupportedOnAdapter) { + return {}; + } + + if (!IsD3D12()) { + mUseDxcEnabledOrNonD3D12 = true; + } else { + for (auto* enabledToggle : GetParam().forceEnabledWorkarounds) { + if (strncmp(enabledToggle, "use_dxc", 7) == 0) { + mUseDxcEnabledOrNonD3D12 = true; + break; + } + } + } + + if (GetParam().mRequireShaderF16Feature && mUseDxcEnabledOrNonD3D12) { + return {wgpu::FeatureName::ShaderF16}; + } + + return {}; + } + + bool IsShaderF16SupportedOnAdapter() const { return mIsShaderF16SupportedOnAdapter; } + bool UseDxcEnabledOrNonD3D12() const { return mUseDxcEnabledOrNonD3D12; } + + private: + bool mIsShaderF16SupportedOnAdapter = false; + bool mUseDxcEnabledOrNonD3D12 = false; +}; + +TEST_P(ShaderF16Tests, BasicShaderF16FeaturesTest) { + const char* computeShader = R"( + enable f16; + + struct Buf { + v : f32, + } + @group(0) @binding(0) var buf : Buf; + + @compute @workgroup_size(1) + fn CSMain() { + let a : f16 = f16(buf.v) + 1.0h; + buf.v = f32(a); + } + )"; + + const bool shouldShaderF16FeatureSupportedByDevice = + // Required when creating device + GetParam().mRequireShaderF16Feature && + // Adapter support the feature + IsShaderF16SupportedOnAdapter() && + // Proper toggle, disallow_unsafe_apis and use_dxc if d3d12 + // Note that "disallow_unsafe_apis" is always disabled in DawnTestBase::CreateDeviceImpl. + !HasToggleEnabled("disallow_unsafe_apis") && UseDxcEnabledOrNonD3D12(); + const bool deviceSupportShaderF16Feature = device.HasFeature(wgpu::FeatureName::ShaderF16); + EXPECT_EQ(deviceSupportShaderF16Feature, shouldShaderF16FeatureSupportedByDevice); + + if (!deviceSupportShaderF16Feature) { + ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, computeShader)); + return; + } + + wgpu::BufferDescriptor bufferDesc; + bufferDesc.size = 4u; + bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc; + wgpu::Buffer bufferOut = device.CreateBuffer(&bufferDesc); + + wgpu::ComputePipelineDescriptor csDesc; + csDesc.compute.module = utils::CreateShaderModule(device, computeShader); + csDesc.compute.entryPoint = "CSMain"; + wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&csDesc); + + wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), + { + {0, bufferOut}, + }); + + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + wgpu::ComputePassEncoder pass = encoder.BeginComputePass(); + pass.SetPipeline(pipeline); + pass.SetBindGroup(0, bindGroup); + pass.DispatchWorkgroups(1); + pass.End(); + wgpu::CommandBuffer commands = encoder.Finish(); + queue.Submit(1, &commands); + + uint32_t expected[] = {0x3f800000}; // 1.0f + EXPECT_BUFFER_U32_RANGE_EQ(expected, bufferOut, 0, 1); +} + +// DawnTestBase::CreateDeviceImpl always disable disallow_unsafe_apis toggle. +DAWN_INSTANTIATE_TEST_P(ShaderF16Tests, + { + D3D12Backend(), + D3D12Backend({"use_dxc"}), + VulkanBackend(), + MetalBackend(), + OpenGLBackend(), + OpenGLESBackend(), + }, + {true, false}); diff --git a/src/dawn/tests/end2end/ShaderFloat16Tests.cpp b/src/dawn/tests/end2end/ShaderFloat16Tests.cpp deleted file mode 100644 index 81c7ed6041..0000000000 --- a/src/dawn/tests/end2end/ShaderFloat16Tests.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2020 The Dawn Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "dawn/common/Math.h" -#include "dawn/tests/DawnTest.h" -#include "dawn/utils/WGPUHelpers.h" - -class ShaderFloat16Tests : public DawnTest { - protected: - std::vector GetRequiredFeatures() override { - mIsShaderFloat16Supported = SupportsFeatures({wgpu::FeatureName::DawnShaderFloat16}); - if (!mIsShaderFloat16Supported) { - return {}; - } - - return {wgpu::FeatureName::DawnShaderFloat16}; - } - - bool IsShaderFloat16Supported() const { return mIsShaderFloat16Supported; } - - bool mIsShaderFloat16Supported = false; -}; - -// Test basic 16bit float arithmetic and 16bit storage features. -// TODO(crbug.com/tint/404): Implement float16 in Tint. -TEST_P(ShaderFloat16Tests, DISABLED_Basic16BitFloatFeaturesTest) { - DAWN_TEST_UNSUPPORTED_IF(!IsShaderFloat16Supported()); - DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsIntel()); // Flaky crashes. crbug.com/dawn/586 - - uint16_t uniformData[] = {Float32ToFloat16(1.23), Float32ToFloat16(0.0)}; // 0.0 is a padding. - wgpu::Buffer uniformBuffer = utils::CreateBufferFromData( - device, &uniformData, sizeof(uniformData), wgpu::BufferUsage::Uniform); - - uint16_t bufferInData[] = {Float32ToFloat16(2.34), Float32ToFloat16(0.0)}; // 0.0 is a padding. - wgpu::Buffer bufferIn = utils::CreateBufferFromData(device, &bufferInData, sizeof(bufferInData), - wgpu::BufferUsage::Storage); - - wgpu::BufferDescriptor bufferDesc; - bufferDesc.size = 2 * sizeof(uint16_t); - bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc; - wgpu::Buffer bufferOut = device.CreateBuffer(&bufferDesc); - - // SPIR-V ASM produced by glslang for the following fragment shader: - // - // #version 450 - // #extension GL_AMD_gpu_shader_half_float : require - // - // struct S { - // float16_t f; - // float16_t padding; - // }; - // layout(std140, set = 0, binding = 0) uniform uniformBuf { S c; }; - // layout(std140, set = 0, binding = 1) readonly buffer bufA { S a; }; - // layout(std140, set = 0, binding = 2) buffer bufB { S b; }; - // - // void main() { - // b.f = a.f + c.f; - // } - - wgpu::ShaderModule module = utils::CreateShaderModuleFromASM(device, R"( -; SPIR-V -; Version: 1.0 -; Generator: Khronos Glslang Reference Front End; 10 -; Bound: 26 -; Schema: 0 - OpCapability Shader - OpCapability Float16 - OpCapability StorageBuffer16BitAccess - OpCapability UniformAndStorageBuffer16BitAccess - OpExtension "SPV_KHR_16bit_storage" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %main "main" - OpExecutionMode %main LocalSize 1 1 1 - OpSource GLSL 450 - OpSourceExtension "GL_AMD_gpu_shader_half_float" - OpName %main "main" - OpName %S "S" - OpMemberName %S 0 "f" - OpMemberName %S 1 "padding" - OpName %bufB "bufB" - OpMemberName %bufB 0 "b" - OpName %_ "" - OpName %bufA "bufA" - OpMemberName %bufA 0 "a" - OpName %__0 "" - OpName %uniformBuf "uniformBuf" - OpMemberName %uniformBuf 0 "c" - OpName %__1 "" - OpMemberDecorate %S 0 Offset 0 - OpMemberDecorate %S 1 Offset 2 - OpMemberDecorate %bufB 0 Offset 0 - OpDecorate %bufB BufferBlock - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 2 - OpMemberDecorate %bufA 0 NonWritable - OpMemberDecorate %bufA 0 Offset 0 - OpDecorate %bufA BufferBlock - OpDecorate %__0 DescriptorSet 0 - OpDecorate %__0 Binding 1 - OpMemberDecorate %uniformBuf 0 Offset 0 - OpDecorate %uniformBuf Block - OpDecorate %__1 DescriptorSet 0 - OpDecorate %__1 Binding 0 - %void = OpTypeVoid - %3 = OpTypeFunction %void - %half = OpTypeFloat 16 - %S = OpTypeStruct %half %half - %bufB = OpTypeStruct %S -%_ptr_Uniform_bufB = OpTypePointer Uniform %bufB - %_ = OpVariable %_ptr_Uniform_bufB Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 - %bufA = OpTypeStruct %S -%_ptr_Uniform_bufA = OpTypePointer Uniform %bufA - %__0 = OpVariable %_ptr_Uniform_bufA Uniform -%_ptr_Uniform_half = OpTypePointer Uniform %half - %uniformBuf = OpTypeStruct %S -%_ptr_Uniform_uniformBuf = OpTypePointer Uniform %uniformBuf - %__1 = OpVariable %_ptr_Uniform_uniformBuf Uniform - %main = OpFunction %void None %3 - %5 = OpLabel - %17 = OpAccessChain %_ptr_Uniform_half %__0 %int_0 %int_0 - %18 = OpLoad %half %17 - %22 = OpAccessChain %_ptr_Uniform_half %__1 %int_0 %int_0 - %23 = OpLoad %half %22 - %24 = OpFAdd %half %18 %23 - %25 = OpAccessChain %_ptr_Uniform_half %_ %int_0 %int_0 - OpStore %25 %24 - OpReturn - OpFunctionEnd - )"); - - wgpu::ComputePipelineDescriptor csDesc; - csDesc.compute.module = module; - csDesc.compute.entryPoint = "main"; - wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&csDesc); - - wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), - { - {0, uniformBuffer, 0, sizeof(uniformData)}, - {1, bufferIn, 0, sizeof(bufferInData)}, - {2, bufferOut}, - }); - - wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - wgpu::ComputePassEncoder pass = encoder.BeginComputePass(); - pass.SetPipeline(pipeline); - pass.SetBindGroup(0, bindGroup); - pass.DispatchWorkgroups(1); - pass.End(); - wgpu::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); - - uint16_t expected[] = {Float32ToFloat16(3.57), Float32ToFloat16(0.0)}; // 0.0 is a padding. - - EXPECT_BUFFER_U16_RANGE_EQ(expected, bufferOut, 0, 2); -} - -DAWN_INSTANTIATE_TEST(ShaderFloat16Tests, - D3D12Backend(), - MetalBackend(), - OpenGLBackend(), - OpenGLESBackend(), - VulkanBackend()); diff --git a/src/dawn/tests/unittests/FeatureTests.cpp b/src/dawn/tests/unittests/FeatureTests.cpp index cb7d7014ce..b4c7fced6c 100644 --- a/src/dawn/tests/unittests/FeatureTests.cpp +++ b/src/dawn/tests/unittests/FeatureTests.cpp @@ -77,6 +77,14 @@ TEST_F(FeatureTests, GetEnabledFeatures) { deviceDescriptor.requiredFeatures = &featureName; deviceDescriptor.requiredFeaturesCount = 1; + // Some features may require DisallowUnsafeApis toggle disabled, otherwise CreateDevice may + // failed. + const char* const disableToggles[] = {"disallow_unsafe_apis"}; + wgpu::DawnTogglesDeviceDescriptor toggleDesc; + toggleDesc.forceDisabledToggles = disableToggles; + toggleDesc.forceDisabledTogglesCount = 1; + deviceDescriptor.nextInChain = &toggleDesc; + dawn::native::DeviceBase* deviceBase = dawn::native::FromAPI( adapter.CreateDevice(reinterpret_cast(&deviceDescriptor))); diff --git a/src/dawn/tests/unittests/native/DeviceCreationTests.cpp b/src/dawn/tests/unittests/native/DeviceCreationTests.cpp index 09fe99424c..3bf15d97bd 100644 --- a/src/dawn/tests/unittests/native/DeviceCreationTests.cpp +++ b/src/dawn/tests/unittests/native/DeviceCreationTests.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include "dawn/dawn_proc.h" #include "dawn/native/DawnNative.h" @@ -90,6 +91,42 @@ TEST_F(DeviceCreationTest, CreateDeviceWithTogglesSuccess) { EXPECT_THAT(toggles, Contains(StrEq(toggle))); } +// Test features guarded by toggles are validated when creating devices. +TEST_F(DeviceCreationTest, CreateDeviceRequiringFeaturesGuardedByToggle) { + std::vector featuresGuardedByToggle = { + wgpu::FeatureName::ShaderF16, wgpu::FeatureName::ChromiumExperimentalDp4a}; + + for (auto feature : featuresGuardedByToggle) { + wgpu::DeviceDescriptor deviceDescriptor; + deviceDescriptor.requiredFeatures = &feature; + deviceDescriptor.requiredFeaturesCount = 1; + + // Test creating device without toggle would fail. + { + wgpu::Device device = adapter.CreateDevice(&deviceDescriptor); + EXPECT_EQ(device, nullptr); + } + + // Test creating device without DisallowUnsafeApis toggle disabled. + { + const char* const disableToggles[] = {"disallow_unsafe_apis"}; + wgpu::DawnTogglesDeviceDescriptor toggleDesc; + toggleDesc.forceDisabledToggles = disableToggles; + toggleDesc.forceDisabledTogglesCount = 1; + deviceDescriptor.nextInChain = &toggleDesc; + + wgpu::Device device = adapter.CreateDevice(&deviceDescriptor); + EXPECT_NE(device, nullptr); + + ASSERT_EQ(1u, device.EnumerateFeatures(nullptr)); + wgpu::FeatureName enabledFeature; + device.EnumerateFeatures(&enabledFeature); + EXPECT_EQ(enabledFeature, feature); + device.Release(); + } + } +} + TEST_F(DeviceCreationTest, CreateDeviceWithCacheSuccess) { // Default device descriptor should have the same cache key as a device descriptor with a // default cache descriptor. diff --git a/src/dawn/wire/SupportedFeatures.cpp b/src/dawn/wire/SupportedFeatures.cpp index aca064fa9c..6358405b72 100644 --- a/src/dawn/wire/SupportedFeatures.cpp +++ b/src/dawn/wire/SupportedFeatures.cpp @@ -23,6 +23,7 @@ bool IsFeatureSupported(WGPUFeatureName feature) { case WGPUFeatureName_Undefined: case WGPUFeatureName_Force32: case WGPUFeatureName_DawnNative: + case WGPUFeatureName_DawnShaderFloat16: // Deprecated return false; case WGPUFeatureName_Depth32FloatStencil8: case WGPUFeatureName_TimestampQuery: @@ -32,10 +33,10 @@ bool IsFeatureSupported(WGPUFeatureName feature) { case WGPUFeatureName_TextureCompressionASTC: case WGPUFeatureName_IndirectFirstInstance: case WGPUFeatureName_DepthClipControl: - case WGPUFeatureName_DawnShaderFloat16: case WGPUFeatureName_DawnInternalUsages: case WGPUFeatureName_DawnMultiPlanarFormats: case WGPUFeatureName_ChromiumExperimentalDp4a: + case WGPUFeatureName_ShaderF16: return true; }