@@ -492,9 +492,9 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format)
492492
493493 MTLTextureDescriptor * desc = [MTLTextureDescriptor
494494 texture2DDescriptorWithPixelFormat: fmt
495- width:std: :max (1 , std::min (width, m_dev.features.max_texsize))
496- height:std: :max (1 , std::min (height, m_dev.features.max_texsize))
497- mipmapped: levels > 1 ];
495+ width:std: :max (1 , std::min (width, m_dev.features.max_texsize))
496+ height:std: :max (1 , std::min (height, m_dev.features.max_texsize))
497+ mipmapped: levels > 1 ];
498498
499499 if (levels > 1 )
500500 [desc setMipmapLevelCount: levels];
@@ -541,7 +541,7 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format)
541541 }
542542}}
543543
544- void GSDeviceMTL::DoMerge (GSTexture* sTex [3 ], GSVector4* sRect , GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c)
544+ void GSDeviceMTL::DoMerge (GSTexture* sTex [3 ], GSVector4* sRect , GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear )
545545{ @autoreleasepool {
546546 id <MTLCommandBuffer > cmdbuf = GetRenderCmdBuf ();
547547 GSScopedDebugGroupMTL dbg (cmdbuf, @" DoMerge" );
@@ -562,12 +562,12 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format)
562562 {
563563 // 2nd output is enabled and selected. Copy it to destination so we can blend it with 1st output
564564 // Note: value outside of dRect must contains the background color (c)
565- StretchRect (sTex [1 ], sRect [1 ], dTex, dRect[1 ], ShaderConvert::COPY);
565+ StretchRect (sTex [1 ], sRect [1 ], dTex, dRect[1 ], ShaderConvert::COPY, linear );
566566 }
567567
568568 // Save 2nd output
569569 if (feedback_write_2) // FIXME I'm not sure dRect[1] is always correct
570- DoStretchRect (dTex, full_r, sTex [2 ], dRect[1 ], m_convert_pipeline[static_cast<int >(ShaderConvert::YUV)], true , LoadAction::DontCareIfFull, &cb_yuv, sizeof (cb_yuv));
570+ DoStretchRect (dTex, full_r, sTex [2 ], dRect[1 ], m_convert_pipeline[static_cast<int >(ShaderConvert::YUV)], linear , LoadAction::DontCareIfFull, &cb_yuv, sizeof (cb_yuv));
571571
572572 if (feedback_write_2_but_blend_bg)
573573 ClearRenderTarget (dTex, c);
@@ -581,34 +581,26 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format)
581581 if (PMODE.MMOD == 1 )
582582 {
583583 // Blend with a constant alpha
584- DoStretchRect (sTex [0 ], sRect [0 ], dTex, dRect[0 ], pipeline, true , LoadAction::Load, &cb_c, sizeof (cb_c));
584+ DoStretchRect (sTex [0 ], sRect [0 ], dTex, dRect[0 ], pipeline, linear , LoadAction::Load, &cb_c, sizeof (cb_c));
585585 }
586586 else
587587 {
588588 // Blend with 2 * input alpha
589- DoStretchRect (sTex [0 ], sRect [0 ], dTex, dRect[0 ], pipeline, true , LoadAction::Load, nullptr , 0 );
589+ DoStretchRect (sTex [0 ], sRect [0 ], dTex, dRect[0 ], pipeline, linear , LoadAction::Load, nullptr , 0 );
590590 }
591591 }
592592
593593 if (feedback_write_1) // FIXME I'm not sure dRect[0] is always correct
594- StretchRect (dTex, full_r, sTex [2 ], dRect[0 ], ShaderConvert::YUV);
594+ StretchRect (dTex, full_r, sTex [2 ], dRect[0 ], ShaderConvert::YUV, linear );
595595}}
596596
597- void GSDeviceMTL::DoInterlace (GSTexture* sTex , GSTexture* dTex, int shader, bool linear, float yoffset, int bufIdx )
597+ void GSDeviceMTL::DoInterlace (GSTexture* sTex , const GSVector4& sRect , GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb )
598598{ @autoreleasepool {
599599 id <MTLCommandBuffer > cmdbuf = GetRenderCmdBuf ();
600600 GSScopedDebugGroupMTL dbg (cmdbuf, @" DoInterlace" );
601601
602- GSVector4 ds = GSVector4 (dTex->GetSize ());
603-
604- GSVector4 sRect (0 , 0 , 1 , 1 );
605- GSVector4 dRect (0 .f , yoffset, ds.x , ds.y + yoffset);
606-
607- GSMTLInterlacePSUniform cb = {};
608- cb.ZrH = {static_cast <float >(bufIdx), 1 .0f / ds.y , ds.y , MAD_SENSITIVITY};
609-
610- const bool can_discard = shader == 0 || shader == 3 ;
611- DoStretchRect (sTex , sRect , dTex, dRect, m_interlace_pipeline[shader], linear, !can_discard ? LoadAction::DontCareIfFull : LoadAction::Load, &cb, sizeof (cb));
602+ const bool can_discard = shader == ShaderInterlace::WEAVE || shader == ShaderInterlace::MAD_BUFFER;
603+ DoStretchRect (sTex , sRect , dTex, dRect, m_interlace_pipeline[static_cast<int >(shader)], linear, !can_discard ? LoadAction::DontCareIfFull : LoadAction::Load, &cb, sizeof (cb));
612604}}
613605
614606void GSDeviceMTL::DoFXAA (GSTexture* sTex , GSTexture* dTex)
@@ -740,15 +732,14 @@ static void setFnConstantI(MTLFunctionConstantValues* fc, unsigned int value, GS
740732 m_features.bptc_textures = true ;
741733 m_features.framebuffer_fetch = m_dev.features .framebuffer_fetch ;
742734 m_features.dual_source_blend = true ;
735+ m_features.clip_control = true ;
743736 m_features.stencil_buffer = true ;
744737 m_features.cas_sharpening = true ;
745738
746739 try
747740 {
748741 // Init metal stuff
749742 m_fn_constants = MRCTransfer ([MTLFunctionConstantValues new ]);
750- vector_float2 upscale2 = vector2 (GSConfig.UpscaleMultiplier , GSConfig.UpscaleMultiplier );
751- [m_fn_constants setConstantValue: &upscale2 type: MTLDataTypeFloat2 atIndex: GSMTLConstantIndex_SCALING_FACTOR];
752743 setFnConstantB (m_fn_constants, m_dev.features .framebuffer_fetch , GSMTLConstantIndex_FRAMEBUFFER_FETCH);
753744
754745 m_draw_sync_fence = MRCTransfer ([m_dev.dev newFence ]);
@@ -1117,7 +1108,7 @@ static void setFnConstantI(MTLFunctionConstantValues* fc, unsigned int value, GS
11171108 [encoder endEncoding ];
11181109}}
11191110
1120- void GSDeviceMTL::DoStretchRect (GSTexture* sTex , const GSVector4& sRect , GSTexture* dTex, const GSVector4& dRect, id <MTLRenderPipelineState > pipeline, bool linear, LoadAction load_action, void * frag_uniform, size_t frag_uniform_len)
1111+ void GSDeviceMTL::DoStretchRect (GSTexture* sTex , const GSVector4& sRect , GSTexture* dTex, const GSVector4& dRect, id <MTLRenderPipelineState > pipeline, bool linear, LoadAction load_action, const void * frag_uniform, size_t frag_uniform_len)
11211112{
11221113 FlushClears (sTex );
11231114
@@ -1253,9 +1244,9 @@ static void setFnConstantI(MTLFunctionConstantValues* fc, unsigned int value, GS
12531244 }
12541245}}
12551246
1256- void GSDeviceMTL::UpdateCLUTTexture (GSTexture* sTex , u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize)
1247+ void GSDeviceMTL::UpdateCLUTTexture (GSTexture* sTex , float sScale , u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize)
12571248{
1258- GSMTLCLUTConvertPSUniform uniform = { ToSimd ( sTex -> GetScale ()) , {offsetX, offsetY}, dOffset };
1249+ GSMTLCLUTConvertPSUniform uniform = { sScale , {offsetX, offsetY}, dOffset };
12591250
12601251 const bool is_clut4 = dSize == 16 ;
12611252 const GSVector4i dRect (0 , 0 , dSize, 1 );
@@ -1265,6 +1256,19 @@ static void setFnConstantI(MTLFunctionConstantValues* fc, unsigned int value, GS
12651256 RenderCopy (sTex , m_clut_pipeline[!is_clut4], dRect);
12661257}
12671258
1259+ void GSDeviceMTL::ConvertToIndexedTexture (GSTexture* sTex , float sScale , u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM)
1260+ { @autoreleasepool {
1261+ const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
1262+ id <MTLRenderPipelineState > pipeline = m_convert_pipeline[static_cast<int >(shader)];
1263+ if (!pipeline)
1264+ [NSException raise: @" StretchRect Missing Pipeline" format: @" No pipeline for %d " , static_cast <int >(shader)];
1265+
1266+ GSMTLIndexedConvertPSUniform uniform = { sScale , SBW, DBW };
1267+
1268+ const GSVector4 dRect (0 , 0 , dTex->GetWidth (), dTex->GetHeight ());
1269+ DoStretchRect (sTex , GSVector4::zero (), dTex, dRect, pipeline, false , LoadAction::DontCareIfFull, &uniform, sizeof (uniform));
1270+ }}
1271+
12681272void GSDeviceMTL::FlushClears (GSTexture* tex)
12691273{
12701274 if (tex)
@@ -1371,16 +1375,19 @@ static GSMTLExpandType ConvertVSExpand(GSHWDrawConfig::VSExpand generic)
13711375 setFnConstantB (m_fn_constants, pssel.ltf , GSMTLConstantIndex_PS_LTF);
13721376 setFnConstantB (m_fn_constants, pssel.shuffle , GSMTLConstantIndex_PS_SHUFFLE);
13731377 setFnConstantB (m_fn_constants, pssel.read_ba , GSMTLConstantIndex_PS_READ_BA);
1378+ setFnConstantB (m_fn_constants, pssel.real16src , GSMTLConstantIndex_PS_READ16_SRC);
13741379 setFnConstantB (m_fn_constants, pssel.write_rg , GSMTLConstantIndex_PS_WRITE_RG);
13751380 setFnConstantB (m_fn_constants, pssel.fbmask , GSMTLConstantIndex_PS_FBMASK);
13761381 setFnConstantI (m_fn_constants, pssel.blend_a , GSMTLConstantIndex_PS_BLEND_A);
13771382 setFnConstantI (m_fn_constants, pssel.blend_b , GSMTLConstantIndex_PS_BLEND_B);
13781383 setFnConstantI (m_fn_constants, pssel.blend_c , GSMTLConstantIndex_PS_BLEND_C);
13791384 setFnConstantI (m_fn_constants, pssel.blend_d , GSMTLConstantIndex_PS_BLEND_D);
1380- setFnConstantI (m_fn_constants, pssel.clr_hw , GSMTLConstantIndex_PS_CLR_HW);
1385+ setFnConstantI (m_fn_constants, pssel.blend_hw , GSMTLConstantIndex_PS_BLEND_HW);
1386+ setFnConstantB (m_fn_constants, pssel.a_masked , GSMTLConstantIndex_PS_A_MASKED);
13811387 setFnConstantB (m_fn_constants, pssel.hdr , GSMTLConstantIndex_PS_HDR);
13821388 setFnConstantB (m_fn_constants, pssel.colclip , GSMTLConstantIndex_PS_COLCLIP);
13831389 setFnConstantI (m_fn_constants, pssel.blend_mix , GSMTLConstantIndex_PS_BLEND_MIX);
1390+ setFnConstantB (m_fn_constants, pssel.round_inv , GSMTLConstantIndex_PS_ROUND_INV);
13841391 setFnConstantB (m_fn_constants, pssel.fixed_one_a , GSMTLConstantIndex_PS_FIXED_ONE_A);
13851392 setFnConstantB (m_fn_constants, pssel.pabe , GSMTLConstantIndex_PS_PABE);
13861393 setFnConstantB (m_fn_constants, pssel.no_color , GSMTLConstantIndex_PS_NO_COLOR);
@@ -1595,6 +1602,7 @@ static void textureBarrier(id<MTLRenderCommandEncoder> enc)
15951602static_assert (offsetof(GSHWDrawConfig::PSConstantBuffer, TCOffsetHack) == offsetof(GSMTLMainPSUniform, tc_offset));
15961603static_assert (offsetof(GSHWDrawConfig::PSConstantBuffer, STScale) == offsetof(GSMTLMainPSUniform, st_scale));
15971604static_assert (offsetof(GSHWDrawConfig::PSConstantBuffer, DitherMatrix) == offsetof(GSMTLMainPSUniform, dither_matrix));
1605+ static_assert (offsetof(GSHWDrawConfig::PSConstantBuffer, ScaleFactor) == offsetof(GSMTLMainPSUniform, scale_factor));
15981606
15991607void GSDeviceMTL::SetupDestinationAlpha (GSTexture* rt, GSTexture* ds, const GSVector4i& r, bool datm)
16001608{
@@ -1699,6 +1707,15 @@ static void textureBarrier(id<MTLRenderCommandEncoder> enc)
16991707 config.ds = nullptr ;
17001708 if (!config.ds && m_current_render.color_target == rt && stencil == m_current_render.stencil_target && m_current_render.depth_target != config.tex )
17011709 config.ds = m_current_render.depth_target ;
1710+ if (!rt && !config.ds )
1711+ {
1712+ // If we were rendering depth-only and depth gets cleared by the above check, that turns into rendering nothing, which should be a no-op
1713+ pxAssertDev (0 , " RenderHW was given a completely useless draw call!" );
1714+ [m_current_render.encoder insertDebugSignpost: @" Skipped no-color no-depth draw" ];
1715+ if (primid_tex)
1716+ Recycle (primid_tex);
1717+ return ;
1718+ }
17021719
17031720 BeginRenderPass (@" RenderHW" , rt, MTLLoadActionLoad , config.ds , MTLLoadActionLoad , stencil, MTLLoadActionLoad );
17041721 id <MTLRenderCommandEncoder > mtlenc = m_current_render.encoder ;
0 commit comments