GS:MTL: Implement ROV

This commit is contained in:
TellowKrinkle
2026-06-04 22:47:27 -05:00
committed by lightningterror
parent 1a13f9707b
commit 2821986fb2
5 changed files with 264 additions and 55 deletions
+1 -1
View File
@@ -899,7 +899,7 @@ struct alignas(16) GSHWDrawConfig
__fi bool HasDepthROV() const
{
return rov_depth == PS_ROV_DEPTH::READ_ONLY || rov_depth == PS_ROV_DEPTH::READ_WRITE;
return rov_depth != PS_ROV_DEPTH::NONE;
}
__fi bool HasDepthROVWrite() const
+10
View File
@@ -279,6 +279,7 @@ public:
std::unordered_map<PipelineSelectorMTL, MRCOwned<id<MTLRenderPipelineState>>> m_hw_pipeline;
MRCOwned<MTLRenderPassDescriptor*> m_render_pass_desc[16];
MRCOwned<MTLRenderPassDescriptor*> m_full_rov_render_pass_desc;
MRCOwned<id<MTLSamplerState>> m_sampler_hw[1 << 8];
@@ -316,12 +317,14 @@ public:
// Clear line (Things below here are tracked by `has` and don't need to be cleared to reset)
SamplerSelector sampler_sel;
u8 blend_color;
struct { u32 w, h; } full_rov_size;
GSVector4i scissor;
PipelineSelectorMTL pipeline_sel;
GSHWDrawConfig::VSConstantBuffer cb_vs;
GSHWDrawConfig::PSConstantBuffer cb_ps;
MainRenderEncoder(const MainRenderEncoder&) = delete;
MainRenderEncoder() = default;
bool is_full_rov() const { return encoder && !color_target && !depth_target && !stencil_target; }
} m_current_render;
MRCOwned<id<MTLCommandBuffer>> m_texture_upload_cmdbuf;
MRCOwned<id<MTLBlitCommandEncoder>> m_texture_upload_encoder;
@@ -330,6 +333,8 @@ public:
MRCOwned<id<MTLBlitCommandEncoder>> m_vertex_upload_encoder;
id<MTLTexture> m_ds_as_rt_texture = nil;
GSTexture* m_ds_as_rt_gstexture = nullptr;
MRCOwned<id<MTLTexture>> m_rov_dummy_texture;
struct { u32 w, h; } m_rov_dummy_texture_size = {};
struct DebugEntry
{
@@ -372,8 +377,12 @@ public:
void FlushEncodersForReadback();
/// End current render pass without flushing
void EndRenderPass();
/// Prepare to begin a new render pass
void PrepareBeginRenderPass();
/// Begin a new render pass (may reuse existing)
void BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load, GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil = nullptr, MTLLoadAction stencil_load = MTLLoadActionDontCare, bool rt1 = false);
/// Begin a new full-ROV render pass (may reuse existing)
void BeginFullROV(NSString* name, uint32_t width, uint32_t height);
/// Call at the end of each frame
void FrameCompleted();
@@ -455,6 +464,7 @@ public:
// MARK: Render HW
void SetupDestinationAlpha(GSTexture* rt, GSTexture* ds, const GSVector4i& r, SetDATM datm);
void PrepareROVTexture(GSTexture** ptex);
void RenderHW(GSHWDrawConfig& config) override;
void SendHWDraw(GSHWDrawConfig& config, id<MTLRenderCommandEncoder> enc, id<MTLBuffer> buffer, size_t off,
bool one_barrier, bool full_barrier);
+118 -15
View File
@@ -419,6 +419,19 @@ static GSVector4 GetRTLoadInfo(GSTextureMTL* tex, MTLLoadAction* load_action)
return {};
};
void GSDeviceMTL::PrepareBeginRenderPass()
{
m_encoders_in_current_cmdbuf++;
if (m_late_texture_upload_encoder)
{
[m_late_texture_upload_encoder endEncoding];
m_late_texture_upload_encoder = nullptr;
}
EndRenderPass();
}
void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load,
GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil, MTLLoadAction stencil_load, bool rt1)
{
@@ -455,14 +468,6 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
return;
}
m_encoders_in_current_cmdbuf++;
if (m_late_texture_upload_encoder)
{
[m_late_texture_upload_encoder endEncoding];
m_late_texture_upload_encoder = nullptr;
}
int idx = 0;
if (mc) idx |= 1;
if (md) idx |= 2;
@@ -502,7 +507,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
color1.clearColor = MTLClearColorMake(depth_load == MTLLoadActionClear ? depth_clear.x : -1, 0, 0, 0);
}
EndRenderPass();
PrepareBeginRenderPass();
m_current_render.encoder = MRCRetain([GetRenderCmdBuf() renderCommandEncoderWithDescriptor:desc]);
m_current_render.name = (__bridge void*)name;
[m_current_render.encoder setLabel:name];
@@ -516,6 +521,61 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
pxAssertRel(m_current_render.encoder, "Failed to create render encoder!");
}
void GSDeviceMTL::BeginFullROV(NSString* name, uint32_t width, uint32_t height)
{
bool needs_new = !m_current_render.is_full_rov()
|| width > m_current_render.full_rov_size.w
|| height > m_current_render.full_rov_size.h;
if (!needs_new)
{
if (m_current_render.name != (__bridge void*)name)
{
m_current_render.name = (__bridge void*)name;
[m_current_render.encoder setLabel:name];
}
return;
}
if (m_current_render.is_full_rov())
{
// Render was too small. Don't let it shrink in one dimension while growing in the other.
width = std::max(width, m_current_render.full_rov_size.w);
height = std::max(height, m_current_render.full_rov_size.h);
}
m_current_render.full_rov_size.w = width;
m_current_render.full_rov_size.h = height;
MTLRenderPassDescriptor* desc = m_full_rov_render_pass_desc;
[desc setRenderTargetWidth:width];
[desc setRenderTargetHeight:height];
if (m_dev.features.rov_requires_rt && (width > m_rov_dummy_texture_size.w || height > m_rov_dummy_texture_size.h))
{
m_rov_dummy_texture_size.w = std::max(m_rov_dummy_texture_size.w, width);
m_rov_dummy_texture_size.h = std::max(m_rov_dummy_texture_size.h, height);
MTLTextureDescriptor* tdesc = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
width:m_rov_dummy_texture_size.w
height:m_rov_dummy_texture_size.h
mipmapped:NO];
[tdesc setUsage:MTLTextureUsageRenderTarget];
[tdesc setStorageMode:MTLStorageModePrivate];
id<MTLTexture> tex = m_rov_dummy_texture = MRCTransfer([m_dev.dev newTextureWithDescriptor:tdesc]);
[tex setLabel:@"ROV Dummy Texture"];
[[[desc colorAttachments] objectAtIndexedSubscript:0] setTexture:tex];
}
PrepareBeginRenderPass();
m_current_render.encoder = MRCRetain([GetRenderCmdBuf() renderCommandEncoderWithDescriptor:desc]);
m_current_render.name = (__bridge void*)name;
[m_current_render.encoder setLabel:name];
if (!m_dev.features.unified_memory)
[m_current_render.encoder waitForFence:m_draw_sync_fence
beforeStages:MTLRenderStageVertex];
}
void GSDeviceMTL::FrameCompleted()
{
if (m_spin_timer)
@@ -999,6 +1059,7 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
m_features.test_and_sample_depth = true;
m_features.depth_feedback = getDepthFeedback(m_dev, m_features.framebuffer_fetch);
m_features.aa1 = GSConfig.HWAA1 && m_features.vs_expand;
m_features.rov = m_dev.features.rov && !m_dev.features.rov_requires_r32 && !m_features.framebuffer_fetch;
m_max_texture_size = m_dev.features.max_texsize;
// Init metal stuff
@@ -1062,6 +1123,17 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
}
m_render_pass_desc[i] = desc;
}
if (m_features.rov)
{
m_full_rov_render_pass_desc = MRCTransfer([MTLRenderPassDescriptor new]);
[m_full_rov_render_pass_desc setDefaultRasterSampleCount:1];
if (m_dev.features.rov_requires_rt)
{
MTLRenderPassColorAttachmentDescriptor* color0 = [[m_full_rov_render_pass_desc colorAttachments] objectAtIndexedSubscript:0];
[color0 setLoadAction:MTLLoadActionDontCare];
[color0 setStoreAction:MTLStoreActionDontCare];
}
}
// Init samplers
m_sampler_hw[SamplerSelector::Linear().key] = CreateSampler(m_dev.dev, SamplerSelector::Linear());
@@ -1978,7 +2050,10 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
setFnConstantI(m_fn_constants, pssel.aa1, GSMTLConstantIndex_PS_AA1);
setFnConstantB(m_fn_constants, pssel.abe, GSMTLConstantIndex_PS_ABE);
setFnConstantI(m_fn_constants, pssel.sw_aniso, GSMTLConstantIndex_PS_SW_ANISO);
auto newps = LoadShader(@"ps_main");
setFnConstantB(m_fn_constants, pssel.rov_color, GSMTLConstantIndex_PS_ROV_COLOR);
setFnConstantI(m_fn_constants, pssel.rov_depth, GSMTLConstantIndex_PS_ROV_DEPTH);
bool eft = pssel.HasColorROV() && !pssel.HasDepthROV() && !pssel.HasDepthOutput();
auto newps = LoadShader(eft ? @"ps_main_rov_eft" : @"ps_main");
ps = newps;
m_hw_ps.insert(std::make_pair(pssel, std::move(newps)));
}
@@ -2017,6 +2092,12 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
MTLRenderPipelineColorAttachmentDescriptor* color1 = [[pdesc colorAttachments] objectAtIndexedSubscript:1];
[color1 setPixelFormat:MTLPixelFormatR32Float];
}
if (m_dev.features.rov_requires_rt && extras.rt == GSTexture::Format::Invalid && !extras.has_depth && !extras.has_stencil)
{
// Dummy texture
[color setPixelFormat:MTLPixelFormatR8Unorm];
[color setWriteMask:MTLColorWriteMaskNone];
}
NSString* pname = [NSString stringWithFormat:@"HW Render %x.%llx.%llx.%x", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey];
auto pipeline = MakePipeline(pdesc, vs, ps, pname);
@@ -2108,6 +2189,7 @@ void GSDeviceMTL::MRESetScissor(const GSVector4i& scissor)
void GSDeviceMTL::MREClearScissor()
{
assert(!m_current_render.is_full_rov());
if (!m_current_render.has.scissor)
return;
m_current_render.has.scissor = false;
@@ -2235,6 +2317,15 @@ void GSDeviceMTL::MREInitHWDraw(GSHWDrawConfig& config, const Map& verts)
MRESetVSIndices(verts.gpu_buffer, verts.gpu_offset + config.nverts * sizeof(*config.verts));
}
__fi void GSDeviceMTL::PrepareROVTexture(GSTexture** ptex)
{
GSTextureMTL* tex = static_cast<GSTextureMTL*>(*ptex);
FlushClears(tex);
tex->m_last_read = m_current_draw;
tex->m_last_write = m_current_draw;
*ptex = nullptr;
}
void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
{ @autoreleasepool {
if (config.tex && (config.ds == config.tex || config.rt == config.tex))
@@ -2371,7 +2462,7 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
}
// Try to reduce render pass restarts
if (!config.ds && m_current_render.color_target == rt && stencil == m_current_render.stencil_target && m_current_render.depth_target != config.tex)
if (!config.ps.HasColorROV() && !config.ds && m_current_render.color_target == rt && stencil == m_current_render.stencil_target && m_current_render.depth_target != config.tex)
config.ds = m_current_render.depth_target;
if (!rt && config.ds == m_current_render.depth_target && m_current_render.color_target != config.tex)
rt = m_current_render.color_target;
@@ -2386,16 +2477,28 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
}
const bool feedback_depth = config.ps.IsFeedbackLoopDepth();
const bool rt1 = feedback_depth && !m_features.depth_feedback;
BeginRenderPass(@"RenderHW", rt, MTLLoadActionLoad, config.ds, MTLLoadActionLoad, stencil, MTLLoadActionLoad, rt1);
const bool rt1 = feedback_depth && !m_features.depth_feedback && !config.ps.HasDepthROV();
GSTexture* rt_bind = rt;
GSTexture* ds_bind = config.ds;
GSTexture* rt_size = rt_bind ? rt_bind : ds_bind;
if (config.ps.HasColorROV() && rt_bind) PrepareROVTexture(&rt_bind);
if (config.ps.HasDepthROV() && ds_bind) PrepareROVTexture(&ds_bind);
if (!rt_bind && !ds_bind && !stencil)
BeginFullROV(@"RenderHWROV", rt_size->GetWidth(), rt_size->GetHeight());
else
BeginRenderPass(@"RenderHW", rt_bind, MTLLoadActionLoad, ds_bind, MTLLoadActionLoad, stencil, MTLLoadActionLoad, rt1);
id<MTLRenderCommandEncoder> mtlenc = m_current_render.encoder;
FlushDebugEntries(mtlenc);
if (usesStencil(config.destination_alpha))
[mtlenc setStencilReferenceValue:1];
MREInitHWDraw(config, allocation);
if (config.require_one_barrier || config.require_full_barrier)
if (config.require_one_barrier || config.require_full_barrier || config.ps.HasColorROV())
MRESetTexture(rt, GSMTLTextureIndexRenderTarget);
if (feedback_depth)
if (config.ps.HasDepthROV())
{
MRESetTexture(config.ds, GSMTLTextureIndexDepthTarget);
}
else if (feedback_depth)
{
GSTexture* tex = !m_features.depth_feedback && !m_features.framebuffer_fetch ? m_ds_as_rt : config.ds;
MRESetTexture(tex, GSMTLTextureIndexDepthTarget);
@@ -227,4 +227,6 @@ enum GSMTLFnConstants
GSMTLConstantIndex_PS_AA1,
GSMTLConstantIndex_PS_ABE,
GSMTLConstantIndex_PS_SW_ANISO,
GSMTLConstantIndex_PS_ROV_COLOR,
GSMTLConstantIndex_PS_ROV_DEPTH,
};
+133 -39
View File
@@ -75,17 +75,21 @@ constant uint PS_SCANMSK [[function_constant(GSMTLConstantIndex_PS_SC
constant uint PS_AA1_RAW [[function_constant(GSMTLConstantIndex_PS_AA1)]];
constant bool PS_ABE [[function_constant(GSMTLConstantIndex_PS_ABE)]];
constant uint PS_SW_ANISO [[function_constant(GSMTLConstantIndex_PS_SW_ANISO)]];
constant bool PS_ROV_COLOR [[function_constant(GSMTLConstantIndex_PS_ROV_COLOR)]];
constant uint PS_ROV_DEPTH_RAW [[function_constant(GSMTLConstantIndex_PS_ROV_DEPTH)]];
using GSShader::VSExpand;
using AFAIL = GSShader::PS_AFAIL;
using ATST = GSShader::PS_ATST;
using GSShader::ZTST;
using AA1 = GSShader::PS_AA1;
using ROV_DEPTH = GSShader::PS_ROV_DEPTH;
constant VSExpand VS_EXPAND_TYPE = static_cast<VSExpand>(VS_EXPAND_TYPE_RAW);
constant AFAIL PS_AFAIL = static_cast<AFAIL>(PS_AFAIL_RAW);
constant ATST PS_ATST = static_cast<ATST>(PS_ATST_RAW);
constant ZTST PS_ZTST = static_cast<ZTST>(PS_ZTST_RAW);
constant AA1 PS_AA1 = static_cast<AA1>(PS_AA1_RAW);
constant ROV_DEPTH PS_ROV_DEPTH = static_cast<ROV_DEPTH>(PS_ROV_DEPTH_RAW);
#if defined(__METAL_MACOS__) && __METAL_VERSION__ >= 220
#define PRIMID_SUPPORT 1
@@ -119,9 +123,9 @@ constant bool NEEDS_DEPTH_FOR_ZTST = PS_ZTST == ZTST::GEQUAL || PS_ZTST == ZTST
constant bool NEEDS_DEPTH_FOR_AA1 = PS_AA1 == AA1::TRIANGLE_SW_Z;
constant bool SW_DEPTH = NEEDS_DEPTH_FOR_AFAIL || NEEDS_DEPTH_FOR_ZTST || NEEDS_DEPTH_FOR_AA1;
constant bool PS_COLOR0 = !PS_NO_COLOR;
constant bool PS_COLOR1 = !PS_NO_COLOR1;
constant bool PS_ZOUTPUT = PS_ZCLAMP || PS_ZFLOOR || SW_DEPTH;
constant bool PS_OUTPUT_COLOR0 = !PS_NO_COLOR && !PS_ROV_COLOR;
constant bool PS_OUTPUT_COLOR1 = !PS_NO_COLOR1 && !PS_ROV_COLOR;
constant bool PS_ZOUTPUT = (PS_ZCLAMP || PS_ZFLOOR || SW_DEPTH) && PS_ROV_DEPTH == ROV_DEPTH::NONE;
constant bool PS_ZOUTPUT_LESS = PS_ZOUTPUT && !SW_DEPTH;
constant bool PS_ZOUTPUT_ANY = PS_ZOUTPUT && SW_DEPTH;
constant bool PS_ZOUTPUT_COLOR = PS_ZOUTPUT_ANY && !DEPTH_FEEDBACK;
@@ -165,21 +169,32 @@ struct MainPSIn
uint interior [[function_constant(PS_INTERIOR)]];
};
struct MainResult
{
float4 c0;
float4 c1;
float depth;
};
struct MainPSOut
{
float4 c0 [[color(0), index(0), function_constant(PS_COLOR0)]];
float4 c1 [[color(0), index(1), function_constant(PS_COLOR1)]];
float4 c0 [[color(0), index(0), function_constant(PS_OUTPUT_COLOR0)]];
float4 c1 [[color(0), index(1), function_constant(PS_OUTPUT_COLOR1)]];
float depthColor [[color(1), function_constant(PS_ZOUTPUT_COLOR)]];
float depthLess [[depth(less), function_constant(PS_ZOUTPUT_LESS)]];
float depthAny [[depth(any), function_constant(PS_ZOUTPUT_ANY)]];
void setDepth(float depth)
MainPSOut(MainResult res)
{
if (PS_OUTPUT_COLOR0)
c0 = res.c0;
if (PS_OUTPUT_COLOR1)
c1 = res.c1;
if (PS_ZOUTPUT_LESS)
depthLess = depth;
depthLess = res.depth;
if (PS_ZOUTPUT_ANY)
depthAny = depth;
depthAny = res.depth;
if (PS_ZOUTPUT_COLOR)
depthColor = depth;
depthColor = res.depth;
}
};
@@ -564,11 +579,37 @@ struct PSMain
float4 current_color;
float current_depth;
uint prim_id;
bool color_discarded = false;
bool depth_discarded = false;
const thread MainPSIn& in;
constant GSMTLMainPSUniform& cb;
PSMain(const thread MainPSIn& in, constant GSMTLMainPSUniform& cb): in(in), cb(cb) {}
void discard()
{
if (PS_ROV_COLOR || PS_ROV_DEPTH != ROV_DEPTH::NONE)
color_discarded = depth_discarded = true;
else
discard_fragment();
}
void discard_color(thread float4& output)
{
if (PS_ROV_COLOR)
color_discarded = true;
else
output = current_color;
}
void discard_depth(thread float& output)
{
if (PS_ROV_DEPTH == ROV_DEPTH::READ_WRITE)
depth_discarded = true;
else
output = current_depth;
}
template <typename... Args>
float4 sample_tex(Args... args)
{
@@ -1454,9 +1495,9 @@ struct PSMain
}
}
MainPSOut ps_main()
MainResult ps_main()
{
MainPSOut out = {};
MainResult out = {};
float input_z = in.p.z;
if (PS_ZFLOOR)
input_z = floor(input_z * 0x1p32) * 0x1p-32;
@@ -1464,15 +1505,15 @@ struct PSMain
if (PS_ZTST == ZTST::GEQUAL || PS_ZTST == ZTST::GREATER)
{
if (PS_ZTST == ZTST::GEQUAL && input_z < current_depth)
discard_fragment();
discard();
if (PS_ZTST == ZTST::GREATER && input_z <= current_depth)
discard_fragment();
discard();
}
if (PS_SCANMSK & 2)
{
if ((uint(in.p.y) & 1) == (PS_SCANMSK & 1))
discard_fragment();
discard();
}
if (PS_DATE >= 5)
@@ -1482,7 +1523,7 @@ struct PSMain
bool bad = PS_RTA_CORRECTION ? ((PS_DATE & 3) == 1 ? (rt_a > (254.5f / 255.f)) : (rt_a < (254.5f / 255.f))) : ((PS_DATE & 3) == 1 ? (rt_a > 0.5) : (rt_a < 0.5));
if (bad)
discard_fragment();
discard();
}
if (PS_DATE == 3)
@@ -1491,7 +1532,7 @@ struct PSMain
// Note prim_id == stencil_ceil will be the primitive that will update
// the bad alpha value so we must keep it.
if (float(prim_id) > stencil_ceil)
discard_fragment();
discard();
}
float4 C = ps_color();
@@ -1500,9 +1541,9 @@ struct PSMain
if (PS_AA1 != AA1::NONE)
{
float cov = PS_AA1 == AA1::LINE ?
saturate(cb.line_cov_scale * (1.f - abs(in.inv_cov))) : // Blur only outer part of the line by scaling coverage.
saturate(1.f - abs(in.inv_cov));
float cov = PS_AA1 == AA1::LINE
? saturate(cb.line_cov_scale * (1.f - abs(in.inv_cov))) // Blur only outer part of the line by scaling coverage.
: saturate(1.f - abs(in.inv_cov));
if (!PS_ABE || floor(C.a) == 128.f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.f * cov;
}
@@ -1514,7 +1555,7 @@ struct PSMain
bool atst_pass = atst(C);
if (PS_AFAIL == AFAIL::KEEP && !atst_pass)
discard_fragment();
discard();
float4 alpha_blend = float4(0.f);
if (SW_AD_TO_HW)
@@ -1620,32 +1661,32 @@ struct PSMain
if (PS_AFAIL == AFAIL::RGB_ONLY_DSB)
alpha_blend.a = float(atst_pass);
if (PS_COLOR0)
if (!PS_NO_COLOR)
{
out.c0.a = PS_RTA_CORRECTION ? C.a / 128.f : C.a / 255.f;
out.c0.rgb = PS_COLCLIP_HW ? float3(C.rgb / 65535.f) : C.rgb / 255.f;
}
if (PS_COLOR1)
if (!PS_NO_COLOR1)
out.c1 = alpha_blend;
if (PS_ZCLAMP)
input_z = min(input_z, cb.max_depth);
if (PS_AA1 == AA1::TRIANGLE_SW_Z && !in.interior)
input_z = current_depth; // No depth update for triangle edges.
discard_depth(input_z); // No depth update for triangle edges.
if (!atst_pass)
{
if (PS_AFAIL == AFAIL::RGB_ONLY_SW_Z || PS_AFAIL == AFAIL::RGB_ONLY)
out.c0.a = current_color.a;
out.c0.a = current_color.a; // discard alpha
else if (PS_AFAIL == AFAIL::ZB_ONLY)
out.c0 = current_color;
discard_color(out.c0);
if (PS_AFAIL == AFAIL::RGB_ONLY_SW_Z || PS_AFAIL == AFAIL::FB_ONLY)
input_z = current_depth;
discard_depth(input_z);
}
out.setDepth(input_z);
out.depth = input_z;
return out;
}
@@ -1657,16 +1698,18 @@ fragment float4 fbfetch_test(float4 in [[color(0), raster_order_group(0)]])
return in * 2;
}
constant bool NEEDS_RT_TEX = NEEDS_RT && !HAS_FBFETCH;
constant bool NEEDS_RT_FBF = NEEDS_RT && HAS_FBFETCH;
constant bool NEEDS_DS_FBF = SW_DEPTH && HAS_FBFETCH && !DEPTH_FEEDBACK;
constant bool NEEDS_RT_TEX = NEEDS_RT && !HAS_FBFETCH && !PS_ROV_COLOR;
constant bool NEEDS_RT_FBF = NEEDS_RT && HAS_FBFETCH && !PS_ROV_COLOR;
constant bool NEEDS_DS_FBF = SW_DEPTH && HAS_FBFETCH && !DEPTH_FEEDBACK && PS_ROV_DEPTH == ROV_DEPTH::NONE;
#else
constant bool NEEDS_RT_TEX = NEEDS_RT;
constant bool NEEDS_RT_TEX = NEEDS_RT && !PS_ROV_COLOR;
constant bool NEEDS_DS_FBF = false;
constant float ds_fbf = 0;
#endif
constant bool NEEDS_DS_TEX = SW_DEPTH && !DEPTH_FEEDBACK && !NEEDS_DS_FBF;
constant bool NEEDS_DS_DEPTH = SW_DEPTH && DEPTH_FEEDBACK || NEEDS_DS_FBF;
constant bool NEEDS_DS_TEX = SW_DEPTH && !DEPTH_FEEDBACK && !NEEDS_DS_FBF && PS_ROV_DEPTH == ROV_DEPTH::NONE;
constant bool NEEDS_DS_DEPTH = (SW_DEPTH && DEPTH_FEEDBACK || NEEDS_DS_FBF) && PS_ROV_DEPTH == ROV_DEPTH::NONE;
constant bool NEEDS_RT_ROV = PS_ROV_COLOR;
constant bool NEEDS_DS_ROV = PS_ROV_DEPTH != ROV_DEPTH::NONE;
fragment MainPSOut ps_main(
MainPSIn in [[stage_in]],
@@ -1685,7 +1728,9 @@ fragment MainPSOut ps_main(
texture2d<float> rt [[texture(GSMTLTextureIndexRenderTarget), function_constant(NEEDS_RT_TEX)]],
texture2d<float> primidtex [[texture(GSMTLTextureIndexPrimIDs), function_constant(PS_PRIM_CHECKING_READ)]],
texture2d<float> ds_tex [[texture(GSMTLTextureIndexDepthTarget), function_constant(NEEDS_DS_TEX)]],
depth2d<float> ds_depth [[texture(GSMTLTextureIndexDepthTarget), function_constant(NEEDS_DS_DEPTH)]])
depth2d<float> ds_depth [[texture(GSMTLTextureIndexDepthTarget), function_constant(NEEDS_DS_DEPTH)]],
texture2d<float, access::read_write> rt_rov [[texture(GSMTLTextureIndexRenderTarget), raster_order_group(0), function_constant(NEEDS_RT_ROV)]],
texture2d<float, access::read_write> ds_rov [[texture(GSMTLTextureIndexDepthTarget), raster_order_group(1), function_constant(NEEDS_DS_ROV)]])
{
PSMain main(in, cb);
main.tex_sampler = s;
@@ -1706,7 +1751,9 @@ fragment MainPSOut ps_main(
if (SW_DEPTH)
{
if (DEPTH_FEEDBACK)
if (PS_ROV_DEPTH != ROV_DEPTH::NONE)
main.current_depth = ds_rov.read(coord).x;
else if (DEPTH_FEEDBACK)
main.current_depth = ds_depth.read(coord);
else if (NEEDS_DS_FBF)
main.current_depth = ds_fbf < 0 ? ds_depth.read(coord) : ds_fbf;
@@ -1714,20 +1761,67 @@ fragment MainPSOut ps_main(
main.current_depth = ds_tex.read(coord).x;
}
if (NEEDS_RT)
if (NEEDS_RT || (PS_ROV_COLOR && any(cb.fbmask == 0xff)))
{
if (PS_ROV_COLOR)
{
main.current_color = rt_rov.read(coord);
}
else
{
#if FBFETCH_SUPPORT
main.current_color = HAS_FBFETCH ? rt_fbf : rt.read(coord);
main.current_color = HAS_FBFETCH ? rt_fbf : rt.read(coord);
#else
main.current_color = rt.read(coord);
main.current_color = rt.read(coord);
#endif
}
}
else
{
main.current_color = 0;
}
return main.ps_main();
MainResult out = main.ps_main();
if (PS_ROV_DEPTH == ROV_DEPTH::READ_WRITE && !main.depth_discarded)
ds_rov.write(out.depth, coord);
if (PS_ROV_COLOR && !main.color_discarded)
{
if (!PS_FBMASK)
out.c0 = select(out.c0, main.current_color, cb.fbmask == 0xff);
rt_rov.write(out.c0, coord);
}
return out;
}
// Metal doesn't let you toggle eft with function constants so we need a separate function for it
[[early_fragment_tests]]
fragment void ps_main_rov_eft(
MainPSIn in [[stage_in]],
constant GSMTLMainPSUniform& cb [[buffer(GSMTLBufferIndexHWUniforms)]],
sampler s [[sampler(0)]],
texture2d<float> tex [[texture(GSMTLTextureIndexTex), function_constant(PS_TEX_IS_COLOR)]],
depth2d<float> depth [[texture(GSMTLTextureIndexTex), function_constant(PS_TEX_IS_DEPTH)]],
texture2d<float> palette [[texture(GSMTLTextureIndexPalette), function_constant(PS_HAS_PALETTE)]],
texture2d<float, access::read_write> rt_rov [[texture(GSMTLTextureIndexRenderTarget), raster_order_group(0)]])
{
PSMain main(in, cb);
main.tex_sampler = s;
if (PS_TEX_IS_COLOR)
main.tex = tex;
else
main.tex_depth = depth;
if (PS_HAS_PALETTE)
main.palette = palette;
uint2 coord = uint2(in.p.xy);
main.current_color = rt_rov.read(coord);
MainPSOut out = main.ps_main();
if (!main.color_discarded)
{
if (!PS_FBMASK)
out.c0 = select(out.c0, main.current_color, cb.fbmask == 0xff);
rt_rov.write(out.c0, coord);
}
}
#if PRIMID_SUPPORT