Clear depth buffers after changing depth rounding mode.

And thus change of depth buffer scale/offset.

Previously, old depth buffers with values that now are out of range
could stick around, causing #16941. This clears them to the expected 0
value, which helps Outrun. Ideally we should convert depth buffers to
the new format, but if we can get away without that, that's also nice.

This is enough for #16941.
This commit is contained in:
Henrik Rydgård 2023-02-10 00:42:46 +01:00
parent ea9245d903
commit d426ce5118
6 changed files with 29 additions and 5 deletions

View file

@ -1059,7 +1059,14 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
if (useBufferedRendering_) {
if (vfb->fbo) {
shaderManager_->DirtyLastShader();
draw_->BindFramebufferAsRenderTarget(vfb->fbo, {Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP}, "FBSwitch");
Draw::RPAction depthAction = Draw::RPAction::KEEP;
float clearDepth = 0.0f;
if (vfb->usageFlags & FB_USAGE_INVALIDATE_DEPTH) {
depthAction = Draw::RPAction::CLEAR;
clearDepth = GetDepthScaleFactors().offset;
vfb->usageFlags &= ~FB_USAGE_INVALIDATE_DEPTH;
}
draw_->BindFramebufferAsRenderTarget(vfb->fbo, {Draw::RPAction::KEEP, depthAction, Draw::RPAction::KEEP, 0, clearDepth}, "FBSwitch");
} else {
// This should only happen very briefly when toggling useBufferedRendering_.
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
@ -2573,6 +2580,12 @@ void FramebufferManagerCommon::ShowScreenResolution() {
INFO_LOG(SYSTEM, "%s", messageStream.str().c_str());
}
void FramebufferManagerCommon::ClearAllDepthBuffers() {
for (auto vfb : vfbs_) {
vfb->usageFlags |= FB_USAGE_INVALIDATE_DEPTH;
}
}
// We might also want to implement an asynchronous callback-style version of this. Would probably
// only be possible to implement optimally on Vulkan, but on GL and D3D11 we could do pixel buffers
// and read on the next frame, then call the callback.

View file

@ -46,6 +46,7 @@ enum {
FB_USAGE_FIRST_FRAME_SAVED = 128,
FB_USAGE_RENDER_DEPTH = 256,
FB_USAGE_COLOR_MIXED_DEPTH = 512,
FB_USAGE_INVALIDATE_DEPTH = 1024, // used to clear depth buffers.
};
enum {
@ -317,6 +318,10 @@ public:
void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor);
bool PerformWriteStencilFromMemory(u32 addr, int size, WriteStencil flags);
// We changed our depth mode, gotta start over.
// Ideally, we should convert depth buffers here, not just clear them.
void ClearAllDepthBuffers();
// Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it.
// In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless
// read framebuffers is on, in which case this should always return false).

View file

@ -161,8 +161,9 @@ void GPU_D3D11::BeginFrame() {
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
shaderManagerD3D11_->ClearShaders();
framebufferManager_->ClearAllDepthBuffers();
drawEngine_.ClearInputLayoutMap();
gstate_c.useFlagsChanged = false;
}

View file

@ -159,8 +159,9 @@ void GPU_DX9::BeginFrame() {
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
shaderManagerDX9_->ClearCache(true);
framebufferManager_->ClearAllDepthBuffers();
gstate_c.useFlagsChanged = false;
}
}

View file

@ -283,8 +283,9 @@ void GPU_GLES::BeginHostFrame() {
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
shaderManagerGL_->ClearCache(true);
framebufferManager_->ClearAllDepthBuffers();
gstate_c.useFlagsChanged = false;
}
}

View file

@ -310,9 +310,12 @@ void GPU_Vulkan::BeginHostFrame() {
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
// TODO: Not all shaders need to be recompiled. In fact, quite few? Of course, depends on
// the use flag change.. This is a major frame rate hitch in the start of a race in Outrun.
shaderManagerVulkan_->ClearShaders();
pipelineManager_->Clear();
framebufferManager_->ClearAllDepthBuffers();
gstate_c.useFlagsChanged = false;
}