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 <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Jiawei Shao 2019-08-02 00:06:38 +00:00 committed by Commit Bot service account
parent 56f3a7b90d
commit 574b951188
28 changed files with 566 additions and 43 deletions

View File

@ -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",

View File

@ -38,6 +38,24 @@ namespace dawn_native {
return mInstance;
}
ExtensionsSet AdapterBase::GetSupportedExtensions() const {
return mSupportedExtensions;
}
bool AdapterBase::SupportsAllRequestedExtensions(
const std::vector<const char*>& 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));

View File

@ -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<const char*>& requestedExtensions) const;
protected:
PCIInfo mPCIInfo = {};
DeviceType mDeviceType = DeviceType::Unknown;
ExtensionsSet mSupportedExtensions;
private:
virtual ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) = 0;

View File

@ -55,6 +55,11 @@ namespace dawn_native {
return mImpl->GetPCIInfo();
}
std::vector<const char*> Adapter::GetSupportedExtensions() const {
ExtensionsSet supportedExtensionsSet = mImpl->GetSupportedExtensions();
return supportedExtensionsSet.GetEnabledExtensionNames();
}
Adapter::operator bool() const {
return mImpl != nullptr;
}

View File

@ -66,6 +66,10 @@ namespace dawn_native {
mDynamicUploader = std::make_unique<DynamicUploader>(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<const char*> DeviceBase::GetEnabledExtensions() const {
return mEnabledExtensions.GetEnabledExtensionNames();
}
std::vector<const char*> 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);
}

View File

@ -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<DynamicUploader*> GetDynamicUploader() const;
std::vector<const char*> GetEnabledExtensions() const;
std::vector<const char*> 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

View File

@ -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 <array>
#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<ExtensionEnumAndInfo, static_cast<size_t>(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<size_t>(extension);
extensionsBitSet.set(extensionIndex);
}
bool ExtensionsSet::IsEnabled(Extension extension) const {
ASSERT(extension != Extension::InvalidEnum);
const size_t extensionIndex = static_cast<size_t>(extension);
return extensionsBitSet[extensionIndex];
}
std::vector<const char*> ExtensionsSet::GetEnabledExtensionNames() const {
std::vector<const char*> enabledExtensionNames(extensionsBitSet.count());
uint32_t index = 0;
for (uint32_t i : IterateBitSet(extensionsBitSet)) {
const char* extensionName = ExtensionEnumToName(static_cast<Extension>(i));
enabledExtensionNames[index] = extensionName;
++index;
}
return enabledExtensionNames;
}
const char* ExtensionEnumToName(Extension extension) {
ASSERT(extension != Extension::InvalidEnum);
const ExtensionEnumAndInfo& extensionNameAndInfo =
kExtensionNameAndInfoList[static_cast<size_t>(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<size_t>(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<size_t>(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<size_t>(iter->second)].extension;
}
return Extension::InvalidEnum;
}
ExtensionsSet ExtensionsInfo::ExtensionNamesToExtensionsSet(
const std::vector<const char*>& 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

View File

@ -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 <bitset>
#include <unordered_map>
#include <vector>
#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<static_cast<size_t>(Extension::EnumCount)> extensionsBitSet;
void EnableExtension(Extension extension);
bool IsEnabled(Extension extension) const;
std::vector<const char*> 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<const char*>& requiredExtensions) const;
private:
std::unordered_map<std::string, Extension> mExtensionNameToEnumMap;
};
} // namespace dawn_native
#endif // DAWNNATIVE_EXTENSIONS_H_

View File

@ -13,6 +13,8 @@
// limitations under the License.
#include "dawn_native/Format.h"
#include "dawn_native/Device.h"
#include "dawn_native/Extensions.h"
#include <bitset>
@ -48,7 +50,7 @@ namespace dawn_native {
return static_cast<size_t>(static_cast<uint32_t>(format));
}
FormatTable BuildFormatTable(const DeviceBase*) {
FormatTable BuildFormatTable(const DeviceBase* device) {
FormatTable table;
std::bitset<kKnownFormatCount> 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

View File

@ -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<const char*>& requiredExtensions) {
return mExtensionsInfo.ExtensionNamesToExtensionsSet(requiredExtensions);
}
const std::vector<std::unique_ptr<AdapterBase>>& InstanceBase::GetAdapters() const {
return mAdapters;
}

View File

@ -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 <array>
@ -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<const char*>& requiredExtensions);
void EnableBackendValidation(bool enableBackendValidation);
bool IsBackendValidationEnabled() const;
@ -74,6 +81,7 @@ namespace dawn_native {
std::vector<std::unique_ptr<BackendConnection>> mBackends;
std::vector<std::unique_ptr<AdapterBase>> mAdapters;
ExtensionsInfo mExtensionsInfo;
TogglesInfo mTogglesInfo;
};

View File

@ -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<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
std::unique_ptr<Device> device = std::make_unique<Device>(this, descriptor);
DAWN_TRY(device->Initialize());

View File

@ -38,6 +38,7 @@ namespace dawn_native { namespace d3d12 {
private:
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
void InitializeSupportedExtensions();
ComPtr<IDXGIAdapter1> mHardwareAdapter;
ComPtr<ID3D12Device> mD3d12Device;

View File

@ -182,6 +182,11 @@ namespace dawn_native { namespace metal {
ResultOrError<DeviceBase*> 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<MTLDevice> mDevice = nil;
};

View File

@ -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 <spirv-cross/spirv_cross.hpp>
@ -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<DeviceBase*> 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<const char*>& requiredExtensions) {
mSupportedExtensions = GetInstance()->ExtensionNamesToExtensionsSet(requiredExtensions);
}
ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
return {new Device(this, descriptor)};
}
class Backend : public BackendConnection {
public:

View File

@ -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<const char*>& requiredExtensions);
private:
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
};
class Buffer : public BufferBase {
public:
Buffer(Device* device, const BufferDescriptor* descriptor);

View File

@ -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<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
std::unique_ptr<Device> device = std::make_unique<Device>(this, descriptor);
DAWN_TRY(device->Initialize());

View File

@ -37,6 +37,7 @@ namespace dawn_native { namespace vulkan {
private:
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
void InitializeSupportedExtensions();
VkPhysicalDevice mPhysicalDevice;
Backend* mBackend;

View File

@ -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
{

View File

@ -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<const char*> requiredExtensions;
std::vector<const char*> forceEnabledToggles;
std::vector<const char*> 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<const char*> GetSupportedExtensions() const;
explicit operator bool() const;

View File

@ -333,9 +333,31 @@ uint32_t DawnTest::GetVendorIdFilter() const {
return gTestEnv->GetVendorIdFilter();
}
std::vector<const char*> DawnTest::GetRequiredExtensions() {
return {};
}
// This function can only be called after SetUp() because it requires mBackendAdapter to be
// initialized.
bool DawnTest::SupportsExtensions(const std::vector<const char*>& extensions) {
ASSERT(mBackendAdapter);
std::set<std::string> 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();

View File

@ -206,6 +206,14 @@ class DawnTest : public ::testing::TestWithParam<DawnTestParam> {
void SwapBuffersForCapture();
bool SupportsExtensions(const std::vector<const char*>& 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<const char*> GetRequiredExtensions();
private:
// Things used to set up testing through the Wire.
std::unique_ptr<dawn_wire::WireServer> mWireServer;
@ -263,6 +271,8 @@ class DawnTest : public ::testing::TestWithParam<DawnTestParam> {
std::unique_ptr<utils::BackendBinding> 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:

View File

@ -67,9 +67,24 @@ class CompressedTextureBCFormatTest : public DawnTest {
{1, dawn::ShaderStageBit::Fragment, dawn::BindingType::SampledTexture}});
}
std::vector<const char*> 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<RGBA8>& 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);

View File

@ -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 <gtest/gtest.h>
#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<const char*> GetAllExtensionNames() {
std::vector<const char*> allExtensionNames(kTotalExtensionsCount);
for (size_t i = 0; i < kTotalExtensionsCount; ++i) {
allExtensionNames[i] = ExtensionEnumToName(static_cast<dawn_native::Extension>(i));
}
return allExtensionNames;
}
static constexpr size_t kTotalExtensionsCount =
static_cast<size_t>(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<const char*> kAllExtensionNames = GetAllExtensionNames();
for (size_t i = 0; i < kTotalExtensionsCount; ++i) {
dawn_native::Extension notSupportedExtension = static_cast<dawn_native::Extension>(i);
std::vector<const char*> 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<const char*>(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<dawn_native::Extension>(i);
const char* extensionName = ExtensionEnumToName(extension);
dawn_native::DeviceDescriptor deviceDescriptor;
deviceDescriptor.requiredExtensions = {extensionName};
dawn_native::DeviceBase* deviceBase =
reinterpret_cast<dawn_native::DeviceBase*>(adapter.CreateDevice(&deviceDescriptor));
std::vector<const char*> enabledExtensions = deviceBase->GetEnabledExtensions();
ASSERT_EQ(1u, enabledExtensions.size());
ASSERT_EQ(0, std::strcmp(extensionName, enabledExtensions[0]));
}
}

View File

@ -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,

View File

@ -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<const char*> 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

View File

@ -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<const char*>());
}
dawn::Device ValidationTest::CreateDeviceFromAdapter(
dawn_native::Adapter adapterToTest,
const std::vector<const char*>& 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() {

View File

@ -29,6 +29,9 @@ class ValidationTest : public testing::Test {
ValidationTest();
~ValidationTest();
dawn::Device CreateDeviceFromAdapter(dawn_native::Adapter adapter,
const std::vector<const char*>& requiredExtensions);
void TearDown() override;
void StartExpectDeviceError();