GS:MTL: Faster fbfetch depth feedback

This commit is contained in:
TellowKrinkle
2026-04-24 01:19:27 +02:00
committed by lightningterror
parent 8f23e31ae4
commit af81d8b7da
6 changed files with 83 additions and 15 deletions
+1 -1
View File
@@ -1073,7 +1073,7 @@ public:
bool IsDSInRTActive() const { return m_ds_as_rt; }
/// Create a temporary color clone of depth for depth feedback
void BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea);
virtual void BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea);
void EndDSAsRT();
/// Returns a string representing the specified API.
+3
View File
@@ -318,6 +318,8 @@ public:
MRCOwned<id<MTLBlitCommandEncoder>> m_late_texture_upload_encoder;
MRCOwned<id<MTLCommandBuffer>> m_vertex_upload_cmdbuf;
MRCOwned<id<MTLBlitCommandEncoder>> m_vertex_upload_encoder;
id<MTLTexture> m_ds_as_rt_texture = nil;
GSTexture* m_ds_as_rt_gstexture = nullptr;
struct DebugEntry
{
@@ -417,6 +419,7 @@ public:
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;
void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override;
void BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea) override;
void FlushClears(GSTexture* tex);
+72 -11
View File
@@ -95,6 +95,11 @@ GSDeviceMTL::GSDeviceMTL()
GSDeviceMTL::~GSDeviceMTL()
{
// m_ds_as_rt_texture is owned if the device has memoryless textures
if (m_dev.features.memoryless_textures)
[m_ds_as_rt_texture release];
else if (m_ds_as_rt_gstexture)
delete m_ds_as_rt_gstexture;
}
GSDeviceMTL::Map GSDeviceMTL::Allocate(UploadBuffer& buffer, size_t amt)
@@ -247,7 +252,10 @@ id<MTLFence> GSDeviceMTL::GetSpinFence()
id<MTLTexture> GSDeviceMTL::GetRT1DepthTexture(GSTextureMTL* depth)
{
return static_cast<GSTextureMTL*>(m_ds_as_rt)->GetTexture();
if (m_dev.features.framebuffer_fetch)
return m_ds_as_rt_texture;
else
return static_cast<GSTextureMTL*>(m_ds_as_rt)->GetTexture();
}
void GSDeviceMTL::DrawCommandBufferFinished(u64 draw, id<MTLCommandBuffer> buffer)
@@ -1023,7 +1031,15 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
{
MTLRenderPassColorAttachmentDescriptor* color1 = [[desc colorAttachments] objectAtIndexedSubscript:1];
[color1 setStoreAction:MTLStoreActionDontCare];
[color1 setLoadAction:MTLLoadActionLoad];
if (m_features.framebuffer_fetch)
{
[color1 setLoadAction:MTLLoadActionClear];
[color1 setClearColor:MTLClearColorMake(-1, 0, 0, 0)];
}
else
{
[color1 setLoadAction:MTLLoadActionLoad];
}
}
m_render_pass_desc[i] = desc;
}
@@ -1311,12 +1327,13 @@ bool GSDeviceMTL::SupportsExclusiveFullscreen() const { return false; }
std::string GSDeviceMTL::GetDriverInfo() const
{ @autoreleasepool {
std::string desc([[m_dev.dev description] UTF8String]);
desc += "\n Texture Swizzle: " + std::string(m_dev.features.texture_swizzle ? "Supported" : "Unsupported");
desc += "\n Unified Memory: " + std::string(m_dev.features.unified_memory ? "Supported" : "Unsupported");
desc += "\n Framebuffer Fetch: " + std::string(m_dev.features.framebuffer_fetch ? "Supported" : "Unsupported");
desc += "\n Primitive ID: " + std::string(m_dev.features.primid ? "Supported" : "Unsupported");
desc += "\n Shader Version: " + std::string(to_string(m_dev.features.shader_version));
desc += "\n Max Texture Size: " + std::to_string(m_dev.features.max_texsize);
desc += "\n Texture Swizzle: " + std::string(m_dev.features.texture_swizzle ? "Supported" : "Unsupported");
desc += "\n Unified Memory: " + std::string(m_dev.features.unified_memory ? "Supported" : "Unsupported");
desc += "\n Framebuffer Fetch: " + std::string(m_dev.features.framebuffer_fetch ? "Supported" : "Unsupported");
desc += "\n Memoryless Textures: " + std::string(m_dev.features.memoryless_textures ? "Supported" : "Unsupported");
desc += "\n Primitive ID: " + std::string(m_dev.features.primid ? "Supported" : "Unsupported");
desc += "\n Shader Version: " + std::string(to_string(m_dev.features.shader_version));
desc += "\n Max Texture Size: " + std::to_string(m_dev.features.max_texsize);
return desc;
}}
@@ -1802,6 +1819,50 @@ void GSDeviceMTL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u3
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
}}
static id<MTLTexture> CreateDSAsRTTexture(id<MTLDevice> dev, NSUInteger width, NSUInteger height, MTLStorageMode storage, NSString* name)
{
MTLTextureDescriptor *desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR32Float width:width height:height mipmapped:false];
[desc setUsage:MTLTextureUsageRenderTarget];
[desc setStorageMode:storage];
id<MTLTexture> result = [dev newTextureWithDescriptor:desc];
[result setLabel:name];
return result;
}
void GSDeviceMTL::BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea)
{
if (!m_features.framebuffer_fetch)
return GSDevice::BeginDSAsRT(ds, drawarea);
u32 needed_width = ds->GetWidth();
u32 needed_height = ds->GetHeight();
u32 current_width = static_cast<u32>([m_ds_as_rt_texture width]);
u32 current_height = static_cast<u32>([m_ds_as_rt_texture height]);
if (m_dev.features.memoryless_textures)
{
if (needed_width > current_width || needed_height > current_height) [[unlikely]] @autoreleasepool
{
u32 width = std::max(needed_width, current_width);
u32 height = std::max(needed_height, current_height);
[m_ds_as_rt_texture release];
m_ds_as_rt_texture = CreateDSAsRTTexture(m_dev.dev, width, height, MTLStorageModeMemoryless, @"DS as RT");
}
}
else
{
if (needed_width == current_width && needed_height == current_height)
return;
if (m_ds_as_rt_gstexture)
Recycle(m_ds_as_rt_gstexture);
m_ds_as_rt_gstexture = CreateRenderTarget(needed_width, needed_height, GSTexture::Format::Float32, false, true);
m_ds_as_rt_texture = static_cast<GSTextureMTL*>(m_ds_as_rt_gstexture)->GetTexture();
@autoreleasepool
{
NSString* name = [NSString stringWithFormat:@"DS as RT %dx%d", needed_width, needed_height];
[m_ds_as_rt_texture setLabel:name];
}
}
}
void GSDeviceMTL::FlushClears(GSTexture* tex)
{
if (tex)
@@ -2328,10 +2389,10 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
MREInitHWDraw(config, allocation);
if (config.require_one_barrier || config.require_full_barrier)
MRESetTexture(rt, GSMTLTextureIndexRenderTarget);
if (feedback_depth && !m_features.framebuffer_fetch)
if (feedback_depth)
{
bool depth_as_rt = m_features.depth_feedback == GSDevice::DepthFeedbackSupport::DepthAsRT;
GSTexture* tex = depth_as_rt ? m_ds_as_rt : config.ds;
GSTexture* tex = depth_as_rt && !m_features.framebuffer_fetch ? m_ds_as_rt : config.ds;
MRESetTexture(tex, GSMTLTextureIndexDepthTarget);
}
if (primid_tex)
@@ -2366,7 +2427,7 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);
SetColorClipTexture(nullptr);
}
}
@@ -34,6 +34,7 @@ struct GSMTLDevice
bool primid : 1;
bool slow_color_compression : 1; ///< Color compression seems to slow down rt read on AMD
bool has_fast_half : 1;
bool memoryless_textures : 1;
MetalVersion shader_version;
DepthFeedbackSupport preferred_depth_feedback : 8;
int max_texsize;
+1 -1
View File
@@ -147,7 +147,7 @@ GSMTLDevice::GSMTLDevice(MRCOwned<id<MTLDevice>> dev)
if (@available(macOS 11.0, iOS 13.0, *))
if ([dev supportsFamily:MTLGPUFamilyApple1])
features.framebuffer_fetch = true;
features.framebuffer_fetch = features.memoryless_textures = true;
if (@available(macOS 10.15, iOS 13.0, *))
if ([dev supportsFamily:MTLGPUFamilyMac2] || [dev supportsFamily:MTLGPUFamilyApple1])
+5 -2
View File
@@ -1413,7 +1413,7 @@ constant bool NEEDS_DS_FBF = false;
constant float ds_fbf = 0;
#endif
constant bool NEEDS_DS_TEX = SW_DEPTH && DEPTH_FEEDBACK == DepthFeedbackSupport::DepthAsRT && !NEEDS_DS_FBF;
constant bool NEEDS_DS_DEPTH = SW_DEPTH && DEPTH_FEEDBACK == DepthFeedbackSupport::Depth;
constant bool NEEDS_DS_DEPTH = SW_DEPTH && DEPTH_FEEDBACK == DepthFeedbackSupport::Depth || NEEDS_DS_FBF;
fragment MainPSOut ps_main(
MainPSIn in [[stage_in]],
@@ -1459,7 +1459,10 @@ fragment MainPSOut ps_main(
main.current_depth = ds_depth.read(coord);
break;
case DepthFeedbackSupport::DepthAsRT:
main.current_depth = HAS_FBFETCH ? ds_fbf : ds_tex.read(coord).x;
if (NEEDS_DS_FBF)
main.current_depth = ds_fbf < 0 ? ds_depth.read(coord) : ds_fbf;
else
main.current_depth = ds_tex.read(coord).x;
break;
case DepthFeedbackSupport::None:
// Should never happen