Skip to content

Commit

Permalink
Clear depth buffers after changing depth rounding mode.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hrydgard committed Feb 9, 2023
1 parent 63ea75d commit 1687720
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 7 deletions.
5 changes: 3 additions & 2 deletions GPU/Common/Draw2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ Draw2DPipelineInfo GenerateDraw2DCopyColorRect2LinFs(ShaderWriter &writer) {
Draw2DPipelineInfo GenerateDraw2DCopyDepthFs(ShaderWriter &writer) {
writer.SetFlags(ShaderWriterFlags::FS_WRITE_DEPTH);
writer.DeclareSamplers(samplers);
writer.BeginFSMain(Slice<UniformDef>::empty(), varyings);
writer.BeginFSMain(g_draw2Duniforms, varyings);
writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n");
writer.C(" gl_FragDepth = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n");
writer.C(" float depth = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n");
writer.C(" gl_FragDepth = ((depth - z_offset) / z_scale) * 65536.0f;\n");
writer.EndFSMain("outColor");

return Draw2DPipelineInfo{
Expand Down
15 changes: 14 additions & 1 deletion GPU/Common/FramebufferManagerCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions GPU/Common/FramebufferManagerCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -317,6 +318,10 @@ class FramebufferManagerCommon {
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).
Expand Down
3 changes: 2 additions & 1 deletion GPU/D3D11/GPU_D3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion GPU/Directx9/GPU_DX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
3 changes: 2 additions & 1 deletion GPU/GLES/GPU_GLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,10 @@ 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);
gstate_c.useFlagsChanged = false;
framebufferManager_->ClearAllDepthBuffers();
}
}

Expand Down
5 changes: 4 additions & 1 deletion GPU/Vulkan/GPU_Vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit 1687720

Please sign in to comment.