From 574b951188bbfa23a144f05519f5fcc048b88fe2 Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Fri, 2 Aug 2019 00:06:38 +0000 Subject: [PATCH] Support BC formats as the first extension in Dawn This patch refactors the current implementation of BC formats to treat it as the first extension in Dawn and adds all the related tests. Note that in Dawn all the extensions are disabled unless we enable them when we create the device, which means the BC formats can only be used when we enable the related extension on the creation of the device, and the creation of the device will fail if the adapter does not support the extension BUG=dawn:42 TEST=dawn_end2end_tests TEST=dawn_unittests Change-Id: I04d818b0218ebb3b1b7a70a4fea71779f308f85f Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9520 Commit-Queue: Jiawei Shao Reviewed-by: Austin Eng --- BUILD.gn | 3 + src/dawn_native/Adapter.cpp | 24 ++++ src/dawn_native/Adapter.h | 6 + src/dawn_native/DawnNative.cpp | 5 + src/dawn_native/Device.cpp | 20 ++++ src/dawn_native/Device.h | 7 ++ src/dawn_native/Extensions.cpp | 113 ++++++++++++++++++ src/dawn_native/Extensions.h | 63 ++++++++++ src/dawn_native/Format.cpp | 37 +++--- src/dawn_native/Instance.cpp | 13 ++ src/dawn_native/Instance.h | 10 +- src/dawn_native/d3d12/AdapterD3D12.cpp | 6 + src/dawn_native/d3d12/AdapterD3D12.h | 1 + src/dawn_native/metal/BackendMTL.mm | 5 + src/dawn_native/null/DeviceNull.cpp | 30 +++-- src/dawn_native/null/DeviceNull.h | 13 ++ src/dawn_native/vulkan/AdapterVk.cpp | 8 ++ src/dawn_native/vulkan/AdapterVk.h | 1 + src/dawn_native/vulkan/DeviceVk.cpp | 7 +- src/include/dawn_native/DawnNative.h | 7 ++ src/tests/DawnTest.cpp | 38 ++++-- src/tests/DawnTest.h | 10 ++ .../end2end/CompressedTextureFormatTests.cpp | 57 ++++++++- src/tests/unittests/ExtensionTests.cpp | 78 ++++++++++++ .../CopyCommandsValidationTests.cpp | 5 + .../validation/TextureValidationTests.cpp | 18 ++- .../unittests/validation/ValidationTest.cpp | 21 +++- .../unittests/validation/ValidationTest.h | 3 + 28 files changed, 566 insertions(+), 43 deletions(-) create mode 100644 src/dawn_native/Extensions.cpp create mode 100644 src/dawn_native/Extensions.h create mode 100644 src/tests/unittests/ExtensionTests.cpp diff --git a/BUILD.gn b/BUILD.gn index 7d33abb11c..2b53fd3d89 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -140,6 +140,8 @@ source_set("libdawn_native_sources") { "src/dawn_native/Error.h", "src/dawn_native/ErrorData.cpp", "src/dawn_native/ErrorData.h", + "src/dawn_native/Extensions.cpp", + "src/dawn_native/Extensions.h", "src/dawn_native/Fence.cpp", "src/dawn_native/Fence.h", "src/dawn_native/FenceSignalTracker.cpp", @@ -605,6 +607,7 @@ test("dawn_unittests") { "src/tests/unittests/CommandAllocatorTests.cpp", "src/tests/unittests/EnumClassBitmasksTests.cpp", "src/tests/unittests/ErrorTests.cpp", + "src/tests/unittests/ExtensionTests.cpp", "src/tests/unittests/MathTests.cpp", "src/tests/unittests/ObjectBaseTests.cpp", "src/tests/unittests/PerStageTests.cpp", diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp index 6e51f17f59..362b540c0b 100644 --- a/src/dawn_native/Adapter.cpp +++ b/src/dawn_native/Adapter.cpp @@ -38,6 +38,24 @@ namespace dawn_native { return mInstance; } + ExtensionsSet AdapterBase::GetSupportedExtensions() const { + return mSupportedExtensions; + } + + bool AdapterBase::SupportsAllRequestedExtensions( + const std::vector& requestedExtensions) const { + for (const char* extensionStr : requestedExtensions) { + Extension extensionEnum = mInstance->ExtensionNameToEnum(extensionStr); + if (extensionEnum == Extension::InvalidEnum) { + return false; + } + if (!mSupportedExtensions.IsEnabled(extensionEnum)) { + return false; + } + } + return true; + } + DeviceBase* AdapterBase::CreateDevice(const DeviceDescriptor* descriptor) { DeviceBase* result = nullptr; @@ -50,6 +68,12 @@ namespace dawn_native { MaybeError AdapterBase::CreateDeviceInternal(DeviceBase** result, const DeviceDescriptor* descriptor) { + if (descriptor != nullptr) { + if (!SupportsAllRequestedExtensions(descriptor->requiredExtensions)) { + return DAWN_VALIDATION_ERROR("One or more requested extensions are not supported"); + } + } + // TODO(cwallez@chromium.org): This will eventually have validation that the device // descriptor is valid and is a subset what's allowed on this adapter. DAWN_TRY_ASSIGN(*result, CreateDeviceImpl(descriptor)); diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h index 6c9d3f1694..f4cb28ae6e 100644 --- a/src/dawn_native/Adapter.h +++ b/src/dawn_native/Adapter.h @@ -18,6 +18,7 @@ #include "dawn_native/DawnNative.h" #include "dawn_native/Error.h" +#include "dawn_native/Extensions.h" namespace dawn_native { @@ -35,9 +36,14 @@ namespace dawn_native { DeviceBase* CreateDevice(const DeviceDescriptor* descriptor = nullptr); + ExtensionsSet GetSupportedExtensions() const; + bool SupportsAllRequestedExtensions( + const std::vector& requestedExtensions) const; + protected: PCIInfo mPCIInfo = {}; DeviceType mDeviceType = DeviceType::Unknown; + ExtensionsSet mSupportedExtensions; private: virtual ResultOrError CreateDeviceImpl(const DeviceDescriptor* descriptor) = 0; diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp index f5909ebd8a..33969aa9d9 100644 --- a/src/dawn_native/DawnNative.cpp +++ b/src/dawn_native/DawnNative.cpp @@ -55,6 +55,11 @@ namespace dawn_native { return mImpl->GetPCIInfo(); } + std::vector Adapter::GetSupportedExtensions() const { + ExtensionsSet supportedExtensionsSet = mImpl->GetSupportedExtensions(); + return supportedExtensionsSet.GetEnabledExtensionNames(); + } + Adapter::operator bool() const { return mImpl != nullptr; } diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp index 2306cf0e00..8fe480052f 100644 --- a/src/dawn_native/Device.cpp +++ b/src/dawn_native/Device.cpp @@ -66,6 +66,10 @@ namespace dawn_native { mDynamicUploader = std::make_unique(this); SetDefaultToggles(); + if (descriptor != nullptr) { + ApplyExtensions(descriptor); + } + mFormatTable = BuildFormatTable(this); } @@ -505,10 +509,26 @@ namespace dawn_native { } } + void DeviceBase::ApplyExtensions(const DeviceDescriptor* deviceDescriptor) { + ASSERT(deviceDescriptor); + ASSERT(GetAdapter()->SupportsAllRequestedExtensions(deviceDescriptor->requiredExtensions)); + + mEnabledExtensions = GetAdapter()->GetInstance()->ExtensionNamesToExtensionsSet( + deviceDescriptor->requiredExtensions); + } + + std::vector DeviceBase::GetEnabledExtensions() const { + return mEnabledExtensions.GetEnabledExtensionNames(); + } + std::vector DeviceBase::GetTogglesUsed() const { return mTogglesSet.GetEnabledToggleNames(); } + bool DeviceBase::IsExtensionEnabled(Extension extension) const { + return mEnabledExtensions.IsEnabled(extension); + } + bool DeviceBase::IsToggleEnabled(Toggle toggle) const { return mTogglesSet.IsEnabled(toggle); } diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h index 3c3d6c773d..89353b607d 100644 --- a/src/dawn_native/Device.h +++ b/src/dawn_native/Device.h @@ -17,6 +17,7 @@ #include "common/Serial.h" #include "dawn_native/Error.h" +#include "dawn_native/Extensions.h" #include "dawn_native/Format.h" #include "dawn_native/Forward.h" #include "dawn_native/ObjectBase.h" @@ -154,7 +155,9 @@ namespace dawn_native { ResultOrError GetDynamicUploader() const; + std::vector GetEnabledExtensions() const; std::vector GetTogglesUsed() const; + bool IsExtensionEnabled(Extension extension) const; bool IsToggleEnabled(Toggle toggle) const; size_t GetLazyClearCountForTesting(); void IncrementLazyClearCountForTesting(); @@ -212,6 +215,8 @@ namespace dawn_native { TextureBase* texture, const TextureViewDescriptor* descriptor); + void ApplyExtensions(const DeviceDescriptor* deviceDescriptor); + void ConsumeError(ErrorData* error); void SetDefaultToggles(); @@ -240,6 +245,8 @@ namespace dawn_native { TogglesSet mTogglesSet; size_t mLazyClearCountForTesting = 0; + + ExtensionsSet mEnabledExtensions; }; } // namespace dawn_native diff --git a/src/dawn_native/Extensions.cpp b/src/dawn_native/Extensions.cpp new file mode 100644 index 0000000000..2de7a8511d --- /dev/null +++ b/src/dawn_native/Extensions.cpp @@ -0,0 +1,113 @@ +// 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 + +#include "common/Assert.h" +#include "common/BitSetIterator.h" +#include "dawn_native/Extensions.h" + +namespace dawn_native { + namespace { + + struct ExtensionEnumAndInfo { + Extension extension; + ExtensionInfo info; + }; + + using ExtensionEnumAndInfoList = + std::array(Extension::EnumCount)>; + + static constexpr ExtensionEnumAndInfoList kExtensionNameAndInfoList = { + {{Extension::TextureCompressionBC, + {"texture_compression_bc", "Support Block Compressed (BC) texture formats", + "https://bugs.chromium.org/p/dawn/issues/detail?id=42"}}}}; + + } // anonymous namespace + + void ExtensionsSet::EnableExtension(Extension extension) { + ASSERT(extension != Extension::InvalidEnum); + const size_t extensionIndex = static_cast(extension); + extensionsBitSet.set(extensionIndex); + } + + bool ExtensionsSet::IsEnabled(Extension extension) const { + ASSERT(extension != Extension::InvalidEnum); + const size_t extensionIndex = static_cast(extension); + return extensionsBitSet[extensionIndex]; + } + + std::vector ExtensionsSet::GetEnabledExtensionNames() const { + std::vector enabledExtensionNames(extensionsBitSet.count()); + + uint32_t index = 0; + for (uint32_t i : IterateBitSet(extensionsBitSet)) { + const char* extensionName = ExtensionEnumToName(static_cast(i)); + enabledExtensionNames[index] = extensionName; + ++index; + } + return enabledExtensionNames; + } + + const char* ExtensionEnumToName(Extension extension) { + ASSERT(extension != Extension::InvalidEnum); + + const ExtensionEnumAndInfo& extensionNameAndInfo = + kExtensionNameAndInfoList[static_cast(extension)]; + ASSERT(extensionNameAndInfo.extension == extension); + return extensionNameAndInfo.info.name; + } + + ExtensionsInfo::ExtensionsInfo() { + for (size_t index = 0; index < kExtensionNameAndInfoList.size(); ++index) { + const ExtensionEnumAndInfo& extensionNameAndInfo = kExtensionNameAndInfoList[index]; + ASSERT(index == static_cast(extensionNameAndInfo.extension)); + mExtensionNameToEnumMap[extensionNameAndInfo.info.name] = + extensionNameAndInfo.extension; + } + } + + const ExtensionInfo* ExtensionsInfo::GetExtensionInfo(const char* extensionName) const { + ASSERT(extensionName); + + const auto& iter = mExtensionNameToEnumMap.find(extensionName); + if (iter != mExtensionNameToEnumMap.cend()) { + return &kExtensionNameAndInfoList[static_cast(iter->second)].info; + } + return nullptr; + } + + Extension ExtensionsInfo::ExtensionNameToEnum(const char* extensionName) const { + ASSERT(extensionName); + + const auto& iter = mExtensionNameToEnumMap.find(extensionName); + if (iter != mExtensionNameToEnumMap.cend()) { + return kExtensionNameAndInfoList[static_cast(iter->second)].extension; + } + return Extension::InvalidEnum; + } + + ExtensionsSet ExtensionsInfo::ExtensionNamesToExtensionsSet( + const std::vector& requiredExtensions) const { + ExtensionsSet extensionsSet; + + for (const char* extensionName : requiredExtensions) { + Extension extensionEnum = ExtensionNameToEnum(extensionName); + ASSERT(extensionEnum != Extension::InvalidEnum); + extensionsSet.EnableExtension(extensionEnum); + } + return extensionsSet; + } + +} // namespace dawn_native diff --git a/src/dawn_native/Extensions.h b/src/dawn_native/Extensions.h new file mode 100644 index 0000000000..274096fe3e --- /dev/null +++ b/src/dawn_native/Extensions.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef DAWNNATIVE_EXTENSIONS_H_ +#define DAWNNATIVE_EXTENSIONS_H_ + +#include +#include +#include + +#include "dawn_native/DawnNative.h" + +namespace dawn_native { + + enum class Extension { + TextureCompressionBC, + + EnumCount, + InvalidEnum = EnumCount, + ExtensionMin = TextureCompressionBC, + }; + + // A wrapper of the bitset to store if an extension is enabled or not. This wrapper provides the + // convenience to convert the enums of enum class Extension to the indices of a bitset. + struct ExtensionsSet { + std::bitset(Extension::EnumCount)> extensionsBitSet; + + void EnableExtension(Extension extension); + bool IsEnabled(Extension extension) const; + std::vector GetEnabledExtensionNames() const; + }; + + const char* ExtensionEnumToName(Extension extension); + + class ExtensionsInfo { + public: + ExtensionsInfo(); + + // Used to query the details of an extension. Return nullptr if extensionName is not a valid + // name of an extension supported in Dawn + const ExtensionInfo* GetExtensionInfo(const char* extensionName) const; + Extension ExtensionNameToEnum(const char* extensionName) const; + ExtensionsSet ExtensionNamesToExtensionsSet( + const std::vector& requiredExtensions) const; + + private: + std::unordered_map mExtensionNameToEnumMap; + }; + +} // namespace dawn_native + +#endif // DAWNNATIVE_EXTENSIONS_H_ \ No newline at end of file diff --git a/src/dawn_native/Format.cpp b/src/dawn_native/Format.cpp index da2946aae4..44ae1d85d2 100644 --- a/src/dawn_native/Format.cpp +++ b/src/dawn_native/Format.cpp @@ -13,6 +13,8 @@ // limitations under the License. #include "dawn_native/Format.h" +#include "dawn_native/Device.h" +#include "dawn_native/Extensions.h" #include @@ -48,7 +50,7 @@ namespace dawn_native { return static_cast(static_cast(format)); } - FormatTable BuildFormatTable(const DeviceBase*) { + FormatTable BuildFormatTable(const DeviceBase* device) { FormatTable table; std::bitset formatsSet; @@ -93,12 +95,12 @@ namespace dawn_native { }; auto AddCompressedFormat = [&AddFormat](dawn::TextureFormat format, uint32_t byteSize, - uint32_t width, uint32_t height) { + uint32_t width, uint32_t height, bool isSupported) { Format internalFormat; internalFormat.format = format; internalFormat.isRenderable = false; internalFormat.isCompressed = true; - internalFormat.isSupported = true; + internalFormat.isSupported = isSupported; internalFormat.aspect = Format::Aspect::Color; internalFormat.blockByteSize = byteSize; internalFormat.blockWidth = width; @@ -168,20 +170,21 @@ namespace dawn_native { AddDepthStencilFormat(dawn::TextureFormat::Depth24PlusStencil8, Format::Aspect::DepthStencil, 4); // BC compressed formats - AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnorm, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC4RSnorm, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC4RUnorm, 8, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnormSrgb, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnormSrgb, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC5RGSnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC5RGUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC6HRGBSfloat, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC6HRGBUfloat, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnorm, 16, 4, 4); - AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4); + bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC); + AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnorm, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC4RSnorm, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC4RUnorm, 8, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC2RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC3RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC5RGSnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC5RGUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC6HRGBSfloat, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC6HRGBUfloat, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnorm, 16, 4, 4, isBCFormatSupported); + AddCompressedFormat(dawn::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); // clang-format on diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp index c106ad17f6..cc3c9cc9a2 100644 --- a/src/dawn_native/Instance.cpp +++ b/src/dawn_native/Instance.cpp @@ -86,6 +86,19 @@ namespace dawn_native { return mTogglesInfo.ToggleNameToEnum(toggleName); } + const ExtensionInfo* InstanceBase::GetExtensionInfo(const char* extensionName) { + return mExtensionsInfo.GetExtensionInfo(extensionName); + } + + Extension InstanceBase::ExtensionNameToEnum(const char* extensionName) { + return mExtensionsInfo.ExtensionNameToEnum(extensionName); + } + + ExtensionsSet InstanceBase::ExtensionNamesToExtensionsSet( + const std::vector& requiredExtensions) { + return mExtensionsInfo.ExtensionNamesToExtensionsSet(requiredExtensions); + } + const std::vector>& InstanceBase::GetAdapters() const { return mAdapters; } diff --git a/src/dawn_native/Instance.h b/src/dawn_native/Instance.h index a3c5ebbd00..c0f6da78e5 100644 --- a/src/dawn_native/Instance.h +++ b/src/dawn_native/Instance.h @@ -17,6 +17,7 @@ #include "dawn_native/Adapter.h" #include "dawn_native/BackendConnection.h" +#include "dawn_native/Extensions.h" #include "dawn_native/Toggles.h" #include @@ -47,9 +48,15 @@ namespace dawn_native { // Used to query the details of a toggle. Return nullptr if toggleName is not a valid name // of a toggle supported in Dawn. const ToggleInfo* GetToggleInfo(const char* toggleName); - Toggle ToggleNameToEnum(const char* toggleName); + // Used to query the details of an extension. Return nullptr if extensionName is not a valid + // name of an extension supported in Dawn. + const ExtensionInfo* GetExtensionInfo(const char* extensionName); + Extension ExtensionNameToEnum(const char* extensionName); + ExtensionsSet ExtensionNamesToExtensionsSet( + const std::vector& requiredExtensions); + void EnableBackendValidation(bool enableBackendValidation); bool IsBackendValidationEnabled() const; @@ -74,6 +81,7 @@ namespace dawn_native { std::vector> mBackends; std::vector> mAdapters; + ExtensionsInfo mExtensionsInfo; TogglesInfo mTogglesInfo; }; diff --git a/src/dawn_native/d3d12/AdapterD3D12.cpp b/src/dawn_native/d3d12/AdapterD3D12.cpp index e2c92ccf14..bb14171757 100644 --- a/src/dawn_native/d3d12/AdapterD3D12.cpp +++ b/src/dawn_native/d3d12/AdapterD3D12.cpp @@ -84,9 +84,15 @@ namespace dawn_native { namespace d3d12 { "Error converting"); mPCIInfo.name = converter.to_bytes(adapterDesc.Description); + InitializeSupportedExtensions(); + return {}; } + void Adapter::InitializeSupportedExtensions() { + mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC); + } + ResultOrError Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { std::unique_ptr device = std::make_unique(this, descriptor); DAWN_TRY(device->Initialize()); diff --git a/src/dawn_native/d3d12/AdapterD3D12.h b/src/dawn_native/d3d12/AdapterD3D12.h index b5a726b88a..6c085f03dd 100644 --- a/src/dawn_native/d3d12/AdapterD3D12.h +++ b/src/dawn_native/d3d12/AdapterD3D12.h @@ -38,6 +38,7 @@ namespace dawn_native { namespace d3d12 { private: ResultOrError CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + void InitializeSupportedExtensions(); ComPtr mHardwareAdapter; ComPtr mD3d12Device; diff --git a/src/dawn_native/metal/BackendMTL.mm b/src/dawn_native/metal/BackendMTL.mm index e09976d558..d8516dffd8 100644 --- a/src/dawn_native/metal/BackendMTL.mm +++ b/src/dawn_native/metal/BackendMTL.mm @@ -182,6 +182,11 @@ namespace dawn_native { namespace metal { ResultOrError CreateDeviceImpl(const DeviceDescriptor* descriptor) override { return {new Device(this, mDevice, descriptor)}; } + void InitializeSupportedExtensions() { + if ([mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) { + mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC); + } + } id mDevice = nil; }; diff --git a/src/dawn_native/null/DeviceNull.cpp b/src/dawn_native/null/DeviceNull.cpp index 693cf09fc9..47a3aec75c 100644 --- a/src/dawn_native/null/DeviceNull.cpp +++ b/src/dawn_native/null/DeviceNull.cpp @@ -17,6 +17,7 @@ #include "dawn_native/BackendConnection.h" #include "dawn_native/Commands.h" #include "dawn_native/DynamicUploader.h" +#include "dawn_native/Instance.h" #include @@ -24,19 +25,24 @@ namespace dawn_native { namespace null { // Implementation of pre-Device objects: the null adapter, null backend connection and Connect() - class Adapter : public AdapterBase { - public: - Adapter(InstanceBase* instance) : AdapterBase(instance, BackendType::Null) { - mPCIInfo.name = "Null backend"; - mDeviceType = DeviceType::CPU; - } - virtual ~Adapter() = default; + Adapter::Adapter(InstanceBase* instance) : AdapterBase(instance, BackendType::Null) { + mPCIInfo.name = "Null backend"; + mDeviceType = DeviceType::CPU; - private: - ResultOrError CreateDeviceImpl(const DeviceDescriptor* descriptor) override { - return {new Device(this, descriptor)}; - } - }; + // Enable all extensions by default for the convenience of tests. + mSupportedExtensions.extensionsBitSet.flip(); + } + + Adapter::~Adapter() = default; + + // Used for the tests that intend to use an adapter without all extensions enabled. + void Adapter::SetSupportedExtensions(const std::vector& requiredExtensions) { + mSupportedExtensions = GetInstance()->ExtensionNamesToExtensionsSet(requiredExtensions); + } + + ResultOrError Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { + return {new Device(this, descriptor)}; + } class Backend : public BackendConnection { public: diff --git a/src/dawn_native/null/DeviceNull.h b/src/dawn_native/null/DeviceNull.h index cff06a0fd5..36139a5d17 100644 --- a/src/dawn_native/null/DeviceNull.h +++ b/src/dawn_native/null/DeviceNull.h @@ -15,6 +15,7 @@ #ifndef DAWNNATIVE_NULL_DEVICENULL_H_ #define DAWNNATIVE_NULL_DEVICENULL_H_ +#include "dawn_native/Adapter.h" #include "dawn_native/BindGroup.h" #include "dawn_native/BindGroupLayout.h" #include "dawn_native/Buffer.h" @@ -137,6 +138,18 @@ namespace dawn_native { namespace null { size_t mMemoryUsage = 0; }; + class Adapter : public AdapterBase { + public: + Adapter(InstanceBase* instance); + virtual ~Adapter(); + + // Used for the tests that intend to use an adapter without all extensions enabled. + void SetSupportedExtensions(const std::vector& requiredExtensions); + + private: + ResultOrError CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + }; + class Buffer : public BufferBase { public: Buffer(Device* device, const BufferDescriptor* descriptor); diff --git a/src/dawn_native/vulkan/AdapterVk.cpp b/src/dawn_native/vulkan/AdapterVk.cpp index 614eedadef..d86a3bb0af 100644 --- a/src/dawn_native/vulkan/AdapterVk.cpp +++ b/src/dawn_native/vulkan/AdapterVk.cpp @@ -40,6 +40,8 @@ namespace dawn_native { namespace vulkan { MaybeError Adapter::Initialize() { DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this)); + InitializeSupportedExtensions(); + mPCIInfo.deviceId = mDeviceInfo.properties.deviceID; mPCIInfo.vendorId = mDeviceInfo.properties.vendorID; mPCIInfo.name = mDeviceInfo.properties.deviceName; @@ -62,6 +64,12 @@ namespace dawn_native { namespace vulkan { return {}; } + void Adapter::InitializeSupportedExtensions() { + if (mDeviceInfo.features.textureCompressionBC == VK_TRUE) { + mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC); + } + } + ResultOrError Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { std::unique_ptr device = std::make_unique(this, descriptor); DAWN_TRY(device->Initialize()); diff --git a/src/dawn_native/vulkan/AdapterVk.h b/src/dawn_native/vulkan/AdapterVk.h index 2d9ed83ed6..a4a3d53b61 100644 --- a/src/dawn_native/vulkan/AdapterVk.h +++ b/src/dawn_native/vulkan/AdapterVk.h @@ -37,6 +37,7 @@ namespace dawn_native { namespace vulkan { private: ResultOrError CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + void InitializeSupportedExtensions(); VkPhysicalDevice mPhysicalDevice; Backend* mBackend; diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp index 7ff3f3f4e2..3d370e3284 100644 --- a/src/dawn_native/vulkan/DeviceVk.cpp +++ b/src/dawn_native/vulkan/DeviceVk.cpp @@ -344,8 +344,11 @@ namespace dawn_native { namespace vulkan { // Always require fragmentStoresAndAtomics because it is required by end2end tests. usedKnobs.features.fragmentStoresAndAtomics = VK_TRUE; - // TODO(jiawei.shao@intel.com): support BC formats as extension - usedKnobs.features.textureCompressionBC = VK_TRUE; + if (IsExtensionEnabled(Extension::TextureCompressionBC)) { + ASSERT(ToBackend(GetAdapter())->GetDeviceInfo().features.textureCompressionBC == + VK_TRUE); + usedKnobs.features.textureCompressionBC = VK_TRUE; + } // Find a universal queue family { diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h index d90abd0867..3382409d3f 100644 --- a/src/include/dawn_native/DawnNative.h +++ b/src/include/dawn_native/DawnNative.h @@ -50,6 +50,7 @@ namespace dawn_native { // An optional parameter of Adapter::CreateDevice() to send additional information when creating // a Device. For example, we can use it to enable a workaround, optimization or feature. struct DAWN_NATIVE_EXPORT DeviceDescriptor { + std::vector requiredExtensions; std::vector forceEnabledToggles; std::vector forceDisabledToggles; }; @@ -63,6 +64,11 @@ namespace dawn_native { const char* url; }; + // A struct to record the information of an extension. An extension 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 ExtensionInfo = ToggleInfo; + // 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 // same GPU can be represented by multiple adapters but on different APIs. @@ -78,6 +84,7 @@ namespace dawn_native { BackendType GetBackendType() const; DeviceType GetDeviceType() const; const PCIInfo& GetPCIInfo() const; + std::vector GetSupportedExtensions() const; explicit operator bool() const; diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp index c8afc2b637..ea2070c3f2 100644 --- a/src/tests/DawnTest.cpp +++ b/src/tests/DawnTest.cpp @@ -333,9 +333,31 @@ uint32_t DawnTest::GetVendorIdFilter() const { return gTestEnv->GetVendorIdFilter(); } +std::vector DawnTest::GetRequiredExtensions() { + return {}; +} + +// This function can only be called after SetUp() because it requires mBackendAdapter to be +// initialized. +bool DawnTest::SupportsExtensions(const std::vector& extensions) { + ASSERT(mBackendAdapter); + + std::set supportedExtensionsSet; + for (const char* supportedExtensionName : mBackendAdapter.GetSupportedExtensions()) { + supportedExtensionsSet.insert(supportedExtensionName); + } + + for (const char* extensionName : extensions) { + if (supportedExtensionsSet.find(extensionName) == supportedExtensionsSet.end()) { + return false; + } + } + + return true; +} + void DawnTest::SetUp() { - // Get an adapter for the backend to use, and create the device. - dawn_native::Adapter backendAdapter; + // Initialize mBackendAdapter, and create the device. const dawn_native::BackendType backendType = GetParam().backendType; { dawn_native::Instance* instance = gTestEnv->GetInstance(); @@ -345,11 +367,11 @@ void DawnTest::SetUp() { if (adapter.GetBackendType() == backendType) { if (HasVendorIdFilter()) { if (adapter.GetPCIInfo().vendorId == GetVendorIdFilter()) { - backendAdapter = adapter; + mBackendAdapter = adapter; break; } } else { - backendAdapter = adapter; + mBackendAdapter = adapter; // On Metal, select the last adapter so that the discrete GPU is tested on // multi-GPU systems. @@ -363,10 +385,10 @@ void DawnTest::SetUp() { } } - ASSERT(backendAdapter); + ASSERT(mBackendAdapter); } - mPCIInfo = backendAdapter.GetPCIInfo(); + mPCIInfo = mBackendAdapter.GetPCIInfo(); for (const char* forceEnabledWorkaround : GetParam().forceEnabledWorkarounds) { ASSERT(gTestEnv->GetInstance()->GetToggleInfo(forceEnabledWorkaround) != nullptr); @@ -377,7 +399,9 @@ void DawnTest::SetUp() { dawn_native::DeviceDescriptor deviceDescriptor; deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds; deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds; - backendDevice = backendAdapter.CreateDevice(&deviceDescriptor); + deviceDescriptor.requiredExtensions = GetRequiredExtensions(); + backendDevice = mBackendAdapter.CreateDevice(&deviceDescriptor); + ASSERT_NE(nullptr, backendDevice); backendProcs = dawn_native::GetProcs(); diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h index 3aa685ed44..bbde83e9fc 100644 --- a/src/tests/DawnTest.h +++ b/src/tests/DawnTest.h @@ -206,6 +206,14 @@ class DawnTest : public ::testing::TestWithParam { void SwapBuffersForCapture(); + bool SupportsExtensions(const std::vector& extensions); + + // Called in SetUp() to get the extensions required to be enabled in the tests. The tests must + // check if the required extensions are supported by the adapter in this function and guarantee + // the returned extensions are all supported by the adapter. The tests may provide different + // code path to handle the situation when not all extensions are supported. + virtual std::vector GetRequiredExtensions(); + private: // Things used to set up testing through the Wire. std::unique_ptr mWireServer; @@ -263,6 +271,8 @@ class DawnTest : public ::testing::TestWithParam { std::unique_ptr mBinding; dawn_native::PCIInfo mPCIInfo; + + dawn_native::Adapter mBackendAdapter; }; // Instantiate the test once for each backend provided after the first argument. Use it like this: diff --git a/src/tests/end2end/CompressedTextureFormatTests.cpp b/src/tests/end2end/CompressedTextureFormatTests.cpp index 157ae9ea13..c19b6ad382 100644 --- a/src/tests/end2end/CompressedTextureFormatTests.cpp +++ b/src/tests/end2end/CompressedTextureFormatTests.cpp @@ -67,9 +67,24 @@ class CompressedTextureBCFormatTest : public DawnTest { {1, dawn::ShaderStageBit::Fragment, dawn::BindingType::SampledTexture}}); } + std::vector GetRequiredExtensions() override { + mIsBCFormatSupported = SupportsExtensions({"texture_compression_bc"}); + if (!mIsBCFormatSupported) { + return {}; + } + + return {"texture_compression_bc"}; + } + + bool IsBCFormatSupported() const { + return mIsBCFormatSupported; + } + // Copy the compressed texture data into the destination texture as is specified in copyConfig. void CopyDataIntoCompressedTexture(dawn::Texture bcCompressedTexture, const CopyConfig& copyConfig) { + ASSERT(IsBCFormatSupported()); + // Compute the upload buffer size with rowPitchAlignment and the copy region. uint32_t actualWidthAtLevel = copyConfig.textureWidthLevel0 >> copyConfig.baseMipmapLevel; uint32_t actualHeightAtLevel = copyConfig.textureHeightLevel0 >> copyConfig.baseMipmapLevel; @@ -121,6 +136,8 @@ class CompressedTextureBCFormatTest : public DawnTest { dawn::TextureFormat bcFormat, uint32_t baseArrayLayer = 0, uint32_t baseMipLevel = 0) { + ASSERT(IsBCFormatSupported()); + dawn::SamplerDescriptor samplerDesc = utils::GetDefaultSamplerDescriptor(); samplerDesc.minFilter = dawn::FilterMode::Nearest; samplerDesc.magFilter = dawn::FilterMode::Nearest; @@ -140,6 +157,8 @@ class CompressedTextureBCFormatTest : public DawnTest { // Create a render pipeline for sampling from a BC texture and rendering into the render target. dawn::RenderPipeline CreateRenderPipelineForTest() { + ASSERT(IsBCFormatSupported()); + dawn::PipelineLayout pipelineLayout = utils::MakeBasicPipelineLayout(device, &mBindGroupLayout); @@ -183,6 +202,8 @@ class CompressedTextureBCFormatTest : public DawnTest { const dawn::Origin3D& expectedOrigin, const dawn::Extent3D& expectedExtent, const std::vector& expected) { + ASSERT(IsBCFormatSupported()); + ASSERT(expected.size() == renderTargetSize.width * renderTargetSize.height); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, renderTargetSize.width, renderTargetSize.height); @@ -207,6 +228,8 @@ class CompressedTextureBCFormatTest : public DawnTest { // Run the tests that copies pre-prepared BC format data into a BC texture and verifies if we // can render correctly with the pixel values sampled from the BC texture. void TestCopyRegionIntoBCFormatTextures(const CopyConfig& config) { + ASSERT(IsBCFormatSupported()); + dawn::Texture bcTexture = Create2DTexture(device, config.format, config.textureWidthLevel0, config.textureHeightLevel0, config.arrayLayerCount, config.mipmapLevelCount); @@ -416,10 +439,14 @@ class CompressedTextureBCFormatTest : public DawnTest { static constexpr uint32_t kBCBlockHeightInTexels = 4; dawn::BindGroupLayout mBindGroupLayout; + + bool mIsBCFormatSupported = false; }; // Test copying into the whole BC texture with 2x2 blocks and sampling from it. TEST_P(CompressedTextureBCFormatTest, Basic) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureWidthLevel0 = 8; config.textureHeightLevel0 = 8; @@ -433,6 +460,8 @@ TEST_P(CompressedTextureBCFormatTest, Basic) { // Test copying into a sub-region of a texture with BC formats works correctly. TEST_P(CompressedTextureBCFormatTest, CopyIntoSubRegion) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureHeightLevel0 = 8; config.textureWidthLevel0 = 8; @@ -451,6 +480,8 @@ TEST_P(CompressedTextureBCFormatTest, CopyIntoSubRegion) { // Test using rowPitch == 0 in the copies with BC formats works correctly. TEST_P(CompressedTextureBCFormatTest, CopyWithZeroRowPitch) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureHeightLevel0 = 8; @@ -468,6 +499,8 @@ TEST_P(CompressedTextureBCFormatTest, CopyWithZeroRowPitch) { // Test copying into the non-zero layer of a 2D array texture with BC formats works correctly. TEST_P(CompressedTextureBCFormatTest, CopyIntoNonZeroArrayLayer) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureHeightLevel0 = 8; config.textureWidthLevel0 = 8; @@ -486,6 +519,8 @@ TEST_P(CompressedTextureBCFormatTest, CopyIntoNonZeroArrayLayer) { // Test copying into a non-zero mipmap level of a texture with BC texture formats. TEST_P(CompressedTextureBCFormatTest, CopyBufferIntoNonZeroMipmapLevel) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureHeightLevel0 = 60; config.textureWidthLevel0 = 60; @@ -517,6 +552,8 @@ TEST_P(CompressedTextureBCFormatTest, CopyBufferIntoNonZeroMipmapLevel) { // Test texture-to-texture whole-size copies with BC formats. TEST_P(CompressedTextureBCFormatTest, CopyWholeTextureSubResourceIntoNonZeroMipmapLevel) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + // TODO(cwallez@chromium.org): This consistently fails on with the 12th pixel being opaque black // instead of opaque red on Win10 FYI Release (NVIDIA GeForce GTX 1660). See // https://bugs.chromium.org/p/chromium/issues/detail?id=981393 @@ -576,6 +613,8 @@ TEST_P(CompressedTextureBCFormatTest, CopyWholeTextureSubResourceIntoNonZeroMipm // Test BC format texture-to-texture partial copies. TEST_P(CompressedTextureBCFormatTest, CopyPartofTextureSubResourceIntoNonZeroMipmapLevel) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + // TODO(jiawei.shao@intel.com): add workaround on the T2T copies where Extent3D fits in one // subresource and does not fit in another one on Vulkan. Currently this test causes an error if // Vulkan validation layer is enabled. @@ -652,6 +691,8 @@ TEST_P(CompressedTextureBCFormatTest, CopyPartofTextureSubResourceIntoNonZeroMip // Test the special case of the B2T copies on the D3D12 backend that the buffer offset and texture // extent exactly fit the RowPitch. TEST_P(CompressedTextureBCFormatTest, BufferOffsetAndExtentFitRowPitch) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureWidthLevel0 = 8; config.textureHeightLevel0 = 8; @@ -677,6 +718,8 @@ TEST_P(CompressedTextureBCFormatTest, BufferOffsetAndExtentFitRowPitch) { // backend the texelOffset.y will be greater than 0 after calcuting the texelOffset in the function // ComputeTexelOffsets(). TEST_P(CompressedTextureBCFormatTest, BufferOffsetExceedsSlicePitch) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureWidthLevel0 = 8; config.textureHeightLevel0 = 8; @@ -703,6 +746,8 @@ TEST_P(CompressedTextureBCFormatTest, BufferOffsetExceedsSlicePitch) { // Test the special case of the B2T copies on the D3D12 backend that the buffer offset and texture // extent exceed the RowPitch. On D3D12 backend two copies are required for this case. TEST_P(CompressedTextureBCFormatTest, CopyWithBufferOffsetAndExtentExceedRowPitch) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureWidthLevel0 = 8; config.textureHeightLevel0 = 8; @@ -729,6 +774,8 @@ TEST_P(CompressedTextureBCFormatTest, CopyWithBufferOffsetAndExtentExceedRowPitc // rowPitch. On D3D12 backend the texelOffset.z will be greater than 0 after calcuting the // texelOffset in the function ComputeTexelOffsets(). TEST_P(CompressedTextureBCFormatTest, RowPitchEqualToSlicePitch) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureWidthLevel0 = 8; config.textureHeightLevel0 = kBCBlockHeightInTexels; @@ -755,6 +802,8 @@ TEST_P(CompressedTextureBCFormatTest, RowPitchEqualToSlicePitch) { // copyExtent.depth) on Metal backends. As copyExtent.depth can only be 1 for BC formats, on Metal // backend we will use two copies to implement such copy. TEST_P(CompressedTextureBCFormatTest, LargeImageHeight) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureWidthLevel0 = 8; config.textureHeightLevel0 = 8; @@ -771,6 +820,8 @@ TEST_P(CompressedTextureBCFormatTest, LargeImageHeight) { // Test the workaround in the B2T copies when (bufferSize - bufferOffset < bytesPerImage * // copyExtent.depth) and copyExtent needs to be clamped. TEST_P(CompressedTextureBCFormatTest, LargeImageHeightAndClampedCopyExtent) { + DAWN_SKIP_TEST_IF(!IsBCFormatSupported()); + CopyConfig config; config.textureHeightLevel0 = 56; config.textureWidthLevel0 = 56; @@ -803,4 +854,8 @@ TEST_P(CompressedTextureBCFormatTest, LargeImageHeightAndClampedCopyExtent) { } // TODO(jiawei.shao@intel.com): support BC formats on OpenGL backend -DAWN_INSTANTIATE_TEST(CompressedTextureBCFormatTest, D3D12Backend, MetalBackend, VulkanBackend); +DAWN_INSTANTIATE_TEST(CompressedTextureBCFormatTest, + D3D12Backend, + MetalBackend, + OpenGLBackend, + VulkanBackend); diff --git a/src/tests/unittests/ExtensionTests.cpp b/src/tests/unittests/ExtensionTests.cpp new file mode 100644 index 0000000000..cef27527f2 --- /dev/null +++ b/src/tests/unittests/ExtensionTests.cpp @@ -0,0 +1,78 @@ +// 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 + +#include "dawn_native/Extensions.h" +#include "dawn_native/Instance.h" +#include "dawn_native/null/DeviceNull.h" + +class ExtensionTests : public testing::Test { + public: + ExtensionTests() : testing::Test(), mInstanceBase(), mAdapterBase(&mInstanceBase) { + } + + std::vector GetAllExtensionNames() { + std::vector allExtensionNames(kTotalExtensionsCount); + for (size_t i = 0; i < kTotalExtensionsCount; ++i) { + allExtensionNames[i] = ExtensionEnumToName(static_cast(i)); + } + return allExtensionNames; + } + + static constexpr size_t kTotalExtensionsCount = + static_cast(dawn_native::Extension::EnumCount); + + protected: + dawn_native::InstanceBase mInstanceBase; + dawn_native::null::Adapter mAdapterBase; +}; + +// Test the creation of a device will fail if the requested extension is not supported on the +// Adapter. +TEST_F(ExtensionTests, AdapterWithRequiredExtensionDisabled) { + const std::vector kAllExtensionNames = GetAllExtensionNames(); + for (size_t i = 0; i < kTotalExtensionsCount; ++i) { + dawn_native::Extension notSupportedExtension = static_cast(i); + + std::vector extensionNamesWithoutOne = kAllExtensionNames; + extensionNamesWithoutOne.erase(extensionNamesWithoutOne.begin() + i); + + mAdapterBase.SetSupportedExtensions(extensionNamesWithoutOne); + dawn_native::Adapter adapterWithoutExtension(&mAdapterBase); + + dawn_native::DeviceDescriptor deviceDescriptor; + const char* extensionName = ExtensionEnumToName(notSupportedExtension); + deviceDescriptor.requiredExtensions = std::vector(1, extensionName); + DawnDevice deviceWithExtension = adapterWithoutExtension.CreateDevice(&deviceDescriptor); + ASSERT_EQ(nullptr, deviceWithExtension); + } +} + +// Test Device.GetEnabledExtensions() can return the names of the enabled extensions correctly. +TEST_F(ExtensionTests, GetEnabledExtensions) { + dawn_native::Adapter adapter(&mAdapterBase); + for (size_t i = 0; i < kTotalExtensionsCount; ++i) { + dawn_native::Extension extension = static_cast(i); + const char* extensionName = ExtensionEnumToName(extension); + + dawn_native::DeviceDescriptor deviceDescriptor; + deviceDescriptor.requiredExtensions = {extensionName}; + dawn_native::DeviceBase* deviceBase = + reinterpret_cast(adapter.CreateDevice(&deviceDescriptor)); + std::vector enabledExtensions = deviceBase->GetEnabledExtensions(); + ASSERT_EQ(1u, enabledExtensions.size()); + ASSERT_EQ(0, std::strcmp(extensionName, enabledExtensions[0])); + } +} diff --git a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp index b2ca88e41e..0ed925cadf 100644 --- a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp +++ b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp @@ -1155,6 +1155,11 @@ TEST_F(CopyCommandTest_T2T, CopyToMipmapOfNonSquareTexture) { } class CopyCommandTest_CompressedTextureFormats : public CopyCommandTest { + public: + CopyCommandTest_CompressedTextureFormats() : CopyCommandTest() { + device = CreateDeviceFromAdapter(adapter, {"texture_compression_bc"}); + } + protected: dawn::Texture Create2DTexture(dawn::TextureFormat format, uint32_t mipmapLevels = 1, diff --git a/src/tests/unittests/validation/TextureValidationTests.cpp b/src/tests/unittests/validation/TextureValidationTests.cpp index bef154eaef..75874f8c5b 100644 --- a/src/tests/unittests/validation/TextureValidationTests.cpp +++ b/src/tests/unittests/validation/TextureValidationTests.cpp @@ -250,10 +250,14 @@ TEST_F(TextureValidationTest, NonRenderableAndOutputAttachment) { ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); } -// TODO(jiawei.shao@intel.com): use compressed texture formats as extensions. // TODO(jiawei.shao@intel.com): add tests to verify we cannot create 1D or 3D textures with // compressed texture formats. class CompressedTextureFormatsValidationTests : public TextureValidationTest { + public: + CompressedTextureFormatsValidationTests() : TextureValidationTest() { + device = CreateDeviceFromAdapter(adapter, {"texture_compression_bc"}); + } + protected: dawn::TextureDescriptor CreateDefaultTextureDescriptor() { dawn::TextureDescriptor descriptor = @@ -309,6 +313,18 @@ TEST_F(CompressedTextureFormatsValidationTests, TextureSize) { } } +// Test the creation of a texture with BC format will fail when the extension textureCompressionBC +// is not enabled. +TEST_F(CompressedTextureFormatsValidationTests, UseBCFormatWithoutEnablingExtension) { + const std::vector kEmptyVector; + dawn::Device deviceWithoutExtension = CreateDeviceFromAdapter(adapter, kEmptyVector); + for (dawn::TextureFormat format : kBCFormats) { + dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); + descriptor.format = format; + ASSERT_DEVICE_ERROR(deviceWithoutExtension.CreateTexture(&descriptor)); + } +} + // Test the validation of texture usages when creating textures in compressed texture formats. TEST_F(CompressedTextureFormatsValidationTests, TextureUsage) { // Test that only CopySrc, CopyDst and Sampled are accepted as the texture usage of the diff --git a/src/tests/unittests/validation/ValidationTest.cpp b/src/tests/unittests/validation/ValidationTest.cpp index 09f6e871a3..af02a0bc57 100644 --- a/src/tests/unittests/validation/ValidationTest.cpp +++ b/src/tests/unittests/validation/ValidationTest.cpp @@ -35,12 +35,29 @@ ValidationTest::ValidationTest() { } ASSERT(foundNullAdapter); - device = dawn::Device::Acquire(adapter.CreateDevice()); DawnProcTable procs = dawn_native::GetProcs(); dawnSetProcs(&procs); - device.SetErrorCallback(ValidationTest::OnDeviceError, this); + device = CreateDeviceFromAdapter(adapter, std::vector()); +} + +dawn::Device ValidationTest::CreateDeviceFromAdapter( + dawn_native::Adapter adapterToTest, + const std::vector& requiredExtensions) { + dawn::Device deviceToTest; + + // Always keep the code path to test creating a device without a device descriptor. + if (requiredExtensions.empty()) { + deviceToTest = dawn::Device::Acquire(adapterToTest.CreateDevice()); + } else { + dawn_native::DeviceDescriptor descriptor; + descriptor.requiredExtensions = requiredExtensions; + deviceToTest = dawn::Device::Acquire(adapterToTest.CreateDevice(&descriptor)); + } + + deviceToTest.SetErrorCallback(ValidationTest::OnDeviceError, this); + return deviceToTest; } ValidationTest::~ValidationTest() { diff --git a/src/tests/unittests/validation/ValidationTest.h b/src/tests/unittests/validation/ValidationTest.h index 92aef16c70..5deb019c92 100644 --- a/src/tests/unittests/validation/ValidationTest.h +++ b/src/tests/unittests/validation/ValidationTest.h @@ -29,6 +29,9 @@ class ValidationTest : public testing::Test { ValidationTest(); ~ValidationTest(); + dawn::Device CreateDeviceFromAdapter(dawn_native::Adapter adapter, + const std::vector& requiredExtensions); + void TearDown() override; void StartExpectDeviceError();