mirror of https://github.com/PCSX2/pcsx2.git
GS/DX12: Combine GSDevice12 and D3D12Context
This commit is contained in:
parent
9678bf1e2f
commit
2887baefb8
|
@ -708,7 +708,6 @@ if(WIN32)
|
|||
GS/Renderers/DX11/GSTexture11.cpp
|
||||
GS/Renderers/DX11/GSTextureFX11.cpp
|
||||
GS/Renderers/DX12/D3D12Builders.cpp
|
||||
GS/Renderers/DX12/D3D12Context.cpp
|
||||
GS/Renderers/DX12/D3D12DescriptorHeapManager.cpp
|
||||
GS/Renderers/DX12/D3D12ShaderCache.cpp
|
||||
GS/Renderers/DX12/D3D12StreamBuffer.cpp
|
||||
|
@ -721,7 +720,6 @@ if(WIN32)
|
|||
GS/Renderers/DX11/GSDevice11.h
|
||||
GS/Renderers/DX11/GSTexture11.h
|
||||
GS/Renderers/DX12/D3D12Builders.h
|
||||
GS/Renderers/DX12/D3D12Context.h
|
||||
GS/Renderers/DX12/D3D12DescriptorHeapManager.h
|
||||
GS/Renderers/DX12/D3D12ShaderCache.h
|
||||
GS/Renderers/DX12/D3D12StreamBuffer.h
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "GS/Renderers/DX12/D3D12Builders.h"
|
||||
#include "GS/Renderers/DX12/D3D12Context.h"
|
||||
#include "GS/Renderers/DX12/D3D12ShaderCache.h"
|
||||
#include "GS/Renderers/DX12/GSDevice12.h"
|
||||
#include "common/Console.h"
|
||||
|
||||
#include <cstdarg>
|
||||
|
@ -291,7 +291,7 @@ void D3D12::RootSignatureBuilder::Clear()
|
|||
|
||||
wil::com_ptr_nothrow<ID3D12RootSignature> D3D12::RootSignatureBuilder::Create(bool clear /*= true*/)
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D12RootSignature> rs = g_d3d12_context->CreateRootSignature(&m_desc);
|
||||
wil::com_ptr_nothrow<ID3D12RootSignature> rs = GSDevice12::GetInstance()->CreateRootSignature(&m_desc);
|
||||
if (!rs)
|
||||
return {};
|
||||
|
||||
|
@ -362,3 +362,20 @@ u32 D3D12::RootSignatureBuilder::AddDescriptorTable(
|
|||
|
||||
return index;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
void D3D12::SetObjectName(ID3D12Object* object, const char* name)
|
||||
{
|
||||
object->SetName(StringUtil::UTF8StringToWideString(name).c_str());
|
||||
}
|
||||
|
||||
void D3D12::SetObjectNameFormatted(ID3D12Object* object, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
SetObjectName(object, StringUtil::StdStringFromFormatV(format, ap).c_str());
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -141,4 +141,15 @@ namespace D3D12
|
|||
D3D12_COMPUTE_PIPELINE_STATE_DESC m_desc;
|
||||
};
|
||||
|
||||
} // namespace D3D12
|
||||
#ifdef _DEBUG
|
||||
void SetObjectName(ID3D12Object* object, const char* name);
|
||||
void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...);
|
||||
#else
|
||||
static inline void SetObjectName(ID3D12Object* object, const char* name)
|
||||
{
|
||||
}
|
||||
static inline void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
} // namespace D3D12
|
||||
|
|
|
@ -1,686 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "GS/Renderers/DX12/D3D12Context.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/General.h"
|
||||
#include "common/ScopedGuard.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "D3D12MemAlloc.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <dxgi1_4.h>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
std::unique_ptr<D3D12Context> g_d3d12_context;
|
||||
|
||||
D3D12Context::D3D12Context() = default;
|
||||
|
||||
D3D12Context::~D3D12Context()
|
||||
{
|
||||
DestroyResources();
|
||||
}
|
||||
|
||||
D3D12Context::ComPtr<ID3DBlob> D3D12Context::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc)
|
||||
{
|
||||
ComPtr<ID3DBlob> blob;
|
||||
ComPtr<ID3DBlob> error_blob;
|
||||
const HRESULT hr = D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.put(), error_blob.put());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("D3D12SerializeRootSignature() failed: %08X", hr);
|
||||
if (error_blob)
|
||||
Console.Error("%s", error_blob->GetBufferPointer());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
D3D12Context::ComPtr<ID3D12RootSignature> D3D12Context::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc)
|
||||
{
|
||||
ComPtr<ID3DBlob> blob = SerializeRootSignature(desc);
|
||||
if (!blob)
|
||||
return {};
|
||||
|
||||
ComPtr<ID3D12RootSignature> rs;
|
||||
const HRESULT hr =
|
||||
m_device->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(rs.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("CreateRootSignature() failed: %08X", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
bool D3D12Context::SupportsTextureFormat(DXGI_FORMAT format)
|
||||
{
|
||||
constexpr u32 required = D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE;
|
||||
|
||||
D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {format};
|
||||
return SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) &&
|
||||
(support.Support1 & required) == required;
|
||||
}
|
||||
|
||||
bool D3D12Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer)
|
||||
{
|
||||
pxAssertRel(!g_d3d12_context, "No context exists");
|
||||
|
||||
g_d3d12_context.reset(new D3D12Context());
|
||||
if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter, enable_debug_layer) ||
|
||||
!g_d3d12_context->CreateCommandQueue() || !g_d3d12_context->CreateAllocator() ||
|
||||
!g_d3d12_context->CreateFence() || !g_d3d12_context->CreateDescriptorHeaps() ||
|
||||
!g_d3d12_context->CreateCommandLists() || !g_d3d12_context->CreateTimestampQuery() ||
|
||||
!g_d3d12_context->CreateTextureStreamBuffer())
|
||||
{
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12Context::Destroy()
|
||||
{
|
||||
if (g_d3d12_context)
|
||||
g_d3d12_context.reset();
|
||||
}
|
||||
|
||||
u32 D3D12Context::GetAdapterVendorID() const
|
||||
{
|
||||
if (!m_adapter)
|
||||
return 0;
|
||||
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
if (FAILED(m_adapter->GetDesc(&desc)))
|
||||
return 0;
|
||||
|
||||
return desc.VendorId;
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
|
||||
if (enable_debug_layer)
|
||||
{
|
||||
hr = D3D12GetDebugInterface(IID_PPV_ARGS(&m_debug_interface));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_debug_interface->EnableDebugLayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Debug layer requested but not available.");
|
||||
enable_debug_layer = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the actual device.
|
||||
hr = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Failed to create D3D12 device: %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// get adapter
|
||||
const LUID luid(m_device->GetAdapterLuid());
|
||||
if (FAILED(dxgi_factory->EnumAdapterByLuid(luid, IID_PPV_ARGS(m_adapter.put()))))
|
||||
Console.Error("Failed to get lookup adapter by device LUID");
|
||||
|
||||
if (enable_debug_layer)
|
||||
{
|
||||
ComPtr<ID3D12InfoQueue> info_queue = m_device.try_query<ID3D12InfoQueue>();
|
||||
if (info_queue)
|
||||
{
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
|
||||
info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
|
||||
}
|
||||
|
||||
D3D12_INFO_QUEUE_FILTER filter = {};
|
||||
std::array<D3D12_MESSAGE_ID, 5> id_list{
|
||||
D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
|
||||
D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
|
||||
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET,
|
||||
D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH,
|
||||
D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE,
|
||||
};
|
||||
filter.DenyList.NumIDs = static_cast<UINT>(id_list.size());
|
||||
filter.DenyList.pIDList = id_list.data();
|
||||
info_queue->PushStorageFilter(&filter);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateCommandQueue()
|
||||
{
|
||||
const D3D12_COMMAND_QUEUE_DESC queue_desc = {
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, D3D12_COMMAND_QUEUE_FLAG_NONE};
|
||||
HRESULT hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue));
|
||||
pxAssertRel(SUCCEEDED(hr), "Create command queue");
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateAllocator()
|
||||
{
|
||||
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
|
||||
allocatorDesc.pDevice = m_device.get();
|
||||
allocatorDesc.pAdapter = m_adapter.get();
|
||||
allocatorDesc.Flags =
|
||||
D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED |
|
||||
D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED /* | D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED*/;
|
||||
|
||||
const HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, m_allocator.put());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("D3D12MA::CreateAllocator() failed with HRESULT %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateFence()
|
||||
{
|
||||
HRESULT hr = m_device->CreateFence(m_completed_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));
|
||||
pxAssertRel(SUCCEEDED(hr), "Create fence");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
m_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
pxAssertRel(m_fence_event != NULL, "Create fence event");
|
||||
if (!m_fence_event)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateDescriptorHeaps()
|
||||
{
|
||||
static constexpr size_t MAX_SRVS = 32768;
|
||||
static constexpr size_t MAX_RTVS = 16384;
|
||||
static constexpr size_t MAX_DSVS = 16384;
|
||||
static constexpr size_t MAX_CPU_SAMPLERS = 1024;
|
||||
|
||||
if (!m_descriptor_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, MAX_SRVS, false) ||
|
||||
!m_rtv_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, MAX_RTVS, false) ||
|
||||
!m_dsv_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV, MAX_DSVS, false) ||
|
||||
!m_sampler_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, MAX_CPU_SAMPLERS, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate null SRV descriptor for unbound textures.
|
||||
constexpr D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = {
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
|
||||
|
||||
if (!m_descriptor_heap_manager.Allocate(&m_null_srv_descriptor))
|
||||
{
|
||||
pxFailRel("Failed to allocate null descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_device->CreateShaderResourceView(nullptr, &null_srv_desc, m_null_srv_descriptor.cpu_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateCommandLists()
|
||||
{
|
||||
static constexpr size_t MAX_GPU_SRVS = 32768;
|
||||
static constexpr size_t MAX_GPU_SAMPLERS = 2048;
|
||||
|
||||
for (u32 i = 0; i < NUM_COMMAND_LISTS; i++)
|
||||
{
|
||||
CommandListResources& res = m_command_lists[i];
|
||||
HRESULT hr;
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
hr = m_device->CreateCommandAllocator(
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(res.command_allocators[i].put()));
|
||||
pxAssertRel(SUCCEEDED(hr), "Create command allocator");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, res.command_allocators[i].get(),
|
||||
nullptr, IID_PPV_ARGS(res.command_lists[i].put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Failed to create command list: %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close the command lists, since the first thing we do is reset them.
|
||||
hr = res.command_lists[i]->Close();
|
||||
pxAssertRel(SUCCEEDED(hr), "Closing new command list failed");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!res.descriptor_allocator.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, MAX_GPU_SRVS))
|
||||
{
|
||||
Console.Error("Failed to create per frame descriptor allocator");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!res.sampler_allocator.Create(m_device.get(), MAX_GPU_SAMPLERS))
|
||||
{
|
||||
Console.Error("Failed to create per frame sampler allocator");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MoveToNextCommandList();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateTextureStreamBuffer()
|
||||
{
|
||||
return m_texture_stream_buffer.Create(TEXTURE_UPLOAD_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void D3D12Context::MoveToNextCommandList()
|
||||
{
|
||||
m_current_command_list = (m_current_command_list + 1) % NUM_COMMAND_LISTS;
|
||||
m_current_fence_value++;
|
||||
|
||||
// We may have to wait if this command list hasn't finished on the GPU.
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
WaitForFence(res.ready_fence_value, false);
|
||||
res.ready_fence_value = m_current_fence_value;
|
||||
res.init_command_list_used = false;
|
||||
|
||||
// Begin command list.
|
||||
res.command_allocators[1]->Reset();
|
||||
res.command_lists[1]->Reset(res.command_allocators[1].get(), nullptr);
|
||||
res.descriptor_allocator.Reset();
|
||||
if (res.sampler_allocator.ShouldReset())
|
||||
res.sampler_allocator.Reset();
|
||||
|
||||
if (res.has_timestamp_query)
|
||||
{
|
||||
// readback timestamp from the last time this cmdlist was used.
|
||||
// we don't need to worry about disjoint in dx12, the frequency is reliable within a single cmdlist.
|
||||
const u32 offset = (m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
|
||||
const D3D12_RANGE read_range = {offset, offset + (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST)};
|
||||
void* map;
|
||||
HRESULT hr = m_timestamp_query_buffer->Map(0, &read_range, &map);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
u64 timestamps[2];
|
||||
std::memcpy(timestamps, static_cast<const u8*>(map) + offset, sizeof(timestamps));
|
||||
m_accumulated_gpu_time +=
|
||||
static_cast<float>(static_cast<double>(timestamps[1] - timestamps[0]) / m_timestamp_frequency);
|
||||
|
||||
const D3D12_RANGE write_range = {};
|
||||
m_timestamp_query_buffer->Unmap(0, &write_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("Map() for timestamp query failed: %08X", hr);
|
||||
}
|
||||
}
|
||||
|
||||
res.has_timestamp_query = m_gpu_timing_enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
{
|
||||
res.command_lists[1]->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST);
|
||||
}
|
||||
|
||||
ID3D12DescriptorHeap* heaps[2] = {
|
||||
res.descriptor_allocator.GetDescriptorHeap(), res.sampler_allocator.GetDescriptorHeap()};
|
||||
res.command_lists[1]->SetDescriptorHeaps(std::size(heaps), heaps);
|
||||
|
||||
m_allocator->SetCurrentFrameIndex(static_cast<UINT>(m_current_fence_value));
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList4* D3D12Context::GetInitCommandList()
|
||||
{
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
if (!res.init_command_list_used)
|
||||
{
|
||||
HRESULT hr = res.command_allocators[0]->Reset();
|
||||
pxAssertMsg(SUCCEEDED(hr), "Reset init command allocator failed");
|
||||
|
||||
res.command_lists[0]->Reset(res.command_allocators[0].get(), nullptr);
|
||||
pxAssertMsg(SUCCEEDED(hr), "Reset init command list failed");
|
||||
res.init_command_list_used = true;
|
||||
}
|
||||
|
||||
return res.command_lists[0].get();
|
||||
}
|
||||
|
||||
bool D3D12Context::ExecuteCommandList(WaitType wait_for_completion)
|
||||
{
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
HRESULT hr;
|
||||
|
||||
if (res.has_timestamp_query)
|
||||
{
|
||||
// write the timestamp back at the end of the cmdlist
|
||||
res.command_lists[1]->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
(m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST) + 1);
|
||||
res.command_lists[1]->ResolveQueryData(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST, NUM_TIMESTAMP_QUERIES_PER_CMDLIST,
|
||||
m_timestamp_query_buffer.get(), m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
|
||||
}
|
||||
|
||||
if (res.init_command_list_used)
|
||||
{
|
||||
hr = res.command_lists[0]->Close();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Closing init command list failed with HRESULT %08X", hr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Close and queue command list.
|
||||
hr = res.command_lists[1]->Close();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Closing main command list failed with HRESULT %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res.init_command_list_used)
|
||||
{
|
||||
const std::array<ID3D12CommandList*, 2> execute_lists{res.command_lists[0].get(), res.command_lists[1].get()};
|
||||
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::array<ID3D12CommandList*, 1> execute_lists{res.command_lists[1].get()};
|
||||
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
|
||||
}
|
||||
|
||||
// Update fence when GPU has completed.
|
||||
hr = m_command_queue->Signal(m_fence.get(), res.ready_fence_value);
|
||||
pxAssertRel(SUCCEEDED(hr), "Signal fence");
|
||||
|
||||
MoveToNextCommandList();
|
||||
if (wait_for_completion != WaitType::None)
|
||||
WaitForFence(res.ready_fence_value, wait_for_completion == WaitType::Spin);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12Context::InvalidateSamplerGroups()
|
||||
{
|
||||
for (CommandListResources& res : m_command_lists)
|
||||
res.sampler_allocator.InvalidateCache();
|
||||
}
|
||||
|
||||
void D3D12Context::DeferObjectDestruction(ID3D12DeviceChild* resource)
|
||||
{
|
||||
if (!resource)
|
||||
return;
|
||||
|
||||
resource->AddRef();
|
||||
m_command_lists[m_current_command_list].pending_resources.emplace_back(nullptr, resource);
|
||||
}
|
||||
|
||||
void D3D12Context::DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource)
|
||||
{
|
||||
if (!resource)
|
||||
return;
|
||||
|
||||
if (allocation)
|
||||
allocation->AddRef();
|
||||
|
||||
resource->AddRef();
|
||||
m_command_lists[m_current_command_list].pending_resources.emplace_back(allocation, resource);
|
||||
}
|
||||
|
||||
void D3D12Context::DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, u32 index)
|
||||
{
|
||||
m_command_lists[m_current_command_list].pending_descriptors.emplace_back(manager, index);
|
||||
}
|
||||
|
||||
void D3D12Context::DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, D3D12DescriptorHandle* handle)
|
||||
{
|
||||
if (handle->index == D3D12DescriptorHandle::INVALID_INDEX)
|
||||
return;
|
||||
|
||||
m_command_lists[m_current_command_list].pending_descriptors.emplace_back(manager, handle->index);
|
||||
handle->Clear();
|
||||
}
|
||||
|
||||
void D3D12Context::DestroyPendingResources(CommandListResources& cmdlist)
|
||||
{
|
||||
for (const auto& dd : cmdlist.pending_descriptors)
|
||||
dd.first.Free(dd.second);
|
||||
cmdlist.pending_descriptors.clear();
|
||||
|
||||
for (const auto& it : cmdlist.pending_resources)
|
||||
{
|
||||
it.second->Release();
|
||||
if (it.first)
|
||||
it.first->Release();
|
||||
}
|
||||
cmdlist.pending_resources.clear();
|
||||
}
|
||||
|
||||
void D3D12Context::DestroyResources()
|
||||
{
|
||||
if (m_command_queue)
|
||||
{
|
||||
ExecuteCommandList(WaitType::Sleep);
|
||||
WaitForGPUIdle();
|
||||
}
|
||||
|
||||
m_texture_stream_buffer.Destroy(false);
|
||||
m_descriptor_heap_manager.Free(&m_null_srv_descriptor);
|
||||
m_timestamp_query_buffer.reset();
|
||||
m_timestamp_query_allocation.reset();
|
||||
m_sampler_heap_manager.Destroy();
|
||||
m_dsv_heap_manager.Destroy();
|
||||
m_rtv_heap_manager.Destroy();
|
||||
m_descriptor_heap_manager.Destroy();
|
||||
m_command_lists = {};
|
||||
m_current_command_list = 0;
|
||||
m_completed_fence_value = 0;
|
||||
m_current_fence_value = 0;
|
||||
if (m_fence_event)
|
||||
{
|
||||
CloseHandle(m_fence_event);
|
||||
m_fence_event = {};
|
||||
}
|
||||
|
||||
m_allocator.reset();
|
||||
m_command_queue.reset();
|
||||
m_debug_interface.reset();
|
||||
m_device.reset();
|
||||
}
|
||||
|
||||
void D3D12Context::WaitForFence(u64 fence, bool spin)
|
||||
{
|
||||
if (m_completed_fence_value >= fence)
|
||||
return;
|
||||
|
||||
if (spin)
|
||||
{
|
||||
u64 value;
|
||||
while ((value = m_fence->GetCompletedValue()) < fence)
|
||||
ShortSpin();
|
||||
m_completed_fence_value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try non-blocking check.
|
||||
m_completed_fence_value = m_fence->GetCompletedValue();
|
||||
if (m_completed_fence_value < fence)
|
||||
{
|
||||
// Fall back to event.
|
||||
HRESULT hr = m_fence->SetEventOnCompletion(fence, m_fence_event);
|
||||
pxAssertRel(SUCCEEDED(hr), "Set fence event on completion");
|
||||
WaitForSingleObject(m_fence_event, INFINITE);
|
||||
m_completed_fence_value = m_fence->GetCompletedValue();
|
||||
}
|
||||
}
|
||||
|
||||
// Release resources for as many command lists which have completed.
|
||||
u32 index = (m_current_command_list + 1) % NUM_COMMAND_LISTS;
|
||||
for (u32 i = 0; i < NUM_COMMAND_LISTS; i++)
|
||||
{
|
||||
CommandListResources& res = m_command_lists[index];
|
||||
if (m_completed_fence_value < res.ready_fence_value)
|
||||
break;
|
||||
|
||||
DestroyPendingResources(res);
|
||||
index = (index + 1) % NUM_COMMAND_LISTS;
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12Context::WaitForGPUIdle()
|
||||
{
|
||||
u32 index = (m_current_command_list + 1) % NUM_COMMAND_LISTS;
|
||||
for (u32 i = 0; i < (NUM_COMMAND_LISTS - 1); i++)
|
||||
{
|
||||
WaitForFence(m_command_lists[index].ready_fence_value, false);
|
||||
index = (index + 1) % NUM_COMMAND_LISTS;
|
||||
}
|
||||
}
|
||||
|
||||
bool D3D12Context::CreateTimestampQuery()
|
||||
{
|
||||
constexpr u32 QUERY_COUNT = NUM_TIMESTAMP_QUERIES_PER_CMDLIST * NUM_COMMAND_LISTS;
|
||||
constexpr u32 BUFFER_SIZE = sizeof(u64) * QUERY_COUNT;
|
||||
|
||||
const D3D12_QUERY_HEAP_DESC desc = {D3D12_QUERY_HEAP_TYPE_TIMESTAMP, QUERY_COUNT};
|
||||
HRESULT hr = m_device->CreateQueryHeap(&desc, IID_PPV_ARGS(m_timestamp_query_heap.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("CreateQueryHeap() for timestamp failed with %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_READBACK};
|
||||
const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, BUFFER_SIZE, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
hr = m_allocator->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||
m_timestamp_query_allocation.put(), IID_PPV_ARGS(m_timestamp_query_buffer.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("CreateResource() for timestamp failed with %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 frequency;
|
||||
hr = m_command_queue->GetTimestampFrequency(&frequency);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("GetTimestampFrequency() failed: %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_timestamp_frequency = static_cast<double>(frequency) / 1000.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
float D3D12Context::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
const float time = m_accumulated_gpu_time;
|
||||
m_accumulated_gpu_time = 0.0f;
|
||||
return time;
|
||||
}
|
||||
|
||||
void D3D12Context::SetEnableGPUTiming(bool enabled)
|
||||
{
|
||||
m_gpu_timing_enabled = enabled;
|
||||
}
|
||||
|
||||
bool D3D12Context::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer,
|
||||
D3D12MA::Allocation** gpu_allocation, const std::function<void(void*)>& fill_callback)
|
||||
{
|
||||
// Try to place the fixed index buffer in GPU local memory.
|
||||
// Use the staging buffer to copy into it.
|
||||
const D3D12_RESOURCE_DESC rd = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0},
|
||||
D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC cpu_ad = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD};
|
||||
|
||||
ComPtr<ID3D12Resource> cpu_buffer;
|
||||
ComPtr<D3D12MA::Allocation> cpu_allocation;
|
||||
HRESULT hr = m_allocator->CreateResource(
|
||||
&cpu_ad, &rd, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, cpu_allocation.put(), IID_PPV_ARGS(cpu_buffer.put()));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate CPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
static constexpr const D3D12_RANGE read_range = {};
|
||||
const D3D12_RANGE write_range = {0, size};
|
||||
void* mapped;
|
||||
hr = cpu_buffer->Map(0, &read_range, &mapped);
|
||||
pxAssertMsg(SUCCEEDED(hr), "Map CPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
fill_callback(mapped);
|
||||
cpu_buffer->Unmap(0, &write_range);
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC gpu_ad = {D3D12MA::ALLOCATION_FLAG_COMMITTED, D3D12_HEAP_TYPE_DEFAULT};
|
||||
|
||||
hr = m_allocator->CreateResource(
|
||||
&gpu_ad, &rd, D3D12_RESOURCE_STATE_COMMON, nullptr, gpu_allocation, IID_PPV_ARGS(gpu_buffer));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate GPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
GetInitCommandList()->CopyBufferRegion(*gpu_buffer, 0, cpu_buffer.get(), 0, size);
|
||||
|
||||
D3D12_RESOURCE_BARRIER rb = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
rb.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
rb.Transition.pResource = *gpu_buffer;
|
||||
rb.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; // COMMON -> COPY_DEST at first use.
|
||||
rb.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
||||
GetInitCommandList()->ResourceBarrier(1, &rb);
|
||||
|
||||
DeferResourceDestruction(cpu_allocation.get(), cpu_buffer.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
void D3D12::SetObjectName(ID3D12Object* object, const char* name)
|
||||
{
|
||||
object->SetName(StringUtil::UTF8StringToWideString(name).c_str());
|
||||
}
|
||||
|
||||
void D3D12::SetObjectNameFormatted(ID3D12Object* object, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
SetObjectName(object, StringUtil::StdStringFromFormatV(format, ap).c_str());
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,235 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "GS/Renderers/DX12/D3D12DescriptorHeapManager.h"
|
||||
#include "GS/Renderers/DX12/D3D12StreamBuffer.h"
|
||||
|
||||
#include <array>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_5.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <wil/com.h>
|
||||
|
||||
struct IDXGIAdapter;
|
||||
struct IDXGIFactory;
|
||||
namespace D3D12MA
|
||||
{
|
||||
class Allocator;
|
||||
class Allocation;
|
||||
} // namespace D3D12MA
|
||||
|
||||
class D3D12Context
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
using ComPtr = wil::com_ptr_nothrow<T>;
|
||||
|
||||
enum : u32
|
||||
{
|
||||
/// Number of command lists. One is being built while the other(s) are executed.
|
||||
NUM_COMMAND_LISTS = 3,
|
||||
|
||||
/// Textures that don't fit into this buffer will be uploaded with a staging buffer.
|
||||
TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024,
|
||||
|
||||
/// Maximum number of samples in a single allocation group.
|
||||
SAMPLER_GROUP_SIZE = 2,
|
||||
|
||||
/// Start/End timestamp queries.
|
||||
NUM_TIMESTAMP_QUERIES_PER_CMDLIST = 2,
|
||||
};
|
||||
|
||||
~D3D12Context();
|
||||
|
||||
/// Creates new device and context.
|
||||
static bool Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer);
|
||||
|
||||
/// Destroys active context.
|
||||
static void Destroy();
|
||||
|
||||
__fi IDXGIAdapter* GetAdapter() const { return m_adapter.get(); }
|
||||
__fi ID3D12Device* GetDevice() const { return m_device.get(); }
|
||||
__fi ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.get(); }
|
||||
__fi D3D12MA::Allocator* GetAllocator() const { return m_allocator.get(); }
|
||||
|
||||
/// Returns the PCI vendor ID of the device, if known.
|
||||
u32 GetAdapterVendorID() const;
|
||||
|
||||
/// Returns the current command list, commands can be recorded directly.
|
||||
ID3D12GraphicsCommandList4* GetCommandList() const
|
||||
{
|
||||
return m_command_lists[m_current_command_list].command_lists[1].get();
|
||||
}
|
||||
|
||||
/// Returns the init command list for uploading.
|
||||
ID3D12GraphicsCommandList4* GetInitCommandList();
|
||||
|
||||
/// Returns the per-frame SRV/CBV/UAV allocator.
|
||||
D3D12DescriptorAllocator& GetDescriptorAllocator()
|
||||
{
|
||||
return m_command_lists[m_current_command_list].descriptor_allocator;
|
||||
}
|
||||
|
||||
/// Returns the per-frame sampler allocator.
|
||||
D3D12GroupedSamplerAllocator<SAMPLER_GROUP_SIZE>& GetSamplerAllocator()
|
||||
{
|
||||
return m_command_lists[m_current_command_list].sampler_allocator;
|
||||
}
|
||||
|
||||
/// Invalidates GPU-side sampler caches for all command lists. Call after you've freed samplers,
|
||||
/// and are going to re-use the handles from GetSamplerHeapManager().
|
||||
void InvalidateSamplerGroups();
|
||||
|
||||
// Descriptor manager access.
|
||||
D3D12DescriptorHeapManager& GetDescriptorHeapManager() { return m_descriptor_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetRTVHeapManager() { return m_rtv_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetDSVHeapManager() { return m_dsv_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetSamplerHeapManager() { return m_sampler_heap_manager; }
|
||||
const D3D12DescriptorHandle& GetNullSRVDescriptor() const { return m_null_srv_descriptor; }
|
||||
D3D12StreamBuffer& GetTextureStreamBuffer() { return m_texture_stream_buffer; }
|
||||
|
||||
// Root signature access.
|
||||
ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc);
|
||||
ComPtr<ID3D12RootSignature> CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc);
|
||||
|
||||
/// 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; }
|
||||
|
||||
/// 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);
|
||||
|
||||
enum class WaitType
|
||||
{
|
||||
None, ///< Don't wait (async)
|
||||
Sleep, ///< Wait normally
|
||||
Spin, ///< Wait by spinning
|
||||
};
|
||||
|
||||
/// Executes the current command list.
|
||||
bool ExecuteCommandList(WaitType wait_for_completion);
|
||||
|
||||
/// Waits for a specific fence.
|
||||
void WaitForFence(u64 fence, bool spin);
|
||||
|
||||
/// Waits for any in-flight command buffers to complete.
|
||||
void WaitForGPUIdle();
|
||||
|
||||
/// Defers destruction of a D3D resource (associates it with the current list).
|
||||
void DeferObjectDestruction(ID3D12DeviceChild* resource);
|
||||
|
||||
/// Defers destruction of a D3D resource (associates it with the current list).
|
||||
void DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource);
|
||||
|
||||
/// Defers destruction of a descriptor handle (associates it with the current list).
|
||||
void DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, u32 index);
|
||||
void DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, D3D12DescriptorHandle* handle);
|
||||
|
||||
float GetAndResetAccumulatedGPUTime();
|
||||
void SetEnableGPUTiming(bool enabled);
|
||||
|
||||
// Allocates a temporary CPU staging buffer, fires the callback with it to populate, then copies to a GPU buffer.
|
||||
bool AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer, D3D12MA::Allocation** gpu_allocation,
|
||||
const std::function<void(void*)>& fill_callback);
|
||||
|
||||
private:
|
||||
struct CommandListResources
|
||||
{
|
||||
std::array<ComPtr<ID3D12CommandAllocator>, 2> command_allocators;
|
||||
std::array<ComPtr<ID3D12GraphicsCommandList4>, 2> command_lists;
|
||||
D3D12DescriptorAllocator descriptor_allocator;
|
||||
D3D12GroupedSamplerAllocator<SAMPLER_GROUP_SIZE> sampler_allocator;
|
||||
std::vector<std::pair<D3D12MA::Allocation*, ID3D12DeviceChild*>> pending_resources;
|
||||
std::vector<std::pair<D3D12DescriptorHeapManager&, u32>> pending_descriptors;
|
||||
u64 ready_fence_value = 0;
|
||||
bool init_command_list_used = false;
|
||||
bool has_timestamp_query = false;
|
||||
};
|
||||
|
||||
D3D12Context();
|
||||
|
||||
bool CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer);
|
||||
bool CreateCommandQueue();
|
||||
bool CreateAllocator();
|
||||
bool CreateFence();
|
||||
bool CreateDescriptorHeaps();
|
||||
bool CreateCommandLists();
|
||||
bool CreateTextureStreamBuffer();
|
||||
bool CreateTimestampQuery();
|
||||
void MoveToNextCommandList();
|
||||
void DestroyPendingResources(CommandListResources& cmdlist);
|
||||
void DestroyResources();
|
||||
|
||||
ComPtr<IDXGIAdapter> m_adapter;
|
||||
ComPtr<ID3D12Debug> m_debug_interface;
|
||||
ComPtr<ID3D12Device> m_device;
|
||||
ComPtr<ID3D12CommandQueue> m_command_queue;
|
||||
ComPtr<D3D12MA::Allocator> m_allocator;
|
||||
|
||||
ComPtr<ID3D12Fence> m_fence;
|
||||
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;
|
||||
|
||||
ComPtr<ID3D12QueryHeap> m_timestamp_query_heap;
|
||||
ComPtr<ID3D12Resource> m_timestamp_query_buffer;
|
||||
ComPtr<D3D12MA::Allocation> m_timestamp_query_allocation;
|
||||
double m_timestamp_frequency = 0.0;
|
||||
float m_accumulated_gpu_time = 0.0f;
|
||||
bool m_gpu_timing_enabled = false;
|
||||
|
||||
D3D12DescriptorHeapManager m_descriptor_heap_manager;
|
||||
D3D12DescriptorHeapManager m_rtv_heap_manager;
|
||||
D3D12DescriptorHeapManager m_dsv_heap_manager;
|
||||
D3D12DescriptorHeapManager m_sampler_heap_manager;
|
||||
D3D12DescriptorHandle m_null_srv_descriptor;
|
||||
D3D12StreamBuffer m_texture_stream_buffer;
|
||||
|
||||
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<D3D12Context> g_d3d12_context;
|
||||
|
||||
namespace D3D12
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
||||
void SetObjectName(ID3D12Object* object, const char* name);
|
||||
void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...);
|
||||
|
||||
#else
|
||||
|
||||
static inline void SetObjectName(ID3D12Object* object, const char* name)
|
||||
{
|
||||
}
|
||||
static inline void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace D3D12
|
|
@ -16,7 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "GS/Renderers/DX12/D3D12StreamBuffer.h"
|
||||
#include "GS/Renderers/DX12/D3D12Context.h"
|
||||
#include "GS/Renderers/DX12/GSDevice12.h"
|
||||
|
||||
#include "common/Align.h"
|
||||
#include "common/Assertions.h"
|
||||
|
@ -45,7 +45,7 @@ bool D3D12StreamBuffer::Create(u32 size)
|
|||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> buffer;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocationDesc, &resource_desc,
|
||||
HRESULT hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocationDesc, &resource_desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate buffer");
|
||||
if (FAILED(hr))
|
||||
|
@ -155,7 +155,7 @@ void D3D12StreamBuffer::Destroy(bool defer)
|
|||
}
|
||||
|
||||
if (m_buffer && defer)
|
||||
g_d3d12_context->DeferResourceDestruction(m_allocation.get(), m_buffer.get());
|
||||
GSDevice12::GetInstance()->DeferResourceDestruction(m_allocation.get(), m_buffer.get());
|
||||
m_buffer.reset();
|
||||
m_allocation.reset();
|
||||
|
||||
|
@ -172,7 +172,7 @@ void D3D12StreamBuffer::UpdateCurrentFencePosition()
|
|||
return;
|
||||
|
||||
// Has the offset changed since the last fence?
|
||||
const u64 fence = g_d3d12_context->GetCurrentFenceValue();
|
||||
const u64 fence = GSDevice12::GetInstance()->GetCurrentFenceValue();
|
||||
if (!m_tracked_fences.empty() && m_tracked_fences.back().first == fence)
|
||||
{
|
||||
// Still haven't executed a command buffer, so just update the offset.
|
||||
|
@ -189,7 +189,7 @@ void D3D12StreamBuffer::UpdateGPUPosition()
|
|||
auto start = m_tracked_fences.begin();
|
||||
auto end = start;
|
||||
|
||||
const u64 completed_counter = g_d3d12_context->GetCompletedFenceValue();
|
||||
const u64 completed_counter = GSDevice12::GetInstance()->GetCompletedFenceValue();
|
||||
while (end != m_tracked_fences.end() && completed_counter >= end->first)
|
||||
{
|
||||
m_current_gpu_position = end->second;
|
||||
|
@ -267,11 +267,11 @@ bool D3D12StreamBuffer::WaitForClearSpace(u32 num_bytes)
|
|||
|
||||
// Did any fences satisfy this condition?
|
||||
// Has the command buffer been executed yet? If not, the caller should execute it.
|
||||
if (iter == m_tracked_fences.end() || iter->first == g_d3d12_context->GetCurrentFenceValue())
|
||||
if (iter == m_tracked_fences.end() || iter->first == GSDevice12::GetInstance()->GetCurrentFenceValue())
|
||||
return false;
|
||||
|
||||
// Wait until this fence is signaled. This will fire the callback, updating the GPU position.
|
||||
g_d3d12_context->WaitForFence(iter->first, false);
|
||||
GSDevice12::GetInstance()->WaitForFence(iter->first, false);
|
||||
m_tracked_fences.erase(
|
||||
m_tracked_fences.begin(), m_current_offset == iter->second ? m_tracked_fences.end() : ++iter);
|
||||
m_current_offset = new_offset;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,13 +20,17 @@
|
|||
#include "GS/Renderers/DX12/GSTexture12.h"
|
||||
#include "GS/Renderers/DX12/D3D12ShaderCache.h"
|
||||
#include "GS/Renderers/DX12/D3D12StreamBuffer.h"
|
||||
|
||||
#include "common/HashCombine.h"
|
||||
|
||||
#include <array>
|
||||
#include <dxgi1_5.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace D3D12MA
|
||||
{
|
||||
class Allocation;
|
||||
class Allocator;
|
||||
}
|
||||
|
||||
class GSDevice12 final : public GSDevice
|
||||
|
@ -35,6 +39,159 @@ public:
|
|||
template <typename T>
|
||||
using ComPtr = wil::com_ptr_nothrow<T>;
|
||||
|
||||
enum : u32
|
||||
{
|
||||
/// Number of command lists. One is being built while the other(s) are executed.
|
||||
NUM_COMMAND_LISTS = 3,
|
||||
|
||||
/// Textures that don't fit into this buffer will be uploaded with a staging buffer.
|
||||
TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024,
|
||||
|
||||
/// Maximum number of samples in a single allocation group.
|
||||
SAMPLER_GROUP_SIZE = 2,
|
||||
|
||||
/// Start/End timestamp queries.
|
||||
NUM_TIMESTAMP_QUERIES_PER_CMDLIST = 2,
|
||||
};
|
||||
|
||||
__fi IDXGIAdapter1* GetAdapter() const { return m_adapter.get(); }
|
||||
__fi ID3D12Device* GetDevice() const { return m_device.get(); }
|
||||
__fi ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.get(); }
|
||||
__fi D3D12MA::Allocator* GetAllocator() const { return m_allocator.get(); }
|
||||
|
||||
/// Returns the PCI vendor ID of the device, if known.
|
||||
u32 GetAdapterVendorID() const;
|
||||
|
||||
/// Returns the current command list, commands can be recorded directly.
|
||||
ID3D12GraphicsCommandList4* GetCommandList() const
|
||||
{
|
||||
return m_command_lists[m_current_command_list].command_lists[1].get();
|
||||
}
|
||||
|
||||
/// Returns the init command list for uploading.
|
||||
ID3D12GraphicsCommandList4* GetInitCommandList();
|
||||
|
||||
/// Returns the per-frame SRV/CBV/UAV allocator.
|
||||
D3D12DescriptorAllocator& GetDescriptorAllocator()
|
||||
{
|
||||
return m_command_lists[m_current_command_list].descriptor_allocator;
|
||||
}
|
||||
|
||||
/// Returns the per-frame sampler allocator.
|
||||
D3D12GroupedSamplerAllocator<SAMPLER_GROUP_SIZE>& GetSamplerAllocator()
|
||||
{
|
||||
return m_command_lists[m_current_command_list].sampler_allocator;
|
||||
}
|
||||
|
||||
/// Invalidates GPU-side sampler caches for all command lists. Call after you've freed samplers,
|
||||
/// and are going to re-use the handles from GetSamplerHeapManager().
|
||||
void InvalidateSamplerGroups();
|
||||
|
||||
// Descriptor manager access.
|
||||
D3D12DescriptorHeapManager& GetDescriptorHeapManager() { return m_descriptor_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetRTVHeapManager() { return m_rtv_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetDSVHeapManager() { return m_dsv_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetSamplerHeapManager() { return m_sampler_heap_manager; }
|
||||
const D3D12DescriptorHandle& GetNullSRVDescriptor() const { return m_null_srv_descriptor; }
|
||||
D3D12StreamBuffer& GetTextureStreamBuffer() { return m_texture_stream_buffer; }
|
||||
|
||||
// Root signature access.
|
||||
ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc);
|
||||
ComPtr<ID3D12RootSignature> CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc);
|
||||
|
||||
/// 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; }
|
||||
|
||||
/// 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);
|
||||
|
||||
enum class WaitType
|
||||
{
|
||||
None, ///< Don't wait (async)
|
||||
Sleep, ///< Wait normally
|
||||
Spin, ///< Wait by spinning
|
||||
};
|
||||
static WaitType GetWaitType(bool wait, bool spin);
|
||||
|
||||
/// Executes the current command list.
|
||||
bool ExecuteCommandList(WaitType wait_for_completion);
|
||||
|
||||
/// Waits for a specific fence.
|
||||
void WaitForFence(u64 fence, bool spin);
|
||||
|
||||
/// Waits for any in-flight command buffers to complete.
|
||||
void WaitForGPUIdle();
|
||||
|
||||
/// Defers destruction of a D3D resource (associates it with the current list).
|
||||
void DeferObjectDestruction(ID3D12DeviceChild* resource);
|
||||
|
||||
/// Defers destruction of a D3D resource (associates it with the current list).
|
||||
void DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource);
|
||||
|
||||
/// Defers destruction of a descriptor handle (associates it with the current list).
|
||||
void DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, u32 index);
|
||||
void DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, D3D12DescriptorHandle* handle);
|
||||
|
||||
// Allocates a temporary CPU staging buffer, fires the callback with it to populate, then copies to a GPU buffer.
|
||||
bool AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer, D3D12MA::Allocation** gpu_allocation,
|
||||
const std::function<void(void*)>& fill_callback);
|
||||
|
||||
private:
|
||||
struct CommandListResources
|
||||
{
|
||||
std::array<ComPtr<ID3D12CommandAllocator>, 2> command_allocators;
|
||||
std::array<ComPtr<ID3D12GraphicsCommandList4>, 2> command_lists;
|
||||
D3D12DescriptorAllocator descriptor_allocator;
|
||||
D3D12GroupedSamplerAllocator<SAMPLER_GROUP_SIZE> sampler_allocator;
|
||||
std::vector<std::pair<D3D12MA::Allocation*, ID3D12DeviceChild*>> pending_resources;
|
||||
std::vector<std::pair<D3D12DescriptorHeapManager&, u32>> pending_descriptors;
|
||||
u64 ready_fence_value = 0;
|
||||
bool init_command_list_used = false;
|
||||
bool has_timestamp_query = false;
|
||||
};
|
||||
|
||||
bool CreateDevice();
|
||||
bool CreateDescriptorHeaps();
|
||||
bool CreateCommandLists();
|
||||
bool CreateTimestampQuery();
|
||||
void MoveToNextCommandList();
|
||||
void DestroyPendingResources(CommandListResources& cmdlist);
|
||||
|
||||
ComPtr<IDXGIAdapter1> m_adapter;
|
||||
ComPtr<ID3D12Device> m_device;
|
||||
ComPtr<ID3D12CommandQueue> m_command_queue;
|
||||
ComPtr<D3D12MA::Allocator> m_allocator;
|
||||
|
||||
ComPtr<ID3D12Fence> m_fence;
|
||||
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;
|
||||
|
||||
ComPtr<ID3D12QueryHeap> m_timestamp_query_heap;
|
||||
ComPtr<ID3D12Resource> m_timestamp_query_buffer;
|
||||
ComPtr<D3D12MA::Allocation> m_timestamp_query_allocation;
|
||||
double m_timestamp_frequency = 0.0;
|
||||
float m_accumulated_gpu_time = 0.0f;
|
||||
bool m_gpu_timing_enabled = false;
|
||||
|
||||
D3D12DescriptorHeapManager m_descriptor_heap_manager;
|
||||
D3D12DescriptorHeapManager m_rtv_heap_manager;
|
||||
D3D12DescriptorHeapManager m_dsv_heap_manager;
|
||||
D3D12DescriptorHeapManager m_sampler_heap_manager;
|
||||
D3D12DescriptorHandle m_null_srv_descriptor;
|
||||
|
||||
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
|
||||
|
||||
public:
|
||||
struct alignas(8) PipelineSelector
|
||||
{
|
||||
GSHWDrawConfig::PSSelector ps;
|
||||
|
@ -156,6 +313,7 @@ private:
|
|||
D3D12StreamBuffer m_index_stream_buffer;
|
||||
D3D12StreamBuffer m_vertex_constant_buffer;
|
||||
D3D12StreamBuffer m_pixel_constant_buffer;
|
||||
D3D12StreamBuffer m_texture_stream_buffer;
|
||||
ComPtr<ID3D12Resource> m_expand_index_buffer;
|
||||
ComPtr<D3D12MA::Allocation> m_expand_index_buffer_allocation;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "GS/Renderers/DX12/GSTexture12.h"
|
||||
#include "GS/Renderers/DX12/D3D12Builders.h"
|
||||
#include "GS/Renderers/DX12/D3D12Context.h"
|
||||
#include "GS/Renderers/DX12/GSDevice12.h"
|
||||
#include "GS/GSPerfMon.h"
|
||||
#include "GS/GSGL.h"
|
||||
|
@ -55,19 +54,20 @@ GSTexture12::~GSTexture12()
|
|||
|
||||
void GSTexture12::Destroy(bool defer)
|
||||
{
|
||||
GSDevice12::GetInstance()->UnbindTexture(this);
|
||||
GSDevice12* const dev = GSDevice12::GetInstance();
|
||||
dev->UnbindTexture(this);
|
||||
|
||||
if (defer)
|
||||
{
|
||||
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_srv_descriptor);
|
||||
dev->DeferDescriptorDestruction(dev->GetDescriptorHeapManager(), &m_srv_descriptor);
|
||||
|
||||
switch (m_write_descriptor_type)
|
||||
{
|
||||
case WriteDescriptorType::RTV:
|
||||
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetRTVHeapManager(), &m_write_descriptor);
|
||||
dev->DeferDescriptorDestruction(dev->GetRTVHeapManager(), &m_write_descriptor);
|
||||
break;
|
||||
case WriteDescriptorType::DSV:
|
||||
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDSVHeapManager(), &m_write_descriptor);
|
||||
dev->DeferDescriptorDestruction(dev->GetDSVHeapManager(), &m_write_descriptor);
|
||||
break;
|
||||
case WriteDescriptorType::None:
|
||||
default:
|
||||
|
@ -75,23 +75,23 @@ void GSTexture12::Destroy(bool defer)
|
|||
}
|
||||
|
||||
if (m_uav_descriptor)
|
||||
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_uav_descriptor);
|
||||
dev->DeferDescriptorDestruction(dev->GetDescriptorHeapManager(), &m_uav_descriptor);
|
||||
|
||||
g_d3d12_context->DeferResourceDestruction(m_allocation.get(), m_resource.get());
|
||||
dev->DeferResourceDestruction(m_allocation.get(), m_resource.get());
|
||||
m_resource.reset();
|
||||
m_allocation.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_d3d12_context->GetDescriptorHeapManager().Free(&m_srv_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&m_srv_descriptor);
|
||||
|
||||
switch (m_write_descriptor_type)
|
||||
{
|
||||
case WriteDescriptorType::RTV:
|
||||
g_d3d12_context->GetRTVHeapManager().Free(&m_write_descriptor);
|
||||
dev->GetRTVHeapManager().Free(&m_write_descriptor);
|
||||
break;
|
||||
case WriteDescriptorType::DSV:
|
||||
g_d3d12_context->GetDSVHeapManager().Free(&m_write_descriptor);
|
||||
dev->GetDSVHeapManager().Free(&m_write_descriptor);
|
||||
break;
|
||||
case WriteDescriptorType::None:
|
||||
default:
|
||||
|
@ -99,7 +99,7 @@ void GSTexture12::Destroy(bool defer)
|
|||
}
|
||||
|
||||
if (m_uav_descriptor)
|
||||
g_d3d12_context->GetDescriptorHeapManager().Free(&m_uav_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&m_uav_descriptor);
|
||||
|
||||
m_resource.reset();
|
||||
m_allocation.reset();
|
||||
|
@ -112,6 +112,8 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
|||
DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format,
|
||||
DXGI_FORMAT uav_format)
|
||||
{
|
||||
GSDevice12* const dev = GSDevice12::GetInstance();
|
||||
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
desc.Width = width;
|
||||
|
@ -179,7 +181,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
|||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocationDesc, &desc, state,
|
||||
HRESULT hr = dev->GetAllocator()->CreateResource(&allocationDesc, &desc, state,
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(),
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
if (FAILED(hr))
|
||||
|
@ -213,7 +215,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
|||
write_descriptor_type = WriteDescriptorType::RTV;
|
||||
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
|
||||
{
|
||||
g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor);
|
||||
dev->GetRTVHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +227,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
|||
write_descriptor_type = WriteDescriptorType::DSV;
|
||||
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor))
|
||||
{
|
||||
g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor);
|
||||
dev->GetDSVHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -243,8 +245,8 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
|||
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), dsv_format, &uav_descriptor))
|
||||
{
|
||||
g_d3d12_context->GetDescriptorHeapManager().Free(&write_descriptor);
|
||||
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&write_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -272,7 +274,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
|||
write_descriptor_type = WriteDescriptorType::RTV;
|
||||
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
|
||||
{
|
||||
g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor);
|
||||
GSDevice12::GetInstance()->GetRTVHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +283,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
|||
write_descriptor_type = WriteDescriptorType::DSV;
|
||||
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor))
|
||||
{
|
||||
g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor);
|
||||
GSDevice12::GetInstance()->GetDSVHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -290,8 +292,8 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
|||
{
|
||||
if (!CreateUAVDescriptor(resource.get(), srv_format, &uav_descriptor))
|
||||
{
|
||||
g_d3d12_context->GetDescriptorHeapManager().Free(&write_descriptor);
|
||||
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
GSDevice12::GetInstance()->GetDescriptorHeapManager().Free(&write_descriptor);
|
||||
GSDevice12::GetInstance()->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +306,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
|||
bool GSTexture12::CreateSRVDescriptor(
|
||||
ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh)
|
||||
{
|
||||
if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh))
|
||||
if (!GSDevice12::GetInstance()->GetDescriptorHeapManager().Allocate(dh))
|
||||
{
|
||||
Console.Error("Failed to allocate SRV descriptor");
|
||||
return false;
|
||||
|
@ -314,46 +316,46 @@ bool GSTexture12::CreateSRVDescriptor(
|
|||
format, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
|
||||
desc.Texture2D.MipLevels = levels;
|
||||
|
||||
g_d3d12_context->GetDevice()->CreateShaderResourceView(resource, &desc, dh->cpu_handle);
|
||||
GSDevice12::GetInstance()->GetDevice()->CreateShaderResourceView(resource, &desc, dh->cpu_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSTexture12::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh)
|
||||
{
|
||||
if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh))
|
||||
if (!GSDevice12::GetInstance()->GetRTVHeapManager().Allocate(dh))
|
||||
{
|
||||
Console.Error("Failed to allocate SRV descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
const D3D12_RENDER_TARGET_VIEW_DESC desc = {format, D3D12_RTV_DIMENSION_TEXTURE2D};
|
||||
g_d3d12_context->GetDevice()->CreateRenderTargetView(resource, &desc, dh->cpu_handle);
|
||||
GSDevice12::GetInstance()->GetDevice()->CreateRenderTargetView(resource, &desc, dh->cpu_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh)
|
||||
{
|
||||
if (!g_d3d12_context->GetDSVHeapManager().Allocate(dh))
|
||||
if (!GSDevice12::GetInstance()->GetDSVHeapManager().Allocate(dh))
|
||||
{
|
||||
Console.Error("Failed to allocate SRV descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, D3D12_DSV_FLAG_NONE};
|
||||
g_d3d12_context->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
|
||||
GSDevice12::GetInstance()->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSTexture12::CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh)
|
||||
{
|
||||
if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh))
|
||||
if (!GSDevice12::GetInstance()->GetDescriptorHeapManager().Allocate(dh))
|
||||
{
|
||||
Console.Error("Failed to allocate UAV descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
const D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {format, D3D12_UAV_DIMENSION_TEXTURE2D};
|
||||
g_d3d12_context->GetDevice()->CreateUnorderedAccessView(resource, nullptr, &desc, dh->cpu_handle);
|
||||
GSDevice12::GetInstance()->GetDevice()->CreateUnorderedAccessView(resource, nullptr, &desc, dh->cpu_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -364,14 +366,15 @@ void* GSTexture12::GetNativeHandle() const
|
|||
|
||||
ID3D12GraphicsCommandList* GSTexture12::GetCommandBufferForUpdate()
|
||||
{
|
||||
if (m_type != Type::Texture || m_use_fence_counter == g_d3d12_context->GetCurrentFenceValue())
|
||||
GSDevice12* const dev = GSDevice12::GetInstance();
|
||||
if (m_type != Type::Texture || m_use_fence_counter == dev->GetCurrentFenceValue())
|
||||
{
|
||||
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
||||
GSDevice12::GetInstance()->EndRenderPass();
|
||||
return g_d3d12_context->GetCommandList();
|
||||
return dev->GetCommandList();
|
||||
}
|
||||
|
||||
return g_d3d12_context->GetInitCommandList();
|
||||
return dev->GetInitCommandList();
|
||||
}
|
||||
|
||||
ID3D12Resource* GSTexture12::AllocateUploadStagingBuffer(
|
||||
|
@ -384,7 +387,7 @@ ID3D12Resource* GSTexture12::AllocateUploadStagingBuffer(
|
|||
const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD};
|
||||
const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE};
|
||||
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc,
|
||||
HRESULT hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocation_desc, &resource_desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
@ -407,7 +410,7 @@ ID3D12Resource* GSTexture12::AllocateUploadStagingBuffer(
|
|||
|
||||
// Immediately queue it for freeing after the command buffer finishes, since it's only needed for the copy.
|
||||
// This adds the reference needed to keep the buffer alive.
|
||||
g_d3d12_context->DeferResourceDestruction(allocation.get(), resource.get());
|
||||
GSDevice12::GetInstance()->DeferResourceDestruction(allocation.get(), resource.get());
|
||||
return resource.get();
|
||||
}
|
||||
|
||||
|
@ -442,7 +445,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
|
|||
|
||||
// If the texture is larger than half our streaming buffer size, use a separate buffer.
|
||||
// Otherwise allocation will either fail, or require lots of cmdbuffer submissions.
|
||||
if (required_size > (g_d3d12_context->GetTextureStreamBuffer().GetSize() / 2))
|
||||
if (required_size > (GSDevice12::GetInstance()->GetTextureStreamBuffer().GetSize() / 2))
|
||||
{
|
||||
srcloc.pResource = AllocateUploadStagingBuffer(data, pitch, upload_pitch, height);
|
||||
if (!srcloc.pResource)
|
||||
|
@ -452,7 +455,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
|
|||
}
|
||||
else
|
||||
{
|
||||
D3D12StreamBuffer& sbuffer = g_d3d12_context->GetTextureStreamBuffer();
|
||||
D3D12StreamBuffer& sbuffer = GSDevice12::GetInstance()->GetTextureStreamBuffer();
|
||||
if (!sbuffer.ReserveMemory(required_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
|
||||
{
|
||||
GSDevice12::GetInstance()->ExecuteCommandList(
|
||||
|
@ -518,7 +521,7 @@ bool GSTexture12::Map(GSMap& m, const GSVector4i* r, int layer)
|
|||
|
||||
// see note in Update() for the reason why.
|
||||
const u32 required_size = CalcUploadSize(m_map_area.height(), m.pitch);
|
||||
D3D12StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer();
|
||||
D3D12StreamBuffer& buffer = GSDevice12::GetInstance()->GetTextureStreamBuffer();
|
||||
if (required_size >= (buffer.GetSize() / 2))
|
||||
return false;
|
||||
|
||||
|
@ -544,7 +547,7 @@ void GSTexture12::Unmap()
|
|||
const u32 height = m_map_area.height();
|
||||
const u32 pitch = Common::AlignUpPow2(CalcUploadPitch(width), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
const u32 required_size = CalcUploadSize(height, pitch);
|
||||
D3D12StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer();
|
||||
D3D12StreamBuffer& buffer = GSDevice12::GetInstance()->GetTextureStreamBuffer();
|
||||
const u32 buffer_offset = buffer.GetCurrentOffset();
|
||||
buffer.CommitMemory(required_size);
|
||||
|
||||
|
@ -608,7 +611,7 @@ void GSTexture12::GenerateMipmap()
|
|||
this, dst_level, dst_width, dst_height, src_level, src_width, src_height);
|
||||
}
|
||||
|
||||
SetUsedThisCommandBuffer();
|
||||
SetUseFenceCounter(GSDevice12::GetInstance()->GetCurrentFenceValue());
|
||||
}
|
||||
|
||||
void GSTexture12::Swap(GSTexture* tex)
|
||||
|
@ -629,7 +632,7 @@ void GSTexture12::Swap(GSTexture* tex)
|
|||
|
||||
void GSTexture12::TransitionToState(D3D12_RESOURCE_STATES state)
|
||||
{
|
||||
TransitionToState(g_d3d12_context->GetCommandList(), state);
|
||||
TransitionToState(GSDevice12::GetInstance()->GetCommandList(), state);
|
||||
}
|
||||
|
||||
void GSTexture12::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state)
|
||||
|
@ -656,7 +659,7 @@ void GSTexture12::CommitClear()
|
|||
|
||||
GSDevice12::GetInstance()->EndRenderPass();
|
||||
|
||||
CommitClear(g_d3d12_context->GetCommandList());
|
||||
CommitClear(GSDevice12::GetInstance()->GetCommandList());
|
||||
}
|
||||
|
||||
void GSTexture12::CommitClear(ID3D12GraphicsCommandList* cmdlist)
|
||||
|
@ -687,7 +690,7 @@ GSDownloadTexture12::~GSDownloadTexture12()
|
|||
GSDownloadTexture12::Unmap();
|
||||
|
||||
if (m_buffer)
|
||||
g_d3d12_context->DeferResourceDestruction(m_allocation.get(), m_buffer.get());
|
||||
GSDevice12::GetInstance()->DeferResourceDestruction(m_allocation.get(), m_buffer.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<GSDownloadTexture12> GSDownloadTexture12::Create(u32 width, u32 height, GSTexture::Format format)
|
||||
|
@ -703,7 +706,7 @@ std::unique_ptr<GSDownloadTexture12> GSDownloadTexture12::Create(u32 width, u32
|
|||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
wil::com_ptr_nothrow<ID3D12Resource> buffer;
|
||||
|
||||
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc,
|
||||
HRESULT hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocation_desc, &resource_desc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
@ -742,7 +745,7 @@ void GSDownloadTexture12::CopyFromTexture(
|
|||
if (IsMapped())
|
||||
Unmap();
|
||||
|
||||
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
|
||||
ID3D12GraphicsCommandList* cmdlist = GSDevice12::GetInstance()->GetCommandList();
|
||||
GL_INS("ReadbackTexture: {%d,%d} %ux%u", src.left, src.top, src.width(), src.height());
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcloc;
|
||||
|
@ -772,7 +775,7 @@ void GSDownloadTexture12::CopyFromTexture(
|
|||
if (old_layout != D3D12_RESOURCE_STATE_COPY_SOURCE)
|
||||
tex12->TransitionSubresourceToState(cmdlist, src_level, D3D12_RESOURCE_STATE_COPY_SOURCE, old_layout);
|
||||
|
||||
m_copy_fence_value = g_d3d12_context->GetCurrentFenceValue();
|
||||
m_copy_fence_value = GSDevice12::GetInstance()->GetCurrentFenceValue();
|
||||
m_needs_flush = true;
|
||||
}
|
||||
|
||||
|
@ -816,12 +819,13 @@ void GSDownloadTexture12::Flush()
|
|||
|
||||
m_needs_flush = false;
|
||||
|
||||
if (g_d3d12_context->GetCompletedFenceValue() >= m_copy_fence_value)
|
||||
GSDevice12* dev = GSDevice12::GetInstance();
|
||||
if (dev->GetCompletedFenceValue() >= m_copy_fence_value)
|
||||
return;
|
||||
|
||||
// Need to execute command buffer.
|
||||
if (g_d3d12_context->GetCurrentFenceValue() == m_copy_fence_value)
|
||||
GSDevice12::GetInstance()->ExecuteCommandListForReadback();
|
||||
if (dev->GetCurrentFenceValue() == m_copy_fence_value)
|
||||
dev->ExecuteCommandListForReadback();
|
||||
else
|
||||
g_d3d12_context->WaitForFence(m_copy_fence_value, GSConfig.HWSpinGPUForReadbacks);
|
||||
dev->WaitForFence(m_copy_fence_value, GSConfig.HWSpinGPUForReadbacks);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "GS/GS.h"
|
||||
#include "GS/Renderers/Common/GSTexture.h"
|
||||
#include "GS/Renderers/DX12/D3D12Context.h"
|
||||
#include "GS/Renderers/DX12/D3D12DescriptorHeapManager.h"
|
||||
|
||||
#include "common/RedtapeWilCom.h"
|
||||
|
@ -67,7 +66,7 @@ public:
|
|||
D3D12_RESOURCE_STATES after_state) const;
|
||||
|
||||
// Call when the texture is bound to the pipeline, or read from in a copy.
|
||||
__fi void SetUsedThisCommandBuffer() { m_use_fence_counter = g_d3d12_context->GetCurrentFenceValue(); }
|
||||
__fi void SetUseFenceCounter(u64 val) { m_use_fence_counter = val; }
|
||||
|
||||
private:
|
||||
enum class WriteDescriptorType : u8
|
||||
|
|
|
@ -182,7 +182,6 @@
|
|||
<ClCompile Include="GameList.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX11\D3D11ShaderCache.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12Builders.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12Context.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12DescriptorHeapManager.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12ShaderCache.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12StreamBuffer.cpp" />
|
||||
|
@ -533,7 +532,6 @@
|
|||
<ClInclude Include="GameList.h" />
|
||||
<ClInclude Include="GS\Renderers\DX11\D3D11ShaderCache.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12Builders.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12Context.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12DescriptorHeapManager.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12ShaderCache.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12StreamBuffer.h" />
|
||||
|
|
|
@ -1274,9 +1274,6 @@
|
|||
<ClCompile Include="GS\Renderers\DX11\D3D11ShaderCache.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12Context.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12DescriptorHeapManager.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2217,9 +2214,6 @@
|
|||
<ClInclude Include="GS\Renderers\DX11\D3D11ShaderCache.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12Context.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12DescriptorHeapManager.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClInclude>
|
||||
|
|
Loading…
Reference in New Issue