rend: clear framebuffer when vram address changes

Fixes top and bottom leftovers from BIOS boot in San Francisco Rush
2049.
Issue #1197
This commit is contained in:
Flyinghead 2023-09-25 18:23:26 +02:00
parent e57ccde532
commit 0f6e1752e3
15 changed files with 74 additions and 36 deletions

View File

@ -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;
}

View File

@ -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()

View File

@ -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 {

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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<COORD_OPENGL> 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])));

View File

@ -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

View File

@ -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<vk::ClearValue, 2> clear_colors = { vk::ClearColorValue(std::array<float, 4> { 0.f, 0.f, 0.f, 1.f }), vk::ClearDepthStencilValue { 0.f, 0 } };
commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(renderPass, *framebuffers[GetCurrentImage()],

View File

@ -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);

View File

@ -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);

View File

@ -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<vk::AttachmentDescription, 4> 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,

View File

@ -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<vk::UniqueRenderPass, 4> renderPasses;
std::array<vk::UniqueRenderPass, 8> 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,