GS/DX12: Copy constant buffers to default heap

This commit is contained in:
TheLastRar
2026-03-04 22:45:35 +00:00
committed by lightningterror
parent 12940f2e1b
commit 0e667a9b0f
3 changed files with 92 additions and 19 deletions
+59 -9
View File
@@ -20,7 +20,7 @@ D3D12StreamBuffer::~D3D12StreamBuffer()
Destroy();
}
bool D3D12StreamBuffer::Create(u32 size)
bool D3D12StreamBuffer::Create(u32 size, bool gpu_backed_buffer)
{
const GSDevice12::D3D12_RESOURCE_DESCU resource_desc = {{D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN,
{1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}};
@@ -51,11 +51,32 @@ bool D3D12StreamBuffer::Create(u32 size)
Destroy(true);
m_buffer = std::move(buffer);
m_allocation = std::move(allocation);
m_buffer_upload = std::move(buffer);
m_allocation_upload = std::move(allocation);
m_host_pointer = host_pointer;
m_size = size;
m_gpu_pointer = m_buffer->GetGPUVirtualAddress();
if (gpu_backed_buffer)
{
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
if (GSDevice12::GetInstance()->UseEnhancedBarriers())
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource3(&allocationDesc, &resource_desc.desc1,
D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr, 0, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
else
hr = GSDevice12::GetInstance()->GetAllocator()->CreateResource(&allocationDesc, &resource_desc.desc,
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
pxAssertMsg(SUCCEEDED(hr), "Allocate buffer");
if (FAILED(hr))
return false;
m_buffer_default = std::move(buffer);
m_allocation_default = std::move(allocation);
m_gpu_pointer = m_buffer_default->GetGPUVirtualAddress();
}
else
m_gpu_pointer = m_buffer_upload->GetGPUVirtualAddress();
return true;
}
@@ -136,21 +157,50 @@ void D3D12StreamBuffer::CommitMemory(u32 final_num_bytes)
m_current_space -= final_num_bytes;
}
void D3D12StreamBuffer::FlushMemory()
{
if (m_buffer_default &&
m_current_space != m_size)
{
if (m_current_copy_offset < m_current_offset)
{
const u32 size = m_current_offset - m_current_copy_offset;
GSDevice12::GetInstance()->GetInitCommandList().list4->CopyBufferRegion(m_buffer_default.get(), m_current_copy_offset,
m_buffer_upload.get(), m_current_copy_offset, size);
}
else
{
const u32 size = m_size - m_current_copy_offset;
GSDevice12::GetInstance()->GetInitCommandList().list4->CopyBufferRegion(m_buffer_default.get(), m_current_copy_offset,
m_buffer_upload.get(), m_current_copy_offset, size);
GSDevice12::GetInstance()->GetInitCommandList().list4->CopyBufferRegion(m_buffer_default.get(), 0,
m_buffer_upload.get(), 0, m_current_offset);
}
m_current_copy_offset = m_current_offset;
}
}
void D3D12StreamBuffer::Destroy(bool defer)
{
if (m_host_pointer)
{
const D3D12_RANGE written_range = {0, m_size};
m_buffer->Unmap(0, &written_range);
m_buffer_upload->Unmap(0, &written_range);
m_host_pointer = nullptr;
}
if (m_buffer && defer)
GSDevice12::GetInstance()->DeferResourceDestruction(m_allocation.get(), m_buffer.get());
m_buffer.reset();
m_allocation.reset();
if (m_buffer_upload && defer)
GSDevice12::GetInstance()->DeferResourceDestruction(m_allocation_upload.get(), m_buffer_upload.get());
m_buffer_upload.reset();
m_allocation_upload.reset();
if (m_buffer_default && defer)
GSDevice12::GetInstance()->DeferResourceDestruction(m_allocation_default.get(), m_buffer_default.get());
m_buffer_default.reset();
m_allocation_default.reset();
m_current_offset = 0;
m_current_copy_offset = 0;
m_current_space = 0;
m_current_gpu_position = 0;
m_tracked_fences.clear();
+18 -5
View File
@@ -6,6 +6,7 @@
#include "common/Pcsx2Defs.h"
#include "common/RedtapeWindows.h"
#include "common/RedtapeWilCom.h"
#include "common/Assertions.h"
#include <d3d12.h>
#include <deque>
@@ -22,10 +23,17 @@ public:
D3D12StreamBuffer();
~D3D12StreamBuffer();
bool Create(u32 size);
// gpu_backed_buffer specifies if a second buffer should be created in the default heap.
bool Create(u32 size, bool gpu_backed_buffer = false);
__fi bool IsValid() const { return static_cast<bool>(m_buffer); }
__fi ID3D12Resource* GetBuffer() const { return m_buffer.get(); }
__fi bool IsValid() const { return static_cast<bool>(m_buffer_upload); }
__fi ID3D12Resource* GetBuffer() const
{
// This function is currently only used for textures, which already need to bt copied to a texture resource.
// For now, assert that gpu_backed_buffer was false.
pxAssert(m_buffer_default == nullptr);
return m_buffer_upload.get();
}
__fi D3D12_GPU_VIRTUAL_ADDRESS GetGPUPointer() const { return m_gpu_pointer; }
__fi void* GetHostPointer() const { return m_host_pointer; }
__fi void* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; }
@@ -36,6 +44,8 @@ public:
bool ReserveMemory(u32 num_bytes, u32 alignment);
void CommitMemory(u32 final_num_bytes);
// Queues copy to default heap if gpu_backed_buffer was true.
void FlushMemory();
void Destroy(bool defer = true);
@@ -48,11 +58,14 @@ private:
u32 m_size = 0;
u32 m_current_offset = 0;
u32 m_current_copy_offset = 0;
u32 m_current_space = 0;
u32 m_current_gpu_position = 0;
wil::com_ptr_nothrow<ID3D12Resource> m_buffer;
wil::com_ptr_nothrow<D3D12MA::Allocation> m_allocation;
wil::com_ptr_nothrow<ID3D12Resource> m_buffer_upload;
wil::com_ptr_nothrow<ID3D12Resource> m_buffer_default;
wil::com_ptr_nothrow<D3D12MA::Allocation> m_allocation_upload;
wil::com_ptr_nothrow<D3D12MA::Allocation> m_allocation_default;
D3D12_GPU_VIRTUAL_ADDRESS m_gpu_pointer = {};
u8* m_host_pointer = nullptr;
+15 -5
View File
@@ -546,6 +546,12 @@ bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
CommandListResources& res = m_command_lists[m_current_command_list];
HRESULT hr;
// Flush stream buffers to GPU memory
m_vertex_stream_buffer.FlushMemory();
m_index_stream_buffer.FlushMemory();
m_vertex_constant_buffer.FlushMemory();
m_pixel_constant_buffer.FlushMemory();
if (res.has_timestamp_query)
{
// write the timestamp back at the end of the cmdlist
@@ -576,7 +582,11 @@ bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
if (res.init_command_list_used)
{
const std::array<ID3D12CommandList*, 2> execute_lists{res.command_lists[0].list4.get(), res.command_lists[1].list4.get()};
// Call as seperate ExecuteCommandLists to ensure constant buffer copies are completed.
// This ends up being faster then using barriers on each buffer.
std::array<ID3D12CommandList*, 1> execute_lists{res.command_lists[0].list4.get()};
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
execute_lists[0] = res.command_lists[1].list4.get();
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
}
else
@@ -2569,25 +2579,25 @@ bool GSDevice12::CreateNullTexture()
bool GSDevice12::CreateBuffers()
{
if (!m_vertex_stream_buffer.Create(VERTEX_BUFFER_SIZE))
if (!m_vertex_stream_buffer.Create(VERTEX_BUFFER_SIZE, false))
{
Host::ReportErrorAsync("GS", "Failed to allocate vertex buffer");
return false;
}
if (!m_index_stream_buffer.Create(INDEX_BUFFER_SIZE))
if (!m_index_stream_buffer.Create(INDEX_BUFFER_SIZE, false))
{
Host::ReportErrorAsync("GS", "Failed to allocate index buffer");
return false;
}
if (!m_vertex_constant_buffer.Create(VERTEX_UNIFORM_BUFFER_SIZE))
if (!m_vertex_constant_buffer.Create(VERTEX_UNIFORM_BUFFER_SIZE, !m_uma))
{
Host::ReportErrorAsync("GS", "Failed to allocate vertex uniform buffer");
return false;
}
if (!m_pixel_constant_buffer.Create(FRAGMENT_UNIFORM_BUFFER_SIZE))
if (!m_pixel_constant_buffer.Create(FRAGMENT_UNIFORM_BUFFER_SIZE, !m_uma))
{
Host::ReportErrorAsync("GS", "Failed to allocate fragment uniform buffer");
return false;