D3D12: Implement GPU-based bounding box
This commit is contained in:
parent
32599559db
commit
ac1cd8279b
|
@ -2,43 +2,160 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "VideoBackends/D3D12/BoundingBox.h"
|
#include "VideoBackends/D3D12/BoundingBox.h"
|
||||||
|
#include "VideoBackends/D3D12/D3DBase.h"
|
||||||
|
#include "VideoBackends/D3D12/D3DCommandListManager.h"
|
||||||
|
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
|
||||||
|
#include "VideoBackends/D3D12/D3DStreamBuffer.h"
|
||||||
|
#include "VideoBackends/D3D12/D3DUtil.h"
|
||||||
|
#include "VideoBackends/D3D12/FramebufferManager.h"
|
||||||
|
#include "VideoBackends/D3D12/Render.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
// D3D12TODO: Support bounding box behavior.
|
|
||||||
namespace DX12
|
namespace DX12
|
||||||
{
|
{
|
||||||
|
|
||||||
ID3D11UnorderedAccessView* BBox::GetUAV()
|
constexpr size_t BBOX_BUFFER_SIZE = sizeof(int) * 4;
|
||||||
{
|
constexpr size_t BBOX_STREAM_BUFFER_SIZE = BBOX_BUFFER_SIZE * 128;
|
||||||
// D3D12TODO: Implement this;
|
|
||||||
return nullptr;
|
static ID3D12Resource* s_bbox_buffer;
|
||||||
}
|
static ID3D12Resource* s_bbox_staging_buffer;
|
||||||
|
static void* s_bbox_staging_buffer_map;
|
||||||
|
static std::unique_ptr<D3DStreamBuffer> s_bbox_stream_buffer;
|
||||||
|
static D3D12_GPU_DESCRIPTOR_HANDLE s_bbox_descriptor_handle;
|
||||||
|
|
||||||
void BBox::Init()
|
void BBox::Init()
|
||||||
{
|
{
|
||||||
if (g_ActiveConfig.backend_info.bSupportsBBox)
|
if (!g_ActiveConfig.backend_info.bSupportsBBox)
|
||||||
{
|
return;
|
||||||
// D3D12TODO: Implement this;
|
|
||||||
}
|
CD3DX12_RESOURCE_DESC buffer_desc(CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, 0));
|
||||||
|
CD3DX12_RESOURCE_DESC staging_buffer_desc(CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_NONE, 0));
|
||||||
|
|
||||||
|
CheckHR(D3D::device12->CreateCommittedResource(
|
||||||
|
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||||
|
D3D12_HEAP_FLAG_NONE,
|
||||||
|
&buffer_desc,
|
||||||
|
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||||
|
nullptr,
|
||||||
|
IID_PPV_ARGS(&s_bbox_buffer)));
|
||||||
|
|
||||||
|
CheckHR(D3D::device12->CreateCommittedResource(
|
||||||
|
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK),
|
||||||
|
D3D12_HEAP_FLAG_NONE,
|
||||||
|
&staging_buffer_desc,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||||
|
nullptr,
|
||||||
|
IID_PPV_ARGS(&s_bbox_staging_buffer)));
|
||||||
|
|
||||||
|
s_bbox_stream_buffer = std::make_unique<D3DStreamBuffer>(BBOX_STREAM_BUFFER_SIZE, BBOX_STREAM_BUFFER_SIZE, nullptr);
|
||||||
|
|
||||||
|
// D3D12 root signature UAV must be raw or structured buffers, not typed. Since we used a typed buffer,
|
||||||
|
// we have to use a descriptor table. Luckily, we only have to allocate this once, and it never changes.
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle;
|
||||||
|
if (!D3D::gpu_descriptor_heap_mgr->Allocate(&cpu_descriptor_handle, &s_bbox_descriptor_handle, nullptr, false))
|
||||||
|
PanicAlert("Failed to create bounding box UAV descriptor");
|
||||||
|
|
||||||
|
D3D12_UNORDERED_ACCESS_VIEW_DESC view_desc = { DXGI_FORMAT_R32_SINT, D3D12_UAV_DIMENSION_BUFFER };
|
||||||
|
view_desc.Buffer.FirstElement = 0;
|
||||||
|
view_desc.Buffer.NumElements = 4;
|
||||||
|
view_desc.Buffer.StructureByteStride = 0;
|
||||||
|
view_desc.Buffer.CounterOffsetInBytes = 0;
|
||||||
|
view_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
|
||||||
|
D3D::device12->CreateUnorderedAccessView(s_bbox_buffer, nullptr, &view_desc, cpu_descriptor_handle);
|
||||||
|
|
||||||
|
Bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBox::Bind()
|
||||||
|
{
|
||||||
|
if (s_bbox_buffer)
|
||||||
|
D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_UAV, s_bbox_descriptor_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBox::Invalidate()
|
||||||
|
{
|
||||||
|
if (!s_bbox_staging_buffer_map)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s_bbox_staging_buffer->Unmap(0, nullptr);
|
||||||
|
s_bbox_staging_buffer_map = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BBox::Shutdown()
|
void BBox::Shutdown()
|
||||||
{
|
{
|
||||||
// D3D12TODO: Implement this;
|
Invalidate();
|
||||||
|
|
||||||
|
if (s_bbox_buffer)
|
||||||
|
{
|
||||||
|
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_buffer);
|
||||||
|
s_bbox_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_bbox_staging_buffer)
|
||||||
|
{
|
||||||
|
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_staging_buffer);
|
||||||
|
s_bbox_staging_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_bbox_stream_buffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BBox::Set(int index, int value)
|
void BBox::Set(int index, int value)
|
||||||
{
|
{
|
||||||
// D3D12TODO: Implement this;
|
// If the buffer is currently mapped, compare the value, and update the staging buffer.
|
||||||
|
if (s_bbox_staging_buffer_map)
|
||||||
|
{
|
||||||
|
int current_value;
|
||||||
|
memcpy(¤t_value, reinterpret_cast<u8*>(s_bbox_staging_buffer_map) + (index * sizeof(int)), sizeof(int));
|
||||||
|
if (current_value == value)
|
||||||
|
{
|
||||||
|
// Value hasn't changed. So skip updating completely.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(reinterpret_cast<u8*>(s_bbox_staging_buffer_map) + (index * sizeof(int)), &value, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_bbox_stream_buffer->AllocateSpaceInBuffer(sizeof(int), sizeof(int)))
|
||||||
|
{
|
||||||
|
// Command list was executed, reset state
|
||||||
|
g_renderer->SetViewport();
|
||||||
|
FramebufferManager::RestoreEFBRenderTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate temporary bytes in upload buffer, then copy to real buffer.
|
||||||
|
memcpy(s_bbox_stream_buffer->GetCPUAddressOfCurrentAllocation(), &value, sizeof(int));
|
||||||
|
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, 0);
|
||||||
|
D3D::current_command_list->CopyBufferRegion(s_bbox_buffer, index * sizeof(int), s_bbox_stream_buffer->GetBuffer(), s_bbox_stream_buffer->GetOffsetOfCurrentAllocation(), sizeof(int));
|
||||||
|
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BBox::Get(int index)
|
int BBox::Get(int index)
|
||||||
{
|
{
|
||||||
// D3D12TODO: Implement this;
|
if (!s_bbox_staging_buffer_map)
|
||||||
return 0;
|
{
|
||||||
|
D3D::command_list_mgr->CPUAccessNotify();
|
||||||
|
|
||||||
|
// Copy from real buffer to staging buffer, then block until we have the results.
|
||||||
|
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, 0);
|
||||||
|
D3D::current_command_list->CopyBufferRegion(s_bbox_staging_buffer, 0, s_bbox_buffer, 0, BBOX_BUFFER_SIZE);
|
||||||
|
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0);
|
||||||
|
|
||||||
|
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||||
|
g_renderer->SetViewport();
|
||||||
|
FramebufferManager::RestoreEFBRenderTargets();
|
||||||
|
|
||||||
|
CheckHR(s_bbox_staging_buffer->Map(0, nullptr, &s_bbox_staging_buffer_map));
|
||||||
|
}
|
||||||
|
|
||||||
|
int value;
|
||||||
|
memcpy(&value, &reinterpret_cast<int*>(s_bbox_staging_buffer_map)[index], sizeof(int));
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,8 +11,9 @@ namespace DX12
|
||||||
class BBox
|
class BBox
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static ID3D11UnorderedAccessView* GetUAV();
|
|
||||||
static void Init();
|
static void Init();
|
||||||
|
static void Bind();
|
||||||
|
static void Invalidate();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
static void Set(int index, int value);
|
static void Set(int index, int value);
|
||||||
|
|
|
@ -637,7 +637,15 @@ void CreateRootSignatures()
|
||||||
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;
|
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
D3D12_ROOT_PARAMETER root_parameters[6];
|
D3D12_DESCRIPTOR_RANGE desc_range_uav = {
|
||||||
|
D3D12_DESCRIPTOR_RANGE_TYPE_UAV, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
|
||||||
|
1, // UINT NumDescriptors;
|
||||||
|
2, // UINT BaseShaderRegister;
|
||||||
|
0, // UINT RegisterSpace;
|
||||||
|
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;
|
||||||
|
};
|
||||||
|
|
||||||
|
D3D12_ROOT_PARAMETER root_parameters[NUM_GRAPHICS_ROOT_PARAMETERS];
|
||||||
|
|
||||||
root_parameters[DESCRIPTOR_TABLE_PS_SRV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
root_parameters[DESCRIPTOR_TABLE_PS_SRV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||||
root_parameters[DESCRIPTOR_TABLE_PS_SRV].DescriptorTable.NumDescriptorRanges = 1;
|
root_parameters[DESCRIPTOR_TABLE_PS_SRV].DescriptorTable.NumDescriptorRanges = 1;
|
||||||
|
@ -669,7 +677,10 @@ void CreateRootSignatures()
|
||||||
root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].Descriptor.ShaderRegister = 1;
|
root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].Descriptor.ShaderRegister = 1;
|
||||||
root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||||
|
|
||||||
// D3D12TODO: Add bounding box UAV to root signature.
|
root_parameters[DESCRIPTOR_TABLE_PS_UAV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||||
|
root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.NumDescriptorRanges = 1;
|
||||||
|
root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.pDescriptorRanges = &desc_range_uav;
|
||||||
|
root_parameters[DESCRIPTOR_TABLE_PS_UAV].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||||
|
|
||||||
D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {};
|
D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {};
|
||||||
root_signature_desc.pParameters = root_parameters;
|
root_signature_desc.pParameters = root_parameters;
|
||||||
|
|
|
@ -44,17 +44,21 @@ class D3DCommandListManager;
|
||||||
class D3DDescriptorHeapManager;
|
class D3DDescriptorHeapManager;
|
||||||
class D3DTexture2D;
|
class D3DTexture2D;
|
||||||
|
|
||||||
|
enum GRAPHICS_ROOT_PARAMETER : u32
|
||||||
|
{
|
||||||
|
DESCRIPTOR_TABLE_PS_SRV,
|
||||||
|
DESCRIPTOR_TABLE_PS_SAMPLER,
|
||||||
|
DESCRIPTOR_TABLE_GS_CBV,
|
||||||
|
DESCRIPTOR_TABLE_VS_CBV,
|
||||||
|
DESCRIPTOR_TABLE_PS_CBVONE,
|
||||||
|
DESCRIPTOR_TABLE_PS_CBVTWO,
|
||||||
|
DESCRIPTOR_TABLE_PS_UAV,
|
||||||
|
NUM_GRAPHICS_ROOT_PARAMETERS
|
||||||
|
};
|
||||||
|
|
||||||
namespace D3D
|
namespace D3D
|
||||||
{
|
{
|
||||||
|
|
||||||
#define DESCRIPTOR_TABLE_PS_SRV 0
|
|
||||||
#define DESCRIPTOR_TABLE_PS_SAMPLER 1
|
|
||||||
#define DESCRIPTOR_TABLE_GS_CBV 2
|
|
||||||
#define DESCRIPTOR_TABLE_VS_CBV 3
|
|
||||||
// #define DESCRIPTOR_TABLE_PS_UAV 4
|
|
||||||
#define DESCRIPTOR_TABLE_PS_CBVONE 4
|
|
||||||
#define DESCRIPTOR_TABLE_PS_CBVTWO 5
|
|
||||||
|
|
||||||
HRESULT LoadDXGI();
|
HRESULT LoadDXGI();
|
||||||
HRESULT LoadD3D();
|
HRESULT LoadD3D();
|
||||||
HRESULT LoadD3DCompiler();
|
HRESULT LoadD3DCompiler();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
|
#include "VideoBackends/D3D12/BoundingBox.h"
|
||||||
#include "VideoBackends/D3D12/D3DBase.h"
|
#include "VideoBackends/D3D12/D3DBase.h"
|
||||||
#include "VideoBackends/D3D12/D3DCommandListManager.h"
|
#include "VideoBackends/D3D12/D3DCommandListManager.h"
|
||||||
#include "VideoBackends/D3D12/D3DUtil.h"
|
#include "VideoBackends/D3D12/D3DUtil.h"
|
||||||
|
@ -208,6 +209,8 @@ void FramebufferManager::RestoreEFBRenderTargets()
|
||||||
D3D::current_command_list->OMSetRenderTargets(1,
|
D3D::current_command_list->OMSetRenderTargets(1,
|
||||||
&FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE,
|
&FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE,
|
||||||
&FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
&FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||||
|
|
||||||
|
BBox::Bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 FramebufferManager::ReadEFBColorAccessCopy(u32 x, u32 y)
|
u32 FramebufferManager::ReadEFBColorAccessCopy(u32 x, u32 y)
|
||||||
|
|
|
@ -735,6 +735,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
||||||
|
|
||||||
// Invalidate EFB access copies. Not strictly necessary, but this avoids having the buffers mapped when calling Present().
|
// Invalidate EFB access copies. Not strictly necessary, but this avoids having the buffers mapped when calling Present().
|
||||||
FramebufferManager::InvalidateEFBAccessCopies();
|
FramebufferManager::InvalidateEFBAccessCopies();
|
||||||
|
BBox::Invalidate();
|
||||||
|
|
||||||
// Prepare to copy the XFBs to our backbuffer
|
// Prepare to copy the XFBs to our backbuffer
|
||||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||||
|
|
|
@ -137,10 +137,7 @@ void VertexManager::vFlush(bool use_dst_alpha)
|
||||||
ShaderCache::LoadAndSetActiveShaders(use_dst_alpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE, current_primitive_type);
|
ShaderCache::LoadAndSetActiveShaders(use_dst_alpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE, current_primitive_type);
|
||||||
|
|
||||||
if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active)
|
if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active)
|
||||||
{
|
BBox::Invalidate();
|
||||||
// D3D12TODO: Support GPU-side bounding box.
|
|
||||||
// D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride();
|
u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride();
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ void InitBackendInfo()
|
||||||
g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported;
|
g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported;
|
||||||
|
|
||||||
// Requires full UAV functionality (only available in shader model 5)
|
// Requires full UAV functionality (only available in shader model 5)
|
||||||
g_Config.backend_info.bSupportsBBox = false;
|
g_Config.backend_info.bSupportsBBox = shader_model_5_supported;
|
||||||
|
|
||||||
// Requires the instance attribute (only available in shader model 5)
|
// Requires the instance attribute (only available in shader model 5)
|
||||||
g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported;
|
g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported;
|
||||||
|
|
Loading…
Reference in New Issue