summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2019-03-09 23:31:35 +1000
committerStenzek <stenzek@gmail.com>2019-03-29 19:52:38 +1000
commitea15080d8f59a62ba347ff4c6037116035bc69b4 (patch)
tree9f05be3e6fbafc9f5a7dadab45865f51eba034e5 /Source/Core
parentf6641b7e4fd666a620843f1a3b5d5117a1397f9c (diff)
Add D3DCommon (shared code between D3D11 and D3D12)
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/VideoBackends/CMakeLists.txt1
-rw-r--r--Source/Core/VideoBackends/D3DCommon/CMakeLists.txt15
-rw-r--r--Source/Core/VideoBackends/D3DCommon/Common.cpp320
-rw-r--r--Source/Core/VideoBackends/D3DCommon/Common.h46
-rw-r--r--Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj68
-rw-r--r--Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters13
-rw-r--r--Source/Core/VideoBackends/D3DCommon/Shader.cpp145
-rw-r--r--Source/Core/VideoBackends/D3DCommon/Shader.h33
-rw-r--r--Source/Core/VideoBackends/D3DCommon/SwapChain.cpp232
-rw-r--r--Source/Core/VideoBackends/D3DCommon/SwapChain.h74
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