diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn index a7389f983b..2d008c0bd3 100644 --- a/src/dawn/native/BUILD.gn +++ b/src/dawn/native/BUILD.gn @@ -397,12 +397,16 @@ source_set("sources") { if (dawn_enable_d3d12) { sources += [ + "d3d/BackendD3D.cpp", + "d3d/BackendD3D.h", "d3d/BlobD3D.cpp", "d3d/BlobD3D.h", "d3d/D3DError.cpp", "d3d/D3DError.h", "d3d/PlatformFunctions.cpp", "d3d/PlatformFunctions.h", + "d3d/UtilsD3D.cpp", + "d3d/UtilsD3D.h", "d3d/d3d_platform.h", ] } diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt index e6d1ccf599..b16c1e0a27 100644 --- a/src/dawn/native/CMakeLists.txt +++ b/src/dawn/native/CMakeLists.txt @@ -253,12 +253,16 @@ endif() if (DAWN_ENABLE_D3D12) target_sources(dawn_native PRIVATE + "d3d/BackendD3D.cpp" + "d3d/BackendD3D.h" "d3d/BlobD3D.cpp" "d3d/BlobD3D.h" "d3d/D3DError.cpp" "d3d/D3DError.h" "d3d/PlatformFunctions.cpp" "d3d/PlatformFunctions.h" + "d3d/UtilsD3D.cpp" + "d3d/UtilsD3D.h" "d3d/d3d_platform.h" ) endif() diff --git a/src/dawn/native/d3d/BackendD3D.cpp b/src/dawn/native/d3d/BackendD3D.cpp new file mode 100644 index 0000000000..07dc4f13a8 --- /dev/null +++ b/src/dawn/native/d3d/BackendD3D.cpp @@ -0,0 +1,240 @@ +// Copyright 2023 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/d3d/BackendD3D.h" + +#include + +#include "dawn/common/Log.h" +#include "dawn/native/Instance.h" +#include "dawn/native/d3d/D3DError.h" +#include "dawn/native/d3d/PlatformFunctions.h" +#include "dawn/native/d3d/UtilsD3D.h" + +namespace dawn::native::d3d { + +namespace { + +ResultOrError> CreateFactory(const PlatformFunctions* functions, + BackendValidationLevel validationLevel) { + ComPtr factory; + + uint32_t dxgiFactoryFlags = 0; + if (validationLevel != BackendValidationLevel::Disabled) { + // Enable additional debug layers. + dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; + } + + if (FAILED(functions->createDxgiFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)))) { + return DAWN_INTERNAL_ERROR("Failed to create a DXGI factory"); + } + + ASSERT(factory != nullptr); + return std::move(factory); +} + +} // anonymous namespace + +Backend::Backend(InstanceBase* instance, wgpu::BackendType type) + : BackendConnection(instance, type) {} + +MaybeError Backend::Initialize(std::unique_ptr functions) { + mFunctions = std::move(functions); + + // Check if DXC is available and cache DXC version information + if (!mFunctions->IsDXCBinaryAvailable()) { + // DXC version information is not available if DXC binaries are not available. + mDxcVersionInfo = DxcUnavailable{"DXC binary is not available"}; + } else { + // Check the DXC version information and validate them being not lower than pre-defined + // minimum version. + AcquireDxcVersionInformation(); + + // Check that DXC version information is acquired successfully. + if (std::holds_alternative(mDxcVersionInfo)) { + const DxcVersionInfo& dxcVersionInfo = std::get(mDxcVersionInfo); + + // The required minimum version for DXC compiler and validator. + // Notes about requirement consideration: + // * DXC version 1.4 has some known issues when compiling Tint generated HLSL program, + // please + // refer to crbug.com/tint/1719 + // * Windows SDK 20348 provides DXC compiler and validator version 1.6 + // Here the minimum version requirement for DXC compiler and validator are both set + // to 1.6. + constexpr uint64_t minimumCompilerMajorVersion = 1; + constexpr uint64_t minimumCompilerMinorVersion = 6; + constexpr uint64_t minimumValidatorMajorVersion = 1; + constexpr uint64_t minimumValidatorMinorVersion = 6; + + // Check that DXC compiler and validator version are not lower than minimum. + if (dxcVersionInfo.DxcCompilerVersion < + MakeDXCVersion(minimumCompilerMajorVersion, minimumCompilerMinorVersion) || + dxcVersionInfo.DxcValidatorVersion < + MakeDXCVersion(minimumValidatorMajorVersion, minimumValidatorMinorVersion)) { + // If DXC version is lower than required minimum, set mDxcVersionInfo to + // DxcUnavailable to indicate that DXC is not available. + std::ostringstream ss; + ss << "DXC version too low: dxil.dll required version 1.6, actual version " + << (dxcVersionInfo.DxcValidatorVersion >> 32) << "." + << (dxcVersionInfo.DxcValidatorVersion & ((uint64_t(1) << 32) - 1)) + << ", dxcompiler.dll required version 1.6, actual version " + << (dxcVersionInfo.DxcCompilerVersion >> 32) << "." + << (dxcVersionInfo.DxcCompilerVersion & ((uint64_t(1) << 32) - 1)); + mDxcVersionInfo = DxcUnavailable{ss.str()}; + } + } + } + + const auto instance = GetInstance(); + + DAWN_TRY_ASSIGN(mFactory, + CreateFactory(mFunctions.get(), instance->GetBackendValidationLevel())); + + return {}; +} + +ComPtr Backend::GetFactory() const { + return mFactory; +} + +MaybeError Backend::EnsureDxcLibrary() { + if (mDxcLibrary == nullptr) { + DAWN_TRY(CheckHRESULT( + mFunctions->dxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&mDxcLibrary)), + "DXC create library")); + ASSERT(mDxcLibrary != nullptr); + } + return {}; +} + +MaybeError Backend::EnsureDxcCompiler() { + if (mDxcCompiler == nullptr) { + DAWN_TRY(CheckHRESULT( + mFunctions->dxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&mDxcCompiler)), + "DXC create compiler")); + ASSERT(mDxcCompiler != nullptr); + } + return {}; +} + +MaybeError Backend::EnsureDxcValidator() { + if (mDxcValidator == nullptr) { + DAWN_TRY(CheckHRESULT( + mFunctions->dxcCreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&mDxcValidator)), + "DXC create validator")); + ASSERT(mDxcValidator != nullptr); + } + return {}; +} + +ComPtr Backend::GetDxcLibrary() const { + ASSERT(mDxcLibrary != nullptr); + return mDxcLibrary; +} + +ComPtr Backend::GetDxcCompiler() const { + ASSERT(mDxcCompiler != nullptr); + return mDxcCompiler; +} + +ComPtr Backend::GetDxcValidator() const { + ASSERT(mDxcValidator != nullptr); + return mDxcValidator; +} + +void Backend::AcquireDxcVersionInformation() { + ASSERT(std::holds_alternative(mDxcVersionInfo)); + + auto tryAcquireDxcVersionInfo = [this]() -> ResultOrError { + DAWN_TRY(EnsureDxcValidator()); + DAWN_TRY(EnsureDxcCompiler()); + + ComPtr compilerVersionInfo; + + DAWN_TRY(CheckHRESULT(mDxcCompiler.As(&compilerVersionInfo), + "D3D12 QueryInterface IDxcCompiler to IDxcVersionInfo")); + uint32_t compilerMajor, compilerMinor; + DAWN_TRY(CheckHRESULT(compilerVersionInfo->GetVersion(&compilerMajor, &compilerMinor), + "IDxcVersionInfo::GetVersion")); + + ComPtr validatorVersionInfo; + + DAWN_TRY(CheckHRESULT(mDxcValidator.As(&validatorVersionInfo), + "D3D12 QueryInterface IDxcValidator to IDxcVersionInfo")); + uint32_t validatorMajor, validatorMinor; + DAWN_TRY(CheckHRESULT(validatorVersionInfo->GetVersion(&validatorMajor, &validatorMinor), + "IDxcVersionInfo::GetVersion")); + + // Pack major and minor version number into a single version number. + uint64_t compilerVersion = MakeDXCVersion(compilerMajor, compilerMinor); + uint64_t validatorVersion = MakeDXCVersion(validatorMajor, validatorMinor); + return DxcVersionInfo{compilerVersion, validatorVersion}; + }; + + auto dxcVersionInfoOrError = tryAcquireDxcVersionInfo(); + + if (dxcVersionInfoOrError.IsSuccess()) { + // Cache the DXC version information. + mDxcVersionInfo = dxcVersionInfoOrError.AcquireSuccess(); + } else { + // Error occurs when acquiring DXC version information, set the cache to unavailable and + // record the error message. + std::string errorMessage = dxcVersionInfoOrError.AcquireError()->GetFormattedMessage(); + dawn::ErrorLog() << errorMessage; + mDxcVersionInfo = DxcUnavailable{errorMessage}; + } +} + +// Return both DXC compiler and DXC validator version, assert that DXC version information is +// acquired succesfully. +DxcVersionInfo Backend::GetDxcVersion() const { + ASSERT(std::holds_alternative(mDxcVersionInfo)); + return DxcVersionInfo(std::get(mDxcVersionInfo)); +} + +// Return true if and only if DXC binary is avaliable, and the DXC version is validated to +// be no older than a pre-defined minimum version. +bool Backend::IsDXCAvailable() const { + // mDxcVersionInfo hold DxcVersionInfo instead of DxcUnavailable if and only if DXC binaries and + // version are validated in `Initialize`. + return std::holds_alternative(mDxcVersionInfo); +} + +// Return true if and only if IsDXCAvailable() return true, and the DXC compiler and validator +// version are validated to be no older than the minimium version given in parameter. +bool Backend::IsDXCAvailableAndVersionAtLeast(uint64_t minimumCompilerMajorVersion, + uint64_t minimumCompilerMinorVersion, + uint64_t minimumValidatorMajorVersion, + uint64_t minimumValidatorMinorVersion) const { + // mDxcVersionInfo hold DxcVersionInfo instead of DxcUnavailable if and only if DXC binaries and + // version are validated in `Initialize`. + if (std::holds_alternative(mDxcVersionInfo)) { + const DxcVersionInfo& dxcVersionInfo = std::get(mDxcVersionInfo); + // Check that DXC compiler and validator version are not lower than given requirements. + if (dxcVersionInfo.DxcCompilerVersion >= + MakeDXCVersion(minimumCompilerMajorVersion, minimumCompilerMinorVersion) && + dxcVersionInfo.DxcValidatorVersion >= + MakeDXCVersion(minimumValidatorMajorVersion, minimumValidatorMinorVersion)) { + return true; + } + } + return false; +} + +const PlatformFunctions* Backend::GetFunctions() const { + return mFunctions.get(); +} + +} // namespace dawn::native::d3d diff --git a/src/dawn/native/d3d/BackendD3D.h b/src/dawn/native/d3d/BackendD3D.h new file mode 100644 index 0000000000..fb179dbe99 --- /dev/null +++ b/src/dawn/native/d3d/BackendD3D.h @@ -0,0 +1,103 @@ +// Copyright 2023 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 SRC_DAWN_NATIVE_D3D_BACKENDD3D_H_ +#define SRC_DAWN_NATIVE_D3D_BACKENDD3D_H_ + +#include +#include +#include + +#include "dawn/native/BackendConnection.h" + +#include "dawn/native/d3d12/d3d12_platform.h" + +namespace dawn::native::d3d { + +class PlatformFunctions; + +// DxcVersionInfo holds both DXC compiler (dxcompiler.dll) version and DXC validator (dxil.dll) +// version, which are not necessarily identical. Both are in uint64_t type, as the result of +// MakeDXCVersion. +struct DxcVersionInfo { + uint64_t DxcCompilerVersion; + uint64_t DxcValidatorVersion; +}; + +// If DXC version information is not avaliable due to no DXC binary or error occurs when acquiring +// version, DxcUnavailable indicates the version information being unavailable and holds the +// detailed error information. +struct DxcUnavailable { + std::string ErrorMessage; +}; + +class Backend : public BackendConnection { + public: + Backend(InstanceBase* instance, wgpu::BackendType type); + + MaybeError Initialize(std::unique_ptr functions); + + ComPtr GetFactory() const; + + MaybeError EnsureDxcLibrary(); + MaybeError EnsureDxcCompiler(); + MaybeError EnsureDxcValidator(); + ComPtr GetDxcLibrary() const; + ComPtr GetDxcCompiler() const; + ComPtr GetDxcValidator() const; + + // Return true if and only if DXC binary is avaliable, and the DXC compiler and validator + // version are validated to be no older than a specific minimium version, currently 1.6. + bool IsDXCAvailable() const; + + // Return true if and only if mIsDXCAvailable is true, and the DXC compiler and validator + // version are validated to be no older than the minimium version given in parameter. + bool IsDXCAvailableAndVersionAtLeast(uint64_t minimumCompilerMajorVersion, + uint64_t minimumCompilerMinorVersion, + uint64_t minimumValidatorMajorVersion, + uint64_t minimumValidatorMinorVersion) const; + + // Return the DXC version information cached in mDxcVersionInformation, assert that the version + // information is valid. Must be called after ensuring `IsDXCAvailable()` return true. + DxcVersionInfo GetDxcVersion() const; + + const PlatformFunctions* GetFunctions() const; + + private: + // Acquiring DXC version information and store the result in mDxcVersionInfo. This function + // should be called only once, during startup in `Initialize`. + void AcquireDxcVersionInformation(); + + // Keep mFunctions as the first member so that in the destructor it is freed last. Otherwise + // the D3D12 DLLs are unloaded before we are done using them. + std::unique_ptr mFunctions; + ComPtr mFactory; + ComPtr mDxcLibrary; + ComPtr mDxcCompiler; + ComPtr mDxcValidator; + + // DXC binaries and DXC version information are checked when start up in `Initialize`. There are + // two possible states: + // 1. The DXC binary is not available, or error occurs when checking the version information + // and therefore no DXC version information available, or the DXC version is lower than + // requested minumum and therefore DXC is not available, represented by DxcUnavailable + // in which a error message is held; + // 3. The DXC version information is acquired successfully and validated not lower than + // requested minimum, stored in DxcVersionInfo. + std::variant mDxcVersionInfo; +}; + +} // namespace dawn::native::d3d + +#endif // SRC_DAWN_NATIVE_D3D_BACKENDD3D_H_ diff --git a/src/dawn/native/d3d/UtilsD3D.cpp b/src/dawn/native/d3d/UtilsD3D.cpp new file mode 100644 index 0000000000..057e730273 --- /dev/null +++ b/src/dawn/native/d3d/UtilsD3D.cpp @@ -0,0 +1,77 @@ +// Copyright 2023 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/d3d/UtilsD3D.h" + +#include + +namespace dawn::native::d3d { + +ResultOrError ConvertStringToWstring(std::string_view s) { + size_t len = s.length(); + if (len == 0) { + return std::wstring(); + } + int numChars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), len, nullptr, 0); + if (numChars == 0) { + return DAWN_INTERNAL_ERROR("Failed to convert string to wide string"); + } + std::wstring result; + result.resize(numChars); + int numConvertedChars = + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), len, &result[0], numChars); + if (numConvertedChars != numChars) { + return DAWN_INTERNAL_ERROR("Failed to convert string to wide string"); + } + return std::move(result); +} + +bool IsTypeless(DXGI_FORMAT format) { + // List generated from + switch (format) { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC7_TYPELESS: + return true; + default: + return false; + } +} + +uint64_t MakeDXCVersion(uint64_t majorVersion, uint64_t minorVersion) { + return (majorVersion << 32) + minorVersion; +} + +} // namespace dawn::native::d3d diff --git a/src/dawn/native/d3d/UtilsD3D.h b/src/dawn/native/d3d/UtilsD3D.h new file mode 100644 index 0000000000..f820279f8c --- /dev/null +++ b/src/dawn/native/d3d/UtilsD3D.h @@ -0,0 +1,33 @@ +// Copyright 2023 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 SRC_DAWN_NATIVE_D3D_UTILSD3D_H_ +#define SRC_DAWN_NATIVE_D3D_UTILSD3D_H_ + +#include + +#include "dawn/native/Error.h" +#include "dawn/native/d3d/d3d_platform.h" + +namespace dawn::native::d3d { + +ResultOrError ConvertStringToWstring(std::string_view s); + +bool IsTypeless(DXGI_FORMAT format); + +uint64_t MakeDXCVersion(uint64_t majorVersion, uint64_t minorVersion); + +} // namespace dawn::native::d3d + +#endif // SRC_DAWN_NATIVE_D3D_UTILSD3D_H_ diff --git a/src/dawn/native/d3d12/BackendD3D12.cpp b/src/dawn/native/d3d12/BackendD3D12.cpp index 1dca30b87b..cbd0eb4f8a 100644 --- a/src/dawn/native/d3d12/BackendD3D12.cpp +++ b/src/dawn/native/d3d12/BackendD3D12.cpp @@ -14,6 +14,7 @@ #include "dawn/native/d3d12/BackendD3D12.h" +#include #include #include "dawn/common/Log.h" @@ -25,49 +26,8 @@ #include "dawn/native/d3d12/UtilsD3D12.h" namespace dawn::native::d3d12 { - namespace { -ResultOrError> CreateFactory(const PlatformFunctions* functions, - BackendValidationLevel validationLevel, - bool beginCaptureOnStartup) { - ComPtr factory; - - uint32_t dxgiFactoryFlags = 0; - - // Enable the debug layer (requires the Graphics Tools "optional feature"). - { - if (validationLevel != BackendValidationLevel::Disabled) { - ComPtr debugController; - if (SUCCEEDED(functions->d3d12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { - ASSERT(debugController != nullptr); - debugController->EnableDebugLayer(); - if (validationLevel == BackendValidationLevel::Full) { - debugController->SetEnableGPUBasedValidation(true); - } - - // Enable additional debug layers. - dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; - } - } - - if (beginCaptureOnStartup) { - ComPtr graphicsAnalysis; - if (functions->dxgiGetDebugInterface1 != nullptr && - SUCCEEDED(functions->dxgiGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)))) { - graphicsAnalysis->BeginCapture(); - } - } - } - - if (FAILED(functions->createDxgiFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)))) { - return DAWN_INTERNAL_ERROR("Failed to create a DXGI factory"); - } - - ASSERT(factory != nullptr); - return std::move(factory); -} - ResultOrError> CreateAdapterFromIDXGIAdapter(Backend* backend, ComPtr dxgiAdapter, const TogglesState& adapterToggles) { @@ -80,197 +40,42 @@ ResultOrError> CreateAdapterFromIDXGIAdapter(Backend* backend, return {std::move(adapter)}; } -} // anonymous namespace +} // namespace -Backend::Backend(InstanceBase* instance) : BackendConnection(instance, wgpu::BackendType::D3D12) {} +Backend::Backend(InstanceBase* instance) : Base(instance, wgpu::BackendType::D3D12) {} MaybeError Backend::Initialize() { - mFunctions = std::make_unique(); - DAWN_TRY(mFunctions->LoadFunctions()); + auto functions = std::make_unique(); + DAWN_TRY(functions->LoadFunctions()); - // Check if DXC is available and cache DXC version information - if (!mFunctions->IsDXCBinaryAvailable()) { - // DXC version information is not available if DXC binaries are not available. - mDxcVersionInfo = DxcUnavailable{"DXC binary is not available"}; - } else { - // Check the DXC version information and validate them being not lower than pre-defined - // minimum version. - AcquireDxcVersionInformation(); - - // Check that DXC version information is acquired successfully. - if (std::holds_alternative(mDxcVersionInfo)) { - const DxcVersionInfo& dxcVersionInfo = std::get(mDxcVersionInfo); - - // The required minimum version for DXC compiler and validator. - // Notes about requirement consideration: - // * DXC version 1.4 has some known issues when compiling Tint generated HLSL program, - // please - // refer to crbug.com/tint/1719 - // * Windows SDK 20348 provides DXC compiler and validator version 1.6 - // Here the minimum version requirement for DXC compiler and validator are both set - // to 1.6. - constexpr uint64_t minimumCompilerMajorVersion = 1; - constexpr uint64_t minimumCompilerMinorVersion = 6; - constexpr uint64_t minimumValidatorMajorVersion = 1; - constexpr uint64_t minimumValidatorMinorVersion = 6; - - // Check that DXC compiler and validator version are not lower than minimum. - if (dxcVersionInfo.DxcCompilerVersion < - MakeDXCVersion(minimumCompilerMajorVersion, minimumCompilerMinorVersion) || - dxcVersionInfo.DxcValidatorVersion < - MakeDXCVersion(minimumValidatorMajorVersion, minimumValidatorMinorVersion)) { - // If DXC version is lower than required minimum, set mDxcVersionInfo to - // DxcUnavailable to indicate that DXC is not available. - std::ostringstream ss; - ss << "DXC version too low: dxil.dll required version 1.6, actual version " - << (dxcVersionInfo.DxcValidatorVersion >> 32) << "." - << (dxcVersionInfo.DxcValidatorVersion & ((uint64_t(1) << 32) - 1)) - << ", dxcompiler.dll required version 1.6, actual version " - << (dxcVersionInfo.DxcCompilerVersion >> 32) << "." - << (dxcVersionInfo.DxcCompilerVersion & ((uint64_t(1) << 32) - 1)); - mDxcVersionInfo = DxcUnavailable{ss.str()}; + // Enable the debug layer (requires the Graphics Tools "optional feature"). + const auto instance = GetInstance(); + if (instance->GetBackendValidationLevel() != BackendValidationLevel::Disabled) { + ComPtr debugController; + if (SUCCEEDED(functions->d3d12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { + ASSERT(debugController != nullptr); + debugController->EnableDebugLayer(); + if (instance->GetBackendValidationLevel() == BackendValidationLevel::Full) { + debugController->SetEnableGPUBasedValidation(true); } } } - const auto instance = GetInstance(); - - DAWN_TRY_ASSIGN(mFactory, CreateFactory(mFunctions.get(), instance->GetBackendValidationLevel(), - instance->IsBeginCaptureOnStartupEnabled())); - - return {}; -} - -ComPtr Backend::GetFactory() const { - return mFactory; -} - -MaybeError Backend::EnsureDxcLibrary() { - if (mDxcLibrary == nullptr) { - DAWN_TRY(CheckHRESULT( - mFunctions->dxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&mDxcLibrary)), - "DXC create library")); - ASSERT(mDxcLibrary != nullptr); - } - return {}; -} - -MaybeError Backend::EnsureDxcCompiler() { - if (mDxcCompiler == nullptr) { - DAWN_TRY(CheckHRESULT( - mFunctions->dxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&mDxcCompiler)), - "DXC create compiler")); - ASSERT(mDxcCompiler != nullptr); - } - return {}; -} - -MaybeError Backend::EnsureDxcValidator() { - if (mDxcValidator == nullptr) { - DAWN_TRY(CheckHRESULT( - mFunctions->dxcCreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&mDxcValidator)), - "DXC create validator")); - ASSERT(mDxcValidator != nullptr); - } - return {}; -} - -ComPtr Backend::GetDxcLibrary() const { - ASSERT(mDxcLibrary != nullptr); - return mDxcLibrary; -} - -ComPtr Backend::GetDxcCompiler() const { - ASSERT(mDxcCompiler != nullptr); - return mDxcCompiler; -} - -ComPtr Backend::GetDxcValidator() const { - ASSERT(mDxcValidator != nullptr); - return mDxcValidator; -} - -void Backend::AcquireDxcVersionInformation() { - ASSERT(std::holds_alternative(mDxcVersionInfo)); - - auto tryAcquireDxcVersionInfo = [this]() -> ResultOrError { - DAWN_TRY(EnsureDxcValidator()); - DAWN_TRY(EnsureDxcCompiler()); - - ComPtr compilerVersionInfo; - - DAWN_TRY(CheckHRESULT(mDxcCompiler.As(&compilerVersionInfo), - "D3D12 QueryInterface IDxcCompiler to IDxcVersionInfo")); - uint32_t compilerMajor, compilerMinor; - DAWN_TRY(CheckHRESULT(compilerVersionInfo->GetVersion(&compilerMajor, &compilerMinor), - "IDxcVersionInfo::GetVersion")); - - ComPtr validatorVersionInfo; - - DAWN_TRY(CheckHRESULT(mDxcValidator.As(&validatorVersionInfo), - "D3D12 QueryInterface IDxcValidator to IDxcVersionInfo")); - uint32_t validatorMajor, validatorMinor; - DAWN_TRY(CheckHRESULT(validatorVersionInfo->GetVersion(&validatorMajor, &validatorMinor), - "IDxcVersionInfo::GetVersion")); - - // Pack major and minor version number into a single version number. - uint64_t compilerVersion = MakeDXCVersion(compilerMajor, compilerMinor); - uint64_t validatorVersion = MakeDXCVersion(validatorMajor, validatorMinor); - return DxcVersionInfo{compilerVersion, validatorVersion}; - }; - - auto dxcVersionInfoOrError = tryAcquireDxcVersionInfo(); - - if (dxcVersionInfoOrError.IsSuccess()) { - // Cache the DXC version information. - mDxcVersionInfo = dxcVersionInfoOrError.AcquireSuccess(); - } else { - // Error occurs when acquiring DXC version information, set the cache to unavailable and - // record the error message. - std::string errorMessage = dxcVersionInfoOrError.AcquireError()->GetFormattedMessage(); - dawn::ErrorLog() << errorMessage; - mDxcVersionInfo = DxcUnavailable{errorMessage}; - } -} - -// Return both DXC compiler and DXC validator version, assert that DXC version information is -// acquired succesfully. -DxcVersionInfo Backend::GetDxcVersion() const { - ASSERT(std::holds_alternative(mDxcVersionInfo)); - return DxcVersionInfo(std::get(mDxcVersionInfo)); -} - -// Return true if and only if DXC binary is avaliable, and the DXC version is validated to -// be no older than a pre-defined minimum version. -bool Backend::IsDXCAvailable() const { - // mDxcVersionInfo hold DxcVersionInfo instead of DxcUnavailable if and only if DXC binaries and - // version are validated in `Initialize`. - return std::holds_alternative(mDxcVersionInfo); -} - -// Return true if and only if IsDXCAvailable() return true, and the DXC compiler and validator -// version are validated to be no older than the minimium version given in parameter. -bool Backend::IsDXCAvailableAndVersionAtLeast(uint64_t minimumCompilerMajorVersion, - uint64_t minimumCompilerMinorVersion, - uint64_t minimumValidatorMajorVersion, - uint64_t minimumValidatorMinorVersion) const { - // mDxcVersionInfo hold DxcVersionInfo instead of DxcUnavailable if and only if DXC binaries and - // version are validated in `Initialize`. - if (std::holds_alternative(mDxcVersionInfo)) { - const DxcVersionInfo& dxcVersionInfo = std::get(mDxcVersionInfo); - // Check that DXC compiler and validator version are not lower than given requirements. - if (dxcVersionInfo.DxcCompilerVersion >= - MakeDXCVersion(minimumCompilerMajorVersion, minimumCompilerMinorVersion) && - dxcVersionInfo.DxcValidatorVersion >= - MakeDXCVersion(minimumValidatorMajorVersion, minimumValidatorMinorVersion)) { - return true; + if (instance->IsBeginCaptureOnStartupEnabled()) { + ComPtr graphicsAnalysis; + if (functions->dxgiGetDebugInterface1 != nullptr && + SUCCEEDED(functions->dxgiGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)))) { + graphicsAnalysis->BeginCapture(); } } - return false; + + DAWN_TRY(Base::Initialize(std::move(functions))); + + return {}; } const PlatformFunctions* Backend::GetFunctions() const { - return mFunctions.get(); + return static_cast(Base::GetFunctions()); } std::vector> Backend::DiscoverDefaultAdapters(const TogglesState& adapterToggles) { @@ -303,7 +108,7 @@ ResultOrError>> Backend::DiscoverAdapters( // Enumerate and discover all available adapters. for (uint32_t adapterIndex = 0;; ++adapterIndex) { ComPtr dxgiAdapter = nullptr; - if (mFactory->EnumAdapters1(adapterIndex, &dxgiAdapter) == DXGI_ERROR_NOT_FOUND) { + if (GetFactory()->EnumAdapters1(adapterIndex, &dxgiAdapter) == DXGI_ERROR_NOT_FOUND) { break; // No more adapters to enumerate. } diff --git a/src/dawn/native/d3d12/BackendD3D12.h b/src/dawn/native/d3d12/BackendD3D12.h index f2bb13f818..203876795d 100644 --- a/src/dawn/native/d3d12/BackendD3D12.h +++ b/src/dawn/native/d3d12/BackendD3D12.h @@ -15,64 +15,23 @@ #ifndef SRC_DAWN_NATIVE_D3D12_BACKENDD3D12_H_ #define SRC_DAWN_NATIVE_D3D12_BACKENDD3D12_H_ -#include -#include -#include #include #include "dawn/native/BackendConnection.h" +#include "dawn/native/d3d/BackendD3D.h" #include "dawn/native/d3d12/d3d12_platform.h" namespace dawn::native::d3d12 { class PlatformFunctions; -// DxcVersionInfo holds both DXC compiler (dxcompiler.dll) version and DXC validator (dxil.dll) -// version, which are not necessarily identical. Both are in uint64_t type, as the result of -// MakeDXCVersion. -struct DxcVersionInfo { - uint64_t DxcCompilerVersion; - uint64_t DxcValidatorVersion; -}; - -// If DXC version information is not avaliable due to no DXC binary or error occurs when acquiring -// version, DxcUnavailable indicates the version information being unavailable and holds the -// detailed error information. -struct DxcUnavailable { - std::string ErrorMessage; -}; - -class Backend : public BackendConnection { +class Backend final : public d3d::Backend { public: explicit Backend(InstanceBase* instance); MaybeError Initialize(); - ComPtr GetFactory() const; - - MaybeError EnsureDxcLibrary(); - MaybeError EnsureDxcCompiler(); - MaybeError EnsureDxcValidator(); - ComPtr GetDxcLibrary() const; - ComPtr GetDxcCompiler() const; - ComPtr GetDxcValidator() const; - - // Return true if and only if DXC binary is avaliable, and the DXC compiler and validator - // version are validated to be no older than a specific minimium version, currently 1.6. - bool IsDXCAvailable() const; - - // Return true if and only if mIsDXCAvailable is true, and the DXC compiler and validator - // version are validated to be no older than the minimium version given in parameter. - bool IsDXCAvailableAndVersionAtLeast(uint64_t minimumCompilerMajorVersion, - uint64_t minimumCompilerMinorVersion, - uint64_t minimumValidatorMajorVersion, - uint64_t minimumValidatorMinorVersion) const; - - // Return the DXC version information cached in mDxcVersionInformation, assert that the version - // information is valid. Must be called after ensuring `IsDXCAvailable()` return true. - DxcVersionInfo GetDxcVersion() const; - const PlatformFunctions* GetFunctions() const; std::vector> DiscoverDefaultAdapters( @@ -82,27 +41,7 @@ class Backend : public BackendConnection { const TogglesState& adapterToggles) override; private: - // Acquiring DXC version information and store the result in mDxcVersionInfo. This function - // should be called only once, during startup in `Initialize`. - void AcquireDxcVersionInformation(); - - // Keep mFunctions as the first member so that in the destructor it is freed last. Otherwise - // the D3D12 DLLs are unloaded before we are done using them. - std::unique_ptr mFunctions; - ComPtr mFactory; - ComPtr mDxcLibrary; - ComPtr mDxcCompiler; - ComPtr mDxcValidator; - - // DXC binaries and DXC version information are checked when start up in `Initialize`. There are - // two possible states: - // 1. The DXC binary is not available, or error occurs when checking the version information - // and therefore no DXC version information available, or the DXC version is lower than - // requested minumum and therefore DXC is not available, represented by DxcUnavailable - // in which a error message is held; - // 3. The DXC version information is acquired successfully and validated not lower than - // requested minimum, stored in DxcVersionInfo. - std::variant mDxcVersionInfo; + using Base = d3d::Backend; }; } // namespace dawn::native::d3d12 diff --git a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp index 2e62d7c2df..9ea85a80af 100644 --- a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp +++ b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp @@ -170,7 +170,7 @@ bool IsClearValueOptimizable(DeviceBase* device, const D3D12_RESOURCE_DESC& reso // textures, or typeless resources // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createcommittedresource // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource - return !IsTypeless(resourceDescriptor.Format) && + return !d3d::IsTypeless(resourceDescriptor.Format) && resourceDescriptor.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER && (resourceDescriptor.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0; diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp index a7047b1aba..de7c2ba47b 100644 --- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp +++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp @@ -186,7 +186,7 @@ ResultOrError> CompileShaderDXC(const D3DBytecodeCompilationReq "DXC create blob")); std::wstring entryPointW; - DAWN_TRY_ASSIGN(entryPointW, ConvertStringToWstring(entryPointName)); + DAWN_TRY_ASSIGN(entryPointW, d3d::ConvertStringToWstring(entryPointName)); std::vector arguments = GetDXCArguments(r.compileFlags, r.hasShaderF16Feature); @@ -498,7 +498,7 @@ ResultOrError ShaderModule::Compile( // available. ASSERT(ToBackend(device->GetAdapter())->GetBackend()->IsDXCAvailable()); // We can get the DXC version information since IsDXCAvailable() is true. - DxcVersionInfo dxcVersionInfo = + d3d::DxcVersionInfo dxcVersionInfo = ToBackend(device->GetAdapter())->GetBackend()->GetDxcVersion(); req.bytecode.compiler = Compiler::DXC; diff --git a/src/dawn/native/d3d12/UtilsD3D12.cpp b/src/dawn/native/d3d12/UtilsD3D12.cpp index b508300f8e..2da422c707 100644 --- a/src/dawn/native/d3d12/UtilsD3D12.cpp +++ b/src/dawn/native/d3d12/UtilsD3D12.cpp @@ -81,25 +81,6 @@ bool NeedBufferSizeWorkaroundForBufferTextureCopyOnD3D12(const BufferCopy& buffe } // anonymous namespace -ResultOrError ConvertStringToWstring(std::string_view s) { - size_t len = s.length(); - if (len == 0) { - return std::wstring(); - } - int numChars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), len, nullptr, 0); - if (numChars == 0) { - return DAWN_INTERNAL_ERROR("Failed to convert string to wide string"); - } - std::wstring result; - result.resize(numChars); - int numConvertedChars = - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), len, &result[0], numChars); - if (numConvertedChars != numChars) { - return DAWN_INTERNAL_ERROR("Failed to convert string to wide string"); - } - return std::move(result); -} - D3D12_COMPARISON_FUNC ToD3D12ComparisonFunc(wgpu::CompareFunction func) { switch (func) { case wgpu::CompareFunction::Never: @@ -167,39 +148,6 @@ D3D12_BOX ComputeD3D12BoxFromOffsetAndSize(const Origin3D& offset, const Extent3 return sourceRegion; } -bool IsTypeless(DXGI_FORMAT format) { - // List generated from - switch (format) { - case DXGI_FORMAT_R32G32B32A32_TYPELESS: - case DXGI_FORMAT_R32G32B32_TYPELESS: - case DXGI_FORMAT_R16G16B16A16_TYPELESS: - case DXGI_FORMAT_R32G32_TYPELESS: - case DXGI_FORMAT_R32G8X24_TYPELESS: - case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: - case DXGI_FORMAT_R10G10B10A2_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_R16G16_TYPELESS: - case DXGI_FORMAT_R32_TYPELESS: - case DXGI_FORMAT_R24G8_TYPELESS: - case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: - case DXGI_FORMAT_R8G8_TYPELESS: - case DXGI_FORMAT_R16_TYPELESS: - case DXGI_FORMAT_R8_TYPELESS: - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC7_TYPELESS: - return true; - default: - return false; - } -} - void RecordBufferTextureCopyFromSplits(BufferTextureCopyDirection direction, ID3D12GraphicsCommandList* commandList, const TextureCopySubresource& baseCopySplit, @@ -386,8 +334,4 @@ void SetDebugName(Device* device, ID3D12Object* object, const char* prefix, std: object->SetPrivateData(WKPDID_D3DDebugObjectName, objectName.length(), objectName.c_str()); } -uint64_t MakeDXCVersion(uint64_t majorVersion, uint64_t minorVersion) { - return (majorVersion << 32) + minorVersion; -} - } // namespace dawn::native::d3d12 diff --git a/src/dawn/native/d3d12/UtilsD3D12.h b/src/dawn/native/d3d12/UtilsD3D12.h index dcbe782cbe..9f8c1fa1db 100644 --- a/src/dawn/native/d3d12/UtilsD3D12.h +++ b/src/dawn/native/d3d12/UtilsD3D12.h @@ -18,6 +18,7 @@ #include #include "dawn/native/Commands.h" +#include "dawn/native/d3d/UtilsD3D.h" #include "dawn/native/d3d12/BufferD3D12.h" #include "dawn/native/d3d12/TextureCopySplitter.h" #include "dawn/native/d3d12/TextureD3D12.h" @@ -26,8 +27,6 @@ namespace dawn::native::d3d12 { -ResultOrError ConvertStringToWstring(std::string_view s); - D3D12_COMPARISON_FUNC ToD3D12ComparisonFunc(wgpu::CompareFunction func); D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, @@ -44,8 +43,6 @@ D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion( Aspect aspect); D3D12_BOX ComputeD3D12BoxFromOffsetAndSize(const Origin3D& offset, const Extent3D& copySize); -bool IsTypeless(DXGI_FORMAT format); - enum class BufferTextureCopyDirection { B2T, T2B, @@ -68,8 +65,6 @@ void RecordBufferTextureCopy(BufferTextureCopyDirection direction, void SetDebugName(Device* device, ID3D12Object* object, const char* prefix, std::string label = ""); -uint64_t MakeDXCVersion(uint64_t majorVersion, uint64_t minorVersion); - } // namespace dawn::native::d3d12 #endif // SRC_DAWN_NATIVE_D3D12_UTILSD3D12_H_