Merge pull request #4424 from Helios747/remove_more_features

Remove D3D12
This commit is contained in:
Mat M
2017-05-18 20:04:40 -04:00
committed by GitHub
53 changed files with 7 additions and 12500 deletions
+1 -4
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?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">
@@ -218,9 +218,6 @@
<ProjectReference Include="..\..\..\Languages\Languages.vcxproj">
<Project>{0e033be3-2e08-428e-9ae9-bc673efa12b5}</Project>
</ProjectReference>
<ProjectReference Include="..\VideoBackends\D3D12\D3D12.vcxproj">
<Project>{570215b7-e32f-4438-95ae-c8d955f9fca3}</Project>
</ProjectReference>
<ProjectReference Include="..\VideoBackends\Vulkan\Vulkan.vcxproj">
<Project>{29f29a19-f141-45ad-9679-5a2923b49da3}</Project>
</ProjectReference>
+2 -5
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?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">
@@ -284,9 +284,6 @@
<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">
@@ -308,4 +305,4 @@
<Message Text="Copy: @(BinaryFiles) -&gt; $(BinaryOutputDir)" Importance="High" />
<Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" />
</Target>
</Project>
</Project>
@@ -1,161 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <memory>
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/D3D12/BoundingBox.h"
#include "VideoBackends/D3D12/D3DBase.h"
#include "VideoBackends/D3D12/D3DCommandListManager.h"
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
#include "VideoBackends/D3D12/D3DStreamBuffer.h"
#include "VideoBackends/D3D12/D3DUtil.h"
#include "VideoBackends/D3D12/FramebufferManager.h"
#include "VideoBackends/D3D12/Render.h"
#include "VideoCommon/VideoConfig.h"
namespace DX12
{
constexpr size_t BBOX_BUFFER_SIZE = sizeof(int) * 4;
constexpr size_t BBOX_STREAM_BUFFER_SIZE = BBOX_BUFFER_SIZE * 128;
static ID3D12Resource* s_bbox_buffer;
static ID3D12Resource* s_bbox_staging_buffer;
static void* s_bbox_staging_buffer_map;
static std::unique_ptr<D3DStreamBuffer> s_bbox_stream_buffer;
static D3D12_GPU_DESCRIPTOR_HANDLE s_bbox_descriptor_handle;
void BBox::Init()
{
CD3DX12_RESOURCE_DESC buffer_desc(CD3DX12_RESOURCE_DESC::Buffer(
BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, 0));
CD3DX12_RESOURCE_DESC staging_buffer_desc(
CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_NONE, 0));
CheckHR(D3D::device12->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &buffer_desc,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&s_bbox_buffer)));
CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK),
D3D12_HEAP_FLAG_NONE, &staging_buffer_desc,
D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
IID_PPV_ARGS(&s_bbox_staging_buffer)));
s_bbox_stream_buffer =
std::make_unique<D3DStreamBuffer>(BBOX_STREAM_BUFFER_SIZE, BBOX_STREAM_BUFFER_SIZE, nullptr);
// D3D12 root signature UAV must be raw or structured buffers, not typed. Since we used a typed
// buffer,
// we have to use a descriptor table. Luckily, we only have to allocate this once, and it never
// changes.
D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle;
if (!D3D::gpu_descriptor_heap_mgr->Allocate(&cpu_descriptor_handle, &s_bbox_descriptor_handle,
nullptr, false))
PanicAlert("Failed to create bounding box UAV descriptor");
D3D12_UNORDERED_ACCESS_VIEW_DESC view_desc = {DXGI_FORMAT_R32_SINT, D3D12_UAV_DIMENSION_BUFFER};
view_desc.Buffer.FirstElement = 0;
view_desc.Buffer.NumElements = 4;
view_desc.Buffer.StructureByteStride = 0;
view_desc.Buffer.CounterOffsetInBytes = 0;
view_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
D3D::device12->CreateUnorderedAccessView(s_bbox_buffer, nullptr, &view_desc,
cpu_descriptor_handle);
Bind();
}
void BBox::Bind()
{
D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_UAV,
s_bbox_descriptor_handle);
}
void BBox::Invalidate()
{
if (!s_bbox_staging_buffer_map)
return;
D3D12_RANGE write_range = {};
s_bbox_staging_buffer->Unmap(0, &write_range);
s_bbox_staging_buffer_map = nullptr;
}
void BBox::Shutdown()
{
Invalidate();
if (s_bbox_buffer)
{
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_buffer);
s_bbox_buffer = nullptr;
}
if (s_bbox_staging_buffer)
{
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_staging_buffer);
s_bbox_staging_buffer = nullptr;
}
s_bbox_stream_buffer.reset();
}
void BBox::Set(int index, int value)
{
// If the buffer is currently mapped, compare the value, and update the staging buffer.
if (s_bbox_staging_buffer_map)
{
int current_value;
memcpy(&current_value, reinterpret_cast<u8*>(s_bbox_staging_buffer_map) + (index * sizeof(int)),
sizeof(int));
if (current_value == value)
{
// Value hasn't changed. So skip updating completely.
return;
}
memcpy(reinterpret_cast<u8*>(s_bbox_staging_buffer_map) + (index * sizeof(int)), &value,
sizeof(int));
}
s_bbox_stream_buffer->AllocateSpaceInBuffer(sizeof(int), sizeof(int));
// Allocate temporary bytes in upload buffer, then copy to real buffer.
memcpy(s_bbox_stream_buffer->GetCPUAddressOfCurrentAllocation(), &value, sizeof(int));
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, 0);
D3D::current_command_list->CopyBufferRegion(
s_bbox_buffer, index * sizeof(int), s_bbox_stream_buffer->GetBuffer(),
s_bbox_stream_buffer->GetOffsetOfCurrentAllocation(), sizeof(int));
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0);
}
int BBox::Get(int index)
{
if (!s_bbox_staging_buffer_map)
{
D3D::command_list_mgr->CPUAccessNotify();
// Copy from real buffer to staging buffer, then block until we have the results.
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE,
0);
D3D::current_command_list->CopyBufferRegion(s_bbox_staging_buffer, 0, s_bbox_buffer, 0,
BBOX_BUFFER_SIZE);
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0);
D3D::command_list_mgr->ExecuteQueuedWork(true);
D3D12_RANGE read_range = {0, BBOX_BUFFER_SIZE};
CheckHR(s_bbox_staging_buffer->Map(0, &read_range, &s_bbox_staging_buffer_map));
}
int value;
memcpy(&value, &reinterpret_cast<int*>(s_bbox_staging_buffer_map)[index], sizeof(int));
return value;
}
};
@@ -1,21 +0,0 @@
// 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 void Init();
static void Bind();
static void Invalidate();
static void Shutdown();
static void Set(int index, int value);
static int Get(int index);
};
};
@@ -1,54 +0,0 @@
set(SRCS
BoundingBox.cpp
BoundingBox.h
D3DBase.cpp
D3DBase.h
D3DCommandListManager.cpp
D3DCommandListManager.h
D3DDescriptorHeapManager.cpp
D3DDescriptorHeapManager.h
D3DQueuedCommandList.cpp
D3DQueuedCommandList.h
D3DShader.cpp
D3DShader.h
D3DState.cpp
D3DState.h
D3DStreamBuffer.cpp
D3DStreamBuffer.h
D3DTexture.cpp
D3DTexture.h
D3DUtil.cpp
D3DUtil.h
FramebufferManager.cpp
FramebufferManager.h
main.cpp
NativeVertexFormat.cpp
NativeVertexFormat.h
PerfQuery.cpp
PerfQuery.h
PSTextureEncoder.cpp
PSTextureEncoder.h
Render.cpp
Render.h
ShaderCache.cpp
ShaderCache.h
ShaderConstantsManager.cpp
ShaderConstantsManager.h
StaticShaderCache.cpp
StaticShaderCache.h
TextureCache.cpp
TextureCache.h
VertexManager.cpp
VertexManager.h
VideoBackend.h
XFBEncoder.cpp
XFBEncoder.h
)
set(LIBS
videocommon
SOIL
common
)
add_dolphin_library(videod3d12 "${SRCS}" "${LIBS}")
@@ -1,106 +0,0 @@
<?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.10586.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="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="TextureCache.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>
@@ -1,143 +0,0 @@
<?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="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="TextureCache.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
-176
View File
@@ -1,176 +0,0 @@
// 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 <d3d12.h>
#include <d3dcompiler.h>
#include <dxgi1_4.h>
#include <memory>
#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 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;
enum GRAPHICS_ROOT_PARAMETER : u32
{
DESCRIPTOR_TABLE_PS_SRV,
DESCRIPTOR_TABLE_PS_SAMPLER,
DESCRIPTOR_TABLE_GS_CBV,
DESCRIPTOR_TABLE_VS_CBV,
DESCRIPTOR_TABLE_PS_CBVONE,
DESCRIPTOR_TABLE_PS_CBVTWO,
DESCRIPTOR_TABLE_PS_UAV,
NUM_GRAPHICS_ROOT_PARAMETERS
};
namespace D3D
{
HRESULT LoadDXGI();
HRESULT LoadD3D();
HRESULT LoadD3DCompiler();
void UnloadDXGI();
void UnloadD3D();
void UnloadD3DCompiler();
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(ID3D12Device* device);
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 std::unique_ptr<D3DDescriptorHeapManager> gpu_descriptor_heap_mgr;
extern std::unique_ptr<D3DDescriptorHeapManager> sampler_descriptor_heap_mgr;
extern std::unique_ptr<D3DDescriptorHeapManager> dsv_descriptor_heap_mgr;
extern std::unique_ptr<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 std::unique_ptr<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();
HRESULT SetFullscreenState(bool enable_fullscreen);
bool GetFullscreenState();
// 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()));
}
return name;
}
} // namespace D3D
using CREATEDXGIFACTORY = HRESULT(WINAPI*)(REFIID, void**);
extern CREATEDXGIFACTORY create_dxgi_factory;
using D3D12CREATEDEVICE = HRESULT(WINAPI*)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**);
extern D3D12CREATEDEVICE d3d12_create_device;
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
@@ -1,389 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#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;
std::fill(m_command_allocator_list_fences.begin(), m_command_allocator_list_fences.end(), 0);
std::fill(m_deferred_destruction_list_fences.begin(), m_deferred_destruction_list_fences.end(),
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
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->ProcessQueuedItems(wait_for_gpu_completion, wait_for_gpu_completion);
#else
CheckHR(m_backing_command_list->Close());
ID3D12CommandList* const execute_list[1] = {m_backing_command_list};
m_command_queue->ExecuteCommandLists(1, execute_list);
CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value));
#endif
// Notify observers of the fence value for the current work to finish.
for (auto it : m_queue_fence_callbacks)
it.second(it.first, m_queue_fence_value);
if (wait_for_gpu_completion)
WaitForGPUCompletion();
// Re-open the command list, using the current allocator.
ResetCommandList();
SetInitialCommandListState();
}
void D3DCommandListManager::ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain,
UINT sync_interval, UINT flags)
{
m_queue_fence_value++;
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
m_queued_command_list->Close();
m_queued_command_list->QueueExecute();
m_queued_command_list->QueuePresent(swap_chain, sync_interval, flags);
m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value);
m_queued_command_list->ProcessQueuedItems(true);
#else
CheckHR(m_backing_command_list->Close());
ID3D12CommandList* const execute_list[1] = {m_backing_command_list};
m_command_queue->ExecuteCommandLists(1, execute_list);
CheckHR(swap_chain->Present(sync_interval, flags));
CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value));
#endif
// Notify observers of the fence value for the current work to finish.
for (auto it : m_queue_fence_callbacks)
it.second(it.first, m_queue_fence_value);
// Move to the next command allocator, this may mean switching allocator lists.
MoveToNextCommandAllocator();
ResetCommandList();
SetInitialCommandListState();
}
void D3DCommandListManager::DestroyAllPendingResources()
{
for (auto& destruction_list : m_deferred_destruction_lists)
{
for (auto& resource : destruction_list)
resource->Release();
destruction_list.clear();
}
}
void D3DCommandListManager::ResetAllCommandAllocators()
{
for (auto& allocator_list : m_command_allocator_lists)
{
for (auto& allocator : allocator_list)
allocator->Reset();
}
// Move back to the start, using the first allocator of first list.
m_current_command_allocator = 0;
m_current_command_allocator_list = 0;
m_current_deferred_destruction_list = 0;
}
void D3DCommandListManager::WaitForGPUCompletion()
{
// Wait for GPU to finish all outstanding work.
// This method assumes that no command lists are open.
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);
m_queued_command_list->ProcessQueuedItems(true);
#else
CheckHR(m_command_queue->Signal(m_queue_frame_fence, m_queue_frame_fence_value));
#endif
WaitOnCPUForFence(m_queue_frame_fence, m_queue_frame_fence_value);
// GPU is up to date with us. Therefore, it has finished with any pending resources.
DestroyAllPendingResources();
// Command allocators are also up-to-date, so reset these.
ResetAllCommandAllocators();
}
void D3DCommandListManager::PerformGPURolloverChecks()
{
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
// 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();
WaitOnCPUForFence(m_queue_frame_fence,
m_deferred_destruction_list_fences[safe_to_delete_deferred_destruction_list]);
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_deferred_destruction_list_fences[m_current_deferred_destruction_list] =
m_queue_frame_fence_value;
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();
WaitOnCPUForFence(m_queue_frame_fence,
m_command_allocator_list_fences[safe_to_reset_command_allocator_list]);
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_command_allocator_list_fences[m_current_command_allocator_list] = m_queue_frame_fence_value;
m_current_command_allocator_list =
(m_current_command_allocator_list + 1) % m_command_allocator_lists.size();
m_current_command_allocator = 0;
// End Command Allocator Resets
}
void D3DCommandListManager::MoveToNextCommandAllocator()
{
// Move to the next allocator in the current allocator list.
m_current_command_allocator = (m_current_command_allocator + 1) %
m_command_allocator_lists[m_current_command_allocator_list].size();
// Did we wrap around? Move to the next set of allocators.
if (m_current_command_allocator == 0)
PerformGPURolloverChecks();
}
void D3DCommandListManager::ResetCommandList()
{
#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);
}
D3DCommandListManager::~D3DCommandListManager()
{
#ifdef USE_D3D12_QUEUED_COMMAND_LISTS
// Wait for background thread to exit.
m_queued_command_list->Release();
#endif
// The command list will still be open, close it before destroying.
m_backing_command_list->Close();
DestroyAllPendingResources();
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)
{
if (fence->GetCompletedValue() >= fence_value)
return;
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
@@ -1,98 +0,0 @@
// 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 DestroyResourceAfterCurrentCommandListExecuted(ID3D12Resource* resource);
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 DestroyAllPendingResources();
void ResetAllCommandAllocators();
void WaitForGPUCompletion();
void PerformGPURolloverChecks();
void MoveToNextCommandAllocator();
void ResetCommandList();
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;
std::array<UINT64, 2> m_command_allocator_list_fences;
ID3D12GraphicsCommandList* m_backing_command_list;
ID3D12QueuedCommandList* m_queued_command_list;
UINT m_current_deferred_destruction_list;
std::array<std::vector<ID3D12Resource*>, 2> m_deferred_destruction_lists;
std::array<UINT64, 2> m_deferred_destruction_list_fences;
};
} // namespace
@@ -1,187 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
#include "VideoBackends/D3D12/D3DBase.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
@@ -1,77 +0,0 @@
// 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
@@ -1,91 +0,0 @@
// 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/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.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,
const 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)
{
WARN_LOG(VIDEO, "Warning generated when compiling %s shader:\n%s",
shader_version_string.c_str(),
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.c_str(), num_failures++);
std::ofstream file;
OpenFStream(file, filename, std::ios_base::out);
file << code;
file << std::endl << "Errors:" << std::endl;
file << static_cast<const char*>(error_buffer->GetBufferPointer());
file.close();
PanicAlert("Failed to compile shader: %s\nDebug info (%s):\n%s", filename.c_str(),
shader_version_string.c_str(),
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
@@ -1,25 +0,0 @@
// 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
@@ -1,486 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/LinearDiskCache.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.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/SamplerCommon.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 = 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 fill 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().GetGameID().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 occurred, 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
// occurrence.
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 > 0 && !SamplerCommon::IsBpTexMode0PointFiltering(state))
{
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 = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f;
sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD);
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)
{
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,
false,
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 = D3D12_DEFAULT_STENCIL_READ_MASK;
depthdc.StencilWriteMask = D3D12_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::OnMSAASettingsChanged()
{
for (auto& it : m_small_pso_map)
{
SAFE_RELEASE(it.second);
}
m_small_pso_map.clear();
// Update sample count for new PSOs being created
gx_state_cache.m_current_pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples;
}
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
-195
View File
@@ -1,195 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <stack>
#include <unordered_map>
#include "Common/BitField.h"
#include "Common/CommonTypes.h"
#include "VideoBackends/D3D12/D3DBase.h"
#include "VideoBackends/D3D12/NativeVertexFormat.h"
#include "VideoBackends/D3D12/ShaderCache.h"
#include "VideoCommon/BPMemory.h"
namespace DX12
{
class PipelineStateCacheInserter;
union RasterizerState
{
BitField<0, 2, D3D12_CULL_MODE> cull_mode;
u32 hex;
};
union BlendState
{
BitField<0, 1, u32> blend_enable;
BitField<1, 3, D3D12_BLEND_OP> blend_op;
BitField<4, 4, u8> write_mask;
BitField<8, 5, D3D12_BLEND> src_blend;
BitField<13, 5, D3D12_BLEND> dst_blend;
BitField<18, 1, u32> use_dst_alpha;
u32 hex;
};
union SamplerState
{
BitField<0, 3, u32> min_filter;
BitField<3, 1, u32> mag_filter;
BitField<4, 8, u32> min_lod;
BitField<12, 8, u32> max_lod;
BitField<20, 8, s32> lod_bias;
BitField<28, 2, u32> wrap_s;
BitField<30, 2, u32> wrap_t;
u32 hex;
};
struct SmallPsoDesc
{
D3D12_SHADER_BYTECODE gs_bytecode;
D3D12_SHADER_BYTECODE ps_bytecode;
D3D12_SHADER_BYTECODE vs_bytecode;
D3DVertexFormat* input_layout;
BlendState blend_state;
RasterizerState rasterizer_state;
ZMode depth_stencil_state;
};
// The Bitfield members in BlendState, RasterizerState, and ZMode cause the..
// static_assert(std::is_trivially_copyable<K>::value, "K must be a trivially copyable type");
// .. check in LinearDiskCache to fail. So, just storing the packed u32 values.
struct SmallPsoDiskDesc
{
u32 blend_state_hex;
u32 rasterizer_state_hex;
u32 depth_stencil_state_hex;
PixelShaderUid ps_uid;
VertexShaderUid vs_uid;
GeometryShaderUid gs_uid;
D3D12_PRIMITIVE_TOPOLOGY_TYPE topology;
PortableVertexDeclaration vertex_declaration; // Used to construct the input layout.
};
class StateCache
{
public:
StateCache();
static void Init();
// Get D3D12 descs for the internal state bitfields.
static D3D12_SAMPLER_DESC GetDesc12(SamplerState state);
static D3D12_BLEND_DESC GetDesc12(BlendState state);
static D3D12_RASTERIZER_DESC GetDesc12(RasterizerState state);
static D3D12_DEPTH_STENCIL_DESC GetDesc12(ZMode state);
HRESULT GetPipelineStateObjectFromCache(D3D12_GRAPHICS_PIPELINE_STATE_DESC* pso_desc,
ID3D12PipelineState** pso);
HRESULT GetPipelineStateObjectFromCache(SmallPsoDesc* pso_desc, ID3D12PipelineState** pso,
D3D12_PRIMITIVE_TOPOLOGY_TYPE topology,
const GeometryShaderUid* gs_uid,
const PixelShaderUid* ps_uid,
const VertexShaderUid* vs_uid);
// Called when the MSAA count/quality changes. Invalidates all small PSOs.
void OnMSAASettingsChanged();
// Release all cached states and clear hash tables.
void Clear();
private:
friend DX12::PipelineStateCacheInserter;
D3D12_GRAPHICS_PIPELINE_STATE_DESC m_current_pso_desc;
struct hash_pso_desc
{
size_t operator()(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& pso_desc) const
{
return ((uintptr_t)pso_desc.PS.pShaderBytecode * 1000000) ^
((uintptr_t)pso_desc.VS.pShaderBytecode * 1000) ^
((uintptr_t)pso_desc.InputLayout.pInputElementDescs);
}
};
struct equality_pipeline_state_desc
{
bool operator()(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& lhs,
const D3D12_GRAPHICS_PIPELINE_STATE_DESC& rhs) const
{
return std::tie(
lhs.PS.pShaderBytecode, lhs.VS.pShaderBytecode, lhs.GS.pShaderBytecode,
lhs.RasterizerState.CullMode, lhs.DepthStencilState.DepthEnable,
lhs.DepthStencilState.DepthFunc, lhs.DepthStencilState.DepthWriteMask,
lhs.BlendState.RenderTarget[0].BlendEnable, lhs.BlendState.RenderTarget[0].BlendOp,
lhs.BlendState.RenderTarget[0].DestBlend, lhs.BlendState.RenderTarget[0].SrcBlend,
lhs.BlendState.RenderTarget[0].RenderTargetWriteMask, lhs.RTVFormats[0],
lhs.SampleDesc.Count) ==
std::tie(
rhs.PS.pShaderBytecode, rhs.VS.pShaderBytecode, rhs.GS.pShaderBytecode,
rhs.RasterizerState.CullMode, rhs.DepthStencilState.DepthEnable,
rhs.DepthStencilState.DepthFunc, rhs.DepthStencilState.DepthWriteMask,
rhs.BlendState.RenderTarget[0].BlendEnable, rhs.BlendState.RenderTarget[0].BlendOp,
rhs.BlendState.RenderTarget[0].DestBlend, rhs.BlendState.RenderTarget[0].SrcBlend,
rhs.BlendState.RenderTarget[0].RenderTargetWriteMask, rhs.RTVFormats[0],
rhs.SampleDesc.Count);
}
};
std::unordered_map<D3D12_GRAPHICS_PIPELINE_STATE_DESC, ID3D12PipelineState*, hash_pso_desc,
equality_pipeline_state_desc>
m_pso_map;
struct hash_small_pso_desc
{
size_t operator()(const SmallPsoDesc& pso_desc) const
{
return ((uintptr_t)pso_desc.vs_bytecode.pShaderBytecode << 10) ^
((uintptr_t)pso_desc.ps_bytecode.pShaderBytecode) + pso_desc.blend_state.hex +
pso_desc.depth_stencil_state.hex;
}
};
struct equality_small_pipeline_state_desc
{
bool operator()(const SmallPsoDesc& lhs, const SmallPsoDesc& rhs) const
{
return std::tie(lhs.ps_bytecode.pShaderBytecode, lhs.vs_bytecode.pShaderBytecode,
lhs.gs_bytecode.pShaderBytecode, lhs.input_layout, lhs.blend_state.hex,
lhs.depth_stencil_state.hex, lhs.rasterizer_state.hex) ==
std::tie(rhs.ps_bytecode.pShaderBytecode, rhs.vs_bytecode.pShaderBytecode,
rhs.gs_bytecode.pShaderBytecode, rhs.input_layout, rhs.blend_state.hex,
rhs.depth_stencil_state.hex, rhs.rasterizer_state.hex);
}
};
struct hash_shader_bytecode
{
size_t operator()(const D3D12_SHADER_BYTECODE& shader) const
{
return (uintptr_t)shader.pShaderBytecode;
}
};
struct equality_shader_bytecode
{
bool operator()(const D3D12_SHADER_BYTECODE& lhs, const D3D12_SHADER_BYTECODE& rhs) const
{
return lhs.pShaderBytecode == rhs.pShaderBytecode;
}
};
std::unordered_map<SmallPsoDesc, ID3D12PipelineState*, hash_small_pso_desc,
equality_small_pipeline_state_desc>
m_small_pso_map;
};
} // namespace DX12
@@ -1,394 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include "VideoBackends/D3D12/D3DBase.h"
#include "VideoBackends/D3D12/D3DCommandListManager.h"
#include "VideoBackends/D3D12/D3DStreamBuffer.h"
#include "VideoBackends/D3D12/D3DUtil.h"
namespace DX12
{
D3DStreamBuffer::D3DStreamBuffer(size_t initial_size, size_t max_size,
bool* buffer_reallocation_notification)
: m_buffer_size(initial_size), m_buffer_max_size(max_size),
m_buffer_reallocation_notification(buffer_reallocation_notification)
{
CHECK(initial_size <= max_size,
"Error: Initial size for D3DStreamBuffer is greater than max_size.");
AllocateBuffer(initial_size);
// Register for callback from D3DCommandListManager each time a fence is queued to be signaled.
m_buffer_tracking_fence =
D3D::command_list_mgr->RegisterQueueFenceCallback(this, &D3DStreamBuffer::QueueFenceCallback);
}
D3DStreamBuffer::~D3DStreamBuffer()
{
D3D::command_list_mgr->RemoveQueueFenceCallback(this);
D3D12_RANGE write_range = {0, m_buffer_size};
m_buffer->Unmap(0, &write_range);
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer);
}
// Function returns true if (worst case), needed to flush existing command list in order to
// ensure the GPU finished with current use of buffer. The calling function will need to take
// care to reset GPU state to what it was previously.
// Obviously this is non-performant, so the buffer max_size should be large enough to
// ensure this never happens.
bool D3DStreamBuffer::AllocateSpaceInBuffer(size_t allocation_size, size_t alignment,
bool allow_execute)
{
CHECK(allocation_size <= m_buffer_max_size, "Error: Requested allocation size in D3DStreamBuffer "
"is greater than max allowed size of backing "
"buffer.");
if (alignment && m_buffer_offset > 0)
{
size_t padding = m_buffer_offset % alignment;
// Check for case when adding alignment causes CPU offset to equal GPU offset,
// which would imply entire buffer is available (if not corrected).
if (m_buffer_offset < m_buffer_gpu_completion_offset &&
m_buffer_offset + alignment - padding >= m_buffer_gpu_completion_offset)
{
m_buffer_gpu_completion_offset++;
}
m_buffer_offset += alignment - padding;
if (m_buffer_offset > m_buffer_size)
{
m_buffer_offset = 0;
// Correct for case where CPU was about to run into GPU.
if (m_buffer_gpu_completion_offset == 0)
m_buffer_gpu_completion_offset = 1;
}
}
// First, check if there is available (not-in-use-by-GPU) space in existing buffer.
if (AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(allocation_size))
{
return false;
}
// Slow path. No room at front, or back, due to the GPU still (possibly) accessing parts of the
// buffer.
// Resize if possible, else stall.
bool command_list_executed = AttemptBufferResizeOrElseStall(allocation_size, allow_execute);
return command_list_executed;
}
// In VertexManager, we don't know the 'real' size of the allocation at the time
// we call AllocateSpaceInBuffer. We have to conservatively allocate 16MB (!).
// After the vertex data is written, we can choose to specify the 'real' allocation
// size to avoid wasting space.
void D3DStreamBuffer::OverrideSizeOfPreviousAllocation(size_t override_allocation_size)
{
m_buffer_offset = m_buffer_current_allocation_offset + override_allocation_size;
}
void D3DStreamBuffer::AllocateBuffer(size_t size)
{
// First, put existing buffer (if it exists) in deferred destruction list.
if (m_buffer)
{
D3D12_RANGE write_range = {0, m_buffer_size};
m_buffer->Unmap(0, &write_range);
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer);
m_buffer = nullptr;
}
CheckHR(D3D::device12->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(size), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
IID_PPV_ARGS(&m_buffer)));
D3D12_RANGE read_range = {};
CheckHR(m_buffer->Map(0, &read_range, &m_buffer_cpu_address));
m_buffer_gpu_address = m_buffer->GetGPUVirtualAddress();
m_buffer_size = size;
// Start at the beginning of the new buffer.
m_buffer_gpu_completion_offset = 0;
m_buffer_current_allocation_offset = 0;
m_buffer_offset = 0;
// Notify observers.
if (m_buffer_reallocation_notification != nullptr)
*m_buffer_reallocation_notification = true;
// If we had any fences queued, they are no longer relevant.
ClearFences();
}
// Function returns true if current command list executed as a result of current command list
// referencing all of buffer's contents, AND we are already at max_size. No alternative but to
// flush. See comments above AllocateSpaceInBuffer for more details.
bool D3DStreamBuffer::AttemptBufferResizeOrElseStall(size_t allocation_size, bool allow_execute)
{
// This function will attempt to increase the size of the buffer, in response
// to running out of room. If the buffer is already at its maximum size specified
// at creation time, then stall waiting for the GPU to finish with the currently
// requested memory.
// Four possibilities, in order of desirability.
// 1) Best - Update GPU tracking progress - maybe the GPU has made enough
// progress such that there is now room.
// 2) Enlarge GPU buffer, up to our max allowed size.
// 3) Stall until GPU finishes existing queued work/advances offset
// in buffer enough to free room.
// 4) Worst - flush current GPU commands and wait, which will free all room
// in buffer.
// 1) First, let's check if GPU has already continued farther along buffer. If it has freed up
// enough of the buffer, we won't have to stall/allocate new memory.
UpdateGPUProgress();
// Now that GPU progress is updated, do we have room in the queue?
if (AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(allocation_size))
{
return false;
}
// 2) Next, prefer increasing buffer size instead of stalling.
size_t new_size = std::min(static_cast<size_t>(m_buffer_size * 1.5f), m_buffer_max_size);
new_size = std::max(new_size, allocation_size);
// Can we grow buffer further?
if (new_size > m_buffer_size)
{
AllocateBuffer(new_size);
m_buffer_offset = allocation_size;
return false;
}
// 3) Bad case - we need to stall.
// This might be ok if we have > 2 frames queued up or something, but
// we don't want to be stalling as we generate the front-of-queue frame.
const bool found_fence_to_wait_on = AttemptToFindExistingFenceToStallOn(allocation_size);
if (found_fence_to_wait_on)
{
return false;
}
// If allow_execute is false, the caller cannot handle command list execution (and the associated
// reset), so re-allocate the same-sized buffer.
if (!allow_execute)
{
AllocateBuffer(new_size);
m_buffer_offset = allocation_size;
return false;
}
// 4) If we get to this point, that means there is no outstanding queued GPU work, and we're still
// out of room.
// This is bad - and performance will suffer due to the CPU/GPU serialization, but the show must
// go on.
// This is guaranteed to succeed, since we've already CHECK'd that the allocation_size <=
// max_buffer_size, and flushing now and waiting will
// free all space in buffer.
D3D::command_list_mgr->ExecuteQueuedWork(true);
m_buffer_offset = allocation_size;
m_buffer_current_allocation_offset = 0;
m_buffer_gpu_completion_offset = 0;
ClearFences();
return true;
}
// Return true if space is found.
bool D3DStreamBuffer::AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(size_t allocation_size)
{
// First, check if there is room at end of buffer. Fast path.
if (m_buffer_offset >= m_buffer_gpu_completion_offset)
{
if (m_buffer_offset + allocation_size <= m_buffer_size)
{
m_buffer_current_allocation_offset = m_buffer_offset;
m_buffer_offset += allocation_size;
return true;
}
if (0 + allocation_size < m_buffer_gpu_completion_offset)
{
m_buffer_current_allocation_offset = 0;
m_buffer_offset = allocation_size;
return true;
}
}
// Next, check if there is room at front of buffer. Fast path.
if (m_buffer_offset < m_buffer_gpu_completion_offset &&
m_buffer_offset + allocation_size < m_buffer_gpu_completion_offset)
{
m_buffer_current_allocation_offset = m_buffer_offset;
m_buffer_offset += allocation_size;
return true;
}
return false;
}
// Returns true if fence was found and waited on.
bool D3DStreamBuffer::AttemptToFindExistingFenceToStallOn(size_t allocation_size)
{
// Let's find the first fence that will free up enough space in our buffer.
UINT64 fence_value_required = 0;
while (m_queued_fences.size() > 0)
{
FenceTrackingInformation tracking_information = m_queued_fences.front();
m_queued_fences.pop();
if (m_buffer_offset >= m_buffer_gpu_completion_offset)
{
// At this point, we need to wrap around, so req'd gpu offset is allocation_size.
if (tracking_information.buffer_offset >= allocation_size)
{
fence_value_required = tracking_information.fence_value;
m_buffer_current_allocation_offset = 0;
m_buffer_offset = allocation_size;
break;
}
}
else
{
if (m_buffer_offset + allocation_size <= m_buffer_size)
{
if (tracking_information.buffer_offset >= m_buffer_offset + allocation_size)
{
fence_value_required = tracking_information.fence_value;
m_buffer_current_allocation_offset = m_buffer_offset;
m_buffer_offset = m_buffer_offset + allocation_size;
break;
}
}
else
{
if (tracking_information.buffer_offset >= allocation_size)
{
fence_value_required = tracking_information.fence_value;
m_buffer_current_allocation_offset = 0;
m_buffer_offset = allocation_size;
break;
}
}
}
}
// Check if we found a fence we can wait on, for GPU to make sufficient progress.
// If so, wait on it.
if (fence_value_required > 0)
{
D3D::command_list_mgr->WaitOnCPUForFence(m_buffer_tracking_fence, fence_value_required);
return true;
}
return false;
}
void D3DStreamBuffer::UpdateGPUProgress()
{
const UINT64 fence_value = m_buffer_tracking_fence->GetCompletedValue();
while (m_queued_fences.size() > 0)
{
FenceTrackingInformation tracking_information = m_queued_fences.front();
m_queued_fences.pop();
// Has fence gone past this point?
if (fence_value >= tracking_information.fence_value)
{
m_buffer_gpu_completion_offset = tracking_information.buffer_offset;
}
else
{
// Fences are stored in ascending order, so once we hit a fence we haven't yet crossed on GPU,
// abort search.
break;
}
}
}
void D3DStreamBuffer::QueueFenceCallback(void* owning_object, UINT64 fence_value)
{
D3DStreamBuffer* owning_stream_buffer = reinterpret_cast<D3DStreamBuffer*>(owning_object);
if (owning_stream_buffer->HasBufferOffsetChangedSinceLastFence())
owning_stream_buffer->QueueFence(fence_value);
}
void D3DStreamBuffer::ClearFences()
{
while (!m_queued_fences.empty())
m_queued_fences.pop();
}
bool D3DStreamBuffer::HasBufferOffsetChangedSinceLastFence() const
{
if (m_queued_fences.empty())
return true;
// Don't add a new fence tracking entry when our offset hasn't changed.
return (m_queued_fences.back().buffer_offset != m_buffer_offset);
}
void D3DStreamBuffer::QueueFence(UINT64 fence_value)
{
FenceTrackingInformation tracking_information = {};
tracking_information.fence_value = fence_value;
tracking_information.buffer_offset = m_buffer_offset;
m_queued_fences.push(tracking_information);
}
ID3D12Resource* D3DStreamBuffer::GetBuffer() const
{
return m_buffer;
}
D3D12_GPU_VIRTUAL_ADDRESS D3DStreamBuffer::GetGPUAddressOfCurrentAllocation() const
{
return m_buffer_gpu_address + m_buffer_current_allocation_offset;
}
void* D3DStreamBuffer::GetCPUAddressOfCurrentAllocation() const
{
return static_cast<u8*>(m_buffer_cpu_address) + m_buffer_current_allocation_offset;
}
size_t D3DStreamBuffer::GetOffsetOfCurrentAllocation() const
{
return m_buffer_current_allocation_offset;
}
size_t D3DStreamBuffer::GetSize() const
{
return m_buffer_size;
}
void* D3DStreamBuffer::GetBaseCPUAddress() const
{
return m_buffer_cpu_address;
}
D3D12_GPU_VIRTUAL_ADDRESS D3DStreamBuffer::GetBaseGPUAddress() const
{
return m_buffer_gpu_address;
}
}

Some files were not shown because too many files have changed in this diff Show More