mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-10-12 02:08:45 +00:00
GS:MTL: Implement depth feedback
This commit is contained in:
committed by
lightningterror
parent
3737b1e06a
commit
8f23e31ae4
@@ -930,12 +930,7 @@ public:
|
||||
Performance
|
||||
};
|
||||
|
||||
enum class DepthFeedbackSupport : u8
|
||||
{
|
||||
None, // No support for depth feedback loops.
|
||||
Depth, // Implement depth feedback loops directly on the depth buffer.
|
||||
DepthAsRT, // Implement depth feedback loops by first converting depth to a color RT.
|
||||
};
|
||||
using DepthFeedbackSupport = GSShader::DepthFeedbackSupport;
|
||||
|
||||
// clang-format off
|
||||
struct FeatureSupport
|
||||
|
||||
@@ -19,6 +19,13 @@ enum class VSExpand : uint8_t
|
||||
TriangleAA1 = 5,
|
||||
};
|
||||
|
||||
enum class DepthFeedbackSupport : uint32_t
|
||||
{
|
||||
None = 0, ///< No support for depth feedback loops.
|
||||
Depth = 1, ///< Implement depth feedback loops directly on the depth buffer.
|
||||
DepthAsRT = 2, ///< Implement depth feedback loops by first converting depth to a color RT.
|
||||
};
|
||||
|
||||
enum class PS_ATST : uint32_t
|
||||
{
|
||||
NONE = 0,
|
||||
@@ -39,6 +46,15 @@ enum class PS_AFAIL : uint32_t
|
||||
RGB_ONLY_SW_Z = 5, ///< RGB only with software Z discard
|
||||
};
|
||||
|
||||
// Identical to GS_ZTST
|
||||
enum class ZTST : uint32_t
|
||||
{
|
||||
NEVER = 0,
|
||||
ALWAYS = 1,
|
||||
GEQUAL = 2,
|
||||
GREATER = 3,
|
||||
};
|
||||
|
||||
enum class PS_AA1 : uint32_t
|
||||
{
|
||||
NONE = 0, ///< No AA1
|
||||
|
||||
@@ -40,14 +40,15 @@ struct PipelineSelectorExtrasMTL
|
||||
GSDevice::BlendFactor dst_factor_alpha : 4;
|
||||
GSDevice::BlendOp blend_op : 2;
|
||||
bool blend_enable : 1;
|
||||
bool has_depth : 1;
|
||||
bool has_stencil : 1;
|
||||
bool has_depth : 1;
|
||||
bool has_stencil : 1;
|
||||
bool has_rt1 : 1;
|
||||
};
|
||||
u32 fullkey;
|
||||
};
|
||||
|
||||
PipelineSelectorExtrasMTL(): fullkey(0) {}
|
||||
PipelineSelectorExtrasMTL(GSHWDrawConfig::BlendState blend, GSTexture* rt, GSHWDrawConfig::ColorMaskSelector cms, bool has_depth, bool has_stencil)
|
||||
PipelineSelectorExtrasMTL(GSHWDrawConfig::BlendState blend, GSTexture* rt, GSHWDrawConfig::ColorMaskSelector cms, bool has_depth, bool has_stencil, bool has_rt1)
|
||||
: fullkey(0)
|
||||
{
|
||||
this->rt = rt ? rt->GetFormat() : GSTexture::Format::Invalid;
|
||||
@@ -65,6 +66,7 @@ struct PipelineSelectorExtrasMTL
|
||||
this->blend_enable = blend.enable;
|
||||
this->has_depth = has_depth;
|
||||
this->has_stencil = has_stencil;
|
||||
this->has_rt1 = has_rt1;
|
||||
}
|
||||
};
|
||||
struct PipelineSelectorMTL
|
||||
@@ -267,7 +269,7 @@ public:
|
||||
std::unordered_map<PSSelector, MRCOwned<id<MTLFunction>>> m_hw_ps;
|
||||
std::unordered_map<PipelineSelectorMTL, MRCOwned<id<MTLRenderPipelineState>>> m_hw_pipeline;
|
||||
|
||||
MRCOwned<MTLRenderPassDescriptor*> m_render_pass_desc[8];
|
||||
MRCOwned<MTLRenderPassDescriptor*> m_render_pass_desc[16];
|
||||
|
||||
MRCOwned<id<MTLSamplerState>> m_sampler_hw[1 << 8];
|
||||
|
||||
@@ -287,7 +289,7 @@ public:
|
||||
GSTexture* color_target = nullptr;
|
||||
GSTexture* depth_target = nullptr;
|
||||
GSTexture* stencil_target = nullptr;
|
||||
GSTexture* tex[8] = {};
|
||||
GSTexture* tex[GSMTLTextureIndexCount] = {};
|
||||
void* vertex_buffer = nullptr;
|
||||
void* name = nullptr;
|
||||
struct Has
|
||||
@@ -298,6 +300,7 @@ public:
|
||||
bool blend_color : 1;
|
||||
bool pipeline_sel : 1;
|
||||
bool sampler : 1;
|
||||
bool rt1_depth : 1;
|
||||
} has = {};
|
||||
DepthStencilSelector depth_sel = DepthStencilSelector::NoDepth();
|
||||
// Clear line (Things below here are tracked by `has` and don't need to be cleared to reset)
|
||||
@@ -347,6 +350,8 @@ public:
|
||||
id<MTLCommandBuffer> GetRenderCmdBufWithoutCreate();
|
||||
/// Get the spin fence if spinning is enabled.
|
||||
id<MTLFence> GetSpinFence();
|
||||
/// Get the texture to use as RT1 depth for the given depth texture
|
||||
id<MTLTexture> GetRT1DepthTexture(GSTextureMTL* depth);
|
||||
/// Called by command buffers when they finish
|
||||
void DrawCommandBufferFinished(u64 draw, id<MTLCommandBuffer> buffer);
|
||||
/// Flush pending operations from all encoders to the GPU
|
||||
@@ -356,7 +361,7 @@ public:
|
||||
/// End current render pass without flushing
|
||||
void EndRenderPass();
|
||||
/// 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);
|
||||
void BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load, GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil = nullptr, MTLLoadAction stencil_load = MTLLoadActionDontCare, bool rt1 = false);
|
||||
/// Call at the end of each frame
|
||||
void FrameCompleted();
|
||||
|
||||
|
||||
@@ -245,6 +245,11 @@ id<MTLFence> GSDeviceMTL::GetSpinFence()
|
||||
return m_spin_timer ? m_spin_fence : nil;
|
||||
}
|
||||
|
||||
id<MTLTexture> GSDeviceMTL::GetRT1DepthTexture(GSTextureMTL* depth)
|
||||
{
|
||||
return static_cast<GSTextureMTL*>(m_ds_as_rt)->GetTexture();
|
||||
}
|
||||
|
||||
void GSDeviceMTL::DrawCommandBufferFinished(u64 draw, id<MTLCommandBuffer> buffer)
|
||||
{
|
||||
// We can do the update non-atomically because we only ever update under the lock
|
||||
@@ -388,14 +393,15 @@ void GSDeviceMTL::EndRenderPass()
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load, GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil, MTLLoadAction stencil_load)
|
||||
void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load, GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil, MTLLoadAction stencil_load, bool rt1)
|
||||
{
|
||||
GSTextureMTL* mc = static_cast<GSTextureMTL*>(color);
|
||||
GSTextureMTL* md = static_cast<GSTextureMTL*>(depth);
|
||||
GSTextureMTL* ms = static_cast<GSTextureMTL*>(stencil);
|
||||
bool needs_new = color != m_current_render.color_target
|
||||
|| depth != m_current_render.depth_target
|
||||
|| stencil != m_current_render.stencil_target;
|
||||
|| stencil != m_current_render.stencil_target
|
||||
|| rt1 != m_current_render.has.rt1_depth;
|
||||
GSVector4 color_clear;
|
||||
float depth_clear;
|
||||
// Depth and stencil might be the same, so do all invalidation checks before resetting invalidation
|
||||
@@ -449,6 +455,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||
if (mc) idx |= 1;
|
||||
if (md) idx |= 2;
|
||||
if (ms) idx |= 4;
|
||||
if (rt1) idx |= 8;
|
||||
|
||||
MTLRenderPassDescriptor* desc = m_render_pass_desc[idx];
|
||||
if (mc)
|
||||
@@ -474,6 +481,11 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||
pxAssert(stencil_load != MTLLoadActionClear);
|
||||
desc.stencilAttachment.loadAction = stencil_load;
|
||||
}
|
||||
if (rt1)
|
||||
{
|
||||
pxAssert(md);
|
||||
desc.colorAttachments[1].texture = GetRT1DepthTexture(md);
|
||||
}
|
||||
|
||||
EndRenderPass();
|
||||
m_current_render.encoder = MRCRetain([GetRenderCmdBuf() renderCommandEncoderWithDescriptor:desc]);
|
||||
@@ -485,6 +497,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||
m_current_render.color_target = color;
|
||||
m_current_render.depth_target = depth;
|
||||
m_current_render.stencil_target = stencil;
|
||||
m_current_render.has.rt1_depth |= rt1;
|
||||
pxAssertRel(m_current_render.encoder, "Failed to create render encoder!");
|
||||
}
|
||||
|
||||
@@ -849,6 +862,21 @@ static MRCOwned<id<MTLSamplerState>> CreateSampler(id<MTLDevice> dev, GSHWDrawCo
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GSDevice::DepthFeedbackSupport getDepthFeedback(const GSMTLDevice& dev, bool fbfetch)
|
||||
{
|
||||
switch (GSConfig.DepthFeedbackMode)
|
||||
{
|
||||
case GSDepthFeedbackMode::None: return GSDevice::DepthFeedbackSupport::None;
|
||||
case GSDepthFeedbackMode::Auto: return dev.features.preferred_depth_feedback;
|
||||
case GSDepthFeedbackMode::DepthAsRT: return GSDevice::DepthFeedbackSupport::DepthAsRT;
|
||||
case GSDepthFeedbackMode::Depth:
|
||||
if (!fbfetch)
|
||||
return GSDevice::DepthFeedbackSupport::Depth;
|
||||
else
|
||||
return GSDevice::DepthFeedbackSupport::DepthAsRT; // Depth + FBFetch not supported
|
||||
}
|
||||
}
|
||||
|
||||
bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
{ @autoreleasepool {
|
||||
if (!GSDevice::Create(vsync_mode, allow_present_throttle))
|
||||
@@ -935,12 +963,13 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
m_features.stencil_buffer = true;
|
||||
m_features.cas_sharpening = true;
|
||||
m_features.test_and_sample_depth = true;
|
||||
m_features.depth_feedback = GSDevice::DepthFeedbackSupport::None;
|
||||
m_features.depth_feedback = getDepthFeedback(m_dev, m_features.framebuffer_fetch);
|
||||
m_max_texture_size = m_dev.features.max_texsize;
|
||||
|
||||
// Init metal stuff
|
||||
m_fn_constants = MRCTransfer([MTLFunctionConstantValues new]);
|
||||
setFnConstantB(m_fn_constants, m_dev.features.framebuffer_fetch, GSMTLConstantIndex_FRAMEBUFFER_FETCH);
|
||||
setFnConstantB(m_fn_constants, m_features.framebuffer_fetch, GSMTLConstantIndex_FRAMEBUFFER_FETCH);
|
||||
setFnConstantI(m_fn_constants, m_features.depth_feedback, GSMTLConstantIndex_DEPTH_FEEDBACK);
|
||||
|
||||
m_draw_sync_fence = MRCTransfer([m_dev.dev newFence]);
|
||||
[m_draw_sync_fence setLabel:@"Draw Sync Fence"];
|
||||
@@ -976,11 +1005,27 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
applyAttribute(m_hw_vertex, GSMTLAttributeIndexUV, MTLVertexFormatUShort2, offsetof(GSVertex, UV), GSMTLBufferIndexHWVertices);
|
||||
applyAttribute(m_hw_vertex, GSMTLAttributeIndexF, MTLVertexFormatUChar4Normalized, offsetof(GSVertex, FOG), GSMTLBufferIndexHWVertices);
|
||||
|
||||
for (auto& desc : m_render_pass_desc)
|
||||
for (size_t i = 0; i < std::size(m_render_pass_desc); i++)
|
||||
{
|
||||
desc = MRCTransfer([MTLRenderPassDescriptor new]);
|
||||
const bool depth = i & 2;
|
||||
const bool stencil = i & 4;
|
||||
const bool rt1 = i & 8;
|
||||
if (rt1 && m_features.depth_feedback != GSDevice::DepthFeedbackSupport::DepthAsRT)
|
||||
continue;
|
||||
if (rt1 && !depth)
|
||||
continue;
|
||||
if (stencil && m_features.framebuffer_fetch)
|
||||
continue;
|
||||
auto desc = MRCTransfer([MTLRenderPassDescriptor new]);
|
||||
[[desc depthAttachment] setStoreAction:MTLStoreActionStore];
|
||||
[[desc stencilAttachment] setStoreAction:MTLStoreActionStore];
|
||||
if (rt1)
|
||||
{
|
||||
MTLRenderPassColorAttachmentDescriptor* color1 = [[desc colorAttachments] objectAtIndexedSubscript:1];
|
||||
[color1 setStoreAction:MTLStoreActionDontCare];
|
||||
[color1 setLoadAction:MTLLoadActionLoad];
|
||||
}
|
||||
m_render_pass_desc[i] = desc;
|
||||
}
|
||||
|
||||
// Init samplers
|
||||
@@ -1800,7 +1845,7 @@ static MTLBlendOperation ConvertBlendOp(GSDevice::BlendOp generic)
|
||||
|
||||
void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDrawConfig::PSSelector pssel, GSHWDrawConfig::BlendState blend, GSHWDrawConfig::ColorMaskSelector cms)
|
||||
{
|
||||
PipelineSelectorExtrasMTL extras(blend, m_current_render.color_target, cms, m_current_render.depth_target, m_current_render.stencil_target);
|
||||
PipelineSelectorExtrasMTL extras(blend, m_current_render.color_target, cms, m_current_render.depth_target, m_current_render.stencil_target, m_current_render.has.rt1_depth);
|
||||
PipelineSelectorMTL fullsel(vssel, pssel, extras);
|
||||
if (m_current_render.has.pipeline_sel && fullsel == m_current_render.pipeline_sel)
|
||||
return;
|
||||
@@ -1842,6 +1887,7 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
|
||||
setFnConstantI(m_fn_constants, pssel.date, GSMTLConstantIndex_PS_DATE);
|
||||
setFnConstantI(m_fn_constants, pssel.atst, GSMTLConstantIndex_PS_ATST);
|
||||
setFnConstantI(m_fn_constants, pssel.afail, GSMTLConstantIndex_PS_AFAIL);
|
||||
setFnConstantI(m_fn_constants, pssel.ztst, GSMTLConstantIndex_PS_ZTST);
|
||||
setFnConstantI(m_fn_constants, pssel.tfx, GSMTLConstantIndex_PS_TFX);
|
||||
setFnConstantB(m_fn_constants, pssel.tcc, GSMTLConstantIndex_PS_TCC);
|
||||
setFnConstantI(m_fn_constants, pssel.wms, GSMTLConstantIndex_PS_WMS);
|
||||
@@ -1921,6 +1967,11 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
|
||||
color.sourceAlphaBlendFactor = ConvertBlendFactor(extras.src_factor_alpha);
|
||||
color.destinationAlphaBlendFactor = ConvertBlendFactor(extras.dst_factor_alpha);
|
||||
}
|
||||
if (extras.has_rt1)
|
||||
{
|
||||
MTLRenderPipelineColorAttachmentDescriptor* color1 = [[pdesc colorAttachments] objectAtIndexedSubscript:1];
|
||||
[color1 setPixelFormat:MTLPixelFormatR32Float];
|
||||
}
|
||||
NSString* pname = [NSString stringWithFormat:@"HW Render %x.%x.%llx.%x", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey];
|
||||
auto pipeline = MakePipeline(pdesc, vs, ps, pname);
|
||||
|
||||
@@ -2267,7 +2318,9 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
||||
return;
|
||||
}
|
||||
|
||||
BeginRenderPass(@"RenderHW", rt, MTLLoadActionLoad, config.ds, MTLLoadActionLoad, stencil, MTLLoadActionLoad);
|
||||
const bool feedback_depth = config.ps.IsFeedbackLoopDepth();
|
||||
const bool rt1 = feedback_depth && m_features.depth_feedback == GSDevice::DepthFeedbackSupport::DepthAsRT;
|
||||
BeginRenderPass(@"RenderHW", rt, MTLLoadActionLoad, config.ds, MTLLoadActionLoad, stencil, MTLLoadActionLoad, rt1);
|
||||
id<MTLRenderCommandEncoder> mtlenc = m_current_render.encoder;
|
||||
FlushDebugEntries(mtlenc);
|
||||
if (usesStencil(config.destination_alpha))
|
||||
@@ -2275,6 +2328,12 @@ 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)
|
||||
{
|
||||
bool depth_as_rt = m_features.depth_feedback == GSDevice::DepthFeedbackSupport::DepthAsRT;
|
||||
GSTexture* tex = depth_as_rt ? m_ds_as_rt : config.ds;
|
||||
MRESetTexture(tex, GSMTLTextureIndexDepthTarget);
|
||||
}
|
||||
if (primid_tex)
|
||||
MRESetTexture(primid_tex, GSMTLTextureIndexPrimIDs);
|
||||
if (config.blend.constant_enable)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "common/MRCHelpers.h"
|
||||
#include "common/Pcsx2Types.h"
|
||||
#include "GS/Renderers/Common/GSShaderEnums.h"
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
struct GSMTLDevice
|
||||
@@ -23,15 +24,18 @@ struct GSMTLDevice
|
||||
Metal23, ///< Metal 2.3 (macOS 11, iOS 14)
|
||||
};
|
||||
|
||||
using DepthFeedbackSupport = GSShader::DepthFeedbackSupport;
|
||||
|
||||
struct Features
|
||||
{
|
||||
bool unified_memory;
|
||||
bool texture_swizzle;
|
||||
bool framebuffer_fetch;
|
||||
bool primid;
|
||||
bool slow_color_compression; ///< Color compression seems to slow down rt read on AMD
|
||||
bool has_fast_half;
|
||||
bool unified_memory : 1;
|
||||
bool texture_swizzle : 1;
|
||||
bool framebuffer_fetch : 1;
|
||||
bool primid : 1;
|
||||
bool slow_color_compression : 1; ///< Color compression seems to slow down rt read on AMD
|
||||
bool has_fast_half : 1;
|
||||
MetalVersion shader_version;
|
||||
DepthFeedbackSupport preferred_depth_feedback : 8;
|
||||
int max_texsize;
|
||||
};
|
||||
|
||||
|
||||
@@ -164,21 +164,49 @@ GSMTLDevice::GSMTLDevice(MRCOwned<id<MTLDevice>> dev)
|
||||
if (features.primid && !detectPrimIDSupport(dev, shaders))
|
||||
features.primid = false;
|
||||
|
||||
if (!features.framebuffer_fetch && features.shader_version >= MetalVersion::Metal23)
|
||||
features.preferred_depth_feedback = DepthFeedbackSupport::DepthAsRT;
|
||||
|
||||
NSString* name = [dev name];
|
||||
if ([name containsString:@"Intel"])
|
||||
{
|
||||
switch (detectIntelGPU(dev, shaders))
|
||||
if (!features.framebuffer_fetch && features.shader_version >= MetalVersion::Metal23)
|
||||
{
|
||||
case DetectionResult::HaswellOrNotIntel:
|
||||
break;
|
||||
case DetectionResult::Broadwell:
|
||||
features.primid = false; // Broken
|
||||
break;
|
||||
case DetectionResult::Skylake:
|
||||
features.primid = false; // Broken
|
||||
features.framebuffer_fetch = true;
|
||||
break;
|
||||
switch (detectIntelGPU(dev, shaders))
|
||||
{
|
||||
case DetectionResult::HaswellOrNotIntel:
|
||||
// Older Intel GPUs seem to be fine with depth feedback
|
||||
features.preferred_depth_feedback = DepthFeedbackSupport::Depth;
|
||||
break;
|
||||
case DetectionResult::Broadwell:
|
||||
features.primid = false; // Broken
|
||||
break;
|
||||
case DetectionResult::Skylake:
|
||||
features.primid = false; // Broken
|
||||
features.framebuffer_fetch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([name containsString:@"AMD"])
|
||||
{
|
||||
// RDNA+ seems to work fine with depth feedback
|
||||
if (@available(macOS 13, iOS 16, *))
|
||||
if ([dev supportsFamily:MTLGPUFamilyMetal3])
|
||||
features.preferred_depth_feedback = DepthFeedbackSupport::Depth;
|
||||
}
|
||||
else if ([name containsString:@"NVIDIA"])
|
||||
{
|
||||
// macOS only supports Kepler, which seems to work fine with depth feedback
|
||||
features.preferred_depth_feedback = DepthFeedbackSupport::Depth;
|
||||
}
|
||||
else if ([name containsString:@"Apple"])
|
||||
{
|
||||
// No special settings
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("Unrecognized GPU vendor %s", [name UTF8String]);
|
||||
}
|
||||
|
||||
if (features.framebuffer_fetch && GSConfig.DisableFramebufferFetch)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,8 @@ enum GSMTLTextureIndex
|
||||
GSMTLTextureIndexPalette,
|
||||
GSMTLTextureIndexRenderTarget,
|
||||
GSMTLTextureIndexPrimIDs,
|
||||
GSMTLTextureIndexDepthTarget,
|
||||
GSMTLTextureIndexCount,
|
||||
};
|
||||
|
||||
struct GSMTLConvertPSUniform
|
||||
@@ -154,6 +156,7 @@ enum GSMTLFnConstants
|
||||
{
|
||||
GSMTLConstantIndex_CAS_SHARPEN_ONLY,
|
||||
GSMTLConstantIndex_FRAMEBUFFER_FETCH,
|
||||
GSMTLConstantIndex_DEPTH_FEEDBACK,
|
||||
GSMTLConstantIndex_FST,
|
||||
GSMTLConstantIndex_IIP,
|
||||
GSMTLConstantIndex_VS_POINT_SIZE,
|
||||
@@ -168,6 +171,7 @@ enum GSMTLFnConstants
|
||||
GSMTLConstantIndex_PS_DATE,
|
||||
GSMTLConstantIndex_PS_ATST,
|
||||
GSMTLConstantIndex_PS_AFAIL,
|
||||
GSMTLConstantIndex_PS_ZTST,
|
||||
GSMTLConstantIndex_PS_TFX,
|
||||
GSMTLConstantIndex_PS_TCC,
|
||||
GSMTLConstantIndex_PS_WMS,
|
||||
|
||||
@@ -12,6 +12,7 @@ constant uint SHUFFLE_READ = 1;
|
||||
constant uint SHUFFLE_READWRITE = 3;
|
||||
|
||||
constant bool HAS_FBFETCH [[function_constant(GSMTLConstantIndex_FRAMEBUFFER_FETCH)]];
|
||||
constant uint DEPTH_FEEDBACK_RAW [[function_constant(GSMTLConstantIndex_DEPTH_FEEDBACK)]];
|
||||
constant bool FST [[function_constant(GSMTLConstantIndex_FST)]];
|
||||
constant bool IIP [[function_constant(GSMTLConstantIndex_IIP)]];
|
||||
constant bool VS_POINT_SIZE [[function_constant(GSMTLConstantIndex_VS_POINT_SIZE)]];
|
||||
@@ -26,6 +27,7 @@ constant bool PS_FOG [[function_constant(GSMTLConstantIndex_PS_FO
|
||||
constant uint PS_DATE [[function_constant(GSMTLConstantIndex_PS_DATE)]];
|
||||
constant uint PS_ATST_RAW [[function_constant(GSMTLConstantIndex_PS_ATST)]];
|
||||
constant uint PS_AFAIL_RAW [[function_constant(GSMTLConstantIndex_PS_AFAIL)]];
|
||||
constant uint PS_ZTST_RAW [[function_constant(GSMTLConstantIndex_PS_ZTST)]];
|
||||
constant uint PS_TFX [[function_constant(GSMTLConstantIndex_PS_TFX)]];
|
||||
constant bool PS_TCC [[function_constant(GSMTLConstantIndex_PS_TCC)]];
|
||||
constant uint PS_WMS [[function_constant(GSMTLConstantIndex_PS_WMS)]];
|
||||
@@ -72,12 +74,16 @@ constant bool PS_REGION_RECT [[function_constant(GSMTLConstantIndex_PS_RE
|
||||
constant uint PS_SCANMSK [[function_constant(GSMTLConstantIndex_PS_SCANMSK)]];
|
||||
constant uint PS_SW_ANISO [[function_constant(GSMTLConstantIndex_PS_SW_ANISO)]];
|
||||
|
||||
using GSShader::DepthFeedbackSupport;
|
||||
using GSShader::VSExpand;
|
||||
using AFAIL = GSShader::PS_AFAIL;
|
||||
using ATST = GSShader::PS_ATST;
|
||||
using GSShader::ZTST;
|
||||
constant DepthFeedbackSupport DEPTH_FEEDBACK = static_cast<DepthFeedbackSupport>(DEPTH_FEEDBACK_RAW);
|
||||
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);
|
||||
|
||||
#if defined(__METAL_MACOS__) && __METAL_VERSION__ >= 220
|
||||
#define PRIMID_SUPPORT 1
|
||||
@@ -104,12 +110,18 @@ constant bool SW_BLEND = (PS_BLEND_A != PS_BLEND_B) || PS_BLEND_D;
|
||||
constant bool SW_AD_TO_HW = (PS_BLEND_C == 1 && PS_A_MASKED);
|
||||
constant bool NEEDS_RT_FOR_BLEND = (((PS_BLEND_A != PS_BLEND_B) && (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1)) || PS_BLEND_D == 1 || SW_AD_TO_HW);
|
||||
constant bool NEEDS_RT_EARLY = PS_TEX_IS_FB || PS_DATE >= 5;
|
||||
constant bool NEEDS_RT_FOR_AFAIL = PS_AFAIL == AFAIL::ZB_ONLY || PS_AFAIL == AFAIL::RGB_ONLY;
|
||||
constant bool NEEDS_RT_FOR_AFAIL = PS_AFAIL == AFAIL::ZB_ONLY || PS_AFAIL == AFAIL::RGB_ONLY || PS_AFAIL == AFAIL::RGB_ONLY_SW_Z;
|
||||
constant bool NEEDS_RT = NEEDS_RT_FOR_AFAIL || NEEDS_RT_EARLY || (!PS_PRIM_CHECKING_INIT && (PS_FBMASK || NEEDS_RT_FOR_BLEND));
|
||||
constant bool NEEDS_DEPTH_FOR_AFAIL = PS_AFAIL == AFAIL::FB_ONLY || PS_AFAIL == AFAIL::RGB_ONLY_SW_Z;
|
||||
constant bool NEEDS_DEPTH_FOR_ZTST = PS_ZTST == ZTST::GEQUAL || PS_ZTST == ZTST::GREATER;
|
||||
constant bool SW_DEPTH = NEEDS_DEPTH_FOR_AFAIL || NEEDS_DEPTH_FOR_ZTST;
|
||||
|
||||
constant bool PS_COLOR0 = !PS_NO_COLOR;
|
||||
constant bool PS_COLOR1 = !PS_NO_COLOR1;
|
||||
constant bool PS_ZOUTPUT = PS_ZCLAMP || PS_ZFLOOR;
|
||||
constant bool PS_ZOUTPUT = PS_ZCLAMP || PS_ZFLOOR || SW_DEPTH;
|
||||
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 == DepthFeedbackSupport::DepthAsRT;
|
||||
|
||||
struct MainVSIn
|
||||
{
|
||||
@@ -145,7 +157,18 @@ struct MainPSOut
|
||||
{
|
||||
float4 c0 [[color(0), index(0), function_constant(PS_COLOR0)]];
|
||||
float4 c1 [[color(0), index(1), function_constant(PS_COLOR1)]];
|
||||
float depth [[depth(less), function_constant(PS_ZOUTPUT)]];
|
||||
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)
|
||||
{
|
||||
if (PS_ZOUTPUT_LESS)
|
||||
depthLess = depth;
|
||||
if (PS_ZOUTPUT_ANY)
|
||||
depthAny = depth;
|
||||
if (PS_ZOUTPUT_COLOR)
|
||||
depthColor = depth;
|
||||
}
|
||||
};
|
||||
|
||||
// MARK: - Vertex functions
|
||||
@@ -300,6 +323,7 @@ struct PSMain
|
||||
texture2d<float> prim_id_tex;
|
||||
sampler tex_sampler;
|
||||
float4 current_color;
|
||||
float current_depth;
|
||||
uint prim_id;
|
||||
const thread MainPSIn& in;
|
||||
constant GSMTLMainPSUniform& cb;
|
||||
@@ -1189,6 +1213,17 @@ struct PSMain
|
||||
MainPSOut ps_main()
|
||||
{
|
||||
MainPSOut out = {};
|
||||
float input_z = in.p.z;
|
||||
if (PS_ZFLOOR)
|
||||
input_z = floor(input_z * 0x1p32) * 0x1p-32;
|
||||
|
||||
if (PS_ZTST == ZTST::GEQUAL || PS_ZTST == ZTST::GREATER)
|
||||
{
|
||||
if (PS_ZTST == ZTST::GEQUAL && input_z < current_depth)
|
||||
discard_fragment();
|
||||
if (PS_ZTST == ZTST::GREATER && input_z <= current_depth)
|
||||
discard_fragment();
|
||||
}
|
||||
|
||||
if (PS_SCANMSK & 2)
|
||||
{
|
||||
@@ -1339,18 +1374,25 @@ struct PSMain
|
||||
{
|
||||
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_AFAIL == AFAIL::RGB_ONLY && !atst_pass)
|
||||
out.c0.a = current_color.a;
|
||||
}
|
||||
if (PS_COLOR1)
|
||||
out.c1 = alpha_blend;
|
||||
|
||||
float depth_value = PS_ZFLOOR ? (floor(in.p.z * exp2(32.0f)) * exp2(-32.0f)) : in.p.z;
|
||||
|
||||
|
||||
if (PS_ZCLAMP)
|
||||
out.depth = min(depth_value, cb.max_depth);
|
||||
else if (PS_ZFLOOR)
|
||||
out.depth = depth_value;
|
||||
input_z = min(input_z, cb.max_depth);
|
||||
|
||||
if (!atst_pass)
|
||||
{
|
||||
if (PS_AFAIL == AFAIL::RGB_ONLY_SW_Z || PS_AFAIL == AFAIL::RGB_ONLY)
|
||||
out.c0.a = current_color.a;
|
||||
else if (PS_AFAIL == AFAIL::ZB_ONLY)
|
||||
out.c0 = current_color;
|
||||
|
||||
if (PS_AFAIL == AFAIL::RGB_ONLY_SW_Z || PS_AFAIL == AFAIL::FB_ONLY)
|
||||
input_z = current_depth;
|
||||
}
|
||||
|
||||
out.setDepth(input_z);
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -1364,9 +1406,14 @@ fragment float4 fbfetch_test(float4 in [[color(0), raster_order_group(0)]])
|
||||
|
||||
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 == DepthFeedbackSupport::DepthAsRT;
|
||||
#else
|
||||
constant bool NEEDS_RT_TEX = NEEDS_RT;
|
||||
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;
|
||||
|
||||
fragment MainPSOut ps_main(
|
||||
MainPSIn in [[stage_in]],
|
||||
@@ -1377,12 +1424,15 @@ fragment MainPSOut ps_main(
|
||||
#endif
|
||||
#if FBFETCH_SUPPORT
|
||||
float4 rt_fbf [[color(0), raster_order_group(0), function_constant(NEEDS_RT_FBF)]],
|
||||
float ds_fbf [[color(1), raster_order_group(1), function_constant(NEEDS_DS_FBF)]],
|
||||
#endif
|
||||
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> rt [[texture(GSMTLTextureIndexRenderTarget), function_constant(NEEDS_RT_TEX)]],
|
||||
texture2d<float> primidtex [[texture(GSMTLTextureIndexPrimIDs), function_constant(PS_PRIM_CHECKING_READ)]])
|
||||
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)]])
|
||||
{
|
||||
PSMain main(in, cb);
|
||||
main.tex_sampler = s;
|
||||
@@ -1399,12 +1449,31 @@ fragment MainPSOut ps_main(
|
||||
main.prim_id = primid;
|
||||
#endif
|
||||
|
||||
uint2 coord = uint2(in.p.xy);
|
||||
|
||||
if (SW_DEPTH)
|
||||
{
|
||||
switch (DEPTH_FEEDBACK)
|
||||
{
|
||||
case DepthFeedbackSupport::Depth:
|
||||
main.current_depth = ds_depth.read(coord);
|
||||
break;
|
||||
case DepthFeedbackSupport::DepthAsRT:
|
||||
main.current_depth = HAS_FBFETCH ? ds_fbf : ds_tex.read(coord).x;
|
||||
break;
|
||||
case DepthFeedbackSupport::None:
|
||||
// Should never happen
|
||||
main.current_depth = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NEEDS_RT)
|
||||
{
|
||||
#if FBFETCH_SUPPORT
|
||||
main.current_color = HAS_FBFETCH ? rt_fbf : rt.read(uint2(in.p.xy));
|
||||
main.current_color = HAS_FBFETCH ? rt_fbf : rt.read(coord);
|
||||
#else
|
||||
main.current_color = rt.read(uint2(in.p.xy));
|
||||
main.current_color = rt.read(coord);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user