mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #7853 from stenzek/d3d12
Re-implement D3D12 video backend
This commit is contained in:
@@ -336,6 +336,7 @@ if(WIN32)
|
||||
)
|
||||
target_link_libraries(core PUBLIC
|
||||
videod3d
|
||||
videod3d12
|
||||
setupapi.lib
|
||||
iphlpapi.lib
|
||||
)
|
||||
|
||||
@@ -475,6 +475,9 @@
|
||||
<ProjectReference Include="..\..\..\Externals\imgui\imgui.vcxproj">
|
||||
<Project>{4c3b2264-ea73-4a7b-9cfe-65b0fd635ebb}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\VideoBackends\D3D12\D3D12.vcxproj">
|
||||
<Project>{570215b7-e32f-4438-95ae-c8d955f9fca3}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -6,5 +6,6 @@ add_subdirectory(Vulkan)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
add_subdirectory(D3DCommon)
|
||||
add_subdirectory(D3D)
|
||||
add_subdirectory(D3D12)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D12/BoundingBox.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "VideoBackends/D3D12/DXContext.h"
|
||||
#include "VideoBackends/D3D12/Renderer.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
BoundingBox::BoundingBox() = default;
|
||||
|
||||
BoundingBox::~BoundingBox()
|
||||
{
|
||||
if (m_gpu_descriptor)
|
||||
g_dx_context->GetDescriptorHeapManager().Free(m_gpu_descriptor);
|
||||
}
|
||||
|
||||
std::unique_ptr<BoundingBox> BoundingBox::Create()
|
||||
{
|
||||
auto bbox = std::unique_ptr<BoundingBox>(new BoundingBox());
|
||||
if (!bbox->CreateBuffers())
|
||||
return nullptr;
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
||||
bool BoundingBox::CreateBuffers()
|
||||
{
|
||||
static constexpr D3D12_HEAP_PROPERTIES gpu_heap_properties = {D3D12_HEAP_TYPE_DEFAULT};
|
||||
static constexpr D3D12_HEAP_PROPERTIES cpu_heap_properties = {D3D12_HEAP_TYPE_READBACK};
|
||||
D3D12_RESOURCE_DESC buffer_desc = {D3D12_RESOURCE_DIMENSION_BUFFER,
|
||||
0,
|
||||
BUFFER_SIZE,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
{1, 0},
|
||||
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
||||
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS};
|
||||
|
||||
HRESULT hr = g_dx_context->GetDevice()->CreateCommittedResource(
|
||||
&gpu_heap_properties, D3D12_HEAP_FLAG_NONE, &buffer_desc,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&m_gpu_buffer));
|
||||
CHECK(SUCCEEDED(hr), "Creating bounding box GPU buffer failed");
|
||||
if (FAILED(hr) || !g_dx_context->GetDescriptorHeapManager().Allocate(&m_gpu_descriptor))
|
||||
return false;
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {DXGI_FORMAT_R32_SINT, D3D12_UAV_DIMENSION_BUFFER};
|
||||
uav_desc.Buffer.NumElements = NUM_VALUES;
|
||||
g_dx_context->GetDevice()->CreateUnorderedAccessView(m_gpu_buffer.Get(), nullptr, &uav_desc,
|
||||
m_gpu_descriptor.cpu_handle);
|
||||
|
||||
buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
hr = g_dx_context->GetDevice()->CreateCommittedResource(
|
||||
&cpu_heap_properties, D3D12_HEAP_FLAG_NONE, &buffer_desc, D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr, IID_PPV_ARGS(&m_readback_buffer));
|
||||
CHECK(SUCCEEDED(hr), "Creating bounding box CPU buffer failed");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
if (!m_upload_buffer.AllocateBuffer(STREAM_BUFFER_SIZE))
|
||||
return false;
|
||||
|
||||
// Both the CPU and GPU buffer's contents is unknown, so force a flush the first time.
|
||||
m_values.fill(0);
|
||||
m_dirty.fill(true);
|
||||
m_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BoundingBox::Readback()
|
||||
{
|
||||
// Copy from GPU->CPU buffer, and wait for the GPU to finish the copy.
|
||||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(),
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
g_dx_context->GetCommandList()->CopyBufferRegion(m_readback_buffer.Get(), 0, m_gpu_buffer.Get(),
|
||||
0, BUFFER_SIZE);
|
||||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(),
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
Renderer::GetInstance()->ExecuteCommandList(true);
|
||||
|
||||
// Read back to cached values.
|
||||
static constexpr D3D12_RANGE read_range = {0, BUFFER_SIZE};
|
||||
void* mapped_pointer;
|
||||
HRESULT hr = m_readback_buffer->Map(0, &read_range, &mapped_pointer);
|
||||
CHECK(SUCCEEDED(hr), "Map bounding box CPU buffer");
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
static constexpr D3D12_RANGE write_range = {0, 0};
|
||||
std::array<s32, NUM_VALUES> new_values;
|
||||
std::memcpy(new_values.data(), mapped_pointer, BUFFER_SIZE);
|
||||
m_readback_buffer->Unmap(0, &write_range);
|
||||
|
||||
// Preserve dirty values, that way we don't need to sync.
|
||||
for (u32 i = 0; i < NUM_VALUES; i++)
|
||||
{
|
||||
if (!m_dirty[i])
|
||||
m_values[i] = new_values[i];
|
||||
}
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
s32 BoundingBox::Get(size_t index)
|
||||
{
|
||||
if (!m_valid)
|
||||
Readback();
|
||||
|
||||
return m_values[index];
|
||||
}
|
||||
|
||||
void BoundingBox::Set(size_t index, s32 value)
|
||||
{
|
||||
m_values[index] = value;
|
||||
m_dirty[index] = true;
|
||||
}
|
||||
|
||||
void BoundingBox::Invalidate()
|
||||
{
|
||||
m_dirty.fill(false);
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
void BoundingBox::Flush()
|
||||
{
|
||||
bool in_copy_state = false;
|
||||
for (u32 start = 0; start < NUM_VALUES;)
|
||||
{
|
||||
if (!m_dirty[start])
|
||||
{
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 end = start + 1;
|
||||
m_dirty[start] = false;
|
||||
for (; end < NUM_VALUES; end++)
|
||||
{
|
||||
if (!m_dirty[end])
|
||||
break;
|
||||
|
||||
m_dirty[end] = false;
|
||||
}
|
||||
|
||||
const u32 copy_size = (end - start) * sizeof(ValueType);
|
||||
if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(ValueType)))
|
||||
{
|
||||
WARN_LOG(VIDEO, "Executing command list while waiting for space in bbox stream buffer");
|
||||
Renderer::GetInstance()->ExecuteCommandList(false);
|
||||
if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(ValueType)))
|
||||
{
|
||||
PanicAlert("Failed to allocate bbox stream buffer space");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const u32 upload_buffer_offset = m_upload_buffer.GetCurrentOffset();
|
||||
std::memcpy(m_upload_buffer.GetCurrentHostPointer(), &m_values[start], copy_size);
|
||||
m_upload_buffer.CommitMemory(copy_size);
|
||||
|
||||
if (!in_copy_state)
|
||||
{
|
||||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(),
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
in_copy_state = true;
|
||||
}
|
||||
|
||||
g_dx_context->GetCommandList()->CopyBufferRegion(m_gpu_buffer.Get(), start * sizeof(ValueType),
|
||||
m_upload_buffer.GetBuffer(),
|
||||
upload_buffer_offset, copy_size);
|
||||
start = end;
|
||||
}
|
||||
|
||||
if (in_copy_state)
|
||||
{
|
||||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(),
|
||||
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
}
|
||||
}
|
||||
}; // namespace DX12
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "VideoBackends/D3D12/Common.h"
|
||||
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
|
||||
#include "VideoBackends/D3D12/StreamBuffer.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
class BoundingBox
|
||||
{
|
||||
public:
|
||||
~BoundingBox();
|
||||
|
||||
static std::unique_ptr<BoundingBox> Create();
|
||||
|
||||
const DescriptorHandle& GetGPUDescriptor() const { return m_gpu_descriptor; }
|
||||
|
||||
s32 Get(size_t index);
|
||||
void Set(size_t index, s32 value);
|
||||
|
||||
void Invalidate();
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
using ValueType = s32;
|
||||
static const u32 NUM_VALUES = 4;
|
||||
static const u32 BUFFER_SIZE = sizeof(ValueType) * NUM_VALUES;
|
||||
static const u32 MAX_UPDATES_PER_FRAME = 128;
|
||||
static const u32 STREAM_BUFFER_SIZE = BUFFER_SIZE * MAX_UPDATES_PER_FRAME;
|
||||
|
||||
BoundingBox();
|
||||
|
||||
bool CreateBuffers();
|
||||
void Readback();
|
||||
|
||||
// Three buffers: GPU for read/write, CPU for reading back, and CPU for staging changes.
|
||||
ComPtr<ID3D12Resource> m_gpu_buffer;
|
||||
ComPtr<ID3D12Resource> m_readback_buffer;
|
||||
StreamBuffer m_upload_buffer;
|
||||
DescriptorHandle m_gpu_descriptor;
|
||||
std::array<ValueType, NUM_VALUES> m_values = {};
|
||||
std::array<bool, NUM_VALUES> m_dirty = {};
|
||||
bool m_valid = true;
|
||||
};
|
||||
}; // namespace DX12
|
||||
@@ -0,0 +1,37 @@
|
||||
add_library(videod3d12
|
||||
BoundingBox.cpp
|
||||
BoundingBox.h
|
||||
DescriptorAllocator.cpp
|
||||
DescriptorAllocator.h
|
||||
DescriptorHeapManager.cpp
|
||||
DescriptorHeapManager.h
|
||||
DXContext.cpp
|
||||
DXContext.h
|
||||
DXPipeline.cpp
|
||||
DXPipeline.h
|
||||
DXShader.cpp
|
||||
DXShader.h
|
||||
DXTexture.cpp
|
||||
DXTexture.h
|
||||
DXVertexFormat.cpp
|
||||
DXVertexFormat.h
|
||||
PerfQuery.cpp
|
||||
PerfQuery.h
|
||||
Renderer.cpp
|
||||
Renderer.h
|
||||
StreamBuffer.cpp
|
||||
StreamBuffer.h
|
||||
SwapChain.cpp
|
||||
SwapChain.h
|
||||
VertexManager.cpp
|
||||
VertexManager.h
|
||||
VideoBackend.cpp
|
||||
VideoBackend.h
|
||||
)
|
||||
|
||||
target_link_libraries(videod3d12
|
||||
PUBLIC
|
||||
common
|
||||
videocommon
|
||||
videod3dcommon
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
#pragma once
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "VideoBackends/D3DCommon/Common.h"
|
||||
|
||||
#define CHECK(cond, Message, ...) \
|
||||
if (!(cond)) \
|
||||
{ \
|
||||
PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, \
|
||||
__VA_ARGS__); \
|
||||
}
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
static void ResourceBarrier(ID3D12GraphicsCommandList* cmdlist, ID3D12Resource* resource,
|
||||
D3D12_RESOURCE_STATES from_state, D3D12_RESOURCE_STATES to_state)
|
||||
{
|
||||
const D3D12_RESOURCE_BARRIER barrier = {
|
||||
D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
{{resource, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, from_state, to_state}}};
|
||||
cmdlist->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,94 @@
|
||||
<?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.17134.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\VSProps\Base.props" />
|
||||
<Import Project="..\..\..\VSProps\PCHUse.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<ForcedIncludeFiles />
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<ForcedIncludeFiles />
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BoundingBox.cpp" />
|
||||
<ClCompile Include="DescriptorAllocator.cpp" />
|
||||
<ClCompile Include="DXContext.cpp" />
|
||||
<ClCompile Include="DescriptorHeapManager.cpp" />
|
||||
<ClCompile Include="DXPipeline.cpp" />
|
||||
<ClCompile Include="DXShader.cpp" />
|
||||
<ClCompile Include="StreamBuffer.cpp" />
|
||||
<ClCompile Include="DXTexture.cpp" />
|
||||
<ClCompile Include="VideoBackend.cpp" />
|
||||
<ClCompile Include="PerfQuery.cpp" />
|
||||
<ClCompile Include="Renderer.cpp" />
|
||||
<ClCompile Include="DXVertexFormat.cpp" />
|
||||
<ClCompile Include="SwapChain.cpp" />
|
||||
<ClCompile Include="VertexManager.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BoundingBox.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="DescriptorAllocator.h" />
|
||||
<ClInclude Include="DXContext.h" />
|
||||
<ClInclude Include="DescriptorHeapManager.h" />
|
||||
<ClInclude Include="DXPipeline.h" />
|
||||
<ClInclude Include="DXShader.h" />
|
||||
<ClInclude Include="StreamBuffer.h" />
|
||||
<ClInclude Include="DXTexture.h" />
|
||||
<ClInclude Include="PerfQuery.h" />
|
||||
<ClInclude Include="Renderer.h" />
|
||||
<ClInclude Include="DXVertexFormat.h" />
|
||||
<ClInclude Include="SwapChain.h" />
|
||||
<ClInclude Include="VertexManager.h" />
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(CoreDir)VideoCommon\VideoCommon.vcxproj">
|
||||
<Project>{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\D3DCommon\D3DCommon.vcxproj">
|
||||
<Project>{dea96cf2-f237-4a1a-b32f-c916769efb50}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="VideoBackend.cpp" />
|
||||
<ClCompile Include="DXContext.cpp" />
|
||||
<ClCompile Include="DXPipeline.cpp" />
|
||||
<ClCompile Include="DXShader.cpp" />
|
||||
<ClCompile Include="DXTexture.cpp" />
|
||||
<ClCompile Include="DXVertexFormat.cpp" />
|
||||
<ClCompile Include="StreamBuffer.cpp" />
|
||||
<ClCompile Include="SwapChain.cpp" />
|
||||
<ClCompile Include="PerfQuery.cpp" />
|
||||
<ClCompile Include="Renderer.cpp" />
|
||||
<ClCompile Include="VertexManager.cpp" />
|
||||
<ClCompile Include="BoundingBox.cpp" />
|
||||
<ClCompile Include="DescriptorHeapManager.cpp" />
|
||||
<ClCompile Include="DescriptorAllocator.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="VideoBackend.h" />
|
||||
<ClInclude Include="SwapChain.h" />
|
||||
<ClInclude Include="DXContext.h" />
|
||||
<ClInclude Include="DXPipeline.h" />
|
||||
<ClInclude Include="DXShader.h" />
|
||||
<ClInclude Include="DXTexture.h" />
|
||||
<ClInclude Include="DXVertexFormat.h" />
|
||||
<ClInclude Include="StreamBuffer.h" />
|
||||
<ClInclude Include="VertexManager.h" />
|
||||
<ClInclude Include="BoundingBox.h" />
|
||||
<ClInclude Include="PerfQuery.h" />
|
||||
<ClInclude Include="Renderer.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="DescriptorHeapManager.h" />
|
||||
<ClInclude Include="DescriptorAllocator.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,191 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/D3D12/Common.h"
|
||||
#include "VideoBackends/D3D12/DescriptorAllocator.h"
|
||||
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
|
||||
#include "VideoBackends/D3D12/StreamBuffer.h"
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
struct IDXGIFactory2;
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
// Vertex/Pixel shader root parameters
|
||||
enum ROOT_PARAMETER
|
||||
{
|
||||
ROOT_PARAMETER_PS_CBV,
|
||||
ROOT_PARAMETER_PS_SRV,
|
||||
ROOT_PARAMETER_PS_SAMPLERS,
|
||||
ROOT_PARAMETER_VS_CBV,
|
||||
ROOT_PARAMETER_GS_CBV,
|
||||
ROOT_PARAMETER_PS_UAV_OR_CBV2,
|
||||
ROOT_PARAMETER_PS_CBV2, // ROOT_PARAMETER_PS_UAV_OR_CBV2 if bbox is not enabled
|
||||
NUM_ROOT_PARAMETERS
|
||||
};
|
||||
// Compute shader root parameters
|
||||
enum CS_ROOT_PARAMETERS
|
||||
{
|
||||
CS_ROOT_PARAMETER_CBV,
|
||||
CS_ROOT_PARAMETER_SRV,
|
||||
CS_ROOT_PARAMETER_SAMPLERS,
|
||||
CS_ROOT_PARAMETER_UAV,
|
||||
NUM_CS_ROOT_PARAMETERS,
|
||||
};
|
||||
|
||||
class DXContext
|
||||
{
|
||||
public:
|
||||
~DXContext();
|
||||
|
||||
// Returns a list of AA modes.
|
||||
static std::vector<u32> GetAAModes(u32 adapter_index);
|
||||
|
||||
// Creates new device and context.
|
||||
static bool Create(u32 adapter_index, bool enable_debug_layer);
|
||||
|
||||
// Destroys active context.
|
||||
static void Destroy();
|
||||
|
||||
IDXGIFactory2* GetDXGIFactory() const { return m_dxgi_factory.Get(); }
|
||||
ID3D12Device* GetDevice() const { return m_device.Get(); }
|
||||
ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.Get(); }
|
||||
|
||||
// Returns the current command list, commands can be recorded directly.
|
||||
ID3D12GraphicsCommandList* GetCommandList() const
|
||||
{
|
||||
return m_command_lists[m_current_command_list].command_list.Get();
|
||||
}
|
||||
DescriptorAllocator* GetDescriptorAllocator()
|
||||
{
|
||||
return &m_command_lists[m_current_command_list].descriptor_allocator;
|
||||
}
|
||||
SamplerAllocator* GetSamplerAllocator()
|
||||
{
|
||||
return &m_command_lists[m_current_command_list].sampler_allocator;
|
||||
}
|
||||
|
||||
// Descriptor manager access.
|
||||
DescriptorHeapManager& GetDescriptorHeapManager() { return m_descriptor_heap_manager; }
|
||||
DescriptorHeapManager& GetRTVHeapManager() { return m_rtv_heap_manager; }
|
||||
DescriptorHeapManager& GetDSVHeapManager() { return m_dsv_heap_manager; }
|
||||
SamplerHeapManager& GetSamplerHeapManager() { return m_sampler_heap_manager; }
|
||||
ID3D12DescriptorHeap* const* GetGPUDescriptorHeaps() const
|
||||
{
|
||||
return m_gpu_descriptor_heaps.data();
|
||||
}
|
||||
u32 GetGPUDescriptorHeapCount() const { return static_cast<u32>(m_gpu_descriptor_heaps.size()); }
|
||||
const DescriptorHandle& GetNullSRVDescriptor() const { return m_null_srv_descriptor; }
|
||||
|
||||
// Root signature access.
|
||||
ID3D12RootSignature* GetGXRootSignature() const { return m_gx_root_signature.Get(); }
|
||||
ID3D12RootSignature* GetUtilityRootSignature() const { return m_utility_root_signature.Get(); }
|
||||
ID3D12RootSignature* GetComputeRootSignature() const { return m_compute_root_signature.Get(); }
|
||||
|
||||
// Fence value for current command list.
|
||||
u64 GetCurrentFenceValue() const { return m_current_fence_value; }
|
||||
|
||||
// Last "completed" fence.
|
||||
u64 GetCompletedFenceValue() const { return m_completed_fence_value; }
|
||||
|
||||
// Texture streaming buffer for uploads.
|
||||
StreamBuffer& GetTextureUploadBuffer() { return m_texture_upload_buffer; }
|
||||
|
||||
// Feature level to use when compiling shaders.
|
||||
D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; }
|
||||
|
||||
// Test for support for the specified texture format.
|
||||
bool SupportsTextureFormat(DXGI_FORMAT format);
|
||||
|
||||
// Creates command lists, global buffers and descriptor heaps.
|
||||
bool CreateGlobalResources();
|
||||
|
||||
// Executes the current command list.
|
||||
void ExecuteCommandList(bool wait_for_completion);
|
||||
|
||||
// Waits for a specific fence.
|
||||
void WaitForFence(u64 fence);
|
||||
|
||||
// Defers destruction of a D3D resource (associates it with the current list).
|
||||
void DeferResourceDestruction(ID3D12Resource* resource);
|
||||
|
||||
// Defers destruction of a descriptor handle (associates it with the current list).
|
||||
void DeferDescriptorDestruction(DescriptorHeapManager& manager, u32 index);
|
||||
|
||||
// Clears all samplers from the per-frame allocators.
|
||||
void ResetSamplerAllocators();
|
||||
|
||||
// Re-creates the root signature. Call when the host config changes (e.g. bbox/per-pixel shading).
|
||||
void RecreateGXRootSignature();
|
||||
|
||||
private:
|
||||
// Number of command lists. One is being built while the other(s) are executed.
|
||||
static const u32 NUM_COMMAND_LISTS = 3;
|
||||
|
||||
// Textures that don't fit into this buffer will be uploaded with a staging buffer.
|
||||
static const u32 TEXTURE_UPLOAD_BUFFER_SIZE = 32 * 1024 * 1024;
|
||||
|
||||
struct CommandListResources
|
||||
{
|
||||
ComPtr<ID3D12CommandAllocator> command_allocator;
|
||||
ComPtr<ID3D12GraphicsCommandList> command_list;
|
||||
DescriptorAllocator descriptor_allocator;
|
||||
SamplerAllocator sampler_allocator;
|
||||
std::vector<ID3D12Resource*> pending_resources;
|
||||
std::vector<std::pair<DescriptorHeapManager&, u32>> pending_descriptors;
|
||||
u64 ready_fence_value = 0;
|
||||
};
|
||||
|
||||
DXContext();
|
||||
|
||||
bool CreateDXGIFactory(bool enable_debug_layer);
|
||||
bool CreateDevice(u32 adapter_index, bool enable_debug_layer);
|
||||
bool CreateCommandQueue();
|
||||
bool CreateFence();
|
||||
bool CreateDescriptorHeaps();
|
||||
bool CreateRootSignatures();
|
||||
bool CreateGXRootSignature();
|
||||
bool CreateUtilityRootSignature();
|
||||
bool CreateComputeRootSignature();
|
||||
bool CreateTextureUploadBuffer();
|
||||
bool CreateCommandLists();
|
||||
void MoveToNextCommandList();
|
||||
void DestroyPendingResources(CommandListResources& cmdlist);
|
||||
|
||||
ComPtr<IDXGIFactory2> m_dxgi_factory;
|
||||
ComPtr<ID3D12Debug> m_debug_interface;
|
||||
ComPtr<ID3D12Device> m_device;
|
||||
ComPtr<ID3D12CommandQueue> m_command_queue;
|
||||
|
||||
ComPtr<ID3D12Fence> m_fence = nullptr;
|
||||
HANDLE m_fence_event = {};
|
||||
u32 m_current_fence_value = 0;
|
||||
u64 m_completed_fence_value = 0;
|
||||
|
||||
std::array<CommandListResources, NUM_COMMAND_LISTS> m_command_lists;
|
||||
u32 m_current_command_list = NUM_COMMAND_LISTS - 1;
|
||||
|
||||
DescriptorHeapManager m_descriptor_heap_manager;
|
||||
DescriptorHeapManager m_rtv_heap_manager;
|
||||
DescriptorHeapManager m_dsv_heap_manager;
|
||||
SamplerHeapManager m_sampler_heap_manager;
|
||||
std::array<ID3D12DescriptorHeap*, 2> m_gpu_descriptor_heaps = {};
|
||||
DescriptorHandle m_null_srv_descriptor;
|
||||
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
|
||||
|
||||
ComPtr<ID3D12RootSignature> m_gx_root_signature;
|
||||
ComPtr<ID3D12RootSignature> m_utility_root_signature;
|
||||
ComPtr<ID3D12RootSignature> m_compute_root_signature;
|
||||
|
||||
StreamBuffer m_texture_upload_buffer;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<DXContext> g_dx_context;
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/D3D12/Common.h"
|
||||
#include "VideoBackends/D3D12/DXContext.h"
|
||||
#include "VideoBackends/D3D12/DXPipeline.h"
|
||||
#include "VideoBackends/D3D12/DXShader.h"
|
||||
#include "VideoBackends/D3D12/DXTexture.h"
|
||||
#include "VideoBackends/D3D12/DXVertexFormat.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
DXPipeline::DXPipeline(ID3D12PipelineState* pipeline, ID3D12RootSignature* root_signature,
|
||||
AbstractPipelineUsage usage, D3D12_PRIMITIVE_TOPOLOGY primitive_topology,
|
||||
bool use_integer_rtv)
|
||||
: m_pipeline(pipeline), m_root_signature(root_signature), m_usage(usage),
|
||||
m_primitive_topology(primitive_topology), m_use_integer_rtv(use_integer_rtv)
|
||||
{
|
||||
}
|
||||
|
||||
DXPipeline::~DXPipeline()
|
||||
{
|
||||
m_pipeline->Release();
|
||||
}
|
||||
|
||||
static D3D12_PRIMITIVE_TOPOLOGY GetD3DTopology(const RasterizationState& state)
|
||||
{
|
||||
switch (state.primitive)
|
||||
{
|
||||
case PrimitiveType::Points:
|
||||
return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
case PrimitiveType::Lines:
|
||||
return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
case PrimitiveType::Triangles:
|
||||
return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case PrimitiveType::TriangleStrip:
|
||||
default:
|
||||
return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
}
|
||||
}
|
||||
|
||||
static D3D12_PRIMITIVE_TOPOLOGY_TYPE GetD3DTopologyType(const RasterizationState& state)
|
||||
{
|
||||
switch (state.primitive)
|
||||
{
|
||||
case PrimitiveType::Points:
|
||||
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
|
||||
case PrimitiveType::Lines:
|
||||
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
case PrimitiveType::Triangles:
|
||||
case PrimitiveType::TriangleStrip:
|
||||
default:
|
||||
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void GetD3DRasterizerDesc(D3D12_RASTERIZER_DESC* desc, const RasterizationState& rs_state,
|
||||
const FramebufferState& fb_state)
|
||||
{
|
||||
// No CULL_ALL here.
|
||||
static constexpr std::array<D3D12_CULL_MODE, 4> cull_modes = {
|
||||
{D3D12_CULL_MODE_NONE, D3D12_CULL_MODE_BACK, D3D12_CULL_MODE_FRONT, D3D12_CULL_MODE_FRONT}};
|
||||
|
||||
desc->FillMode = D3D12_FILL_MODE_SOLID;
|
||||
desc->CullMode = cull_modes[rs_state.cullmode];
|
||||
desc->MultisampleEnable = fb_state.samples > 1;
|
||||
}
|
||||
|
||||
static void GetD3DDepthDesc(D3D12_DEPTH_STENCIL_DESC* desc, const DepthState& state)
|
||||
{
|
||||
// Less/greater are swapped due to inverted depth.
|
||||
static constexpr std::array<D3D12_COMPARISON_FUNC, 8> compare_funcs = {
|
||||
{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}};
|
||||
|
||||
desc->DepthEnable = state.testenable;
|
||||
desc->DepthFunc = compare_funcs[state.func];
|
||||
desc->DepthWriteMask =
|
||||
state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||
}
|
||||
|
||||
static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
|
||||
{
|
||||
static constexpr std::array<D3D12_BLEND, 8> src_dual_src_factors = {
|
||||
{D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_DEST_COLOR, D3D12_BLEND_INV_DEST_COLOR,
|
||||
D3D12_BLEND_SRC1_ALPHA, D3D12_BLEND_INV_SRC1_ALPHA, D3D12_BLEND_DEST_ALPHA,
|
||||
D3D12_BLEND_INV_DEST_ALPHA}};
|
||||
static constexpr std::array<D3D12_BLEND, 8> dst_dual_src_factors = {
|
||||
{D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_SRC_COLOR, D3D12_BLEND_INV_SRC_COLOR,
|
||||
D3D12_BLEND_SRC1_ALPHA, D3D12_BLEND_INV_SRC1_ALPHA, D3D12_BLEND_DEST_ALPHA,
|
||||
D3D12_BLEND_INV_DEST_ALPHA}};
|
||||
static constexpr std::array<D3D12_BLEND, 8> src_factors = {
|
||||
{D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_DEST_COLOR, D3D12_BLEND_INV_DEST_COLOR,
|
||||
D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_DEST_ALPHA,
|
||||
D3D12_BLEND_INV_DEST_ALPHA}};
|
||||
|
||||
static constexpr std::array<D3D12_BLEND, 8> dst_factors = {
|
||||
{D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_SRC_COLOR, D3D12_BLEND_INV_SRC_COLOR,
|
||||
D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_DEST_ALPHA,
|
||||
D3D12_BLEND_INV_DEST_ALPHA}};
|
||||
|
||||
static constexpr std::array<D3D12_LOGIC_OP, 16> logic_ops = {
|
||||
{D3D12_LOGIC_OP_CLEAR, D3D12_LOGIC_OP_AND, D3D12_LOGIC_OP_AND_REVERSE, D3D12_LOGIC_OP_COPY,
|
||||
D3D12_LOGIC_OP_AND_INVERTED, D3D12_LOGIC_OP_NOOP, D3D12_LOGIC_OP_XOR, D3D12_LOGIC_OP_OR,
|
||||
D3D12_LOGIC_OP_NOR, D3D12_LOGIC_OP_EQUIV, D3D12_LOGIC_OP_INVERT, D3D12_LOGIC_OP_OR_REVERSE,
|
||||
D3D12_LOGIC_OP_COPY_INVERTED, D3D12_LOGIC_OP_OR_INVERTED, D3D12_LOGIC_OP_NAND,
|
||||
D3D12_LOGIC_OP_SET}};
|
||||
|
||||
desc->AlphaToCoverageEnable = FALSE;
|
||||
desc->IndependentBlendEnable = FALSE;
|
||||
|
||||
D3D12_RENDER_TARGET_BLEND_DESC* rtblend = &desc->RenderTarget[0];
|
||||
if (state.colorupdate)
|
||||
{
|
||||
rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED |
|
||||
D3D12_COLOR_WRITE_ENABLE_GREEN |
|
||||
D3D12_COLOR_WRITE_ENABLE_BLUE;
|
||||
}
|
||||
if (state.alphaupdate)
|
||||
{
|
||||
rtblend->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
|
||||
}
|
||||
|
||||
// blend takes precedence over logic op
|
||||
rtblend->BlendEnable = state.blendenable;
|
||||
if (state.blendenable)
|
||||
{
|
||||
rtblend->BlendOp = state.subtract ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
|
||||
rtblend->BlendOpAlpha = state.subtractAlpha ? D3D12_BLEND_OP_REV_SUBTRACT : D3D12_BLEND_OP_ADD;
|
||||
if (state.usedualsrc)
|
||||
{
|
||||
rtblend->SrcBlend = src_dual_src_factors[state.srcfactor];
|
||||
rtblend->SrcBlendAlpha = src_dual_src_factors[state.srcfactoralpha];
|
||||
rtblend->DestBlend = dst_dual_src_factors[state.dstfactor];
|
||||
rtblend->DestBlendAlpha = dst_dual_src_factors[state.dstfactoralpha];
|
||||
}
|
||||
else
|
||||
{
|
||||
rtblend->SrcBlend = src_factors[state.srcfactor];
|
||||
rtblend->SrcBlendAlpha = src_factors[state.srcfactoralpha];
|
||||
rtblend->DestBlend = dst_factors[state.dstfactor];
|
||||
rtblend->DestBlendAlpha = dst_factors[state.dstfactoralpha];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rtblend->LogicOpEnable = state.logicopenable;
|
||||
if (state.logicopenable)
|
||||
rtblend->LogicOp = logic_ops[state.logicmode];
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config)
|
||||
{
|
||||
DEBUG_ASSERT(config.vertex_shader && config.pixel_shader);
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {};
|
||||
switch (config.usage)
|
||||
{
|
||||
case AbstractPipelineUsage::GX:
|
||||
desc.pRootSignature = g_dx_context->GetGXRootSignature();
|
||||
break;
|
||||
case AbstractPipelineUsage::Utility:
|
||||
desc.pRootSignature = g_dx_context->GetUtilityRootSignature();
|
||||
break;
|
||||
default:
|
||||
PanicAlert("Unknown pipeline layout.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (config.vertex_shader)
|
||||
desc.VS = static_cast<const DXShader*>(config.vertex_shader)->GetD3DByteCode();
|
||||
if (config.geometry_shader)
|
||||
desc.GS = static_cast<const DXShader*>(config.geometry_shader)->GetD3DByteCode();
|
||||
if (config.pixel_shader)
|
||||
desc.PS = static_cast<const DXShader*>(config.pixel_shader)->GetD3DByteCode();
|
||||
|
||||
GetD3DBlendDesc(&desc.BlendState, config.blending_state);
|
||||
desc.SampleMask = 0xFFFFFFFF;
|
||||
GetD3DRasterizerDesc(&desc.RasterizerState, config.rasterization_state, config.framebuffer_state);
|
||||
GetD3DDepthDesc(&desc.DepthStencilState, config.depth_state);
|
||||
if (config.vertex_format)
|
||||
static_cast<const DXVertexFormat*>(config.vertex_format)->GetInputLayoutDesc(&desc.InputLayout);
|
||||
desc.IBStripCutValue = config.rasterization_state.primitive == PrimitiveType::TriangleStrip ?
|
||||
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF :
|
||||
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
||||
desc.PrimitiveTopologyType = GetD3DTopologyType(config.rasterization_state);
|
||||
if (config.framebuffer_state.color_texture_format != AbstractTextureFormat::Undefined)
|
||||
{
|
||||
desc.NumRenderTargets = 1;
|
||||
desc.RTVFormats[0] = D3DCommon::GetRTVFormatForAbstractFormat(
|
||||
config.framebuffer_state.color_texture_format, config.blending_state.logicopenable);
|
||||
}
|
||||
if (config.framebuffer_state.depth_texture_format != AbstractTextureFormat::Undefined)
|
||||
desc.DSVFormat =
|
||||
D3DCommon::GetDSVFormatForAbstractFormat(config.framebuffer_state.depth_texture_format);
|
||||
desc.SampleDesc.Count = config.framebuffer_state.samples;
|
||||
desc.NodeMask = 1;
|
||||
|
||||
ID3D12PipelineState* pso;
|
||||
HRESULT hr = g_dx_context->GetDevice()->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pso));
|
||||
CHECK(SUCCEEDED(hr), "Create PSO");
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
const bool use_integer_rtv =
|
||||
!config.blending_state.blendenable && config.blending_state.logicopenable;
|
||||
return std::make_unique<DXPipeline>(pso, desc.pRootSignature, config.usage,
|
||||
GetD3DTopology(config.rasterization_state), use_integer_rtv);
|
||||
}
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <memory>
|
||||
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
class DXPipeline final : public AbstractPipeline
|
||||
{
|
||||
public:
|
||||
DXPipeline(ID3D12PipelineState* pipeline, ID3D12RootSignature* root_signature,
|
||||
AbstractPipelineUsage usage, D3D12_PRIMITIVE_TOPOLOGY primitive_topology,
|
||||
bool use_integer_rtv);
|
||||
~DXPipeline() override;
|
||||
|
||||
static std::unique_ptr<DXPipeline> Create(const AbstractPipelineConfig& config);
|
||||
|
||||
ID3D12PipelineState* GetPipeline() const { return m_pipeline; }
|
||||
ID3D12RootSignature* GetRootSignature() const { return m_root_signature; }
|
||||
AbstractPipelineUsage GetUsage() const { return m_usage; }
|
||||
D3D12_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_primitive_topology; }
|
||||
bool UseIntegerRTV() const { return m_use_integer_rtv; }
|
||||
|
||||
private:
|
||||
ID3D12PipelineState* m_pipeline;
|
||||
ID3D12RootSignature* m_root_signature;
|
||||
AbstractPipelineUsage m_usage;
|
||||
D3D12_PRIMITIVE_TOPOLOGY m_primitive_topology;
|
||||
bool m_use_integer_rtv;
|
||||
};
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D12/DXShader.h"
|
||||
#include "VideoBackends/D3D12/Common.h"
|
||||
#include "VideoBackends/D3D12/DXContext.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
DXShader::DXShader(ShaderStage stage, BinaryData bytecode)
|
||||
: D3DCommon::Shader(stage, std::move(bytecode))
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::~DXShader() = default;
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromBytecode(ShaderStage stage, BinaryData bytecode)
|
||||
{
|
||||
std::unique_ptr<DXShader> shader(new DXShader(stage, std::move(bytecode)));
|
||||
if (stage == ShaderStage::Compute && !shader->CreateComputePipeline())
|
||||
return nullptr;
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length)
|
||||
{
|
||||
BinaryData bytecode;
|
||||
if (!CompileShader(g_dx_context->GetFeatureLevel(), &bytecode, stage, source, length))
|
||||
return nullptr;
|
||||
|
||||
return CreateFromBytecode(stage, std::move(bytecode));
|
||||
}
|
||||
|
||||
D3D12_SHADER_BYTECODE DXShader::GetD3DByteCode() const
|
||||
{
|
||||
return D3D12_SHADER_BYTECODE{m_bytecode.data(), m_bytecode.size()};
|
||||
}
|
||||
|
||||
bool DXShader::CreateComputePipeline()
|
||||
{
|
||||
D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {};
|
||||
desc.pRootSignature = g_dx_context->GetComputeRootSignature();
|
||||
desc.CS = GetD3DByteCode();
|
||||
desc.NodeMask = 1;
|
||||
|
||||
HRESULT hr = g_dx_context->GetDevice()->CreateComputePipelineState(
|
||||
&desc, IID_PPV_ARGS(&m_compute_pipeline));
|
||||
CHECK(SUCCEEDED(hr), "Creating compute pipeline failed");
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "VideoBackends/D3D12/Common.h"
|
||||
#include "VideoBackends/D3DCommon/Shader.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
class DXShader final : public D3DCommon::Shader
|
||||
{
|
||||
public:
|
||||
~DXShader() override;
|
||||
|
||||
ID3D12PipelineState* GetComputePipeline() const { return m_compute_pipeline.Get(); }
|
||||
D3D12_SHADER_BYTECODE GetD3DByteCode() const;
|
||||
|
||||
static std::unique_ptr<DXShader> CreateFromBytecode(ShaderStage stage, BinaryData bytecode);
|
||||
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length);
|
||||
|
||||
private:
|
||||
DXShader(ShaderStage stage, BinaryData bytecode);
|
||||
|
||||
bool CreateComputePipeline();
|
||||
|
||||
ComPtr<ID3D12PipelineState> m_compute_pipeline;
|
||||
};
|
||||
|
||||
} // namespace DX12
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,126 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoBackends/D3D12/Common.h"
|
||||
#include "VideoBackends/D3D12/DescriptorHeapManager.h"
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
class DXTexture final : public AbstractTexture
|
||||
{
|
||||
public:
|
||||
~DXTexture();
|
||||
|
||||
static std::unique_ptr<DXTexture> Create(const TextureConfig& config);
|
||||
static std::unique_ptr<DXTexture> CreateAdopted(ID3D12Resource* resource);
|
||||
|
||||
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||
size_t buffer_size) override;
|
||||
void CopyRectangleFromTexture(const AbstractTexture* src,
|
||||
const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
|
||||
u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
|
||||
u32 dst_layer, u32 dst_level) override;
|
||||
void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
|
||||
u32 layer, u32 level) override;
|
||||
void FinishedRendering() override;
|
||||
|
||||
ID3D12Resource* GetResource() const { return m_resource.Get(); }
|
||||
const DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
|
||||
const DescriptorHandle& GetUAVDescriptor() const { return m_uav_descriptor; }
|
||||
D3D12_RESOURCE_STATES GetState() const { return m_state; }
|
||||
u32 CalcSubresource(u32 level, u32 layer) const { return level + layer * m_config.layers; }
|
||||
|
||||
void TransitionToState(D3D12_RESOURCE_STATES state) const;
|
||||
|
||||
// Destoys the resource backing this texture. The resource must not be in use by the GPU.
|
||||
void DestroyResource();
|
||||
|
||||
private:
|
||||
DXTexture(const TextureConfig& config, ID3D12Resource* resource, D3D12_RESOURCE_STATES state);
|
||||
|
||||
bool CreateSRVDescriptor();
|
||||
bool CreateUAVDescriptor();
|
||||
|
||||
ComPtr<ID3D12Resource> m_resource;
|
||||
DescriptorHandle m_srv_descriptor = {};
|
||||
DescriptorHandle m_uav_descriptor = {};
|
||||
|
||||
mutable D3D12_RESOURCE_STATES m_state;
|
||||
};
|
||||
|
||||
class DXFramebuffer final : public AbstractFramebuffer
|
||||
{
|
||||
public:
|
||||
~DXFramebuffer() override;
|
||||
|
||||
const DescriptorHandle& GetRTVDescriptor() const { return m_rtv_descriptor; }
|
||||
const DescriptorHandle& GetIntRTVDescriptor() const { return m_int_rtv_descriptor; }
|
||||
const DescriptorHandle& GetDSVDescriptor() const { return m_dsv_descriptor; }
|
||||
|
||||
UINT GetRTVDescriptorCount() const { return m_color_attachment ? 1 : 0; }
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE* GetRTVDescriptorArray() const
|
||||
{
|
||||
return m_color_attachment ? &m_rtv_descriptor.cpu_handle : nullptr;
|
||||
}
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE* GetIntRTVDescriptorArray() const
|
||||
{
|
||||
return m_color_attachment ? &m_int_rtv_descriptor.cpu_handle : nullptr;
|
||||
}
|
||||
const D3D12_CPU_DESCRIPTOR_HANDLE* GetDSVDescriptorArray() const
|
||||
{
|
||||
return m_depth_attachment ? &m_dsv_descriptor.cpu_handle : nullptr;
|
||||
}
|
||||
|
||||
static std::unique_ptr<DXFramebuffer> Create(DXTexture* color_attachment,
|
||||
DXTexture* depth_attachment);
|
||||
|
||||
private:
|
||||
DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||
AbstractTextureFormat color_format, AbstractTextureFormat depth_format, u32 width,
|
||||
u32 height, u32 layers, u32 samples);
|
||||
|
||||
bool CreateRTVDescriptor();
|
||||
bool CreateDSVDescriptor();
|
||||
|
||||
DescriptorHandle m_rtv_descriptor = {};
|
||||
DescriptorHandle m_int_rtv_descriptor = {};
|
||||
DescriptorHandle m_dsv_descriptor = {};
|
||||
};
|
||||
|
||||
class DXStagingTexture final : public AbstractStagingTexture
|
||||
{
|
||||
public:
|
||||
~DXStagingTexture();
|
||||
|
||||
void CopyFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& src_rect,
|
||||
u32 src_layer, u32 src_level,
|
||||
const MathUtil::Rectangle<int>& dst_rect) override;
|
||||
void CopyToTexture(const MathUtil::Rectangle<int>& src_rect, AbstractTexture* dst,
|
||||
const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
|
||||
u32 dst_level) override;
|
||||
|
||||
bool Map() override;
|
||||
void Unmap() override;
|
||||
void Flush() override;
|
||||
|
||||
static std::unique_ptr<DXStagingTexture> Create(StagingTextureType type,
|
||||
const TextureConfig& config);
|
||||
|
||||
private:
|
||||
DXStagingTexture(StagingTextureType type, const TextureConfig& config, ID3D12Resource* resource,
|
||||
u32 stride, u32 buffer_size);
|
||||
|
||||
ComPtr<ID3D12Resource> m_resource;
|
||||
u64 m_completed_fence = 0;
|
||||
u32 m_buffer_size;
|
||||
};
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D12/DXVertexFormat.h"
|
||||
|
||||
#include "Common/Assert.h"
|
||||
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
static DXGI_FORMAT VarToDXGIFormat(VarType t, u32 components, bool integer)
|
||||
{
|
||||
// NOTE: 3-component formats are not valid.
|
||||
static const DXGI_FORMAT float_type_lookup[][4] = {
|
||||
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM}, // VAR_UNSIGNED_BYTE
|
||||
{DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_SNORM}, // VAR_BYTE
|
||||
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_UNORM}, // VAR_UNSIGNED_SHORT
|
||||
{DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16B16A16_SNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM}, // VAR_SHORT
|
||||
{DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT} // VAR_FLOAT
|
||||
};
|
||||
|
||||
static const DXGI_FORMAT integer_type_lookup[][4] = {
|
||||
{DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8B8A8_UINT,
|
||||
DXGI_FORMAT_R8G8B8A8_UINT}, // VAR_UNSIGNED_BYTE
|
||||
{DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8B8A8_SINT,
|
||||
DXGI_FORMAT_R8G8B8A8_SINT}, // VAR_BYTE
|
||||
{DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16B16A16_UINT,
|
||||
DXGI_FORMAT_R16G16B16A16_UINT}, // VAR_UNSIGNED_SHORT
|
||||
{DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16B16A16_SINT,
|
||||
DXGI_FORMAT_R16G16B16A16_SINT}, // VAR_SHORT
|
||||
{DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT} // VAR_FLOAT
|
||||
};
|
||||
|
||||
ASSERT(components > 0 && components <= 4);
|
||||
return integer ? integer_type_lookup[t][components - 1] : float_type_lookup[t][components - 1];
|
||||
}
|
||||
|
||||
DXVertexFormat::DXVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
: NativeVertexFormat(vtx_decl)
|
||||
{
|
||||
MapAttributes();
|
||||
}
|
||||
|
||||
void DXVertexFormat::GetInputLayoutDesc(D3D12_INPUT_LAYOUT_DESC* desc) const
|
||||
{
|
||||
desc->pInputElementDescs = m_attribute_descriptions.data();
|
||||
desc->NumElements = m_num_attributes;
|
||||
}
|
||||
|
||||
void DXVertexFormat::AddAttribute(const char* semantic_name, u32 semantic_index, u32 slot,
|
||||
DXGI_FORMAT format, u32 offset)
|
||||
{
|
||||
ASSERT(m_num_attributes < MAX_VERTEX_ATTRIBUTES);
|
||||
|
||||
auto* attr_desc = &m_attribute_descriptions[m_num_attributes];
|
||||
attr_desc->SemanticName = semantic_name;
|
||||
attr_desc->SemanticIndex = semantic_index;
|
||||
attr_desc->Format = format;
|
||||
attr_desc->InputSlot = slot;
|
||||
attr_desc->AlignedByteOffset = offset;
|
||||
attr_desc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
attr_desc->InstanceDataStepRate = 0;
|
||||
|
||||
m_num_attributes++;
|
||||
}
|
||||
|
||||
void DXVertexFormat::MapAttributes()
|
||||
{
|
||||
m_num_attributes = 0;
|
||||
|
||||
if (m_decl.position.enable)
|
||||
{
|
||||
AddAttribute(
|
||||
"POSITION", 0, 0,
|
||||
VarToDXGIFormat(m_decl.position.type, m_decl.position.components, m_decl.position.integer),
|
||||
m_decl.position.offset);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 3; i++)
|
||||
{
|
||||
if (m_decl.normals[i].enable)
|
||||
{
|
||||
AddAttribute("NORMAL", i, 0,
|
||||
VarToDXGIFormat(m_decl.normals[i].type, m_decl.normals[i].components,
|
||||
m_decl.normals[i].integer),
|
||||
m_decl.normals[i].offset);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 2; i++)
|
||||
{
|
||||
if (m_decl.colors[i].enable)
|
||||
{
|
||||
AddAttribute("COLOR", i, 0,
|
||||
VarToDXGIFormat(m_decl.colors[i].type, m_decl.colors[i].components,
|
||||
m_decl.colors[i].integer),
|
||||
m_decl.colors[i].offset);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (m_decl.texcoords[i].enable)
|
||||
{
|
||||
AddAttribute("TEXCOORD", i, 0,
|
||||
VarToDXGIFormat(m_decl.texcoords[i].type, m_decl.texcoords[i].components,
|
||||
m_decl.texcoords[i].integer),
|
||||
m_decl.texcoords[i].offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_decl.posmtx.enable)
|
||||
{
|
||||
AddAttribute(
|
||||
"BLENDINDICES", 0, 0,
|
||||
VarToDXGIFormat(m_decl.posmtx.type, m_decl.posmtx.components, m_decl.posmtx.integer),
|
||||
m_decl.posmtx.offset);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DX12
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
class DXVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
public:
|
||||
static const u32 MAX_VERTEX_ATTRIBUTES = 16;
|
||||
|
||||
DXVertexFormat(const PortableVertexDeclaration& vtx_decl);
|
||||
|
||||
// Passed to pipeline state creation
|
||||
void GetInputLayoutDesc(D3D12_INPUT_LAYOUT_DESC* desc) const;
|
||||
|
||||
private:
|
||||
void AddAttribute(const char* semantic_name, u32 semantic_index, u32 slot, DXGI_FORMAT format,
|
||||
u32 offset);
|
||||
void MapAttributes();
|
||||
|
||||
std::array<D3D12_INPUT_ELEMENT_DESC, MAX_VERTEX_ATTRIBUTES> m_attribute_descriptions = {};
|
||||
u32 m_num_attributes = 0;
|
||||
};
|
||||
} // namespace Vulkan
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/D3D12/DescriptorAllocator.h"
|
||||
#include "VideoBackends/D3D12/DXContext.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
DescriptorAllocator::DescriptorAllocator() = default;
|
||||
DescriptorAllocator::~DescriptorAllocator() = default;
|
||||
|
||||
bool DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type,
|
||||
u32 num_descriptors)
|
||||
{
|
||||
const D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast<UINT>(num_descriptors),
|
||||
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE};
|
||||
HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_descriptor_heap));
|
||||
CHECK(SUCCEEDED(hr), "Creating descriptor heap for linear allocator failed");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
m_num_descriptors = num_descriptors;
|
||||
m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(type);
|
||||
m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart();
|
||||
m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorAllocator::Allocate(u32 num_handles, DescriptorHandle* out_base_handle)
|
||||
{
|
||||
if ((m_current_offset + num_handles) > m_num_descriptors)
|
||||
return false;
|
||||
|
||||
out_base_handle->index = m_current_offset;
|
||||
out_base_handle->cpu_handle.ptr =
|
||||
m_heap_base_cpu.ptr + m_current_offset * m_descriptor_increment_size;
|
||||
out_base_handle->gpu_handle.ptr =
|
||||
m_heap_base_gpu.ptr + m_current_offset * m_descriptor_increment_size;
|
||||
m_current_offset += num_handles;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DescriptorAllocator::Reset()
|
||||
{
|
||||
m_current_offset = 0;
|
||||
}
|
||||
|
||||
bool operator==(const SamplerStateSet& lhs, const SamplerStateSet& rhs)
|
||||
{
|
||||
// There shouldn't be any padding here, so this will be safe.
|
||||
return std::memcmp(lhs.states, rhs.states, sizeof(lhs.states)) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const SamplerStateSet& lhs, const SamplerStateSet& rhs)
|
||||
{
|
||||
return std::memcmp(lhs.states, rhs.states, sizeof(lhs.states)) != 0;
|
||||
}
|
||||
|
||||
bool operator<(const SamplerStateSet& lhs, const SamplerStateSet& rhs)
|
||||
{
|
||||
return std::memcmp(lhs.states, rhs.states, sizeof(lhs.states)) < 0;
|
||||
}
|
||||
|
||||
SamplerAllocator::SamplerAllocator() = default;
|
||||
SamplerAllocator::~SamplerAllocator() = default;
|
||||
|
||||
bool SamplerAllocator::Create(ID3D12Device* device)
|
||||
{
|
||||
return DescriptorAllocator::Create(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
|
||||
D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE);
|
||||
}
|
||||
|
||||
bool SamplerAllocator::GetGroupHandle(const SamplerStateSet& sss,
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE* handle)
|
||||
{
|
||||
auto it = m_sampler_map.find(sss);
|
||||
if (it != m_sampler_map.end())
|
||||
{
|
||||
*handle = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate a group of descriptors.
|
||||
DescriptorHandle allocation;
|
||||
if (!Allocate(SamplerStateSet::NUM_SAMPLERS_PER_GROUP, &allocation))
|
||||
return false;
|
||||
|
||||
// Lookup sampler handles from global cache.
|
||||
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, SamplerStateSet::NUM_SAMPLERS_PER_GROUP> source_handles;
|
||||
for (u32 i = 0; i < SamplerStateSet::NUM_SAMPLERS_PER_GROUP; i++)
|
||||
{
|
||||
if (!g_dx_context->GetSamplerHeapManager().Lookup(sss.states[i], &source_handles[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy samplers from the sampler heap.
|
||||
static constexpr std::array<UINT, SamplerStateSet::NUM_SAMPLERS_PER_GROUP> source_sizes = {
|
||||
{1, 1, 1, 1, 1, 1, 1, 1}};
|
||||
g_dx_context->GetDevice()->CopyDescriptors(
|
||||
1, &allocation.cpu_handle, &SamplerStateSet::NUM_SAMPLERS_PER_GROUP,
|
||||
SamplerStateSet::NUM_SAMPLERS_PER_GROUP, source_handles.data(), source_sizes.data(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
*handle = allocation.gpu_handle;
|
||||
m_sampler_map.emplace(sss, allocation.gpu_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SamplerAllocator::ShouldReset() const
|
||||
{
|
||||
// We only reset the sampler heap if more than half of the descriptors are used.
|
||||
// This saves descriptor copying when there isn't a large number of sampler configs per frame.
|
||||
return m_sampler_map.size() >= (D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE / 2);
|
||||
}
|
||||
|
||||
void SamplerAllocator::Reset()
|
||||
{
|
||||
DescriptorAllocator::Reset();
|
||||
m_sampler_map.clear();
|
||||
}
|
||||
} // 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