// Copyright 2019 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 "dawn/native/Features.h" #include #include #include "dawn/common/Assert.h" #include "dawn/common/BitSetIterator.h" namespace dawn::native { namespace { struct FeatureEnumAndInfo { Feature feature; FeatureInfo info; }; using FeatureEnumAndInfoList = std::array(Feature::EnumCount)>; 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", 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", 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", FeatureInfo::FeatureState::Stable}}, {Feature::PipelineStatisticsQuery, {"pipeline-statistics-query", "Support Pipeline Statistics Query", "https://bugs.chromium.org/p/dawn/issues/detail?id=434", FeatureInfo::FeatureState::Experimental}}, {Feature::TimestampQuery, {"timestamp-query", "Support Timestamp Query", "https://bugs.chromium.org/p/dawn/issues/detail?id=434", FeatureInfo::FeatureState::Experimental}}, {Feature::TimestampQueryInsidePasses, {"timestamp-query-inside-passes", "Support Timestamp Query inside render/compute pass", "https://bugs.chromium.org/p/dawn/issues/detail?id=434", FeatureInfo::FeatureState::Experimental}}, {Feature::DepthClipControl, {"depth-clip-control", "Disable depth clipping of primitives to the clip volume", "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", FeatureInfo::FeatureState::Stable}}, {Feature::ChromiumExperimentalDp4a, {"chromium-experimental-dp4a", "Support experimental DP4a instructions in WGSL", "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", 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::RG11B10UfloatRenderable, {"rg11b10ufloat-renderable", "Allows the RENDER_ATTACHMENT usage on textures with format \"rg11b10ufloat\", and also " "allows textures of that format to be multisampled.", "https://bugs.chromium.org/p/dawn/issues/detail?id=1518", FeatureInfo::FeatureState::Stable}}, {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", 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", 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", 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; case wgpu::FeatureName::TimestampQueryInsidePasses: return Feature::TimestampQueryInsidePasses; case wgpu::FeatureName::PipelineStatisticsQuery: return Feature::PipelineStatisticsQuery; case wgpu::FeatureName::TextureCompressionBC: return Feature::TextureCompressionBC; case wgpu::FeatureName::TextureCompressionETC2: return Feature::TextureCompressionETC2; case wgpu::FeatureName::TextureCompressionASTC: return Feature::TextureCompressionASTC; case wgpu::FeatureName::DepthClipControl: return Feature::DepthClipControl; case wgpu::FeatureName::Depth32FloatStencil8: return Feature::Depth32FloatStencil8; case wgpu::FeatureName::IndirectFirstInstance: return Feature::IndirectFirstInstance; case wgpu::FeatureName::DawnInternalUsages: return Feature::DawnInternalUsages; case wgpu::FeatureName::DawnMultiPlanarFormats: return Feature::MultiPlanarFormats; case wgpu::FeatureName::DawnNative: return Feature::DawnNative; case wgpu::FeatureName::ChromiumExperimentalDp4a: return Feature::ChromiumExperimentalDp4a; case wgpu::FeatureName::ShaderF16: return Feature::ShaderF16; case wgpu::FeatureName::RG11B10UfloatRenderable: return Feature::RG11B10UfloatRenderable; } return Feature::InvalidEnum; } wgpu::FeatureName ToAPIFeature(Feature feature) { switch (feature) { case Feature::TextureCompressionBC: return wgpu::FeatureName::TextureCompressionBC; case Feature::TextureCompressionETC2: return wgpu::FeatureName::TextureCompressionETC2; case Feature::TextureCompressionASTC: return wgpu::FeatureName::TextureCompressionASTC; case Feature::PipelineStatisticsQuery: return wgpu::FeatureName::PipelineStatisticsQuery; case Feature::TimestampQuery: return wgpu::FeatureName::TimestampQuery; case Feature::TimestampQueryInsidePasses: return wgpu::FeatureName::TimestampQueryInsidePasses; case Feature::DepthClipControl: return wgpu::FeatureName::DepthClipControl; case Feature::Depth32FloatStencil8: return wgpu::FeatureName::Depth32FloatStencil8; case Feature::IndirectFirstInstance: return wgpu::FeatureName::IndirectFirstInstance; case Feature::DawnInternalUsages: return wgpu::FeatureName::DawnInternalUsages; case Feature::MultiPlanarFormats: return wgpu::FeatureName::DawnMultiPlanarFormats; case Feature::DawnNative: return wgpu::FeatureName::DawnNative; case Feature::ChromiumExperimentalDp4a: return wgpu::FeatureName::ChromiumExperimentalDp4a; case Feature::ShaderF16: return wgpu::FeatureName::ShaderF16; case Feature::RG11B10UfloatRenderable: return wgpu::FeatureName::RG11B10UfloatRenderable; case Feature::EnumCount: break; } UNREACHABLE(); } } // anonymous namespace void FeaturesSet::EnableFeature(Feature feature) { ASSERT(feature != Feature::InvalidEnum); const size_t featureIndex = static_cast(feature); featuresBitSet.set(featureIndex); } void FeaturesSet::EnableFeature(wgpu::FeatureName feature) { EnableFeature(FromAPIFeature(feature)); } bool FeaturesSet::IsEnabled(Feature feature) const { ASSERT(feature != Feature::InvalidEnum); const size_t featureIndex = static_cast(feature); return featuresBitSet[featureIndex]; } bool FeaturesSet::IsEnabled(wgpu::FeatureName feature) const { Feature f = FromAPIFeature(feature); return f != Feature::InvalidEnum && IsEnabled(f); } size_t FeaturesSet::EnumerateFeatures(wgpu::FeatureName* features) const { for (uint32_t i : IterateBitSet(featuresBitSet)) { wgpu::FeatureName feature = ToAPIFeature(static_cast(i)); if (features != nullptr) { *features = feature; features += 1; } } return featuresBitSet.count(); } std::vector FeaturesSet::GetEnabledFeatureNames() const { std::vector enabledFeatureNames(featuresBitSet.count()); uint32_t index = 0; for (uint32_t i : IterateBitSet(featuresBitSet)) { Feature feature = static_cast(i); ASSERT(feature != Feature::InvalidEnum); const FeatureEnumAndInfo& featureNameAndInfo = kFeatureNameAndInfoList[i]; ASSERT(featureNameAndInfo.feature == feature); enabledFeatureNames[index] = featureNameAndInfo.info.name; ++index; } return enabledFeatureNames; } wgpu::FeatureName FeatureEnumToAPIFeature(Feature feature) { ASSERT(feature != Feature::InvalidEnum); return ToAPIFeature(feature); } FeaturesInfo::FeaturesInfo() { for (size_t index = 0; index < kFeatureNameAndInfoList.size(); ++index) { const FeatureEnumAndInfo& featureNameAndInfo = kFeatureNameAndInfoList[index]; ASSERT(index == static_cast(featureNameAndInfo.feature)); mFeatureNameToEnumMap[featureNameAndInfo.info.name] = featureNameAndInfo.feature; } } FeaturesInfo::~FeaturesInfo() = default; const FeatureInfo* FeaturesInfo::GetFeatureInfo(wgpu::FeatureName feature) const { Feature f = FromAPIFeature(feature); if (f == Feature::InvalidEnum) { return nullptr; } return &kFeatureNameAndInfoList[static_cast(f)].info; } Feature FeaturesInfo::FeatureNameToEnum(const char* featureName) const { ASSERT(featureName); const auto& iter = mFeatureNameToEnumMap.find(featureName); if (iter != mFeatureNameToEnumMap.cend()) { return kFeatureNameAndInfoList[static_cast(iter->second)].feature; } return Feature::InvalidEnum; } wgpu::FeatureName FeaturesInfo::FeatureNameToAPIEnum(const char* featureName) const { Feature f = FeatureNameToEnum(featureName); if (f != Feature::InvalidEnum) { return ToAPIFeature(f); } // Pass something invalid. return static_cast(-1); } } // namespace dawn::native