@@ -505,6 +505,8 @@ static GSVector4 GetRTLoadInfo(GSTextureMTL* tex, MTLLoadAction* load_action)
505505 color1.texture = GetRT1DepthTexture (md);
506506 if (m_features.framebuffer_fetch )
507507 color1.clearColor = MTLClearColorMake (depth_load == MTLLoadActionClear ? depth_clear.x : -1 , 0 , 0 , 0 );
508+ else
509+ color1.loadAction = MTLLoadActionLoad ;
508510 }
509511
510512 PrepareBeginRenderPass ();
@@ -576,6 +578,27 @@ static GSVector4 GetRTLoadInfo(GSTextureMTL* tex, MTLLoadAction* load_action)
576578 beforeStages: MTLRenderStageVertex ];
577579}
578580
581+ void GSDeviceMTL::BeginROVCopy (GSTextureMTL* color, GSTextureMTL* depth)
582+ {
583+ pxAssert (!m_features.framebuffer_fetch );
584+ color->SetState (GSTexture::State::Dirty);
585+ depth->SetState (GSTexture::State::Dirty);
586+ MTLRenderPassDescriptor * desc = m_render_pass_desc[1 | 8 ];
587+ MTLRenderPassColorAttachmentDescriptor * color0 = desc.colorAttachments [0 ];
588+ color0.loadAction = MTLLoadActionDontCare ;
589+ color0.texture = color->GetTexture ();
590+ MTLRenderPassColorAttachmentDescriptor * color1 = desc.colorAttachments [1 ];
591+ color1.loadAction = MTLLoadActionDontCare ;
592+ color1.storeAction = MTLStoreActionStore ;
593+ color1.texture = depth->GetTexture ();
594+ PrepareBeginRenderPass ();
595+ m_current_render.encoder = MRCRetain ([GetRenderCmdBuf () renderCommandEncoderWithDescriptor: desc]);
596+ [m_current_render.encoder setLabel: @" ROV Clear" ];
597+ if (!m_dev.features .unified_memory )
598+ [m_current_render.encoder waitForFence: m_draw_sync_fence
599+ beforeStages: MTLRenderStageVertex ];
600+ }
601+
579602void GSDeviceMTL::FrameCompleted ()
580603{
581604 if (m_spin_timer)
@@ -1125,11 +1148,11 @@ static bool ConvertShaderNotNeeded(ShaderConvert shader)
11251148 auto desc = MRCTransfer ([MTLRenderPassDescriptor new ]);
11261149 [[desc depthAttachment ] setStoreAction: MTLStoreActionStore ];
11271150 [[desc stencilAttachment ] setStoreAction: MTLStoreActionStore ];
1128- if (rt1)
1151+ if (rt1 && m_features. framebuffer_fetch )
11291152 {
11301153 MTLRenderPassColorAttachmentDescriptor * color1 = [[desc colorAttachments ] objectAtIndexedSubscript: 1 ];
11311154 [color1 setStoreAction: MTLStoreActionDontCare ];
1132- [color1 setLoadAction: m_features.framebuffer_fetch ? MTLLoadActionClear : MTLLoadActionLoad ];
1155+ [color1 setLoadAction: MTLLoadActionClear ];
11331156 }
11341157 m_render_pass_desc[i] = desc;
11351158 }
@@ -1304,8 +1327,22 @@ static bool ConvertShaderNotNeeded(ShaderConvert shader)
13041327 setFnConstantB (m_fn_constants, shader.DepthOutput (), GSMTLConstantIndex_DEPTH_OUT);
13051328 m_convert_pipeline[shader.Index ()] = MakePipeline (pdesc, vs_convert, LoadShader (shader_name), name);
13061329 }
1330+
13071331 pdesc.colorAttachments [0 ].writeMask = MTLColorWriteMaskAll ;
13081332 pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid ;
1333+ pdesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid ;
1334+
1335+ if (m_features.rov )
1336+ {
1337+ pdesc.colorAttachments [0 ].pixelFormat = MTLPixelFormatRGBA8Unorm ;
1338+ pdesc.colorAttachments [1 ].pixelFormat = MTLPixelFormatR32Float ;
1339+ m_rov_copy_both_pipeline = MakePipeline (pdesc, vs_convert, LoadShader (@" ps_rov_copy_both" ), @" ROV Copy Both" );
1340+ pdesc.colorAttachments [1 ].pixelFormat = MTLPixelFormatInvalid ;
1341+ m_rov_copy_one_pipeline[1 ] = MakePipeline (pdesc, vs_convert, LoadShader (@" ps_rov_copy_color" ), @" ROV Copy Color" );
1342+ pdesc.colorAttachments [0 ].pixelFormat = MTLPixelFormatR32Float ;
1343+ m_rov_copy_one_pipeline[0 ] = MakePipeline (pdesc, vs_convert, LoadShader (@" ps_rov_copy_depth" ), @" ROV Copy Depth" );
1344+ }
1345+
13091346 for (size_t i = 0 ; i < std::size (m_present_pipeline); i++)
13101347 {
13111348 PresentShader conv = static_cast <PresentShader>(i);
@@ -1845,6 +1882,102 @@ static bool ConvertShaderNotNeeded(ShaderConvert shader)
18451882 flush (num_rects);
18461883}}
18471884
1885+ void GSDeviceMTL::SetupOneshotROV (const GSHWDrawConfig& config, GSTextureMTL* rt, GSTextureMTL* ds, const std::vector<GSVector4i>& rects, const GSVector2i& size_i)
1886+ {
1887+ g_perfmon.Put (GSPerfMon::TextureCopies, 1 );
1888+ g_perfmon.Put (GSPerfMon::TextureCopiesROV, 1 );
1889+ g_perfmon.Put (GSPerfMon::DrawCallsROV, 1 );
1890+
1891+ bool rt_copy = config.ps .HasOneshotColorROV ();
1892+ bool ds_copy = config.ps .HasOneshotDepthROV ();
1893+
1894+ // Create ROV textures
1895+ if (rt_copy && (!m_rov_rt || m_rov_rt->GetSize () != size_i))
1896+ {
1897+ if (m_rov_rt)
1898+ Recycle (m_rov_rt.release ());
1899+ m_rov_rt.reset (static_cast <GSTextureMTL*>(CreateShaderWriteTarget (size_i, GSTexture::Format::Color, false )));
1900+ #if PCSX2_DEVBUILD
1901+ m_rov_rt->SetDebugName (fmt::format (" RT for oneshot ROV {}x{}" , size_i.x , size_i.y ));
1902+ #endif
1903+ }
1904+ if (ds_copy && (!m_rov_ds || m_rov_ds->GetSize () != size_i))
1905+ {
1906+ if (m_rov_ds)
1907+ Recycle (m_rov_ds.release ());
1908+ m_rov_ds.reset (static_cast <GSTextureMTL*>(CreateShaderWriteTarget (size_i, GSTexture::Format::DepthColor, false )));
1909+ #if PCSX2_DEVBUILD
1910+ m_rov_ds->SetDebugName (fmt::format (" DS for oneshot ROV {}x{}" , size_i.x , size_i.y ));
1911+ #endif
1912+ }
1913+
1914+ // Avoid copies if the original is cleared.
1915+ if (rt_copy && rt->GetState () == GSTexture::State::Cleared)
1916+ {
1917+ m_rov_rt->SetClearColor (rt->GetClearColor ());
1918+ m_rov_rt->FlushClears ();
1919+ rt_copy = false ;
1920+ }
1921+ if (ds_copy && ds->GetState () == GSTexture::State::Cleared)
1922+ {
1923+ m_rov_ds->SetClearDepth (ds->GetClearDepth ());
1924+ m_rov_ds->FlushClears ();
1925+ ds_copy = false ;
1926+ }
1927+
1928+ if (!(rt_copy || ds_copy))
1929+ return ; // Copy handled with clear.
1930+
1931+ // Vertices / IA
1932+ const u32 num_rects = static_cast <u32 >(rects.size ());
1933+ const Map allocation = Allocate (m_vertex_upload_buf, sizeof (ConvertShaderVertex) * 4 * num_rects);
1934+ std::array<GSVector4, 4 >* write = static_cast <std::array<GSVector4, 4 >*>(allocation.cpu_buffer );
1935+
1936+ const GSVector2 size (static_cast <float >(size_i.x ), static_cast <float >(size_i.y ));
1937+ for (const GSVector4i& rect_i : rects)
1938+ {
1939+ GSVector4 rect (rect_i);
1940+ *write++ = CalcStrechRectPoints (rect, rect, size);
1941+ }
1942+
1943+ // Render pass
1944+ if (rt_copy && ds_copy)
1945+ {
1946+ BeginROVCopy (m_rov_rt.get (), m_rov_ds.get ());
1947+ MRESetTexture (rt, 0 );
1948+ MRESetTexture (ds, 1 );
1949+ MRESetPipeline (m_rov_copy_both_pipeline);
1950+ }
1951+ else
1952+ {
1953+ GSTextureMTL* src = rt_copy ? rt : ds;
1954+ GSTextureMTL* dst = rt_copy ? m_rov_rt.get () : m_rov_ds.get ();
1955+ BeginRenderPass (@" ROV Copy" , dst, MTLLoadActionDontCare , nullptr , MTLLoadActionDontCare , nullptr , MTLLoadActionDontCare , false );
1956+ MRESetTexture (src, GSMTLTextureIndexNonHW);
1957+ MRESetPipeline (m_rov_copy_one_pipeline[rt_copy]);
1958+ }
1959+
1960+ FlushDebugEntries (m_current_render.encoder );
1961+ MREClearScissor ();
1962+ MRESetDSS (DepthStencilSelector::NoDepth ());
1963+
1964+ const id <MTLRenderCommandEncoder > enc = m_current_render.encoder ;
1965+ [enc setVertexBuffer: allocation.gpu_buffer
1966+ offset: allocation.gpu_offset
1967+ atIndex: GSMTLBufferIndexVertices];
1968+
1969+ [enc drawIndexedPrimitives: MTLPrimitiveTypeTriangle
1970+ indexCount: num_rects * 6
1971+ indexType: MTLIndexTypeUInt16
1972+ indexBuffer: m_expand_index_buffer
1973+ indexBufferOffset: 0
1974+ instanceCount: 1
1975+ baseVertex: 0
1976+ baseInstance: 0 ];
1977+
1978+ EndRenderPass ();
1979+ }
1980+
18481981void GSDeviceMTL::UpdateCLUTTexture (GSTexture* sTex , float sScale , u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize)
18491982{
18501983 GSMTLCLUTConvertPSUniform uniform = { sScale , {offsetX, offsetY}, dOffset };
@@ -2060,7 +2193,7 @@ static MTLBlendOperation ConvertBlendOp(GSDevice::BlendOp generic)
20602193 setFnConstantI (m_fn_constants, pssel.aa1 , GSMTLConstantIndex_PS_AA1);
20612194 setFnConstantB (m_fn_constants, pssel.abe , GSMTLConstantIndex_PS_ABE);
20622195 setFnConstantI (m_fn_constants, pssel.sw_aniso , GSMTLConstantIndex_PS_SW_ANISO);
2063- setFnConstantB (m_fn_constants, pssel.rov_color , GSMTLConstantIndex_PS_ROV_COLOR);
2196+ setFnConstantI (m_fn_constants, pssel.rov_color , GSMTLConstantIndex_PS_ROV_COLOR);
20642197 setFnConstantI (m_fn_constants, pssel.rov_depth , GSMTLConstantIndex_PS_ROV_DEPTH);
20652198 bool eft = pssel.HasColorROV () && !pssel.HasDepthROV () && !pssel.HasDepthOutput ();
20662199 auto newps = LoadShader (eft ? @" ps_main_rov_eft" : @" ps_main" );
@@ -2347,6 +2480,13 @@ static bool usesStencil(GSHWDrawConfig::DestinationAlphaMode dstalpha)
23472480
23482481void GSDeviceMTL::RenderHW (GSHWDrawConfig& config)
23492482{ @autoreleasepool {
2483+ if (config.ps .HasOneshotROV ())
2484+ {
2485+ // Do this first since it requires a different vertex upload from the main draw.
2486+ const GSVector2i rtsize = (config.rt ? config.rt : config.ds )->GetSize ();
2487+ SetupOneshotROV (config, static_cast <GSTextureMTL*>(config.rt ), static_cast <GSTextureMTL*>(config.ds ), *config.draw_coarse_rasterize , rtsize);
2488+ }
2489+
23502490 if (config.tex && (config.ds == config.tex || config.rt == config.tex ))
23512491 EndRenderPass (); // Barrier
23522492
@@ -2481,7 +2621,7 @@ static bool usesStencil(GSHWDrawConfig::DestinationAlphaMode dstalpha)
24812621 }
24822622
24832623 // Try to reduce render pass restarts
2484- 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 )
2624+ if (!config.HasContinuousColorROV () && !config.ds && m_current_render.color_target == rt && stencil == m_current_render.stencil_target && m_current_render.depth_target != config.tex )
24852625 config.ds = m_current_render.depth_target ;
24862626 if (!rt && config.ds == m_current_render.depth_target && m_current_render.color_target != config.tex )
24872627 rt = m_current_render.color_target ;
@@ -2496,12 +2636,12 @@ static bool usesStencil(GSHWDrawConfig::DestinationAlphaMode dstalpha)
24962636 }
24972637
24982638 const bool feedback_depth = config.ps .IsFeedbackLoopDepth ();
2499- const bool rt1 = feedback_depth && !m_features.depth_feedback && !config.ps . HasDepthROV ();
2639+ const bool rt1 = feedback_depth && !m_features.depth_feedback && !config.HasContinuousDepthROV ();
25002640 GSTexture* rt_bind = rt;
25012641 GSTexture* ds_bind = config.ds ;
25022642 GSTexture* rt_size = rt_bind ? rt_bind : ds_bind;
2503- if (config.ps . HasColorROV () && rt_bind) PrepareROVTexture (&rt_bind);
2504- if (config.ps . HasDepthROV () && ds_bind) PrepareROVTexture (&ds_bind);
2643+ if (config.HasContinuousColorROV () && rt_bind) PrepareROVTexture (&rt_bind);
2644+ if (config.HasContinuousDepthROV () && ds_bind) PrepareROVTexture (&ds_bind);
25052645 if (!rt_bind && !ds_bind && !stencil)
25062646 BeginFullROV (@" RenderHWROV" , rt_size->GetWidth (), rt_size->GetHeight ());
25072647 else
@@ -2511,13 +2651,13 @@ static bool usesStencil(GSHWDrawConfig::DestinationAlphaMode dstalpha)
25112651 if (usesStencil (config.destination_alpha ))
25122652 [mtlenc setStencilReferenceValue: 1 ];
25132653 MREInitHWDraw (config, allocation);
2514- if (config.ps . HasColorROV () && m_dev.features .rov_requires_r32 )
2654+ if (config.HasContinuousColorROV () && m_dev.features .rov_requires_r32 )
25152655 MRESetTexture (reinterpret_cast <GSTextureMTL*>(rt)->GetROVTexture (), GSMTLTextureIndexRenderTarget);
2516- else if (config.require_one_barrier || config.require_full_barrier || config.ps . HasColorROV ())
2517- MRESetTexture (rt, GSMTLTextureIndexRenderTarget);
2518- if (config.ps . HasDepthROV ())
2656+ else if (config.require_one_barrier || config.require_full_barrier || config.HasColorROV ())
2657+ MRESetTexture (config. HasOneshotColorROV () ? m_rov_rt. get () : rt, GSMTLTextureIndexRenderTarget);
2658+ if (config.HasDepthROV ())
25192659 {
2520- MRESetTexture (config.ds , GSMTLTextureIndexDepthTarget);
2660+ MRESetTexture (config.HasOneshotDepthROV () ? m_rov_ds. get () : config. ds , GSMTLTextureIndexDepthTarget);
25212661 }
25222662 else if (feedback_depth)
25232663 {
0 commit comments