From 0f6e1752e3debd48ac7c903c20973ef70497e850 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Mon, 25 Sep 2023 18:23:26 +0200 Subject: [PATCH] rend: clear framebuffer when vram address changes Fixes top and bottom leftovers from BIOS boot in San Francisco Rush 2049. Issue #1197 --- core/hw/pvr/Renderer_if.cpp | 16 ++++++++++++++++ core/hw/pvr/ta_ctx.h | 18 ++++++++---------- core/hw/pvr/ta_vtx.cpp | 8 ++------ core/rend/dx11/dx11_renderer.cpp | 7 +++++++ core/rend/dx11/oit/dx11_oitrenderer.cpp | 10 +++++++++- core/rend/dx9/d3d_renderer.cpp | 2 ++ core/rend/gl4/gldraw.cpp | 9 +++++++++ core/rend/gles/gldraw.cpp | 2 +- core/rend/gles/gles.cpp | 10 ++++++---- core/rend/gles/postprocess.cpp | 2 +- core/rend/vulkan/drawer.cpp | 2 +- core/rend/vulkan/oit/oit_drawer.cpp | 2 +- core/rend/vulkan/oit/oit_pipeline.h | 2 +- core/rend/vulkan/oit/oit_renderpass.cpp | 4 ++-- core/rend/vulkan/oit/oit_renderpass.h | 16 ++++++++-------- 15 files changed, 74 insertions(+), 36 deletions(-) diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index 5686eb27f..1be24b6a3 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -38,6 +38,7 @@ static bool rendererEnabled = true; TA_context* _pvrrc; static bool presented; +static u32 fbAddrHistory[2] { 1, 1 }; class PvrMessageQueue { @@ -343,6 +344,8 @@ void rend_reset() fb_w_cur = 1; pvrQueue.reset(); rendererEnabled = true; + fbAddrHistory[0] = 1; + fbAddrHistory[1] = 1; } void rend_start_render() @@ -395,7 +398,18 @@ void rend_start_render() ctx->rend.fog_clamp_max = FOG_CLAMP_MAX; if (!ctx->rend.isRTT) + { + if (FB_W_SOF1 != fbAddrHistory[0] && FB_W_SOF1 != fbAddrHistory[1]) + { + ctx->rend.clearFramebuffer = true; + fbAddrHistory[0] = fbAddrHistory[1]; + fbAddrHistory[1] = FB_W_SOF1; + } + else { + ctx->rend.clearFramebuffer = false; + } ggpo::endOfFrame(); + } if (QueueRender(ctx)) { @@ -530,4 +544,6 @@ void rend_deserialize(Deserializer& deser) deser >> fb_watch_addr_end; } pend_rend = false; + fbAddrHistory[0] = 1; + fbAddrHistory[1] = 1; } diff --git a/core/hw/pvr/ta_ctx.h b/core/hw/pvr/ta_ctx.h index a55f12208..4eb70788a 100644 --- a/core/hw/pvr/ta_ctx.h +++ b/core/hw/pvr/ta_ctx.h @@ -227,13 +227,10 @@ struct SortedTriangle struct rend_context { - u8* proc_start; - u8* proc_end; - - f32 fZ_min; f32 fZ_max; bool isRTT; + bool clearFramebuffer; TA_GLOB_TILE_CLIP_type ta_GLOB_TILE_CLIP; SCALER_CTL_type scaler_ctl; @@ -280,10 +277,10 @@ struct rend_context global_param_op.back().init(); verts.resize(4); - fZ_min = 1000000.0f; fZ_max = 1.0f; matrices.clear(); lightModels.clear(); + clearFramebuffer = false; } void newRenderPass(); @@ -329,10 +326,12 @@ struct TA_context sa2: idx: 36094, vtx: 24520, op: 1330, pt: 10, tr: 177, mvo: 39, modt: 360, ov: 0 */ - void MarkRend() - { - rend.proc_start = tad.thd_root; - rend.proc_end = tad.End(); + u8 *getTADataBegin() { + return tad.thd_root; + } + + u8 *getTADataEnd() { + return tad.End(); } void Alloc() @@ -362,7 +361,6 @@ struct TA_context tad.Clear(); nextContext = nullptr; rend.Clear(); - rend.proc_end = rend.proc_start = tad.thd_root; } ~TA_context() diff --git a/core/hw/pvr/ta_vtx.cpp b/core/hw/pvr/ta_vtx.cpp index d24653976..2fb3328e5 100644 --- a/core/hw/pvr/ta_vtx.cpp +++ b/core/hw/pvr/ta_vtx.cpp @@ -1210,12 +1210,8 @@ static void ta_parse_vdrc(TA_context* ctx, bool primRestart) while (childCtx != nullptr) { - childCtx->MarkRend(); - vd_rc.proc_start = childCtx->rend.proc_start; - vd_rc.proc_end = childCtx->rend.proc_end; - - Ta_Dma* ta_data = (Ta_Dma *)vd_rc.proc_start; - Ta_Dma* ta_data_end = (Ta_Dma *)vd_rc.proc_end; + Ta_Dma* ta_data = (Ta_Dma *)childCtx->getTADataBegin(); + Ta_Dma* ta_data_end = (Ta_Dma *)childCtx->getTADataEnd(); while (ta_data < ta_data_end) try { diff --git a/core/rend/dx11/dx11_renderer.cpp b/core/rend/dx11/dx11_renderer.cpp index 994f34d85..cdade9403 100644 --- a/core/rend/dx11/dx11_renderer.cpp +++ b/core/rend/dx11/dx11_renderer.cpp @@ -459,6 +459,13 @@ bool DX11Renderer::Render() resize(pvrrc.framebufferWidth, pvrrc.framebufferHeight); deviceContext->OMSetRenderTargets(1, &fbRenderTarget.get(), depthTexView); deviceContext->ClearDepthStencilView(depthTexView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0); + if (pvrrc.clearFramebuffer) + { + float colors[4]; + VO_BORDER_COL.getRGBColor(colors); + colors[3] = 1.f; + deviceContext->ClearRenderTargetView(fbRenderTarget, colors); + } } configVertexShader(); diff --git a/core/rend/dx11/oit/dx11_oitrenderer.cpp b/core/rend/dx11/oit/dx11_oitrenderer.cpp index 308686aec..1a6cc1394 100644 --- a/core/rend/dx11/oit/dx11_oitrenderer.cpp +++ b/core/rend/dx11/oit/dx11_oitrenderer.cpp @@ -446,7 +446,8 @@ struct DX11OITRenderer : public DX11Renderer deviceContext->PSSetShaderResources(0, 1, &opaqueTextureView.get()); auto sampler = samplers->getSampler(false); deviceContext->PSSetSamplers(0, 1, &sampler.get()); - deviceContext->RSSetScissorRects(1, &scissorRect); + D3D11_RECT rect { 0, 0, (LONG)width, (LONG)height }; + deviceContext->RSSetScissorRects(1, &rect); deviceContext->OMSetDepthStencilState(depthStencilStates.getState(false, false, 0, false), 0); setCullMode(0); @@ -512,6 +513,13 @@ struct DX11OITRenderer : public DX11Renderer buffers.bind(); deviceContext->ClearDepthStencilView(depthTexView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0); deviceContext->ClearDepthStencilView(depthStencilView2, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0); + if (pvrrc.clearFramebuffer && !pvrrc.isRTT) + { + float colors[4]; + VO_BORDER_COL.getRGBColor(colors); + colors[3] = 1.f; + deviceContext->ClearRenderTargetView(opaqueRenderTarget, colors); + } RenderPass previous_pass {}; int render_pass_count = (int)pvrrc.render_passes.size(); diff --git a/core/rend/dx9/d3d_renderer.cpp b/core/rend/dx9/d3d_renderer.cpp index 82679e7b2..b21aca056 100644 --- a/core/rend/dx9/d3d_renderer.cpp +++ b/core/rend/dx9/d3d_renderer.cpp @@ -964,6 +964,8 @@ bool D3DRenderer::Render() else { resize(pvrrc.framebufferWidth, pvrrc.framebufferHeight); + if (pvrrc.clearFramebuffer) + device->ColorFill(framebufferSurface, 0, D3DCOLOR_ARGB(255, VO_BORDER_COL._red, VO_BORDER_COL._green, VO_BORDER_COL._blue)); rc = SUCCEEDED(device->SetRenderTarget(0, framebufferSurface)); verify(rc); D3DVIEWPORT9 viewport; diff --git a/core/rend/gl4/gldraw.cpp b/core/rend/gl4/gldraw.cpp index b3ebbbc21..6ab6b4135 100644 --- a/core/rend/gl4/gldraw.cpp +++ b/core/rend/gl4/gldraw.cpp @@ -481,6 +481,15 @@ void gl4DrawStrips(GLuint output_fbo, int width, int height) { checkOverflowAndReset(); glBindFramebuffer(GL_FRAMEBUFFER, geom_fbo); + if (!pvrrc.isRTT && pvrrc.clearFramebuffer) + { + glcache.Disable(GL_SCISSOR_TEST); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glcache.ClearColor(VO_BORDER_COL.red(), VO_BORDER_COL.green(), VO_BORDER_COL.blue(), 1.f); + glClear(GL_COLOR_BUFFER_BIT); + if (gl4ShaderUniforms.base_clipping.enabled) + glcache.Enable(GL_SCISSOR_TEST); + } if (texSamplers[0] == 0) glGenSamplers(2, texSamplers); diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index 0264fe65d..1346c1c80 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -692,7 +692,7 @@ void writeFramebufferToVRAM() gl.fbscaling.framebuffer->bind(); glViewport(0, 0, scaledW, scaledH); glcache.Disable(GL_SCISSOR_TEST); - glcache.ClearColor(1.f, 0.f, 0.f, 1.f); + glcache.ClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.framebuffer->getTexture()); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 24414fabc..ececa2cc4 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1173,7 +1173,6 @@ bool OpenGLRenderer::renderFrame(int width, int height) bool is_rtt = pvrrc.isRTT; - float vtx_min_fZ = 0.f; //pvrrc.fZ_min; float vtx_max_fZ = pvrrc.fZ_max; //sanitise the values, now with NaN detection (for omap) @@ -1182,7 +1181,6 @@ bool OpenGLRenderer::renderFrame(int width, int height) vtx_max_fZ = 10 * 1024; //add some extra range to avoid clipping border cases - vtx_min_fZ *= 0.98f; vtx_max_fZ *= 1.001f; TransformMatrix matrices(pvrrc, is_rtt ? pvrrc.getFramebufferWidth() : width, @@ -1191,8 +1189,8 @@ bool OpenGLRenderer::renderFrame(int width, int height) const glm::mat4& scissor_mat = matrices.GetScissorMatrix(); ViewportMatrix = matrices.GetViewportMatrix(); - ShaderUniforms.depth_coefs[0] = 2 / (vtx_max_fZ - vtx_min_fZ); - ShaderUniforms.depth_coefs[1] = -vtx_min_fZ - 1; + ShaderUniforms.depth_coefs[0] = 2.f / vtx_max_fZ; + ShaderUniforms.depth_coefs[1] = -1.f; ShaderUniforms.depth_coefs[2] = 0; ShaderUniforms.depth_coefs[3] = 0; @@ -1310,6 +1308,8 @@ bool OpenGLRenderer::renderFrame(int width, int height) glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glCheck(); if (!is_rtt) glcache.ClearColor(VO_BORDER_COL.red(), VO_BORDER_COL.green(), VO_BORDER_COL.blue(), 1.f); + else + glcache.ClearColor(0.f, 0.f, 0.f, 0.f); if (!is_rtt && (FB_R_CTRL.fb_enable == 0 || VO_CONTROL.blank_video == 1)) { @@ -1318,6 +1318,8 @@ bool OpenGLRenderer::renderFrame(int width, int height) } else { + if (is_rtt || pvrrc.clearFramebuffer) + glClear(GL_COLOR_BUFFER_BIT); //move vertex to gpu //Main VBO gl.vbo.geometry->update(&pvrrc.verts[0], pvrrc.verts.size() * sizeof(decltype(pvrrc.verts[0]))); diff --git a/core/rend/gles/postprocess.cpp b/core/rend/gles/postprocess.cpp index 52d8eca54..577c738be 100644 --- a/core/rend/gles/postprocess.cpp +++ b/core/rend/gles/postprocess.cpp @@ -325,7 +325,7 @@ void PostProcessor::render(GLuint output_fbo) if (_pvrrc == nullptr) // Framebuffer render: no dithering - PostProcessShader::select(!config::EmulateFramebuffer, + PostProcessShader::select(false, SPG_CONTROL.interlace, FB_R_CTRL.vclk_div == 1 && SPG_CONTROL.interlace == 0); else diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp index a18642fc3..c8ff717d4 100644 --- a/core/rend/vulkan/drawer.cpp +++ b/core/rend/vulkan/drawer.cpp @@ -715,7 +715,7 @@ vk::CommandBuffer ScreenDrawer::BeginRenderPass() transitionNeeded[GetCurrentImage()] = false; } - vk::RenderPass renderPass = clearNeeded[GetCurrentImage()] ? *renderPassClear : *renderPassLoad; + vk::RenderPass renderPass = clearNeeded[GetCurrentImage()] || pvrrc.clearFramebuffer ? *renderPassClear : *renderPassLoad; clearNeeded[GetCurrentImage()] = false; const std::array clear_colors = { vk::ClearColorValue(std::array { 0.f, 0.f, 0.f, 1.f }), vk::ClearDepthStencilValue { 0.f, 0 } }; commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(renderPass, *framebuffers[GetCurrentImage()], diff --git a/core/rend/vulkan/oit/oit_drawer.cpp b/core/rend/vulkan/oit/oit_drawer.cpp index a7625643c..616b53707 100644 --- a/core/rend/vulkan/oit/oit_drawer.cpp +++ b/core/rend/vulkan/oit/oit_drawer.cpp @@ -362,7 +362,7 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture) else targetFramebuffer = GetFinalFramebuffer(); cmdBuffer.beginRenderPass( - vk::RenderPassBeginInfo(pipelineManager->GetRenderPass(initialPass, finalPass), + vk::RenderPassBeginInfo(pipelineManager->GetRenderPass(initialPass, finalPass, initialPass && pvrrc.clearFramebuffer), targetFramebuffer, viewport, clear_colors), vk::SubpassContents::eInline); diff --git a/core/rend/vulkan/oit/oit_pipeline.h b/core/rend/vulkan/oit/oit_pipeline.h index 24ef63bac..58e669018 100644 --- a/core/rend/vulkan/oit/oit_pipeline.h +++ b/core/rend/vulkan/oit/oit_pipeline.h @@ -383,7 +383,7 @@ public: vk::DescriptorSetLayout GetPerPolyDSLayout() const { return *perPolyLayout; } vk::DescriptorSetLayout GetColorInputDSLayout() const { return *colorInputLayout; } - vk::RenderPass GetRenderPass(bool initial, bool last) { return renderPasses->GetRenderPass(initial, last); } + vk::RenderPass GetRenderPass(bool initial, bool last, bool loadClear = false) { return renderPasses->GetRenderPass(initial, last, loadClear); } private: void CreateModVolPipeline(ModVolMode mode, int cullMode, bool naomi2); diff --git a/core/rend/vulkan/oit/oit_renderpass.cpp b/core/rend/vulkan/oit/oit_renderpass.cpp index 056d693f4..b19f6fc8c 100644 --- a/core/rend/vulkan/oit/oit_renderpass.cpp +++ b/core/rend/vulkan/oit/oit_renderpass.cpp @@ -20,11 +20,11 @@ */ #include "oit_renderpass.h" -vk::UniqueRenderPass RenderPasses::MakeRenderPass(bool initial, bool last) +vk::UniqueRenderPass RenderPasses::MakeRenderPass(bool initial, bool last, bool loadClear) { std::array attachmentDescriptions = { // Swap chain image - GetAttachment0Description(initial, last), + GetAttachment0Description(initial, last, loadClear), // OP+PT color attachment vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1, initial ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, diff --git a/core/rend/vulkan/oit/oit_renderpass.h b/core/rend/vulkan/oit/oit_renderpass.h index a67af4f11..fb400e838 100644 --- a/core/rend/vulkan/oit/oit_renderpass.h +++ b/core/rend/vulkan/oit/oit_renderpass.h @@ -24,11 +24,11 @@ class RenderPasses { public: - vk::RenderPass GetRenderPass(bool initial, bool last) + vk::RenderPass GetRenderPass(bool initial, bool last, bool loadClear = false) { - size_t index = (initial ? 1 : 0) | (last ? 2 : 0); + size_t index = (initial ? 1 : 0) | (last ? 2 : 0) | (loadClear ? 4 : 0); if (!renderPasses[index]) - renderPasses[index] = MakeRenderPass(initial, last); + renderPasses[index] = MakeRenderPass(initial, last, loadClear); return *renderPasses[index]; } void Reset() @@ -40,11 +40,11 @@ public: protected: VulkanContext *GetContext() const { return VulkanContext::Instance(); } - vk::UniqueRenderPass MakeRenderPass(bool initial, bool last); - virtual vk::AttachmentDescription GetAttachment0Description(bool initial, bool last) const + vk::UniqueRenderPass MakeRenderPass(bool initial, bool last, bool loadClear); + virtual vk::AttachmentDescription GetAttachment0Description(bool initial, bool last, bool loadClear) const { return vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1, - vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eStore, + loadClear ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, config::EmulateFramebuffer && last ? vk::ImageLayout::eTransferSrcOptimal : vk::ImageLayout::eShaderReadOnlyOptimal, config::EmulateFramebuffer && last ? vk::ImageLayout::eTransferSrcOptimal : vk::ImageLayout::eShaderReadOnlyOptimal); @@ -59,13 +59,13 @@ protected: } private: - std::array renderPasses; + std::array renderPasses; }; class RttRenderPasses : public RenderPasses { protected: - vk::AttachmentDescription GetAttachment0Description(bool initial, bool last) const override + vk::AttachmentDescription GetAttachment0Description(bool initial, bool last, bool loadClear) const override { return vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore,