diff options
| author | Stenzek <stenzek@gmail.com> | 2019-03-09 23:31:35 +1000 |
|---|---|---|
| committer | Stenzek <stenzek@gmail.com> | 2019-03-29 19:52:38 +1000 |
| commit | ea15080d8f59a62ba347ff4c6037116035bc69b4 (patch) | |
| tree | 9f05be3e6fbafc9f5a7dadab45865f51eba034e5 /Source/Core | |
| parent | f6641b7e4fd666a620843f1a3b5d5117a1397f9c (diff) | |
Add D3DCommon (shared code between D3D11 and D3D12)
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/VideoBackends/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/Common.cpp | 320 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/Common.h | 46 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj | 68 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters | 13 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/Shader.cpp | 145 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/Shader.h | 33 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/SwapChain.cpp | 232 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/D3DCommon/SwapChain.h | 74 |
10 files changed, 947 insertions, 0 deletions
diff --git a/Source/Core/VideoBackends/CMakeLists.txt b/Source/Core/VideoBackends/CMakeLists.txt index e670dd7d4a..b53d85e10a 100644 --- a/Source/Core/VideoBackends/CMakeLists.txt +++ b/Source/Core/VideoBackends/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(Software) add_subdirectory(Vulkan) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + add_subdirectory(D3DCommon) add_subdirectory(D3D) endif() diff --git a/Source/Core/VideoBackends/D3DCommon/CMakeLists.txt b/Source/Core/VideoBackends/D3DCommon/CMakeLists.txt new file mode 100644 index 0000000000..ba24ba133f --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(videod3dcommon + Common.cpp + Common.h + Shader.cpp + Shader.h + SwapChain.cpp + SwapChain.h +) + +target_link_libraries(videod3dcommon +PUBLIC + common + videocommon + videod3dcommon +) diff --git a/Source/Core/VideoBackends/D3DCommon/Common.cpp b/Source/Core/VideoBackends/D3DCommon/Common.cpp new file mode 100644 index 0000000000..f82c2d3f8c --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Common.cpp @@ -0,0 +1,320 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include <d3d11.h> +#include <d3d12.h> +#include <dxgi1_3.h> +#include <wrl/client.h> + +#include "Common/Assert.h" +#include "Common/DynamicLibrary.h" +#include "Common/MsgHandler.h" +#include "Common/StringUtil.h" +#include "VideoBackends/D3DCommon/Common.h" +#include "VideoCommon/TextureConfig.h" +#include "VideoCommon/VideoConfig.h" + +namespace D3DCommon +{ +pD3DCompile d3d_compile; + +static Common::DynamicLibrary s_dxgi_library; +static Common::DynamicLibrary s_d3dcompiler_library; +static bool s_libraries_loaded = false; + +static HRESULT (*create_dxgi_factory)(REFIID riid, _COM_Outptr_ void** ppFactory); +static HRESULT (*create_dxgi_factory2)(UINT Flags, REFIID riid, void** ppFactory); + +bool LoadLibraries() +{ + if (s_libraries_loaded) + return true; + + if (!s_dxgi_library.Open("dxgi.dll")) + { + PanicAlertT("Failed to load dxgi.dll"); + return false; + } + + if (!s_d3dcompiler_library.Open(D3DCOMPILER_DLL_A)) + { + PanicAlertT("Failed to load %s. If you are using Windows 7, try installing the " + "KB4019990 update package.", + D3DCOMPILER_DLL_A); + s_dxgi_library.Close(); + return false; + } + + // Required symbols. + if (!s_d3dcompiler_library.GetSymbol("D3DCompile", &d3d_compile) || + !s_dxgi_library.GetSymbol("CreateDXGIFactory", &create_dxgi_factory)) + { + PanicAlertT("Failed to find one or more D3D symbols"); + s_d3dcompiler_library.Close(); + s_dxgi_library.Close(); + return false; + } + + // Optional symbols. + s_dxgi_library.GetSymbol("CreateDXGIFactory2", &create_dxgi_factory2); + s_libraries_loaded = true; + return true; +} + +void UnloadLibraries() +{ + create_dxgi_factory = nullptr; + create_dxgi_factory2 = nullptr; + d3d_compile = nullptr; + s_d3dcompiler_library.Close(); + s_dxgi_library.Close(); + s_libraries_loaded = false; +} + +IDXGIFactory2* CreateDXGIFactory(bool debug_device) +{ + IDXGIFactory2* factory; + + // Use Win8.1 version if available. + if (create_dxgi_factory2 && + SUCCEEDED(create_dxgi_factory2(debug_device ? DXGI_CREATE_FACTORY_DEBUG : 0, + IID_PPV_ARGS(&factory)))) + { + return factory; + } + + // Fallback to original version, without debug support. + HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(&factory)); + if (FAILED(hr)) + { + PanicAlert("CreateDXGIFactory() failed with HRESULT %08X", hr); + return nullptr; + } + + return factory; +} + +std::vector<std::string> GetAdapterNames() +{ + Microsoft::WRL::ComPtr<IDXGIFactory> factory; + HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(&factory)); + if (!SUCCEEDED(hr)) + return {}; + + std::vector<std::string> adapters; + IDXGIAdapter* adapter; + while (factory->EnumAdapters(static_cast<UINT>(adapters.size()), &adapter) != + DXGI_ERROR_NOT_FOUND) + { + std::string name; + DXGI_ADAPTER_DESC desc; + if (SUCCEEDED(adapter->GetDesc(&desc))) + name = UTF16ToUTF8(desc.Description); + + adapters.push_back(std::move(name)); + } + + return adapters; +} + +DXGI_FORMAT GetDXGIFormatForAbstractFormat(AbstractTextureFormat format, bool typeless) +{ + switch (format) + { + case AbstractTextureFormat::DXT1: + return DXGI_FORMAT_BC1_UNORM; + case AbstractTextureFormat::DXT3: + return DXGI_FORMAT_BC2_UNORM; + case AbstractTextureFormat::DXT5: + return DXGI_FORMAT_BC3_UNORM; + case AbstractTextureFormat::BPTC: + return DXGI_FORMAT_BC7_UNORM; + case AbstractTextureFormat::RGBA8: + return typeless ? DXGI_FORMAT_R8G8B8A8_TYPELESS : DXGI_FORMAT_R8G8B8A8_UNORM; + case AbstractTextureFormat::BGRA8: + return typeless ? DXGI_FORMAT_B8G8R8A8_TYPELESS : DXGI_FORMAT_B8G8R8A8_UNORM; + case AbstractTextureFormat::R16: + return typeless ? DXGI_FORMAT_R16_TYPELESS : DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::R32F: + return typeless ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R32_FLOAT; + case AbstractTextureFormat::D16: + return DXGI_FORMAT_R16_TYPELESS; + case AbstractTextureFormat::D24_S8: + return DXGI_FORMAT_R24G8_TYPELESS; + case AbstractTextureFormat::D32F: + return DXGI_FORMAT_R32_TYPELESS; + case AbstractTextureFormat::D32F_S8: + return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + default: + PanicAlert("Unhandled texture format."); + return DXGI_FORMAT_R8G8B8A8_UNORM; + } +} +DXGI_FORMAT GetSRVFormatForAbstractFormat(AbstractTextureFormat format) +{ + switch (format) + { + case AbstractTextureFormat::DXT1: + return DXGI_FORMAT_BC1_UNORM; + case AbstractTextureFormat::DXT3: + return DXGI_FORMAT_BC2_UNORM; + case AbstractTextureFormat::DXT5: + return DXGI_FORMAT_BC3_UNORM; + case AbstractTextureFormat::BPTC: + return DXGI_FORMAT_BC7_UNORM; + case AbstractTextureFormat::RGBA8: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case AbstractTextureFormat::BGRA8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case AbstractTextureFormat::R16: + return DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::R32F: + return DXGI_FORMAT_R32_FLOAT; + case AbstractTextureFormat::D16: + return DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::D24_S8: + return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + case AbstractTextureFormat::D32F: + return DXGI_FORMAT_R32_FLOAT; + case AbstractTextureFormat::D32F_S8: + return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + default: + PanicAlert("Unhandled SRV format"); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetRTVFormatForAbstractFormat(AbstractTextureFormat format, bool integer) +{ + switch (format) + { + case AbstractTextureFormat::RGBA8: + return integer ? DXGI_FORMAT_R8G8B8A8_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; + case AbstractTextureFormat::BGRA8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case AbstractTextureFormat::R16: + return integer ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::R32F: + return DXGI_FORMAT_R32_FLOAT; + default: + PanicAlert("Unhandled RTV format"); + return DXGI_FORMAT_UNKNOWN; + } +} +DXGI_FORMAT GetDSVFormatForAbstractFormat(AbstractTextureFormat format) +{ + switch (format) + { + case AbstractTextureFormat::D16: + return DXGI_FORMAT_D16_UNORM; + case AbstractTextureFormat::D24_S8: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case AbstractTextureFormat::D32F: + return DXGI_FORMAT_D32_FLOAT; + case AbstractTextureFormat::D32F_S8: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + default: + PanicAlert("Unhandled DSV format"); + return DXGI_FORMAT_UNKNOWN; + } +} + +AbstractTextureFormat GetAbstractFormatForDXGIFormat(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + return AbstractTextureFormat::RGBA8; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return AbstractTextureFormat::BGRA8; + + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_TYPELESS: + return AbstractTextureFormat::R16; + + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: + return AbstractTextureFormat::R32F; + + case DXGI_FORMAT_D16_UNORM: + return AbstractTextureFormat::D16; + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + return AbstractTextureFormat::D24_S8; + + case DXGI_FORMAT_D32_FLOAT: + return AbstractTextureFormat::D32F; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + return AbstractTextureFormat::D32F_S8; + + case DXGI_FORMAT_BC1_UNORM: + return AbstractTextureFormat::DXT1; + case DXGI_FORMAT_BC2_UNORM: + return AbstractTextureFormat::DXT3; + case DXGI_FORMAT_BC3_UNORM: + return AbstractTextureFormat::DXT5; + case DXGI_FORMAT_BC7_UNORM: + return AbstractTextureFormat::BPTC; + + default: + return AbstractTextureFormat::Undefined; + } +} + +void SetDebugObjectName(IUnknown* resource, const char* format, ...) +{ + if (!g_ActiveConfig.bEnableValidationLayer) + return; + + std::va_list ap; + va_start(ap, format); + std::string name = StringFromFormatV(format, ap); + va_end(ap); + + Microsoft::WRL::ComPtr<ID3D11DeviceChild> child11; + Microsoft::WRL::ComPtr<ID3D12DeviceChild> child12; + if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child11)))) + { + child11->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(name.length()), + name.c_str()); + } + else if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child12)))) + { + child12->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(name.length()), + name.c_str()); + } +} + +std::string GetDebugObjectName(IUnknown* resource) +{ + if (!g_ActiveConfig.bEnableValidationLayer) + return {}; + + std::string name; + UINT size = 0; + + Microsoft::WRL::ComPtr<ID3D11DeviceChild> child11; + Microsoft::WRL::ComPtr<ID3D12DeviceChild> child12; + if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child11)))) + { + child11->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); + name.resize(size); + child11->GetPrivateData(WKPDID_D3DDebugObjectName, &size, name.data()); + } + else if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child12)))) + { + child12->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); + name.resize(size); + child12->GetPrivateData(WKPDID_D3DDebugObjectName, &size, name.data()); + } + + return name; +} +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/Common.h b/Source/Core/VideoBackends/D3DCommon/Common.h new file mode 100644 index 0000000000..3fd5710b05 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Common.h @@ -0,0 +1,46 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include <d3dcompiler.h> +#include <dxgiformat.h> +#include <string> +#include <vector> + +#include "Common/CommonTypes.h" +#include "VideoCommon/VideoCommon.h" + +struct IDXGIFactory2; + +enum class AbstractTextureFormat : u32; + +namespace D3DCommon +{ +// Loading dxgi.dll and d3dcompiler.dll +bool LoadLibraries(); +void UnloadLibraries(); + +// Returns a list of D3D device names. +std::vector<std::string> GetAdapterNames(); + +// Helper function which creates a DXGI factory. +IDXGIFactory2* CreateDXGIFactory(bool debug_device); + +// Globally-accessible D3DCompiler function. +extern pD3DCompile d3d_compile; + +// Helpers for texture format conversion. +DXGI_FORMAT GetDXGIFormatForAbstractFormat(AbstractTextureFormat format, bool typeless); +DXGI_FORMAT GetSRVFormatForAbstractFormat(AbstractTextureFormat format); +DXGI_FORMAT GetRTVFormatForAbstractFormat(AbstractTextureFormat format, bool integer); +DXGI_FORMAT GetDSVFormatForAbstractFormat(AbstractTextureFormat format); +AbstractTextureFormat GetAbstractFormatForDXGIFormat(DXGI_FORMAT format); + +// This function will assign a name to the given resource. +// The DirectX debug layer will make it easier to identify resources that way, +// e.g. when listing up all resources who have unreleased references. +void SetDebugObjectName(IUnknown* resource, const char* format, ...); +std::string GetDebugObjectName(IUnknown* resource); +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj new file mode 100644 index 0000000000..7b94ad2b97 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{DEA96CF2-F237-4A1A-B32F-C916769EFB50}</ProjectGuid> + <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\..\VSProps\Base.props" /> + <Import Project="..\..\..\VSProps\PCHUse.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <ForcedIncludeFiles /> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <ForcedIncludeFiles /> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="Common.cpp" /> + <ClCompile Include="Shader.cpp" /> + <ClCompile Include="SwapChain.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Common.h" /> + <ClInclude Include="Shader.h" /> + <ClInclude Include="SwapChain.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="$(CoreDir)VideoCommon\VideoCommon.vcxproj"> + <Project>{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters new file mode 100644 index 0000000000..94fb9dd5a9 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="SwapChain.cpp" /> + <ClCompile Include="Common.cpp" /> + <ClCompile Include="Shader.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="SwapChain.h" /> + <ClInclude Include="Common.h" /> + <ClInclude Include="Shader.h" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Source/Core/VideoBackends/D3DCommon/Shader.cpp b/Source/Core/VideoBackends/D3DCommon/Shader.cpp new file mode 100644 index 0000000000..d53c5ab2e4 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Shader.cpp @@ -0,0 +1,145 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include <fstream> +#include <wrl/client.h> + +#include "Common/Assert.h" +#include "Common/FileUtil.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/StringUtil.h" + +#include "VideoBackends/D3DCommon/Shader.h" +#include "VideoCommon/VideoConfig.h" + +namespace D3DCommon +{ +Shader::Shader(ShaderStage stage, BinaryData bytecode) + : AbstractShader(stage), m_bytecode(std::move(bytecode)) +{ +} + +Shader::~Shader() = default; + +bool Shader::HasBinary() const +{ + return true; +} + +AbstractShader::BinaryData Shader::GetBinary() const +{ + return m_bytecode; +} + +static const char* GetCompileTarget(D3D_FEATURE_LEVEL feature_level, ShaderStage stage) +{ + switch (stage) + { + case ShaderStage::Vertex: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + return "vs_4_0"; + case D3D_FEATURE_LEVEL_10_1: + return "vs_4_1"; + default: + return "vs_5_0"; + } + } + + case ShaderStage::Geometry: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + return "gs_4_0"; + case D3D_FEATURE_LEVEL_10_1: + return "gs_4_1"; + default: + return "gs_5_0"; + } + } + + case ShaderStage::Pixel: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + return "ps_4_0"; + case D3D_FEATURE_LEVEL_10_1: + return "ps_4_1"; + default: + return "ps_5_0"; + } + } + + case ShaderStage::Compute: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_10_1: + return ""; + + default: + return "cs_5_0"; + } + } + + default: + return ""; + } +} + +bool Shader::CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode, + ShaderStage stage, const char* source, size_t length) +{ + static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}}; + const UINT flags = g_ActiveConfig.bEnableValidationLayer ? + (D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) : + (D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION); + const char* target = GetCompileTarget(feature_level, stage); + + Microsoft::WRL::ComPtr<ID3DBlob> code; + Microsoft::WRL::ComPtr<ID3DBlob> errors; + HRESULT hr = d3d_compile(source, length, nullptr, macros, nullptr, "main", target, flags, 0, + &code, &errors); + if (FAILED(hr)) + { + static int num_failures = 0; + std::string filename = StringFromFormat( + "%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++); + std::ofstream file; + File::OpenFStream(file, filename, std::ios_base::out); + file.write(source, length); + file << "\n"; + file.write(static_cast<const char*>(errors->GetBufferPointer()), errors->GetBufferSize()); + file.close(); + + PanicAlert("Failed to compile %s:\nDebug info (%s):\n%s", filename.c_str(), target, + static_cast<const char*>(errors->GetBufferPointer())); + return false; + } + + if (errors && errors->GetBufferSize() > 0) + { + WARN_LOG(VIDEO, "%s compilation succeeded with warnings:\n%s", target, + static_cast<const char*>(errors->GetBufferPointer())); + } + + out_bytecode->resize(code->GetBufferSize()); + std::memcpy(out_bytecode->data(), code->GetBufferPointer(), code->GetBufferSize()); + return true; +} + +AbstractShader::BinaryData Shader::CreateByteCode(const void* data, size_t length) +{ + BinaryData bytecode(length); + std::memcpy(bytecode.data(), data, length); + return bytecode; +} + +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/Shader.h b/Source/Core/VideoBackends/D3DCommon/Shader.h new file mode 100644 index 0000000000..6513cd11fe --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Shader.h @@ -0,0 +1,33 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once +#include <memory> +#include "VideoBackends/D3DCommon/Common.h" +#include "VideoCommon/AbstractShader.h" + +namespace D3DCommon +{ +class Shader : public AbstractShader +{ +public: + virtual ~Shader() override; + + const BinaryData& GetByteCode() const { return m_bytecode; } + + bool HasBinary() const override; + BinaryData GetBinary() const override; + + static bool CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode, + ShaderStage stage, const char* source, size_t length); + + static BinaryData CreateByteCode(const void* data, size_t length); + +protected: + Shader(ShaderStage stage, BinaryData bytecode); + + BinaryData m_bytecode; +}; + +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp new file mode 100644 index 0000000000..376f891a96 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp @@ -0,0 +1,232 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "VideoBackends/D3DCommon/SwapChain.h" + +#include <algorithm> +#include <cstdint> + +#include "Common/Assert.h" +#include "Common/CommonFuncs.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "VideoCommon/VideoConfig.h" + +static bool IsTearingSupported(IDXGIFactory2* dxgi_factory) +{ + Microsoft::WRL::ComPtr<IDXGIFactory5> factory5; + if (FAILED(dxgi_factory->QueryInterface(IID_PPV_ARGS(&factory5)))) + return false; + + UINT allow_tearing = 0; + return SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, + sizeof(allow_tearing))) && + allow_tearing != 0; +} + +static bool GetFullscreenState(IDXGISwapChain1* swap_chain) +{ + BOOL fs = FALSE; + return SUCCEEDED(swap_chain->GetFullscreenState(&fs, nullptr)) && fs; +} + +namespace D3DCommon +{ +SwapChain::SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, IUnknown* d3d_device) + : m_wsi(wsi), m_dxgi_factory(dxgi_factory), m_d3d_device(d3d_device), + m_allow_tearing_supported(IsTearingSupported(dxgi_factory)) +{ +} + +SwapChain::~SwapChain() +{ + // Can't destroy swap chain while it's fullscreen. + if (m_swap_chain && GetFullscreenState(m_swap_chain.Get())) + m_swap_chain->SetFullscreenState(FALSE, nullptr); +} + +bool SwapChain::WantsStereo() +{ + return g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer; +} + +u32 SwapChain::GetSwapChainFlags() const +{ + // This flag is necessary if we want to use a flip-model swapchain without locking the framerate + return m_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; +} + +bool SwapChain::CreateSwapChain(bool stereo) +{ + RECT client_rc; + if (GetClientRect(static_cast<HWND>(m_wsi.render_surface), &client_rc)) + { + m_width = client_rc.right - client_rc.left; + m_height = client_rc.bottom - client_rc.top; + } + + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; + swap_chain_desc.Width = m_width; + swap_chain_desc.Height = m_height; + swap_chain_desc.BufferCount = SWAP_CHAIN_BUFFER_COUNT; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.Format = GetDXGIFormatForAbstractFormat(m_texture_format, false); + swap_chain_desc.Scaling = DXGI_SCALING_STRETCH; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swap_chain_desc.Stereo = stereo; + swap_chain_desc.Flags = GetSwapChainFlags(); + + HRESULT hr = m_dxgi_factory->CreateSwapChainForHwnd( + m_d3d_device.Get(), static_cast<HWND>(m_wsi.render_surface), &swap_chain_desc, nullptr, + nullptr, &m_swap_chain); + if (FAILED(hr)) + { + // Flip-model discard swapchains aren't supported on Windows 8, so here we fall back to + // a sequential swapchain + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + hr = m_dxgi_factory->CreateSwapChainForHwnd(m_d3d_device.Get(), + static_cast<HWND>(m_wsi.render_surface), + &swap_chain_desc, nullptr, nullptr, &m_swap_chain); + } + + if (FAILED(hr)) + { + // Flip-model swapchains aren't supported on Windows 7, so here we fall back to a legacy + // BitBlt-model swapchain + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + hr = m_dxgi_factory->CreateSwapChainForHwnd(m_d3d_device.Get(), + static_cast<HWND>(m_wsi.render_surface), + &swap_chain_desc, nullptr, nullptr, &m_swap_chain); + } + + if (FAILED(hr)) + { + PanicAlert("Failed to create swap chain with HRESULT %08X", hr); + return false; + } + + // We handle fullscreen ourselves. + hr = m_dxgi_factory->MakeWindowAssociation(static_cast<HWND>(m_wsi.render_surface), + DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER); + if (FAILED(hr)) + WARN_LOG(VIDEO, "MakeWindowAssociation() failed with HRESULT %08X", hr); + + m_stereo = stereo; + if (!CreateSwapChainBuffers()) + { + PanicAlert("Failed to create swap chain buffers"); + DestroySwapChainBuffers(); + m_swap_chain.Reset(); + return false; + } + + return true; +} + +void SwapChain::DestroySwapChain() +{ + DestroySwapChainBuffers(); + + // Can't destroy swap chain while it's fullscreen. + if (m_swap_chain && GetFullscreenState(m_swap_chain.Get())) + m_swap_chain->SetFullscreenState(FALSE, nullptr); + + m_swap_chain.Reset(); +} + +bool SwapChain::ResizeSwapChain() +{ + DestroySwapChainBuffers(); + + HRESULT hr = m_swap_chain->ResizeBuffers(SWAP_CHAIN_BUFFER_COUNT, 0, 0, + GetDXGIFormatForAbstractFormat(m_texture_format, false), + GetSwapChainFlags()); + if (FAILED(hr)) + WARN_LOG(VIDEO, "ResizeBuffers() failed with HRESULT %08X", hr); + + DXGI_SWAP_CHAIN_DESC1 desc; + if (SUCCEEDED(m_swap_chain->GetDesc1(&desc))) + { + m_width = desc.Width; + m_height = desc.Height; + } + + return CreateSwapChainBuffers(); +} + +void SwapChain::SetStereo(bool stereo) +{ + if (m_stereo == stereo) + return; + + DestroySwapChain(); + if (!CreateSwapChain(stereo)) + { + PanicAlert("Failed to switch swap chain stereo mode"); + CreateSwapChain(false); + } +} + +bool SwapChain::GetFullscreen() const +{ + return GetFullscreenState(m_swap_chain.Get()); +} + +void SwapChain::SetFullscreen(bool request) +{ + m_swap_chain->SetFullscreenState(request, nullptr); +} + +bool SwapChain::CheckForFullscreenChange() +{ + if (m_fullscreen_request != m_has_fullscreen) + { + HRESULT hr = m_swap_chain->SetFullscreenState(m_fullscreen_request, nullptr); + if (SUCCEEDED(hr)) + { + m_has_fullscreen = m_fullscreen_request; + return true; + } + } + + const bool new_fullscreen_state = GetFullscreenState(m_swap_chain.Get()); + if (new_fullscreen_state != m_has_fullscreen) + { + m_has_fullscreen = new_fullscreen_state; + m_fullscreen_request = new_fullscreen_state; + return true; + } + + return false; +} + +bool SwapChain::Present() +{ + // When using sync interval 0, it is recommended to always pass the tearing flag when it is + // supported, even when presenting in windowed mode. However, this flag cannot be used if the app + // is in fullscreen mode as a result of calling SetFullscreenState. + UINT present_flags = 0; + if (m_allow_tearing_supported && !g_ActiveConfig.bVSyncActive && !m_has_fullscreen) + present_flags |= DXGI_PRESENT_ALLOW_TEARING; + + HRESULT hr = m_swap_chain->Present(static_cast<UINT>(g_ActiveConfig.bVSyncActive), present_flags); + if (FAILED(hr)) + { + WARN_LOG(VIDEO, "Swap chain present failed with HRESULT %08X", hr); + return false; + } + + return true; +} + +bool SwapChain::ChangeSurface(void* native_handle) +{ + DestroySwapChain(); + m_wsi.render_surface = native_handle; + return CreateSwapChain(m_stereo); +} + +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/SwapChain.h b/Source/Core/VideoBackends/D3DCommon/SwapChain.h new file mode 100644 index 0000000000..b84c1a95c3 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/SwapChain.h @@ -0,0 +1,74 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include <dxgi1_5.h> +#include <wrl/client.h> + +#include "Common/CommonTypes.h" +#include "Common/WindowSystemInfo.h" +#include "VideoBackends/D3DCommon/Common.h" +#include "VideoCommon/TextureConfig.h" + +namespace D3DCommon +{ +class SwapChain +{ +public: + SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, IUnknown* d3d_device); + virtual ~SwapChain(); + + // Sufficient buffers for triple buffering. + static const u32 SWAP_CHAIN_BUFFER_COUNT = 3; + + // Returns true if the stereo mode is quad-buffering. + static bool WantsStereo(); + + IDXGISwapChain1* GetDXGISwapChain() const { return m_swap_chain.Get(); } + AbstractTextureFormat GetFormat() const { return m_texture_format; } + u32 GetWidth() const { return m_width; } + u32 GetHeight() const { return m_height; } + u32 GetLayers() const { return m_stereo ? 2u : 1u; } + bool IsStereoEnabled() const { return m_stereo; } + bool HasExclusiveFullscreen() const { return m_has_fullscreen; } + + // Mode switches. + bool GetFullscreen() const; + void SetFullscreen(bool request); + + // Checks for loss of exclusive fullscreen. + bool CheckForFullscreenChange(); + + // Presents the swap chain to the screen. + virtual bool Present(); + + bool ChangeSurface(void* native_handle); + bool ResizeSwapChain(); + void SetStereo(bool stereo); + +protected: + u32 GetSwapChainFlags() const; + bool CreateSwapChain(bool stereo); + void DestroySwapChain(); + + virtual bool CreateSwapChainBuffers() = 0; + virtual void DestroySwapChainBuffers() = 0; + + WindowSystemInfo m_wsi; + Microsoft::WRL::ComPtr<IDXGIFactory2> m_dxgi_factory; + Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swap_chain; + Microsoft::WRL::ComPtr<IUnknown> m_d3d_device; + AbstractTextureFormat m_texture_format = AbstractTextureFormat::RGBA8; + + u32 m_width = 1; + u32 m_height = 1; + + bool m_stereo = false; + bool m_allow_tearing_supported = false; + bool m_has_fullscreen = false; + bool m_fullscreen_request = false; +}; + +} // namespace D3DCommon |
