GS/DX12: Fix validation errors when depth testing and sampling

This commit is contained in:
TheLastRar
2026-01-01 01:20:13 +01:00
committed by lightningterror
parent bc41666d53
commit 43e073a18d
4 changed files with 81 additions and 32 deletions
+14 -17
View File
@@ -2181,13 +2181,13 @@ void GSDevice12::IASetIndexBuffer(const void* index, size_t count)
m_index_stream_buffer.CommitMemory(size);
}
void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor)
void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor, bool depth_read)
{
GSTexture12* vkRt = static_cast<GSTexture12*>(rt);
GSTexture12* vkDs = static_cast<GSTexture12*>(ds);
pxAssert(vkRt || vkDs);
if (m_current_render_target != vkRt || m_current_depth_target != vkDs)
if (m_current_render_target != vkRt || m_current_depth_target != vkDs || m_current_depth_read_only != depth_read)
{
// framebuffer change
EndRenderPass();
@@ -2214,13 +2214,14 @@ void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
m_current_render_target = vkRt;
m_current_depth_target = vkDs;
m_current_depth_read_only = depth_read;
if (!InRenderPass())
{
if (vkRt)
vkRt->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
if (vkDs)
vkDs->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
vkDs->TransitionToState(depth_read ? (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) : D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
// This is used to set/initialize the framebuffer for tfx rendering.
@@ -3330,6 +3331,7 @@ void GSDevice12::UnbindTexture(GSTexture12* tex)
{
EndRenderPass();
m_current_depth_target = nullptr;
m_current_depth_read_only = false;
}
}
@@ -3450,7 +3452,7 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC ds = {};
if (m_current_depth_target)
{
ds.cpuDescriptor = m_current_depth_target->GetWriteDescriptor();
ds.cpuDescriptor = m_current_depth_read_only ? m_current_depth_target->GetReadDepthViewDescriptor() : m_current_depth_target->GetWriteDescriptor();
ds.DepthEndingAccess.Type = depth_end;
ds.DepthBeginningAccess.Type = depth_begin;
if (depth_begin == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR)
@@ -3470,7 +3472,8 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
}
GetCommandList()->BeginRenderPass(m_current_render_target ? 1 : 0,
m_current_render_target ? &rt : nullptr, m_current_depth_target ? &ds : nullptr, D3D12_RENDER_PASS_FLAG_NONE);
m_current_render_target ? &rt : nullptr, m_current_depth_target ? &ds : nullptr,
(m_current_depth_target && m_current_depth_read_only) ? (D3D12_RENDER_PASS_FLAG_BIND_READ_ONLY_DEPTH) : D3D12_RENDER_PASS_FLAG_NONE);
}
void GSDevice12::EndRenderPass()
@@ -3552,11 +3555,13 @@ __ri void GSDevice12::ApplyBaseState(u32 flags, ID3D12GraphicsCommandList* cmdli
if (m_current_render_target)
{
cmdlist->OMSetRenderTargets(1, &m_current_render_target->GetWriteDescriptor().cpu_handle, FALSE,
m_current_depth_target ? &m_current_depth_target->GetWriteDescriptor().cpu_handle : nullptr);
m_current_depth_target ?
(m_current_depth_read_only ? &m_current_depth_target->GetReadDepthViewDescriptor().cpu_handle : &m_current_depth_target->GetWriteDescriptor().cpu_handle) :
nullptr);
}
else if (m_current_depth_target)
{
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, &m_current_depth_target->GetWriteDescriptor().cpu_handle);
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, m_current_depth_read_only ? &m_current_depth_target->GetReadDepthViewDescriptor().cpu_handle : &m_current_depth_target->GetWriteDescriptor().cpu_handle);
}
}
}
@@ -3924,15 +3929,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
if (config.blend.constant_enable)
SetBlendConstants(config.blend.constant);
// Depth testing and sampling, bind resource as dsv read only and srv at the same time without the need of a copy.
if (config.tex && config.tex == config.ds)
{
EndRenderPass();
// Transition dsv as read only.
draw_ds->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_READ);
}
// Primitive ID tracking DATE setup.
GSTexture12* date_image = nullptr;
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
@@ -4034,7 +4030,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
Console.Warning("D3D12: Failed to allocate temp texture for RT copy.");
}
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
// For depth testing and sampling, use a read only dsv, otherwise use a write dsv
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, config.tex && config.tex == config.ds);
// Begin render pass if new target or out of the area.
if (!m_in_render_pass)
+2 -1
View File
@@ -459,7 +459,7 @@ public:
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, bool feedback = false);
void PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor, bool depth_read = false);
void SetVSConstantBuffer(const GSHWDrawConfig::VSConstantBuffer& cb);
void SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb);
@@ -580,6 +580,7 @@ private:
GSTexture12* m_current_render_target = nullptr;
GSTexture12* m_current_depth_target = nullptr;
bool m_current_depth_read_only = false;
D3D12_VIEWPORT m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
GSVector4i m_scissor = GSVector4i::zero();
+59 -11
View File
@@ -17,13 +17,15 @@
GSTexture12::GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
const D3D12DescriptorHandle& fbl_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
const D3D12DescriptorHandle& uav_descriptor, const D3D12DescriptorHandle& fbl_descriptor,
WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
: m_resource(std::move(resource))
, m_resource_fbl(std::move(resource_fbl))
, m_allocation(std::move(allocation))
, m_srv_descriptor(srv_descriptor)
, m_write_descriptor(write_descriptor)
, m_read_dsv_descriptor(ro_dsv_descriptor)
, m_uav_descriptor(uav_descriptor)
, m_fbl_descriptor(fbl_descriptor)
, m_write_descriptor_type(wdtype)
@@ -58,6 +60,7 @@ void GSTexture12::Destroy(bool defer)
break;
case WriteDescriptorType::DSV:
dev->DeferDescriptorDestruction(dev->GetDSVHeapManager(), &m_write_descriptor);
dev->DeferDescriptorDestruction(dev->GetDSVHeapManager(), &m_read_dsv_descriptor);
break;
case WriteDescriptorType::None:
default:
@@ -87,6 +90,7 @@ void GSTexture12::Destroy(bool defer)
break;
case WriteDescriptorType::DSV:
dev->GetDSVHeapManager().Free(&m_write_descriptor);
dev->GetDSVHeapManager().Free(&m_read_dsv_descriptor);
break;
case WriteDescriptorType::None:
default:
@@ -237,7 +241,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
}
}
D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor, fbl_descriptor;
D3D12DescriptorHandle srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor;
WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
if (srv_format != DXGI_FORMAT_UNKNOWN)
{
@@ -261,11 +265,17 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
case Type::DepthStencil:
{
write_descriptor_type = WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor))
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
{
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
{
dev->GetDSVHeapManager().Free(&write_descriptor);
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
}
break;
@@ -281,6 +291,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
dev->GetRTVHeapManager().Free(&write_descriptor);
break;
case WriteDescriptorType::DSV:
dev->GetDSVHeapManager().Free(&ro_dsv_descriptor);
dev->GetDSVHeapManager().Free(&write_descriptor);
break;
default:
@@ -301,6 +312,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
dev->GetRTVHeapManager().Free(&write_descriptor);
break;
case WriteDescriptorType::DSV:
dev->GetDSVHeapManager().Free(&ro_dsv_descriptor);
dev->GetDSVHeapManager().Free(&write_descriptor);
break;
default:
@@ -313,7 +325,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
return std::unique_ptr<GSTexture12>(
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
srv_descriptor, write_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, state));
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, state));
}
std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Type type, Format format,
@@ -322,7 +334,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
{
const D3D12_RESOURCE_DESC desc = resource->GetDesc();
D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor;
D3D12DescriptorHandle srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor;
WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
if (srv_format != DXGI_FORMAT_UNKNOWN)
{
@@ -342,11 +354,17 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
else if (type == Type::DepthStencil)
{
write_descriptor_type = WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor))
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
{
GSDevice12::GetInstance()->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
{
GSDevice12::GetInstance()->GetDSVHeapManager().Free(&write_descriptor);
GSDevice12::GetInstance()->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
}
if (uav_format != DXGI_FORMAT_UNKNOWN)
@@ -359,6 +377,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
GSDevice12::GetInstance()->GetRTVHeapManager().Free(&write_descriptor);
break;
case WriteDescriptorType::DSV:
GSDevice12::GetInstance()->GetDSVHeapManager().Free(&ro_dsv_descriptor);
GSDevice12::GetInstance()->GetDSVHeapManager().Free(&write_descriptor);
break;
default:
@@ -371,7 +390,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
}
return std::unique_ptr<GSTexture12>(new GSTexture12(type, format, static_cast<u32>(desc.Width), desc.Height,
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, uav_descriptor,
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, {}, uav_descriptor,
{}, write_descriptor_type, resource_state));
}
@@ -405,7 +424,7 @@ bool GSTexture12::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT form
return true;
}
bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh)
bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh, bool read_only)
{
if (!GSDevice12::GetInstance()->GetDSVHeapManager().Allocate(dh))
{
@@ -413,7 +432,7 @@ bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT form
return false;
}
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, D3D12_DSV_FLAG_NONE};
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, read_only ? D3D12_DSV_FLAG_READ_ONLY_DEPTH : D3D12_DSV_FLAG_NONE };
GSDevice12::GetInstance()->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
return true;
}
@@ -708,7 +727,36 @@ void GSTexture12::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RE
if (m_resource_state == state)
return;
TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_resource_state, state);
// Read only depth requires special handling as we might want to write stencil.
// Also batch the transition barriers as per recommendation from docs.
if (state == (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE))
{
// Transition to read depth/write stencil
const D3D12_RESOURCE_BARRIER barriers[2] = {
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 0, m_resource_state, (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)}}},
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 1, m_resource_state, D3D12_RESOURCE_STATE_DEPTH_WRITE}}},
};
GSDevice12::GetInstance()->GetCommandList()->ResourceBarrier(m_resource_state == D3D12_RESOURCE_STATE_DEPTH_WRITE ? 1 : 2, barriers);
}
else if (m_resource_state == (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE))
{
// Transition from read depth/write stencil
const D3D12_RESOURCE_BARRIER barriers[2] = {
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 0, (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), state}}},
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 1, D3D12_RESOURCE_STATE_DEPTH_WRITE, state}}},
};
GSDevice12::GetInstance()->GetCommandList()->ResourceBarrier(state == D3D12_RESOURCE_STATE_DEPTH_WRITE ? 1 : 2, barriers);
}
else
{
// Normal transition
TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_resource_state, state);
}
m_resource_state = state;
}
+6 -3
View File
@@ -30,6 +30,7 @@ public:
__fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
__fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; }
__fi const D3D12DescriptorHandle& GetReadDepthViewDescriptor() const { return m_read_dsv_descriptor; }
__fi const D3D12DescriptorHandle& GetUAVDescriptor() const { return m_uav_descriptor; }
__fi const D3D12DescriptorHandle& GetFBLDescriptor() const { return m_fbl_descriptor; }
__fi D3D12_RESOURCE_STATES GetResourceState() const { return m_resource_state; }
@@ -72,13 +73,14 @@ private:
GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
const D3D12DescriptorHandle& fbl_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
const D3D12DescriptorHandle& uav_descriptor, const D3D12DescriptorHandle& fbl_descriptor,
WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
static bool CreateSRVDescriptor(
ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
static bool CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh, bool read_only);
static bool CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
ID3D12GraphicsCommandList* GetCommandBufferForUpdate();
@@ -91,6 +93,7 @@ private:
D3D12DescriptorHandle m_srv_descriptor = {};
D3D12DescriptorHandle m_write_descriptor = {};
D3D12DescriptorHandle m_read_dsv_descriptor = {};
D3D12DescriptorHandle m_uav_descriptor = {};
D3D12DescriptorHandle m_fbl_descriptor = {};
WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None;