diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index 7f4b2c9dfe..48efb0cbc9 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -137,6 +137,15 @@ bool GSDevice12::SupportsTextureFormat(DXGI_FORMAT format) (support.Support1 & required) == required; } +bool GSDevice12::SupportsProgrammableSamplePositions() +{ + D3D12_FEATURE_DATA_D3D12_OPTIONS2 options = {}; + if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &options, sizeof(options)))) + return options.ProgrammableSamplePositionsTier != D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED; + + return false; +} + u32 GSDevice12::GetAdapterVendorID() const { if (!m_adapter) @@ -1250,6 +1259,9 @@ bool GSDevice12::CheckFeatures(const u32& vendor_id) m_max_texture_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + m_programmable_sample_positions = SupportsProgrammableSamplePositions(); + Console.WriteLnFmt("D3D12: Programmable Sample Position: {}", m_programmable_sample_positions ? "Supported" : "Not Supported"); + BOOL allow_tearing_supported = false; const HRESULT hr = m_dxgi_factory->CheckFeatureSupport( DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, sizeof(allow_tearing_supported)); @@ -1351,8 +1363,18 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, GSTexture12* const sTex12 = static_cast(sTex); GSTexture12* const dTex12 = static_cast(dTex); + const GSVector4i src_rect(0, 0, sTex12->GetWidth(), sTex12->GetHeight()); const GSVector4i dst_rect(0, 0, dTex12->GetWidth(), dTex12->GetHeight()); - const bool full_draw_copy = dst_rect.eq(r); + const bool src_dst_rect_match = src_rect.eq(dst_rect); + + // Sizes must match for full depth copies when no partial copies are supported. + if (sTex12->IsDepthStencil() && !src_dst_rect_match && !m_programmable_sample_positions) + { + GL_INS("D3D12: CopyRect rect mismatch for full depth copy."); + return; + } + + const bool full_draw_copy = (sTex->IsDepthStencil() && !m_programmable_sample_positions) || dst_rect.eq(r); // Source is cleared, if destination is a render target, we can carry the clear forward. if (sTex12->GetState() == GSTexture::State::Cleared) @@ -1414,8 +1436,8 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, dstloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstloc.SubresourceIndex = 0; - const GSVector4i src_rect(0, 0, sTex->GetWidth(), sTex->GetHeight()); - const bool full_rt_copy = destX == 0 && destY == 0 && r.eq(src_rect) && src_rect.eq(dst_rect); + // DX12 requires ProgrammableSamplePositions tier 1 to support partial depth copies, otherwise fallback to full depth copies. + const bool full_rt_copy = src_dst_rect_match && ((sTex12->IsDepthStencil() && !m_programmable_sample_positions) || (destX == 0 && destY == 0 && r.eq(src_rect))); if (full_rt_copy) { GetCommandList()->CopyResource(dTex12->GetResource(), sTex12->GetResource()); diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.h b/pcsx2/GS/Renderers/DX12/GSDevice12.h index 4c41528436..7244dc64b2 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.h +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.h @@ -99,6 +99,9 @@ public: /// Test for support for the specified texture format. bool SupportsTextureFormat(DXGI_FORMAT format); + // Partial depth copies require ProgrammableSamplePositions tier 1. + bool SupportsProgrammableSamplePositions(); + enum class WaitType { None, ///< Don't wait (async) @@ -170,6 +173,7 @@ private: double m_timestamp_frequency = 0.0; float m_accumulated_gpu_time = 0.0f; bool m_gpu_timing_enabled = false; + bool m_programmable_sample_positions = false; D3D12DescriptorHeapManager m_descriptor_heap_manager; D3D12DescriptorHeapManager m_rtv_heap_manager;