From 1a13f9707babeac30a732c8f9e902824290b1078 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Thu, 4 Jun 2026 20:26:04 -0500 Subject: [PATCH] GS:MTL: GPU ROV feature detection --- pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm | 14 ++++++++++++++ pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.h | 3 +++ pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.mm | 9 +++++++++ 3 files changed, 26 insertions(+) diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index f20bdb7d9c..ab3f47db7e 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -1295,6 +1295,19 @@ bool GSDeviceMTL::UpdateWindow() bool GSDeviceMTL::SupportsExclusiveFullscreen() const { return false; } +static const char* GetROVString(const GSMTLDevice::Features& features) +{ + if (!features.rov) + return "Unsupported"; + if (features.rov_requires_r32 && features.rov_requires_rt) + return "With R32 Reinterpret and RT Texture"; + if (features.rov_requires_r32) + return "With R32 Reinterpret"; + if (features.rov_requires_rt) + return "With RT Texture"; + return "Supported"; +} + std::string GSDeviceMTL::GetDriverInfo() const { @autoreleasepool { std::string desc([[m_dev.dev description] UTF8String]); @@ -1304,6 +1317,7 @@ std::string GSDeviceMTL::GetDriverInfo() const 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 Depth Feedback: " + std::string(m_dev.features.depth_feedback ? "Supported" : "Unsupported"); + desc += "\n ROV: " + std::string(GetROVString(m_dev.features)); 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; diff --git a/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.h b/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.h index 1a7d45a003..f8fe13d8e8 100644 --- a/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.h +++ b/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.h @@ -34,6 +34,9 @@ struct GSMTLDevice bool has_fast_half : 1; bool memoryless_textures : 1; bool depth_feedback : 1; + bool rov : 1; + bool rov_requires_rt : 1; + bool rov_requires_r32 : 1; MetalVersion shader_version; int max_texsize; }; diff --git a/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.mm b/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.mm index 5e316931da..e8d103651c 100644 --- a/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.mm +++ b/pcsx2/GS/Renderers/Metal/GSMTLDeviceInfo.mm @@ -166,6 +166,9 @@ GSMTLDevice::GSMTLDevice(MRCOwned> dev) features.depth_feedback = false; + features.rov = [dev areRasterOrderGroupsSupported]; + features.rov_requires_r32 = [dev readWriteTextureSupport] < MTLReadWriteTextureTier2; + NSString* name = [dev name]; if ([name containsString:@"Intel"]) { @@ -193,6 +196,9 @@ GSMTLDevice::GSMTLDevice(MRCOwned> dev) if (@available(macOS 13, iOS 16, *)) if ([dev supportsFamily:MTLGPUFamilyMetal3]) features.depth_feedback = true; + // ROV doesn't work on AMD GPUs with no render target + // Ideally the driver would insert a dummy texture for us (it does on Linux) but the Metal driver doesn't. + features.rov_requires_rt = true; } else if ([name containsString:@"NVIDIA"]) { @@ -219,6 +225,9 @@ GSMTLDevice::GSMTLDevice(MRCOwned> dev) else features.slow_color_compression = [[dev name] containsString:@"AMD"] || [[dev name] isEqualToString:@"Intel HD Graphics 4000"]; + if (char* env = getenv("MTL_ROV_WITH_RT")) + features.rov_requires_rt = env[0] == '1' || env[0] == 'y' || env[0] == 'Y'; + features.max_texsize = GetMaxTextureSize(dev); this->dev = std::move(dev);