mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Vendored
+1553
File diff suppressed because it is too large
Load Diff
Vendored
+2
@@ -6,6 +6,8 @@ Dolphin includes or links code of the following third-party software projects:
|
||||
[LGPLv2.1+](https://git.kernel.org/cgit/bluetooth/bluez.git/tree/COPYING.LIB)
|
||||
- [Bochs](http://bochs.sourceforge.net/):
|
||||
[LGPLv2.1+](http://bochs.sourceforge.net/cgi-bin/lxr/source/COPYING)
|
||||
- [d3dx12.h](https://github.com/Microsoft/DirectX-Graphics-Samples/blob/master/Samples/D3D1211On12/src/d3dx12.h):
|
||||
[MIT](https://github.com/Microsoft/DirectX-Graphics-Samples/blob/master/LICENSE)
|
||||
- [ENet](http://enet.bespin.org/):
|
||||
[MIT](http://enet.bespin.org/License.html)
|
||||
- [GCEmu](http://sourceforge.net/projects/gcemu-project/):
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
// Helper functions:
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
template <typename T>
|
||||
static inline int CountSetBits(T v)
|
||||
{
|
||||
|
||||
@@ -233,6 +233,9 @@
|
||||
<ProjectReference Include="$(CoreDir)VideoCommon\VideoCommon.vcxproj">
|
||||
<Project>{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(CoreDir)VideoBackends\D3D12\D3D12.vcxproj">
|
||||
<Project>{570215b7-e32f-4438-95ae-c8d955f9fca3}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -532,7 +532,7 @@ void Host_ConnectWiimote(int wm_idx, bool connect)
|
||||
void Host_ShowVideoConfig(void* parent, const std::string& backend_name,
|
||||
const std::string& config_name)
|
||||
{
|
||||
if (backend_name == "Direct3D" || backend_name == "OpenGL")
|
||||
if (backend_name == "Direct3D" || backend_name == "Direct3D 12 (experimental)" || backend_name == "OpenGL")
|
||||
{
|
||||
VideoConfigDiag diag((wxWindow*)parent, backend_name, config_name);
|
||||
diag.ShowModal();
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "VideoBackends/D3D12/BoundingBox.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
// D3D12TODO: Support bounding box behavior.
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
ID3D11UnorderedAccessView* BBox::GetUAV()
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BBox::Init()
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
}
|
||||
}
|
||||
|
||||
void BBox::Shutdown()
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
}
|
||||
|
||||
void BBox::Set(int index, int value)
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
}
|
||||
|
||||
int BBox::Get(int index)
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
class BBox
|
||||
{
|
||||
public:
|
||||
static ID3D11UnorderedAccessView* GetUAV();
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static void Set(int index, int value);
|
||||
static int Get(int index);
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
<?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>{570215B7-E32F-4438-95AE-C8D955F9FCA3}</ProjectGuid>
|
||||
<WindowsTargetPlatformVersion>10.0.10240.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v140</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="BoundingBox.cpp" />
|
||||
<ClCompile Include="D3DBase.cpp" />
|
||||
<ClCompile Include="D3DCommandListManager.cpp" />
|
||||
<ClCompile Include="D3DDescriptorHeapManager.cpp" />
|
||||
<ClCompile Include="D3DQueuedCommandList.cpp" />
|
||||
<ClCompile Include="D3DShader.cpp" />
|
||||
<ClCompile Include="D3DState.cpp" />
|
||||
<ClCompile Include="D3DStreamBuffer.cpp" />
|
||||
<ClCompile Include="D3DTexture.cpp" />
|
||||
<ClCompile Include="D3DUtil.cpp" />
|
||||
<ClCompile Include="FramebufferManager.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="NativeVertexFormat.cpp" />
|
||||
<ClCompile Include="PerfQuery.cpp" />
|
||||
<ClCompile Include="PSTextureEncoder.cpp" />
|
||||
<ClCompile Include="Render.cpp" />
|
||||
<ClCompile Include="ShaderCache.cpp" />
|
||||
<ClCompile Include="ShaderConstantsManager.cpp" />
|
||||
<ClCompile Include="StaticShaderCache.cpp" />
|
||||
<ClCompile Include="Television.cpp" />
|
||||
<ClCompile Include="TextureCache.cpp" />
|
||||
<ClCompile Include="VertexManager.cpp" />
|
||||
<ClCompile Include="XFBEncoder.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BoundingBox.h" />
|
||||
<ClInclude Include="D3DBase.h" />
|
||||
<ClInclude Include="D3DCommandListManager.h" />
|
||||
<ClInclude Include="D3DDescriptorHeapManager.h" />
|
||||
<ClInclude Include="D3DQueuedCommandList.h" />
|
||||
<ClInclude Include="D3DShader.h" />
|
||||
<ClInclude Include="D3DState.h" />
|
||||
<ClInclude Include="D3DStreamBuffer.h" />
|
||||
<ClInclude Include="D3DTexture.h" />
|
||||
<ClInclude Include="D3DUtil.h" />
|
||||
<ClInclude Include="FramebufferManager.h" />
|
||||
<ClInclude Include="NativeVertexFormat.h" />
|
||||
<ClInclude Include="PerfQuery.h" />
|
||||
<ClInclude Include="PSTextureEncoder.h" />
|
||||
<ClInclude Include="Render.h" />
|
||||
<ClInclude Include="ShaderCache.h" />
|
||||
<ClInclude Include="ShaderConstantsManager.h" />
|
||||
<ClInclude Include="StaticShaderCache.h" />
|
||||
<ClInclude Include="Television.h" />
|
||||
<ClInclude Include="TextureCache.h" />
|
||||
<ClInclude Include="TextureEncoder.h" />
|
||||
<ClInclude Include="VertexManager.h" />
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
<ClInclude Include="XFBEncoder.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>
|
||||
@@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Render">
|
||||
<UniqueIdentifier>{3683d29b-19f6-4e7a-803f-4ac70b1d49fd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="D3D12">
|
||||
<UniqueIdentifier>{ae700f7e-33c8-45b5-b7ee-a0ded3630549}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="D3DBase.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DShader.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DTexture.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DUtil.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DState.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FramebufferManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NativeVertexFormat.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PerfQuery.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PSTextureEncoder.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Render.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Television.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextureCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VertexManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XFBEncoder.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="BoundingBox.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DCommandListManager.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DDescriptorHeapManager.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DQueuedCommandList.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StaticShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ShaderConstantsManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="D3DStreamBuffer.cpp">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="D3DBase.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DShader.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DTexture.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DUtil.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DState.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FramebufferManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PerfQuery.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PSTextureEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Render.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Television.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VertexManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="XFBEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
<ClInclude Include="BoundingBox.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DCommandListManager.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DDescriptorHeapManager.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NativeVertexFormat.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DQueuedCommandList.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StaticShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ShaderConstantsManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="D3DStreamBuffer.h">
|
||||
<Filter>D3D12</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,158 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#define USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
|
||||
// D3D12TODO: Support this from Graphics Settings, not require a recompile to enable.
|
||||
//#define USE_D3D12_DEBUG_LAYER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <dxgi1_4.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../../Externals/d3dx12/d3dx12.h"
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = nullptr; }
|
||||
#define SAFE_DELETE(x) { delete (x); (x) = nullptr; }
|
||||
#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = nullptr; }
|
||||
#define CHECK(cond, Message, ...) if (!(cond)) { __debugbreak(); PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); }
|
||||
|
||||
// DEBUGCHECK is for high-frequency functions that we only want to check on debug builds.
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define DEBUGCHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); }
|
||||
#else
|
||||
#define DEBUGCHECK(cond, Message, ...)
|
||||
#endif
|
||||
|
||||
inline void CheckHR(HRESULT hr)
|
||||
{
|
||||
CHECK(SUCCEEDED(hr), "Failed HRESULT.");
|
||||
}
|
||||
|
||||
class D3DCommandListManager;
|
||||
class D3DDescriptorHeapManager;
|
||||
class D3DTexture2D;
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
#define DESCRIPTOR_TABLE_PS_SRV 0
|
||||
#define DESCRIPTOR_TABLE_PS_SAMPLER 1
|
||||
#define DESCRIPTOR_TABLE_GS_CBV 2
|
||||
#define DESCRIPTOR_TABLE_VS_CBV 3
|
||||
// #define DESCRIPTOR_TABLE_PS_UAV 4
|
||||
#define DESCRIPTOR_TABLE_PS_CBVONE 4
|
||||
#define DESCRIPTOR_TABLE_PS_CBVTWO 5
|
||||
|
||||
HRESULT LoadDXGI();
|
||||
HRESULT LoadD3D();
|
||||
HRESULT LoadD3DCompiler();
|
||||
void UnloadDXGI();
|
||||
void UnloadD3D();
|
||||
void UnloadD3DCompiler();
|
||||
|
||||
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter);
|
||||
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter);
|
||||
|
||||
bool AlertUserIfSelectedAdapterDoesNotSupportD3D12();
|
||||
|
||||
HRESULT Create(HWND wnd);
|
||||
|
||||
void CreateDescriptorHeaps();
|
||||
void CreateRootSignatures();
|
||||
|
||||
void WaitForOutstandingRenderingToComplete();
|
||||
void Close();
|
||||
|
||||
extern ID3D12Device* device12;
|
||||
|
||||
extern unsigned int resource_descriptor_size;
|
||||
extern unsigned int sampler_descriptor_size;
|
||||
extern D3DDescriptorHeapManager* gpu_descriptor_heap_mgr;
|
||||
extern D3DDescriptorHeapManager* sampler_descriptor_heap_mgr;
|
||||
extern D3DDescriptorHeapManager* dsv_descriptor_heap_mgr;
|
||||
extern D3DDescriptorHeapManager* rtv_descriptor_heap_mgr;
|
||||
extern std::array<ID3D12DescriptorHeap*, 2> gpu_descriptor_heaps;
|
||||
|
||||
|
||||
extern D3D12_CPU_DESCRIPTOR_HANDLE null_srv_cpu;
|
||||
extern D3D12_CPU_DESCRIPTOR_HANDLE null_srv_cpu_shadow;
|
||||
|
||||
extern D3DCommandListManager* command_list_mgr;
|
||||
extern ID3D12GraphicsCommandList* current_command_list;
|
||||
|
||||
extern ID3D12RootSignature* default_root_signature;
|
||||
|
||||
extern HWND hWnd;
|
||||
|
||||
void Reset();
|
||||
bool BeginFrame();
|
||||
void EndFrame();
|
||||
void Present();
|
||||
|
||||
unsigned int GetBackBufferWidth();
|
||||
unsigned int GetBackBufferHeight();
|
||||
D3DTexture2D*& GetBackBuffer();
|
||||
const std::string PixelShaderVersionString();
|
||||
const std::string GeometryShaderVersionString();
|
||||
const std::string VertexShaderVersionString();
|
||||
|
||||
unsigned int GetMaxTextureSize();
|
||||
|
||||
HRESULT SetFullscreenState(bool enable_fullscreen);
|
||||
HRESULT GetFullscreenState(bool* fullscreen_state);
|
||||
|
||||
// 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.
|
||||
static void SetDebugObjectName12(ID3D12Resource* resource, LPCSTR name)
|
||||
{
|
||||
HRESULT hr = resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
throw std::exception("Failure setting name for D3D12 object");
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GetDebugObjectName12(ID3D12Resource* resource)
|
||||
{
|
||||
std::string name;
|
||||
if (resource)
|
||||
{
|
||||
UINT size = 0;
|
||||
resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); //get required size
|
||||
name.resize(size);
|
||||
resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast<char*>(name.data()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace D3D
|
||||
|
||||
using CREATEDXGIFACTORY = HRESULT(WINAPI*)(REFIID, void**);
|
||||
extern CREATEDXGIFACTORY create_dxgi_factory;
|
||||
|
||||
using D3D12CREATEDEVICE = HRESULT(WINAPI*)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**);
|
||||
using D3D12SERIALIZEROOTSIGNATURE = HRESULT(WINAPI*)(const D3D12_ROOT_SIGNATURE_DESC* pRootSignature, D3D_ROOT_SIGNATURE_VERSION Version, ID3DBlob** ppBlob, ID3DBlob** ppErrorBlob);
|
||||
using D3D12GETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID riid, void** ppvDebug);
|
||||
|
||||
using D3DREFLECT = HRESULT(WINAPI*)(LPCVOID, SIZE_T, REFIID, void**);
|
||||
extern D3DREFLECT d3d_reflect;
|
||||
|
||||
using D3DCREATEBLOB = HRESULT(WINAPI*)(SIZE_T, ID3DBlob**);
|
||||
extern D3DCREATEBLOB d3d_create_blob;
|
||||
|
||||
extern pD3DCompile d3d_compile;
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,355 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DCommandListManager.h"
|
||||
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
|
||||
#include "VideoBackends/D3D12/D3DQueuedCommandList.h"
|
||||
#include "VideoBackends/D3D12/D3DState.h"
|
||||
#include "VideoBackends/D3D12/D3DTexture.h"
|
||||
|
||||
#include "VideoBackends/D3D12/Render.h"
|
||||
#include "VideoBackends/D3D12/ShaderConstantsManager.h"
|
||||
#include "VideoBackends/D3D12/VertexManager.h"
|
||||
|
||||
static constexpr unsigned int COMMAND_ALLOCATORS_PER_LIST = 2;
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
extern StateCache gx_state_cache;
|
||||
|
||||
D3DCommandListManager::D3DCommandListManager(
|
||||
D3D12_COMMAND_LIST_TYPE command_list_type,
|
||||
ID3D12Device* device,
|
||||
ID3D12CommandQueue* command_queue
|
||||
) :
|
||||
m_device(device),
|
||||
m_command_queue(command_queue)
|
||||
{
|
||||
// Create two lists, with two command allocators each. This corresponds to up to two frames in flight at once.
|
||||
m_current_command_allocator = 0;
|
||||
m_current_command_allocator_list = 0;
|
||||
for (UINT i = 0; i < COMMAND_ALLOCATORS_PER_LIST; i++)
|
||||
{
|
||||
for (UINT j = 0; j < m_command_allocator_lists.size(); j++)
|
||||
{
|
||||
ID3D12CommandAllocator* command_allocator = nullptr;
|
||||
|
||||
CheckHR(m_device->CreateCommandAllocator(command_list_type, IID_PPV_ARGS(&command_allocator)));
|
||||
m_command_allocator_lists[j].push_back(command_allocator);
|
||||
}
|
||||
}
|
||||
|
||||
// Create backing command list.
|
||||
CheckHR(m_device->CreateCommandList(0, command_list_type, m_command_allocator_lists[m_current_command_allocator_list][0], nullptr, IID_PPV_ARGS(&m_backing_command_list)));
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
m_queued_command_list = new ID3D12QueuedCommandList(m_backing_command_list, m_command_queue);
|
||||
#endif
|
||||
|
||||
// Create fence that will be used to measure GPU progress of app rendering requests (e.g. CPU readback of GPU data).
|
||||
m_queue_fence_value = 0;
|
||||
CheckHR(m_device->CreateFence(m_queue_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_queue_fence)));
|
||||
|
||||
// Create fence that will be used internally by D3DCommandListManager for frame-level resource tracking.
|
||||
m_queue_frame_fence_value = 0;
|
||||
CheckHR(m_device->CreateFence(m_queue_frame_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_queue_frame_fence)));
|
||||
|
||||
// Create event that will be used for waiting on CPU until a fence is signaled by GPU.
|
||||
m_wait_on_cpu_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
|
||||
// Pre-size the deferred destruction lists.
|
||||
for (UINT i = 0; i < m_deferred_destruction_lists.size(); i++)
|
||||
{
|
||||
m_deferred_destruction_lists[i].reserve(200);
|
||||
}
|
||||
|
||||
m_current_deferred_destruction_list = 0;
|
||||
}
|
||||
|
||||
void D3DCommandListManager::SetInitialCommandListState()
|
||||
{
|
||||
ID3D12GraphicsCommandList* command_list = nullptr;
|
||||
GetCommandList(&command_list);
|
||||
|
||||
command_list->SetDescriptorHeaps(static_cast<unsigned int>(D3D::gpu_descriptor_heaps.size()), D3D::gpu_descriptor_heaps.data());
|
||||
command_list->SetGraphicsRootSignature(D3D::default_root_signature);
|
||||
|
||||
if (g_renderer)
|
||||
{
|
||||
// It is possible that we change command lists in the middle of the frame. In that case, restore
|
||||
// the viewport/scissor to the current console GPU state.
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
m_command_list_dirty_state = UINT_MAX;
|
||||
|
||||
command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
m_command_list_current_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
|
||||
if (g_vertex_manager)
|
||||
reinterpret_cast<VertexManager*>(g_vertex_manager.get())->SetIndexBuffer();
|
||||
}
|
||||
|
||||
void D3DCommandListManager::GetCommandList(ID3D12GraphicsCommandList** command_list) const
|
||||
{
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
*command_list = this->m_queued_command_list;
|
||||
#else
|
||||
*command_list = this->m_backing_command_list;
|
||||
#endif
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ExecuteQueuedWork(bool wait_for_gpu_completion)
|
||||
{
|
||||
m_queue_fence_value++;
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
CheckHR(m_queued_command_list->Close());
|
||||
m_queued_command_list->QueueExecute();
|
||||
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
|
||||
|
||||
ResetCommandListWithIdleCommandAllocator();
|
||||
|
||||
m_queued_command_list->ProcessQueuedItems();
|
||||
#else
|
||||
CheckHR(m_backing_command_list->Close());
|
||||
|
||||
ID3D12CommandList* const commandListsToExecute[1] = { m_backing_command_list };
|
||||
m_command_queue->ExecuteCommandLists(1, commandListsToExecute);
|
||||
|
||||
if (wait_for_gpu_completion)
|
||||
{
|
||||
CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value));
|
||||
}
|
||||
|
||||
if (m_current_command_allocator == 0)
|
||||
{
|
||||
PerformGpuRolloverChecks();
|
||||
}
|
||||
|
||||
ResetCommandListWithIdleCommandAllocator();
|
||||
#endif
|
||||
|
||||
for (auto it : m_queue_fence_callbacks)
|
||||
it.second(it.first, m_queue_fence_value);
|
||||
|
||||
SetInitialCommandListState();
|
||||
|
||||
if (wait_for_gpu_completion)
|
||||
{
|
||||
WaitOnCPUForFence(m_queue_fence, m_queue_fence_value);
|
||||
}
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags)
|
||||
{
|
||||
m_queue_fence_value++;
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
CheckHR(m_queued_command_list->Close());
|
||||
m_queued_command_list->QueueExecute();
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
|
||||
m_queued_command_list->QueuePresent(swap_chain, sync_interval, flags);
|
||||
m_queued_command_list->ProcessQueuedItems(true);
|
||||
|
||||
if (m_current_command_allocator == 0)
|
||||
{
|
||||
PerformGpuRolloverChecks();
|
||||
}
|
||||
|
||||
m_current_command_allocator = (m_current_command_allocator + 1) % m_command_allocator_lists[m_current_command_allocator_list].size();
|
||||
|
||||
ResetCommandListWithIdleCommandAllocator();
|
||||
|
||||
SetInitialCommandListState();
|
||||
#else
|
||||
ExecuteQueuedWork();
|
||||
m_command_queue->Signal(m_queue_fence, m_queue_fence_value);
|
||||
CheckHR(swap_chain->Present(sync_interval, flags));
|
||||
#endif
|
||||
|
||||
for (auto it : m_queue_fence_callbacks)
|
||||
it.second(it.first, m_queue_fence_value);
|
||||
}
|
||||
|
||||
void D3DCommandListManager::WaitForQueuedWorkToBeExecutedOnGPU()
|
||||
{
|
||||
// Wait for GPU to finish all outstanding work.
|
||||
m_queue_fence_value++;
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
m_queued_command_list->QueueExecute();
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
|
||||
|
||||
m_queued_command_list->ProcessQueuedItems(true);
|
||||
#else
|
||||
CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value));
|
||||
#endif
|
||||
|
||||
WaitOnCPUForFence(m_queue_fence, m_queue_fence_value);
|
||||
}
|
||||
|
||||
void D3DCommandListManager::PerformGpuRolloverChecks()
|
||||
{
|
||||
// Insert fence to measure GPU progress, ensure we aren't using in-use command allocators.
|
||||
if (m_queue_frame_fence->GetCompletedValue() < m_queue_frame_fence_value)
|
||||
{
|
||||
WaitOnCPUForFence(m_queue_frame_fence, m_queue_frame_fence_value);
|
||||
}
|
||||
|
||||
// We now know that the previous 'set' of command lists has completed on GPU, and it is safe to
|
||||
// release resources / start back at beginning of command allocator list.
|
||||
|
||||
// Begin Deferred Resource Destruction
|
||||
UINT safe_to_delete_deferred_destruction_list = (m_current_deferred_destruction_list - 1) % m_deferred_destruction_lists.size();
|
||||
|
||||
for (UINT i = 0; i < m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list].size(); i++)
|
||||
{
|
||||
CHECK(m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list][i]->Release() == 0, "Resource leak.");
|
||||
}
|
||||
|
||||
m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list].clear();
|
||||
|
||||
m_current_deferred_destruction_list = (m_current_deferred_destruction_list + 1) % m_deferred_destruction_lists.size();
|
||||
// End Deferred Resource Destruction
|
||||
|
||||
|
||||
// Begin Command Allocator Resets
|
||||
UINT safe_to_reset_command_allocator_list = (m_current_command_allocator_list - 1) % m_command_allocator_lists.size();
|
||||
|
||||
for (UINT i = 0; i < m_command_allocator_lists[safe_to_reset_command_allocator_list].size(); i++)
|
||||
{
|
||||
CheckHR(m_command_allocator_lists[safe_to_reset_command_allocator_list][i]->Reset());
|
||||
}
|
||||
|
||||
m_current_command_allocator_list = (m_current_command_allocator_list + 1) % m_command_allocator_lists.size();
|
||||
// End Command Allocator Resets
|
||||
|
||||
m_queue_frame_fence_value++;
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_frame_fence, m_queue_frame_fence_value);
|
||||
#else
|
||||
CheckHR(m_command_queue->Signal(m_queue_frame_fence, m_queue_frame_fence_value));
|
||||
#endif
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ResetCommandListWithIdleCommandAllocator()
|
||||
{
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
ID3D12QueuedCommandList* command_list = m_queued_command_list;
|
||||
#else
|
||||
ID3D12GraphicsCommandList* command_list = m_backing_command_list;
|
||||
#endif
|
||||
|
||||
CheckHR(command_list->Reset(m_command_allocator_lists[m_current_command_allocator_list][m_current_command_allocator], nullptr));
|
||||
}
|
||||
|
||||
void D3DCommandListManager::DestroyResourceAfterCurrentCommandListExecuted(ID3D12Resource* resource)
|
||||
{
|
||||
CHECK(resource, "Null resource being inserted!");
|
||||
|
||||
m_deferred_destruction_lists[m_current_deferred_destruction_list].push_back(resource);
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ImmediatelyDestroyAllResourcesScheduledForDestruction()
|
||||
{
|
||||
for (auto& destruction_list : m_deferred_destruction_lists)
|
||||
{
|
||||
for (auto& resource : destruction_list)
|
||||
resource->Release();
|
||||
|
||||
destruction_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void D3DCommandListManager::ClearQueueAndWaitForCompletionOfInflightWork()
|
||||
{
|
||||
// Wait for GPU to finish all outstanding work.
|
||||
m_queue_fence_value++;
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
m_queued_command_list->ClearQueue(); // Waits for currently-processing work to finish, then clears queue.
|
||||
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
|
||||
m_queued_command_list->ProcessQueuedItems(true);
|
||||
#else
|
||||
CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value));
|
||||
#endif
|
||||
WaitOnCPUForFence(m_queue_fence, m_queue_fence_value);
|
||||
}
|
||||
|
||||
D3DCommandListManager::~D3DCommandListManager()
|
||||
{
|
||||
ImmediatelyDestroyAllResourcesScheduledForDestruction();
|
||||
|
||||
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
|
||||
m_queued_command_list->Release();
|
||||
#endif
|
||||
m_backing_command_list->Release();
|
||||
|
||||
for (auto& allocator_list : m_command_allocator_lists)
|
||||
{
|
||||
for (auto& resource : allocator_list)
|
||||
resource->Release();
|
||||
}
|
||||
|
||||
m_queue_fence->Release();
|
||||
m_queue_frame_fence->Release();
|
||||
|
||||
CloseHandle(m_wait_on_cpu_fence_event);
|
||||
}
|
||||
|
||||
void D3DCommandListManager::WaitOnCPUForFence(ID3D12Fence* fence, UINT64 fence_value)
|
||||
{
|
||||
CheckHR(fence->SetEventOnCompletion(fence_value, m_wait_on_cpu_fence_event));
|
||||
|
||||
WaitForSingleObject(m_wait_on_cpu_fence_event, INFINITE);
|
||||
}
|
||||
|
||||
void D3DCommandListManager::SetCommandListDirtyState(unsigned int command_list_state, bool dirty)
|
||||
{
|
||||
if (dirty)
|
||||
m_command_list_dirty_state |= command_list_state;
|
||||
else
|
||||
m_command_list_dirty_state &= ~command_list_state;
|
||||
}
|
||||
|
||||
bool D3DCommandListManager::GetCommandListDirtyState(COMMAND_LIST_STATE command_list_state) const
|
||||
{
|
||||
return ((m_command_list_dirty_state & command_list_state) != 0);
|
||||
}
|
||||
|
||||
void D3DCommandListManager::SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY primitive_topology)
|
||||
{
|
||||
m_command_list_current_topology = primitive_topology;
|
||||
}
|
||||
|
||||
D3D_PRIMITIVE_TOPOLOGY D3DCommandListManager::GetCommandListPrimitiveTopology() const
|
||||
{
|
||||
return m_command_list_current_topology;
|
||||
}
|
||||
|
||||
void D3DCommandListManager::CPUAccessNotify()
|
||||
{
|
||||
m_cpu_access_last_frame = true;
|
||||
m_cpu_access_this_frame = true;
|
||||
m_draws_since_last_execution = 0;
|
||||
};
|
||||
|
||||
ID3D12Fence* D3DCommandListManager::RegisterQueueFenceCallback(void* owning_object, PFN_QUEUE_FENCE_CALLBACK* callback_function)
|
||||
{
|
||||
m_queue_fence_callbacks[owning_object] = callback_function;
|
||||
|
||||
return m_queue_fence;
|
||||
}
|
||||
|
||||
void D3DCommandListManager::RemoveQueueFenceCallback(void* owning_object)
|
||||
{
|
||||
m_queue_fence_callbacks.erase(owning_object);
|
||||
}
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "D3DQueuedCommandList.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
enum COMMAND_LIST_STATE
|
||||
{
|
||||
COMMAND_LIST_STATE_GS_CBV = 1,
|
||||
COMMAND_LIST_STATE_PS_CBV = 2,
|
||||
COMMAND_LIST_STATE_VS_CBV = 4,
|
||||
COMMAND_LIST_STATE_PSO = 8,
|
||||
COMMAND_LIST_STATE_SAMPLERS = 16,
|
||||
COMMAND_LIST_STATE_VERTEX_BUFFER = 32
|
||||
};
|
||||
|
||||
// This class provides an abstraction for D3D12 descriptor heaps.
|
||||
class D3DCommandListManager
|
||||
{
|
||||
public:
|
||||
|
||||
D3DCommandListManager(D3D12_COMMAND_LIST_TYPE command_list_type, ID3D12Device* device, ID3D12CommandQueue* command_queue);
|
||||
~D3DCommandListManager();
|
||||
|
||||
void SetInitialCommandListState();
|
||||
|
||||
void GetCommandList(ID3D12GraphicsCommandList** command_list) const;
|
||||
|
||||
void ExecuteQueuedWork(bool wait_for_gpu_completion = false);
|
||||
void ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags);
|
||||
|
||||
void WaitForQueuedWorkToBeExecutedOnGPU();
|
||||
|
||||
void ClearQueueAndWaitForCompletionOfInflightWork();
|
||||
void DestroyResourceAfterCurrentCommandListExecuted(ID3D12Resource* resource);
|
||||
void ImmediatelyDestroyAllResourcesScheduledForDestruction();
|
||||
|
||||
void SetCommandListDirtyState(unsigned int command_list_state, bool dirty);
|
||||
bool GetCommandListDirtyState(COMMAND_LIST_STATE command_list_state) const;
|
||||
|
||||
void SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY primitive_topology);
|
||||
D3D_PRIMITIVE_TOPOLOGY GetCommandListPrimitiveTopology() const;
|
||||
|
||||
unsigned int m_draws_since_last_execution = 0;
|
||||
bool m_cpu_access_last_frame = false;
|
||||
bool m_cpu_access_this_frame = false;
|
||||
|
||||
void CPUAccessNotify();
|
||||
|
||||
// Allow other components to register for a callback each time a fence is queued.
|
||||
using PFN_QUEUE_FENCE_CALLBACK = void(void* owning_object, UINT64 fence_value);
|
||||
ID3D12Fence* RegisterQueueFenceCallback(void* owning_object, PFN_QUEUE_FENCE_CALLBACK* callback_function);
|
||||
void RemoveQueueFenceCallback(void* owning_object);
|
||||
|
||||
void WaitOnCPUForFence(ID3D12Fence* fence, UINT64 fence_value);
|
||||
|
||||
private:
|
||||
|
||||
void PerformGpuRolloverChecks();
|
||||
void ResetCommandListWithIdleCommandAllocator();
|
||||
|
||||
unsigned int m_command_list_dirty_state = UINT_MAX;
|
||||
D3D_PRIMITIVE_TOPOLOGY m_command_list_current_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||
|
||||
HANDLE m_wait_on_cpu_fence_event;
|
||||
|
||||
ID3D12Device* m_device;
|
||||
ID3D12CommandQueue* m_command_queue;
|
||||
UINT64 m_queue_fence_value;
|
||||
ID3D12Fence* m_queue_fence;
|
||||
UINT64 m_queue_frame_fence_value;
|
||||
ID3D12Fence* m_queue_frame_fence;
|
||||
|
||||
std::map<void*, PFN_QUEUE_FENCE_CALLBACK*> m_queue_fence_callbacks;
|
||||
|
||||
UINT m_current_command_allocator;
|
||||
UINT m_current_command_allocator_list;
|
||||
std::array<std::vector<ID3D12CommandAllocator*>, 2> m_command_allocator_lists;
|
||||
|
||||
ID3D12GraphicsCommandList* m_backing_command_list;
|
||||
ID3D12QueuedCommandList* m_queued_command_list;
|
||||
|
||||
ID3D12RootSignature* m_default_root_signature;
|
||||
|
||||
UINT m_current_deferred_destruction_list;
|
||||
std::array<std::vector<ID3D12Resource*>, 2> m_deferred_destruction_lists;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
|
||||
#include "VideoBackends/D3D12/D3DState.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
bool operator==(const D3DDescriptorHeapManager::SamplerStateSet& lhs, const D3DDescriptorHeapManager::SamplerStateSet& rhs)
|
||||
{
|
||||
// D3D12TODO: Do something more efficient than this.
|
||||
return (!memcmp(&lhs, &rhs, sizeof(D3DDescriptorHeapManager::SamplerStateSet)));
|
||||
}
|
||||
|
||||
D3DDescriptorHeapManager::D3DDescriptorHeapManager(D3D12_DESCRIPTOR_HEAP_DESC* desc, ID3D12Device* device, unsigned int temporarySlots) :
|
||||
m_device(device)
|
||||
{
|
||||
CheckHR(device->CreateDescriptorHeap(desc, IID_PPV_ARGS(&m_descriptor_heap)));
|
||||
|
||||
m_descriptor_heap_size = desc->NumDescriptors;
|
||||
m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(desc->Type);
|
||||
m_gpu_visible = (desc->Flags == D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
|
||||
|
||||
if (m_gpu_visible)
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC cpu_shadow_heap_desc = *desc;
|
||||
cpu_shadow_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
|
||||
CheckHR(device->CreateDescriptorHeap(&cpu_shadow_heap_desc, IID_PPV_ARGS(&m_descriptor_heap_cpu_shadow)));
|
||||
|
||||
m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart();
|
||||
m_heap_base_gpu_cpu_shadow = m_descriptor_heap_cpu_shadow->GetCPUDescriptorHandleForHeapStart();
|
||||
}
|
||||
|
||||
m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart();
|
||||
|
||||
m_first_temporary_slot_in_heap = m_descriptor_heap_size - temporarySlots;
|
||||
m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap;
|
||||
}
|
||||
|
||||
bool D3DDescriptorHeapManager::Allocate(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadow, bool temporary)
|
||||
{
|
||||
bool allocated_from_current_heap = true;
|
||||
|
||||
if (m_current_permanent_offset_in_heap + 1 >= m_first_temporary_slot_in_heap)
|
||||
{
|
||||
// If out of room in the heap, start back at beginning.
|
||||
allocated_from_current_heap = false;
|
||||
m_current_permanent_offset_in_heap = 0;
|
||||
}
|
||||
|
||||
CHECK(!gpu_handle || (gpu_handle && m_gpu_visible), "D3D12_GPU_DESCRIPTOR_HANDLE used on non-GPU-visible heap.");
|
||||
|
||||
if (temporary && m_current_temporary_offset_in_heap + 1 >= m_descriptor_heap_size)
|
||||
{
|
||||
m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap;
|
||||
}
|
||||
|
||||
unsigned int heapOffsetToUse = temporary ? m_current_temporary_offset_in_heap : m_current_permanent_offset_in_heap;
|
||||
|
||||
if (m_gpu_visible)
|
||||
{
|
||||
gpu_handle->ptr = m_heap_base_gpu.ptr + heapOffsetToUse * m_descriptor_increment_size;
|
||||
|
||||
if (gpu_handle_cpu_shadow)
|
||||
gpu_handle_cpu_shadow->ptr = m_heap_base_gpu_cpu_shadow.ptr + heapOffsetToUse * m_descriptor_increment_size;
|
||||
}
|
||||
|
||||
cpu_handle->ptr = m_heap_base_cpu.ptr + heapOffsetToUse * m_descriptor_increment_size;
|
||||
|
||||
if (!temporary)
|
||||
{
|
||||
m_current_permanent_offset_in_heap++;
|
||||
}
|
||||
|
||||
return allocated_from_current_heap;
|
||||
}
|
||||
|
||||
bool D3DDescriptorHeapManager::AllocateGroup(D3D12_CPU_DESCRIPTOR_HANDLE* base_cpu_handle, unsigned int num_handles, D3D12_GPU_DESCRIPTOR_HANDLE* base_gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE* base_gpu_handle_cpu_shadow, bool temporary)
|
||||
{
|
||||
bool allocated_from_current_heap = true;
|
||||
|
||||
if (m_current_permanent_offset_in_heap + num_handles >= m_first_temporary_slot_in_heap)
|
||||
{
|
||||
// If out of room in the heap, start back at beginning.
|
||||
allocated_from_current_heap = false;
|
||||
m_current_permanent_offset_in_heap = 0;
|
||||
}
|
||||
|
||||
CHECK(!base_gpu_handle || (base_gpu_handle && m_gpu_visible), "D3D12_GPU_DESCRIPTOR_HANDLE used on non-GPU-visible heap.");
|
||||
|
||||
if (temporary && m_current_temporary_offset_in_heap + num_handles >= m_descriptor_heap_size)
|
||||
{
|
||||
m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap;
|
||||
}
|
||||
|
||||
unsigned int heapOffsetToUse = temporary ? m_current_temporary_offset_in_heap : m_current_permanent_offset_in_heap;
|
||||
|
||||
if (m_gpu_visible)
|
||||
{
|
||||
base_gpu_handle->ptr = m_heap_base_gpu.ptr + heapOffsetToUse * m_descriptor_increment_size;
|
||||
|
||||
if (base_gpu_handle_cpu_shadow)
|
||||
base_gpu_handle_cpu_shadow->ptr = m_heap_base_gpu_cpu_shadow.ptr + heapOffsetToUse * m_descriptor_increment_size;
|
||||
}
|
||||
|
||||
base_cpu_handle->ptr = m_heap_base_cpu.ptr + heapOffsetToUse * m_descriptor_increment_size;
|
||||
|
||||
if (temporary)
|
||||
{
|
||||
m_current_temporary_offset_in_heap += num_handles;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current_permanent_offset_in_heap += num_handles;
|
||||
}
|
||||
|
||||
return allocated_from_current_heap;
|
||||
}
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE D3DDescriptorHeapManager::GetHandleForSamplerGroup(SamplerState* sampler_state, unsigned int num_sampler_samples)
|
||||
{
|
||||
auto it = m_sampler_map.find(*reinterpret_cast<SamplerStateSet*>(sampler_state));
|
||||
|
||||
if (it == m_sampler_map.end())
|
||||
{
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE base_sampler_cpu_handle;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE base_sampler_gpu_handle;
|
||||
|
||||
bool allocatedFromExistingHeap = AllocateGroup(&base_sampler_cpu_handle, num_sampler_samples, &base_sampler_gpu_handle);
|
||||
|
||||
if (!allocatedFromExistingHeap)
|
||||
{
|
||||
m_sampler_map.clear();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num_sampler_samples; i++)
|
||||
{
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE destinationDescriptor;
|
||||
destinationDescriptor.ptr = base_sampler_cpu_handle.ptr + i * D3D::sampler_descriptor_size;
|
||||
|
||||
D3D::device12->CreateSampler(&StateCache::GetDesc12(sampler_state[i]), destinationDescriptor);
|
||||
}
|
||||
|
||||
m_sampler_map[*reinterpret_cast<SamplerStateSet*>(sampler_state)] = base_sampler_gpu_handle;
|
||||
|
||||
return base_sampler_gpu_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12DescriptorHeap* D3DDescriptorHeapManager::GetDescriptorHeap() const
|
||||
{
|
||||
return m_descriptor_heap;
|
||||
}
|
||||
|
||||
D3DDescriptorHeapManager::~D3DDescriptorHeapManager()
|
||||
{
|
||||
SAFE_RELEASE(m_descriptor_heap);
|
||||
SAFE_RELEASE(m_descriptor_heap_cpu_shadow);
|
||||
}
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "VideoBackends/D3D12/D3DState.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
// This class provides an abstraction for D3D12 descriptor heaps.
|
||||
class D3DDescriptorHeapManager
|
||||
{
|
||||
public:
|
||||
|
||||
D3DDescriptorHeapManager(D3D12_DESCRIPTOR_HEAP_DESC* desc, ID3D12Device* device, unsigned int temporarySlots = 0);
|
||||
~D3DDescriptorHeapManager();
|
||||
|
||||
bool Allocate(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handle = nullptr, D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadow = nullptr, bool temporary = false);
|
||||
bool AllocateGroup(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handles, unsigned int num_handles, D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handles = nullptr, D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadows = nullptr, bool temporary = false);
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE GetHandleForSamplerGroup(SamplerState* sampler_state, unsigned int num_sampler_samples);
|
||||
|
||||
ID3D12DescriptorHeap* GetDescriptorHeap() const;
|
||||
|
||||
struct SamplerStateSet
|
||||
{
|
||||
SamplerState desc0;
|
||||
SamplerState desc1;
|
||||
SamplerState desc2;
|
||||
SamplerState desc3;
|
||||
SamplerState desc4;
|
||||
SamplerState desc5;
|
||||
SamplerState desc6;
|
||||
SamplerState desc7;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
ID3D12Device* m_device = nullptr;
|
||||
ID3D12DescriptorHeap* m_descriptor_heap = nullptr;
|
||||
ID3D12DescriptorHeap* m_descriptor_heap_cpu_shadow = nullptr;
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_gpu_cpu_shadow;
|
||||
|
||||
struct hash_sampler_desc
|
||||
{
|
||||
size_t operator()(const SamplerStateSet sampler_state_set) const
|
||||
{
|
||||
return sampler_state_set.desc0.hex;
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<SamplerStateSet, D3D12_GPU_DESCRIPTOR_HANDLE, hash_sampler_desc> m_sampler_map;
|
||||
|
||||
unsigned int m_current_temporary_offset_in_heap = 0;
|
||||
unsigned int m_current_permanent_offset_in_heap = 0;
|
||||
|
||||
unsigned int m_descriptor_increment_size;
|
||||
unsigned int m_descriptor_heap_size;
|
||||
bool m_gpu_visible;
|
||||
|
||||
unsigned int m_first_temporary_slot_in_heap;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,84 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DShader.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
bool CompileShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines, std::string shader_version_string)
|
||||
{
|
||||
ID3D10Blob* shader_buffer = nullptr;
|
||||
ID3D10Blob* error_buffer = nullptr;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_DEBUG;
|
||||
#else
|
||||
UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION;
|
||||
#endif
|
||||
HRESULT hr = d3d_compile(code.c_str(), code.length(), nullptr, defines, nullptr, "main", shader_version_string.data(),
|
||||
flags, 0, &shader_buffer, &error_buffer);
|
||||
|
||||
if (error_buffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Shader compiler messages:\n%s\n",
|
||||
static_cast<const char*>(error_buffer->GetBufferPointer()));
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat("%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), shader_version_string, num_failures++);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, filename, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile shader: %s\nDebug info (%s):\n%s",
|
||||
filename.c_str(), shader_version_string, static_cast<const char*>(error_buffer->GetBufferPointer()));
|
||||
|
||||
*blob = nullptr;
|
||||
error_buffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = shader_buffer;
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileVertexShader(const std::string& code, ID3DBlob** blob)
|
||||
{
|
||||
return CompileShader(code, blob, nullptr, D3D::VertexShaderVersionString());
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileGeometryShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines)
|
||||
{
|
||||
return CompileShader(code, blob, defines, D3D::GeometryShaderVersionString());
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompilePixelShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines)
|
||||
{
|
||||
return CompileShader(code, blob, defines, D3D::PixelShaderVersionString());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
|
||||
class D3DBlob;
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
// The returned bytecode buffers should be Release()d.
|
||||
bool CompileVertexShader(const std::string& code, ID3DBlob** blob);
|
||||
bool CompileGeometryShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines = nullptr);
|
||||
bool CompilePixelShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines = nullptr);
|
||||
|
||||
}
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,482 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/LinearDiskCache.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DState.h"
|
||||
#include "VideoBackends/D3D12/D3DUtil.h"
|
||||
|
||||
#include "VideoBackends/D3D12/NativeVertexFormat.h"
|
||||
#include "VideoBackends/D3D12/ShaderCache.h"
|
||||
#include "VideoBackends/D3D12/StaticShaderCache.h"
|
||||
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
static bool s_cache_is_corrupted = false;
|
||||
static LinearDiskCache<SmallPsoDiskDesc, u8> s_pso_disk_cache;
|
||||
|
||||
class PipelineStateCacheInserter : public LinearDiskCacheReader<SmallPsoDiskDesc, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const SmallPsoDiskDesc& key, const u8* value, u32 value_size)
|
||||
{
|
||||
if (s_cache_is_corrupted)
|
||||
return;
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {};
|
||||
desc.pRootSignature = D3D::default_root_signature;
|
||||
desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; // This state changes in PSTextureEncoder::Encode.
|
||||
desc.DSVFormat = DXGI_FORMAT_D32_FLOAT; // This state changes in PSTextureEncoder::Encode.
|
||||
desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||
desc.NumRenderTargets = 1;
|
||||
desc.SampleMask = UINT_MAX;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
|
||||
desc.GS = ShaderCache::GetGeometryShaderFromUid(&key.gs_uid);
|
||||
desc.PS = ShaderCache::GetPixelShaderFromUid(&key.ps_uid);
|
||||
desc.VS = ShaderCache::GetVertexShaderFromUid(&key.vs_uid);
|
||||
|
||||
if (!desc.PS.pShaderBytecode || !desc.VS.pShaderBytecode)
|
||||
{
|
||||
s_cache_is_corrupted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
BlendState blend_state = {};
|
||||
blend_state.hex = key.blend_state_hex;
|
||||
desc.BlendState = StateCache::GetDesc12(blend_state);
|
||||
|
||||
ZMode depth_stencil_state = {};
|
||||
depth_stencil_state.hex = key.depth_stencil_state_hex;
|
||||
desc.DepthStencilState = StateCache::GetDesc12(depth_stencil_state);
|
||||
|
||||
RasterizerState rasterizer_state = {};
|
||||
rasterizer_state.hex = key.rasterizer_state_hex;
|
||||
desc.RasterizerState = StateCache::GetDesc12(rasterizer_state);
|
||||
|
||||
desc.PrimitiveTopologyType = key.topology;
|
||||
|
||||
// search for a cached native vertex format
|
||||
const PortableVertexDeclaration& native_vtx_decl = key.vertex_declaration;
|
||||
std::unique_ptr<NativeVertexFormat>& native = (*VertexLoaderManager::GetNativeVertexFormatMap())[native_vtx_decl];
|
||||
|
||||
if (!native)
|
||||
{
|
||||
native.reset(g_vertex_manager->CreateNativeVertexFormat(native_vtx_decl));
|
||||
}
|
||||
|
||||
desc.InputLayout = reinterpret_cast<D3DVertexFormat*>(native.get())->GetActiveInputLayout12();
|
||||
|
||||
desc.CachedPSO.CachedBlobSizeInBytes = value_size;
|
||||
desc.CachedPSO.pCachedBlob = value;
|
||||
|
||||
ID3D12PipelineState* pso = nullptr;
|
||||
HRESULT hr = D3D::device12->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pso));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Failure can occur if disk cache is corrupted, or a driver upgrade invalidates the existing blobs.
|
||||
// In this case, we need to clear the disk cache.
|
||||
|
||||
s_cache_is_corrupted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
SmallPsoDesc small_desc = {};
|
||||
small_desc.blend_state.hex = key.blend_state_hex;
|
||||
small_desc.depth_stencil_state.hex = key.depth_stencil_state_hex;
|
||||
small_desc.rasterizer_state.hex = key.rasterizer_state_hex;
|
||||
small_desc.gs_bytecode = desc.GS;
|
||||
small_desc.ps_bytecode = desc.PS;
|
||||
small_desc.vs_bytecode = desc.VS;
|
||||
small_desc.input_layout = reinterpret_cast<D3DVertexFormat*>(native.get());
|
||||
|
||||
gx_state_cache.m_small_pso_map[small_desc] = pso;
|
||||
}
|
||||
};
|
||||
|
||||
StateCache::StateCache()
|
||||
{
|
||||
m_current_pso_desc = {};
|
||||
|
||||
m_current_pso_desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; // This state changes in PSTextureEncoder::Encode.
|
||||
m_current_pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT; // This state changes in PSTextureEncoder::Encode.
|
||||
m_current_pso_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
|
||||
m_current_pso_desc.NumRenderTargets = 1;
|
||||
m_current_pso_desc.SampleMask = UINT_MAX;
|
||||
}
|
||||
|
||||
void StateCache::Init()
|
||||
{
|
||||
// Root signature isn't available at time of StateCache construction, so fill it in now.
|
||||
gx_state_cache.m_current_pso_desc.pRootSignature = D3D::default_root_signature;
|
||||
|
||||
// Multi-sample configuration isn't available at time of StateCache construction, so fille it in now.
|
||||
gx_state_cache.m_current_pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples;
|
||||
gx_state_cache.m_current_pso_desc.SampleDesc.Quality = 0;
|
||||
|
||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
||||
|
||||
std::string cache_filename = StringFromFormat("%sdx12-%s-pso.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
||||
SConfig::GetInstance().m_strUniqueID.c_str());
|
||||
|
||||
PipelineStateCacheInserter inserter;
|
||||
s_pso_disk_cache.OpenAndRead(cache_filename, inserter);
|
||||
|
||||
if (s_cache_is_corrupted)
|
||||
{
|
||||
// If a PSO fails to create, that means either:
|
||||
// - The file itself is corrupt.
|
||||
// - A driver/HW change has occured, causing the existing cache blobs to be invalid.
|
||||
//
|
||||
// In either case, we want to re-create the disk cache. This should not be a frequent occurence.
|
||||
|
||||
s_pso_disk_cache.Close();
|
||||
|
||||
for (auto it : gx_state_cache.m_small_pso_map)
|
||||
{
|
||||
SAFE_RELEASE(it.second);
|
||||
}
|
||||
gx_state_cache.m_small_pso_map.clear();
|
||||
|
||||
File::Delete(cache_filename);
|
||||
|
||||
s_pso_disk_cache.OpenAndRead(cache_filename, inserter);
|
||||
|
||||
s_cache_is_corrupted = false;
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_SAMPLER_DESC StateCache::GetDesc12(SamplerState state)
|
||||
{
|
||||
const unsigned int d3d_mip_filters[4] =
|
||||
{
|
||||
TexMode0::TEXF_NONE,
|
||||
TexMode0::TEXF_POINT,
|
||||
TexMode0::TEXF_LINEAR,
|
||||
TexMode0::TEXF_NONE, //reserved
|
||||
};
|
||||
const D3D12_TEXTURE_ADDRESS_MODE d3d_clamps[4] =
|
||||
{
|
||||
D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
|
||||
D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
||||
D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
|
||||
D3D12_TEXTURE_ADDRESS_MODE_WRAP //reserved
|
||||
};
|
||||
|
||||
D3D12_SAMPLER_DESC sampdc;
|
||||
|
||||
unsigned int mip = d3d_mip_filters[state.min_filter & 3];
|
||||
|
||||
sampdc.MaxAnisotropy = 1;
|
||||
if (g_ActiveConfig.iMaxAnisotropy > 1)
|
||||
{
|
||||
sampdc.Filter = D3D12_FILTER_ANISOTROPIC;
|
||||
sampdc.MaxAnisotropy = 1 << g_ActiveConfig.iMaxAnisotropy;
|
||||
}
|
||||
else if (state.min_filter & 4) // linear min filter
|
||||
{
|
||||
if (state.mag_filter) // linear mag filter
|
||||
{
|
||||
if (mip == TexMode0::TEXF_NONE)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_POINT)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_LINEAR)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
}
|
||||
else // point mag filter
|
||||
{
|
||||
if (mip == TexMode0::TEXF_NONE)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_POINT)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_LINEAR)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
||||
}
|
||||
}
|
||||
else // point min filter
|
||||
{
|
||||
if (state.mag_filter) // linear mag filter
|
||||
{
|
||||
if (mip == TexMode0::TEXF_NONE)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_POINT)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_LINEAR)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
|
||||
}
|
||||
else // point mag filter
|
||||
{
|
||||
if (mip == TexMode0::TEXF_NONE)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_POINT)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
else if (mip == TexMode0::TEXF_LINEAR)
|
||||
sampdc.Filter = D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
sampdc.AddressU = d3d_clamps[state.wrap_s];
|
||||
sampdc.AddressV = d3d_clamps[state.wrap_t];
|
||||
sampdc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
|
||||
sampdc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
||||
|
||||
sampdc.BorderColor[0] = sampdc.BorderColor[1] = sampdc.BorderColor[2] = sampdc.BorderColor[3] = 1.0f;
|
||||
|
||||
sampdc.MaxLOD = (mip == TexMode0::TEXF_NONE) ? 0.0f : static_cast<float>(state.max_lod) / 16.f;
|
||||
sampdc.MinLOD = static_cast<float>(state.min_lod) / 16.f;
|
||||
sampdc.MipLODBias = static_cast<s32>(state.lod_bias) / 32.0f;
|
||||
|
||||
return sampdc;
|
||||
}
|
||||
|
||||
D3D12_BLEND GetBlendingAlpha(D3D12_BLEND blend)
|
||||
{
|
||||
switch (blend)
|
||||
{
|
||||
case D3D12_BLEND_SRC_COLOR:
|
||||
return D3D12_BLEND_SRC_ALPHA;
|
||||
case D3D12_BLEND_INV_SRC_COLOR:
|
||||
return D3D12_BLEND_INV_SRC_ALPHA;
|
||||
case D3D12_BLEND_DEST_COLOR:
|
||||
return D3D12_BLEND_DEST_ALPHA;
|
||||
case D3D12_BLEND_INV_DEST_COLOR:
|
||||
return D3D12_BLEND_INV_DEST_ALPHA;
|
||||
|
||||
default:
|
||||
return blend;
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_BLEND_DESC StateCache::GetDesc12(BlendState state)
|
||||
{
|
||||
if (!state.blend_enable)
|
||||
{
|
||||
state.src_blend = D3D12_BLEND_ONE;
|
||||
state.dst_blend = D3D12_BLEND_ZERO;
|
||||
state.blend_op = D3D12_BLEND_OP_ADD;
|
||||
state.use_dst_alpha = false;
|
||||
}
|
||||
|
||||
D3D12_BLEND_DESC blenddc = {
|
||||
FALSE, // BOOL AlphaToCoverageEnable;
|
||||
FALSE, // BOOL IndependentBlendEnable;
|
||||
{
|
||||
state.blend_enable, // BOOL BlendEnable;
|
||||
FALSE, // BOOL LogicOpEnable;
|
||||
state.src_blend, // D3D12_BLEND SrcBlend;
|
||||
state.dst_blend, // D3D12_BLEND DestBlend;
|
||||
state.blend_op, // D3D12_BLEND_OP BlendOp;
|
||||
state.src_blend, // D3D12_BLEND SrcBlendAlpha;
|
||||
state.dst_blend, // D3D12_BLEND DestBlendAlpha;
|
||||
state.blend_op, // D3D12_BLEND_OP BlendOpAlpha;
|
||||
D3D12_LOGIC_OP_NOOP, // D3D12_LOGIC_OP LogicOp
|
||||
state.write_mask // UINT8 RenderTargetWriteMask;
|
||||
}
|
||||
};
|
||||
|
||||
blenddc.RenderTarget[0].SrcBlendAlpha = GetBlendingAlpha(blenddc.RenderTarget[0].SrcBlend);
|
||||
blenddc.RenderTarget[0].DestBlendAlpha = GetBlendingAlpha(blenddc.RenderTarget[0].DestBlend);
|
||||
|
||||
if (state.use_dst_alpha)
|
||||
{
|
||||
// Colors should blend against SRC1_ALPHA
|
||||
if (blenddc.RenderTarget[0].SrcBlend == D3D12_BLEND_SRC_ALPHA)
|
||||
blenddc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC1_ALPHA;
|
||||
else if (blenddc.RenderTarget[0].SrcBlend == D3D12_BLEND_INV_SRC_ALPHA)
|
||||
blenddc.RenderTarget[0].SrcBlend = D3D12_BLEND_INV_SRC1_ALPHA;
|
||||
|
||||
// Colors should blend against SRC1_ALPHA
|
||||
if (blenddc.RenderTarget[0].DestBlend == D3D12_BLEND_SRC_ALPHA)
|
||||
blenddc.RenderTarget[0].DestBlend = D3D12_BLEND_SRC1_ALPHA;
|
||||
else if (blenddc.RenderTarget[0].DestBlend == D3D12_BLEND_INV_SRC_ALPHA)
|
||||
blenddc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC1_ALPHA;
|
||||
|
||||
blenddc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
|
||||
blenddc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
|
||||
blenddc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
||||
}
|
||||
|
||||
return blenddc;
|
||||
}
|
||||
|
||||
D3D12_RASTERIZER_DESC StateCache::GetDesc12(RasterizerState state)
|
||||
{
|
||||
return {
|
||||
D3D12_FILL_MODE_SOLID,
|
||||
state.cull_mode,
|
||||
false,
|
||||
0,
|
||||
0.f,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF
|
||||
};
|
||||
}
|
||||
|
||||
inline D3D12_DEPTH_STENCIL_DESC StateCache::GetDesc12(ZMode state)
|
||||
{
|
||||
D3D12_DEPTH_STENCIL_DESC depthdc;
|
||||
|
||||
depthdc.StencilEnable = FALSE;
|
||||
depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
||||
depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
||||
|
||||
D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
|
||||
depthdc.FrontFace = defaultStencilOp;
|
||||
depthdc.BackFace = defaultStencilOp;
|
||||
|
||||
const D3D12_COMPARISON_FUNC d3dCmpFuncs[8] =
|
||||
{
|
||||
D3D12_COMPARISON_FUNC_NEVER,
|
||||
D3D12_COMPARISON_FUNC_GREATER,
|
||||
D3D12_COMPARISON_FUNC_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_GREATER_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_LESS,
|
||||
D3D12_COMPARISON_FUNC_NOT_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_LESS_EQUAL,
|
||||
D3D12_COMPARISON_FUNC_ALWAYS
|
||||
};
|
||||
|
||||
if (state.testenable)
|
||||
{
|
||||
depthdc.DepthEnable = TRUE;
|
||||
depthdc.DepthWriteMask = state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||
depthdc.DepthFunc = d3dCmpFuncs[state.func];
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the test is disabled write is disabled too
|
||||
depthdc.DepthEnable = FALSE;
|
||||
depthdc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||
}
|
||||
|
||||
return depthdc;
|
||||
}
|
||||
|
||||
HRESULT StateCache::GetPipelineStateObjectFromCache(D3D12_GRAPHICS_PIPELINE_STATE_DESC* pso_desc, ID3D12PipelineState** pso)
|
||||
{
|
||||
auto it = m_pso_map.find(*pso_desc);
|
||||
|
||||
if (it == m_pso_map.end())
|
||||
{
|
||||
// Not found, create new PSO.
|
||||
|
||||
ID3D12PipelineState* new_pso = nullptr;
|
||||
HRESULT hr = D3D::device12->CreateGraphicsPipelineState(pso_desc, IID_PPV_ARGS(&new_pso));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_pso_map[*pso_desc] = new_pso;
|
||||
*pso = new_pso;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pso = it->second;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT StateCache::GetPipelineStateObjectFromCache(SmallPsoDesc* pso_desc, ID3D12PipelineState** pso, D3D12_PRIMITIVE_TOPOLOGY_TYPE topology, const GeometryShaderUid* gs_uid, const PixelShaderUid* ps_uid, const VertexShaderUid* vs_uid)
|
||||
{
|
||||
auto it = m_small_pso_map.find(*pso_desc);
|
||||
|
||||
if (it == m_small_pso_map.end())
|
||||
{
|
||||
// Not found, create new PSO.
|
||||
|
||||
// RootSignature, SampleMask, SampleDesc, NumRenderTargets, RTVFormats, DSVFormat
|
||||
// never change so they are set in constructor and forgotten.
|
||||
m_current_pso_desc.GS = pso_desc->gs_bytecode;
|
||||
m_current_pso_desc.PS = pso_desc->ps_bytecode;
|
||||
m_current_pso_desc.VS = pso_desc->vs_bytecode;
|
||||
m_current_pso_desc.BlendState = GetDesc12(pso_desc->blend_state);
|
||||
m_current_pso_desc.DepthStencilState = GetDesc12(pso_desc->depth_stencil_state);
|
||||
m_current_pso_desc.RasterizerState = GetDesc12(pso_desc->rasterizer_state);
|
||||
m_current_pso_desc.PrimitiveTopologyType = topology;
|
||||
m_current_pso_desc.InputLayout = pso_desc->input_layout->GetActiveInputLayout12();
|
||||
|
||||
ID3D12PipelineState* new_pso = nullptr;
|
||||
HRESULT hr = D3D::device12->CreateGraphicsPipelineState(&m_current_pso_desc, IID_PPV_ARGS(&new_pso));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_small_pso_map[*pso_desc] = new_pso;
|
||||
*pso = new_pso;
|
||||
|
||||
// This contains all of the information needed to reconstruct a PSO at startup.
|
||||
SmallPsoDiskDesc disk_desc = {};
|
||||
disk_desc.blend_state_hex = pso_desc->blend_state.hex;
|
||||
disk_desc.depth_stencil_state_hex = pso_desc->depth_stencil_state.hex;
|
||||
disk_desc.rasterizer_state_hex = pso_desc->rasterizer_state.hex;
|
||||
disk_desc.ps_uid = *ps_uid;
|
||||
disk_desc.vs_uid = *vs_uid;
|
||||
disk_desc.gs_uid = *gs_uid;
|
||||
disk_desc.vertex_declaration = pso_desc->input_layout->GetVertexDeclaration();
|
||||
disk_desc.topology = topology;
|
||||
|
||||
// This shouldn't fail.. but if it does, don't cache to disk.
|
||||
ID3DBlob* psoBlob = nullptr;
|
||||
hr = new_pso->GetCachedBlob(&psoBlob);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
s_pso_disk_cache.Append(disk_desc, reinterpret_cast<const u8*>(psoBlob->GetBufferPointer()), static_cast<u32>(psoBlob->GetBufferSize()));
|
||||
psoBlob->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pso = it->second;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void StateCache::Clear()
|
||||
{
|
||||
for (auto& it : m_pso_map)
|
||||
{
|
||||
SAFE_RELEASE(it.second);
|
||||
}
|
||||
m_pso_map.clear();
|
||||
|
||||
for (auto& it : m_small_pso_map)
|
||||
{
|
||||
SAFE_RELEASE(it.second);
|
||||
}
|
||||
m_small_pso_map.clear();
|
||||
|
||||
s_pso_disk_cache.Sync();
|
||||
s_pso_disk_cache.Close();
|
||||
}
|
||||
|
||||
} // namespace DX12
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user