Track depth buffers separately from framebuffers to track previous use for copies

Fixes the depth testing problem reported in #11013

(WIP: Does not yet include the extra checking unknown suggested for
depth/color address clashes)
This commit is contained in:
Henrik Rydgård 2022-07-17 18:14:55 +02:00
parent de3a6e7381
commit b5f5aa1653
2 changed files with 77 additions and 7 deletions

View file

@ -69,6 +69,12 @@ FramebufferManagerCommon::~FramebufferManagerCommon() {
}
bvfbs_.clear();
// Shouldn't be anything left here in theory, but just in case...
for (auto trackedDepth : trackedDepthBuffers_) {
delete trackedDepth;
}
trackedDepthBuffers_.clear();
delete presentation_;
}
@ -400,9 +406,16 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
ResizeFramebufFBO(vfb, drawing_width, drawing_height, true);
NotifyRenderFramebufferCreated(vfb);
// Looks up by z_address, so if one is found here and not have last pointers equal to this one,
// there is another one.
TrackedDepthBuffer *prevDepth = GetOrCreateTrackedDepthBuffer(vfb);
// We might already want to copy depth, in case this is a temp buffer. See #7810.
if (currentRenderVfb_ && !params.isClearingDepth) {
BlitFramebufferDepth(currentRenderVfb_, vfb);
if (prevDepth->vfb != vfb) {
if (!params.isClearingDepth) {
BlitFramebufferDepth(prevDepth->vfb, vfb);
}
prevDepth->vfb = vfb;
}
SetColorUpdated(vfb, skipDrawReason);
@ -495,6 +508,16 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) {
if (prevPrevDisplayFramebuf_ == v)
prevPrevDisplayFramebuf_ = nullptr;
// Remove any depth buffer tracking related to this vfb.
for (auto it = trackedDepthBuffers_.begin(); it != trackedDepthBuffers_.end(); it) {
if ((*it)->vfb == v) {
delete *it;
it = trackedDepthBuffers_.erase(it);
} else {
it++;
}
}
delete v;
}
@ -503,9 +526,10 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
// Check that the depth address is even the same before actually blitting.
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
bool matchingSize = src->width == dst->width && src->height == dst->height;
if (!matchingDepthBuffer || !matchingSize)
bool matchingSize = (src->width == dst->width || src->width == 512 && dst->width == 480) || (src->width == 480 && dst->width == 512) && src->height == dst->height;
if (!matchingDepthBuffer || !matchingSize) {
return;
}
// Copy depth value from the previously bound framebuffer to the current one.
bool hasNewerDepth = src->last_frame_depth_render != 0 && src->last_frame_depth_render >= dst->last_frame_depth_updated;
@ -520,7 +544,9 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
int w = std::min(src->renderWidth, dst->renderWidth);
int h = std::min(src->renderHeight, dst->renderHeight);
// Note: We prefer Blit ahead of Copy here, since at least on GL, Copy will always also copy stencil which we don't want. See #9740.
// Note: We prefer Blit ahead of Copy here, since at least on GL, Copy will always also copy stencil which we don't want.
// See #9740.
// TODO: This ordering should probably apply to GL only, since in Vulkan you can totally copy just the depth aspect.
if (gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH)) {
draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth");
RebindFramebuffer("After BlitFramebufferDepth");
@ -531,6 +557,23 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
dst->last_frame_depth_updated = gpuStats.numFlips;
}
TrackedDepthBuffer *FramebufferManagerCommon::GetOrCreateTrackedDepthBuffer(VirtualFramebuffer *vfb) {
for (auto tracked : trackedDepthBuffers_) {
if (vfb->z_address == tracked->z_address && vfb->z_stride == tracked->z_stride) {
return tracked;
}
}
TrackedDepthBuffer *tracked = new TrackedDepthBuffer();
tracked->vfb = vfb;
tracked->z_address = vfb->z_address;
tracked->z_stride = vfb->z_stride;
trackedDepthBuffers_.push_back(tracked);
return tracked;
}
void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) {
if (!useBufferedRendering_) {
// Let's ignore rendering to targets that have not (yet) been displayed.
@ -738,8 +781,14 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
shaderManager_->DirtyLastShader();
// Copy depth between the framebuffers, if the z_address is the same (checked inside.)
if (prevVfb && !isClearingDepth) {
BlitFramebufferDepth(prevVfb, vfb);
TrackedDepthBuffer *prevDepth = GetOrCreateTrackedDepthBuffer(vfb);
// We might already want to copy depth, in case this is a temp buffer. See #7810.
if (prevDepth->vfb != vfb) {
if (!isClearingDepth) {
BlitFramebufferDepth(prevDepth->vfb, vfb);
}
prevDepth->vfb = vfb;
}
if (vfb->drawnFormat != vfb->format) {