@@ -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,25 @@ static GSVector4 GetRTLoadInfo(GSTextureMTL* tex, MTLLoadAction* load_action)
576578 beforeStages: MTLRenderStageVertex ];
577579}
578580
581+ void GSDeviceMTL::BeginROVCopy (GSTexture* color, GSTexture* depth)
582+ {
583+ pxAssert (!m_features.framebuffer_fetch );
584+ MTLRenderPassDescriptor * desc = m_render_pass_desc[1 | 8 ];
585+ MTLRenderPassColorAttachmentDescriptor * color0 = desc.colorAttachments [0 ];
586+ color0.loadAction = MTLLoadActionDontCare ;
587+ color0.texture = static_cast <GSTextureMTL*>(color)->GetTexture ();
588+ MTLRenderPassColorAttachmentDescriptor * color1 = desc.colorAttachments [1 ];
589+ color1.loadAction = MTLLoadActionDontCare ;
590+ color1.storeAction = MTLStoreActionStore ;
591+ color1.texture = static_cast <GSTextureMTL*>(depth)->GetTexture ();
592+ PrepareBeginRenderPass ();
593+ m_current_render.encoder = MRCRetain ([GetRenderCmdBuf () renderCommandEncoderWithDescriptor: desc]);
594+ [m_current_render.encoder setLabel: @" ROV Clear" ];
595+ if (!m_dev.features .unified_memory )
596+ [m_current_render.encoder waitForFence: m_draw_sync_fence
597+ beforeStages: MTLRenderStageVertex ];
598+ }
599+
579600void GSDeviceMTL::FrameCompleted ()
580601{
581602 if (m_spin_timer)
@@ -1125,11 +1146,11 @@ static bool ConvertShaderNotNeeded(ShaderConvert shader)
11251146 auto desc = MRCTransfer ([MTLRenderPassDescriptor new ]);
11261147 [[desc depthAttachment ] setStoreAction: MTLStoreActionStore ];
11271148 [[desc stencilAttachment ] setStoreAction: MTLStoreActionStore ];
1128- if (rt1)
1149+ if (rt1 && m_features. framebuffer_fetch )
11291150 {
11301151 MTLRenderPassColorAttachmentDescriptor * color1 = [[desc colorAttachments ] objectAtIndexedSubscript: 1 ];
11311152 [color1 setStoreAction: MTLStoreActionDontCare ];
1132- [color1 setLoadAction: m_features.framebuffer_fetch ? MTLLoadActionClear : MTLLoadActionLoad ];
1153+ [color1 setLoadAction: MTLLoadActionClear ];
11331154 }
11341155 m_render_pass_desc[i] = desc;
11351156 }
@@ -1304,8 +1325,22 @@ static bool ConvertShaderNotNeeded(ShaderConvert shader)
13041325 setFnConstantB (m_fn_constants, shader.DepthOutput (), GSMTLConstantIndex_DEPTH_OUT);
13051326 m_convert_pipeline[shader.Index ()] = MakePipeline (pdesc, vs_convert, LoadShader (shader_name), name);
13061327 }
1328+
13071329 pdesc.colorAttachments [0 ].writeMask = MTLColorWriteMaskAll ;
13081330 pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid ;
1331+ pdesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid ;
1332+
1333+ if (m_features.rov )
1334+ {
1335+ pdesc.colorAttachments [0 ].pixelFormat = MTLPixelFormatRGBA8Unorm ;
1336+ pdesc.colorAttachments [1 ].pixelFormat = MTLPixelFormatR32Float ;
1337+ m_rov_copy_both_pipeline = MakePipeline (pdesc, vs_convert, LoadShader (@" ps_rov_copy_both" ), @" ROV Copy Both" );
1338+ pdesc.colorAttachments [1 ].pixelFormat = MTLPixelFormatInvalid ;
1339+ m_rov_copy_one_pipeline[1 ] = MakePipeline (pdesc, vs_convert, LoadShader (@" ps_rov_copy_color" ), @" ROV Copy Color" );
1340+ pdesc.colorAttachments [0 ].pixelFormat = MTLPixelFormatR32Float ;
1341+ m_rov_copy_one_pipeline[0 ] = MakePipeline (pdesc, vs_convert, LoadShader (@" ps_rov_copy_depth" ), @" ROV Copy Depth" );
1342+ }
1343+
13091344 for (size_t i = 0 ; i < std::size (m_present_pipeline); i++)
13101345 {
13111346 PresentShader conv = static_cast <PresentShader>(i);
@@ -1845,6 +1880,101 @@ static bool ConvertShaderNotNeeded(ShaderConvert shader)
18451880 flush (num_rects);
18461881}}
18471882
1883+ void GSDeviceMTL::SetupOneshotROV (const GSHWDrawConfig& config, GSTextureMTL* rt, GSTextureMTL* ds, const std::vector<GSVector4i>& rects, const GSVector2i& size_i)
1884+ {
1885+ g_perfmon.Put (GSPerfMon::TextureCopies, 1 );
1886+ g_perfmon.Put (GSPerfMon::TextureCopiesROV, 1 );
1887+ g_perfmon.Put (GSPerfMon::DrawCallsROV, 1 );
1888+
1889+ bool rt_copy = config.ps .HasOneshotColorROV ();
1890+ bool ds_copy = config.ps .HasOneshotDepthROV ();
1891+
1892+ // Create ROV textures
1893+ if (rt_copy && (!m_rov_rt || m_rov_rt->GetSize () != size_i))
1894+ {
1895+ if (m_rov_rt)
1896+ Recycle (m_rov_rt.release ());
1897+ m_rov_rt.reset (static_cast <GSTextureMTL*>(CreateShaderWriteTarget (size_i, GSTexture::Format::Color, false )));
1898+ #if PCSX2_DEVBUILD
1899+ m_rov_rt->SetDebugName (fmt::format (" RT for oneshot ROV {}x{}" , size_i.x , size_i.y ));
1900+ #endif
1901+ }
1902+ if (ds_copy && (!m_rov_ds || m_rov_ds->GetSize () != size_i))
1903+ {
1904+ if (m_rov_ds)
1905+ Recycle (m_rov_ds.release ());
1906+ m_rov_ds.reset (static_cast <GSTextureMTL*>(CreateShaderWriteTarget (size_i, GSTexture::Format::DepthColor, false )));
1907+ #if PCSX2_DEVBUILD
1908+ m_rov_ds->SetDebugName (fmt::format (" DS for oneshot ROV {}x{}" , size_i.x , size_i.y ));
1909+ #endif
1910+ }
1911+
1912+ // Avoid copies if the original is cleared.
1913+ if (rt_copy && rt->GetState () == GSTexture::State::Cleared)
1914+ {
1915+ m_rov_rt->SetClearColor (rt->GetClearColor ());
1916+ m_rov_rt->FlushClears ();
1917+ rt_copy = false ;
1918+ }
1919+ if (ds_copy && ds->GetState () == GSTexture::State::Cleared)
1920+ {
1921+ m_rov_ds->SetClearDepth (ds->GetClearDepth ());
1922+ m_rov_ds->FlushClears ();
1923+ ds_copy = false ;
1924+ }
1925+
1926+ if (!(rt_copy || ds_copy))
1927+ return ; // Copy handled with clear.
1928+
1929+ // Vertices / IA
1930+ const u32 num_rects = static_cast <u32 >(rects.size ());
1931+ const Map allocation = Allocate (m_vertex_upload_buf, sizeof (ConvertShaderVertex) * 4 * num_rects);
1932+ std::array<GSVector4, 4 >* write = static_cast <std::array<GSVector4, 4 >*>(allocation.cpu_buffer );
1933+ const id <MTLRenderCommandEncoder > enc = m_current_render.encoder ;
1934+ [enc setVertexBuffer: allocation.gpu_buffer
1935+ offset: allocation.gpu_offset
1936+ atIndex: GSMTLBufferIndexVertices];
1937+
1938+ const GSVector2 size (static_cast <float >(size_i.x ), static_cast <float >(size_i.y ));
1939+ for (const GSVector4i& rect_i : rects)
1940+ {
1941+ GSVector4 rect (rect_i);
1942+ *write++ = CalcStrechRectPoints (rect, rect, size);
1943+ }
1944+
1945+ // Render pass
1946+ if (rt_copy && ds_copy)
1947+ {
1948+ BeginROVCopy (m_rov_rt.get (), m_rov_ds.get ());
1949+ MRESetTexture (rt, 0 );
1950+ MRESetTexture (ds, 1 );
1951+ MRESetPipeline (m_rov_copy_both_pipeline);
1952+ }
1953+ else
1954+ {
1955+ GSTextureMTL* src = rt_copy ? rt : ds;
1956+ GSTextureMTL* dst = rt_copy ? m_rov_rt.get () : m_rov_ds.get ();
1957+ BeginRenderPass (@" ROV Copy" , dst, MTLLoadActionDontCare , nullptr , MTLLoadActionDontCare , nullptr , MTLLoadActionDontCare , false );
1958+ MRESetTexture (src, GSMTLTextureIndexNonHW);
1959+ MRESetPipeline (m_rov_copy_one_pipeline[rt_copy]);
1960+ }
1961+
1962+ FlushDebugEntries (m_current_render.encoder );
1963+ MREClearScissor ();
1964+ MRESetDSS (DepthStencilSelector::NoDepth ());
1965+
1966+ [enc drawIndexedPrimitives: MTLPrimitiveTypeTriangle
1967+ indexCount: num_rects * 6
1968+ indexType: MTLIndexTypeUInt16
1969+ indexBuffer: m_expand_index_buffer
1970+ indexBufferOffset: 0
1971+ instanceCount: 1
1972+ baseVertex: 0
1973+ baseInstance: 0 ];
1974+
1975+ EndRenderPass ();
1976+ }
1977+
18481978void GSDeviceMTL::UpdateCLUTTexture (GSTexture* sTex , float sScale , u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize)
18491979{
18501980 GSMTLCLUTConvertPSUniform uniform = { sScale , {offsetX, offsetY}, dOffset };
@@ -2060,7 +2190,7 @@ static MTLBlendOperation ConvertBlendOp(GSDevice::BlendOp generic)
20602190 setFnConstantI (m_fn_constants, pssel.aa1 , GSMTLConstantIndex_PS_AA1);
20612191 setFnConstantB (m_fn_constants, pssel.abe , GSMTLConstantIndex_PS_ABE);
20622192 setFnConstantI (m_fn_constants, pssel.sw_aniso , GSMTLConstantIndex_PS_SW_ANISO);
2063- setFnConstantB (m_fn_constants, pssel.rov_color , GSMTLConstantIndex_PS_ROV_COLOR);
2193+ setFnConstantI (m_fn_constants, pssel.rov_color , GSMTLConstantIndex_PS_ROV_COLOR);
20642194 setFnConstantI (m_fn_constants, pssel.rov_depth , GSMTLConstantIndex_PS_ROV_DEPTH);
20652195 bool eft = pssel.HasColorROV () && !pssel.HasDepthROV () && !pssel.HasDepthOutput ();
20662196 auto newps = LoadShader (eft ? @" ps_main_rov_eft" : @" ps_main" );
@@ -2347,6 +2477,14 @@ static bool usesStencil(GSHWDrawConfig::DestinationAlphaMode dstalpha)
23472477
23482478void GSDeviceMTL::RenderHW (GSHWDrawConfig& config)
23492479{ @autoreleasepool {
2480+ if (config.ps .HasOneshotROV ())
2481+ {
2482+ // Do this first since it requires a different vertex upload from the main draw.
2483+ const GSVector2i rtsize = (config.rt ? config.rt : config.ds )->GetSize ();
2484+ SetupOneshotROV (config, static_cast <GSTextureMTL*>(config.rt ), static_cast <GSTextureMTL*>(config.ds ),
2485+ *config.draw_coarse_rasterize , rtsize);
2486+ }
2487+
23502488 if (config.tex && (config.ds == config.tex || config.rt == config.tex ))
23512489 EndRenderPass (); // Barrier
23522490
0 commit comments