Tighten up some color format checks with displays and copies

Now that we allow multiple color format buffers to overlap, and don't
just take one and change its format during copy for example, we could
use some additional checking.

Additionally, do a simple heuristic to reject "obviously" wrong copies
copies to framebuffers.

Fixes #15959, should also help #16124
This commit is contained in:
Henrik Rydgård 2022-10-01 23:53:13 +02:00
parent f12a5101e6
commit ab08db6fca

View file

@ -1358,6 +1358,12 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
for (auto v : vfbs_) {
const u32 v_addr = v->fb_address & 0x3FFFFFFF;
const u32 v_size = ColorBufferByteSize(v);
if (v->fb_format != displayFormat_ || v->fb_stride != displayStride_) {
// Displaying a buffer of the wrong format or stride is nonsense, ignore it.
continue;
}
if (addr >= v_addr && addr < v_addr + v_size) {
const u32 dstBpp = BufferFormatBytesPerPixel(v->fb_format);
const u32 v_offsetX = ((addr - v_addr) / dstBpp) % v->fb_stride;
@ -1623,7 +1629,9 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
dst &= 0x3FFFFFFF;
src &= 0x3FFFFFFF;
// TODO: Merge the below into FindTransferFramebuffer
// TODO: Merge the below into FindTransferFramebuffer.
// Or at least this should be like the other ones, gathering possible candidates
// with the ability to list them out for debugging.
VirtualFramebuffer *dstBuffer = 0;
VirtualFramebuffer *srcBuffer = 0;
@ -1643,6 +1651,14 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
const u32 vfb_byteStride = vfb->fb_stride * vfb_bpp;
const int vfb_byteWidth = vfb->width * vfb_bpp;
// Heuristic to try to prevent potential glitches with video playback.
if (vfb_address == dst && (size == 0x44000 && vfb_size == 0x88000 || size == 0x88000 && vfb_size == 0x44000)) {
// Not likely to be a correct color format copy for this buffer. Ignore it, there will either be RAM
// that can be displayed from, or another matching buffer with the right format if rendering is going on.
WARN_LOG_N_TIMES(notify_copy_2x, 5, G3D, "Framebuffer size %08x conspicuously not matching copy size %08x in NotifyFramebufferCopy. Ignoring.", size, vfb_size);
continue;
}
if (dst >= vfb_address && (dst + size <= vfb_address + vfb_size || dst == vfb_address)) {
const u32 offset = dst - vfb_address;
const u32 yOffset = offset / vfb_byteStride;