Merge pull request #16160 from unknownbrackets/vram-mirrors

GPU: Use flags to fix triggered upload/download
This commit is contained in:
Henrik Rydgård 2022-10-04 08:45:06 +02:00 committed by GitHub
commit b333695cd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 39 additions and 28 deletions

View File

@ -1637,7 +1637,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
// This is called from detected memcopies and framebuffer initialization from VRAM. Not block transfers.
// MotoGP goes this path so we need to catch those copies here.
bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, bool isMemset, u32 skipDrawReason) {
bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, GPUCopyFlag flags, u32 skipDrawReason) {
if (size == 0) {
return false;
}
@ -1653,8 +1653,11 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
// 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;
VirtualFramebuffer *dstBuffer = nullptr;
VirtualFramebuffer *srcBuffer = nullptr;
bool ignoreDstBuffer = flags & GPUCopyFlag::FORCE_DST_MEM;
bool ignoreSrcBuffer = flags & (GPUCopyFlag::FORCE_SRC_MEM | GPUCopyFlag::MEMSET);
u32 dstY = (u32)-1;
u32 dstH = 0;
u32 srcY = (u32)-1;
@ -1672,14 +1675,14 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
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)) {
if (!ignoreDstBuffer && 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)) {
if (!ignoreDstBuffer && dst >= vfb_address && (dst + size <= vfb_address + vfb_size || dst == vfb_address)) {
const u32 offset = dst - vfb_address;
const u32 yOffset = offset / vfb_byteStride;
if ((offset % vfb_byteStride) == 0 && (size == vfb_byteWidth || (size % vfb_byteStride) == 0) && yOffset < dstY) {
@ -1689,7 +1692,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
}
}
if (src >= vfb_address && (src + size <= vfb_address + vfb_size || src == vfb_address)) {
if (!ignoreSrcBuffer && src >= vfb_address && (src + size <= vfb_address + vfb_size || src == vfb_address)) {
const u32 offset = src - vfb_address;
const u32 yOffset = offset / vfb_byteStride;
if ((offset % vfb_byteStride) == 0 && (size == vfb_byteWidth || (size % vfb_byteStride) == 0) && yOffset < srcY) {
@ -1731,7 +1734,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
dstBuffer->last_frame_used = gpuStats.numFlips;
}
if (dstBuffer && srcBuffer && !isMemset) {
if (dstBuffer && srcBuffer) {
if (srcBuffer == dstBuffer) {
WARN_LOG_ONCE(dstsrccpy, G3D, "Intra-buffer memcpy (not supported) %08x -> %08x (size: %x)", src, dst, size);
} else {
@ -1743,7 +1746,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
}
return false;
} else if (dstBuffer) {
if (isMemset) {
if (flags & GPUCopyFlag::MEMSET) {
gpuStats.numClears++;
}
WARN_LOG_ONCE(btucpy, G3D, "Memcpy fbo upload %08x -> %08x (size: %x)", src, dst, size);

View File

@ -306,7 +306,7 @@ public:
void CopyDisplayToOutput(bool reallyDirty);
bool NotifyFramebufferCopy(u32 src, u32 dest, int size, bool isMemset, u32 skipDrawReason);
bool NotifyFramebufferCopy(u32 src, u32 dest, int size, GPUCopyFlag flags, u32 skipDrawReason);
void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt);
void UpdateFromMemory(u32 addr, int size);
void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor);

View File

@ -691,10 +691,11 @@ void NotifyUpload(u32 dest, u32 sz) {
return;
}
CheckEdramTrans();
NotifyMemcpy(dest, dest, sz);
if (Memory::IsVRAMAddress(dest))
if (Memory::IsVRAMAddress(dest)) {
// This also checks the edram translation value.
NotifyMemcpy(dest, dest, sz);
DirtyVRAM(dest, sz, DirtyVRAMFlag::DIRTY);
}
}
static bool HasDrawCommands() {

View File

@ -3046,10 +3046,10 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) {
cyclesExecuted += ((height * width * bpp) * 16) / 10;
}
bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size) {
bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags) {
// Track stray copies of a framebuffer in RAM. MotoGP does this.
if (framebufferManager_->MayIntersectFramebuffer(src) || framebufferManager_->MayIntersectFramebuffer(dest)) {
if (!framebufferManager_->NotifyFramebufferCopy(src, dest, size, false, gstate_c.skipDrawReason)) {
if (!framebufferManager_->NotifyFramebufferCopy(src, dest, size, flags, gstate_c.skipDrawReason)) {
// We use a little hack for PerformMemoryDownload/PerformMemoryUpload using a VRAM mirror.
// Since they're identical we don't need to copy.
if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) {
@ -3071,7 +3071,8 @@ bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size) {
NotifyMemInfo(MemBlockFlags::WRITE, dest, size, tag.c_str(), tag.size());
}
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
GPURecord::NotifyMemcpy(dest, src, size);
if (!(flags & GPUCopyFlag::DEBUG_NOTIFIED))
GPURecord::NotifyMemcpy(dest, src, size);
return false;
}
@ -3079,7 +3080,7 @@ bool GPUCommon::PerformMemorySet(u32 dest, u8 v, int size) {
// This may indicate a memset, usually to 0, of a framebuffer.
if (framebufferManager_->MayIntersectFramebuffer(dest)) {
Memory::Memset(dest, v, size, "GPUMemset");
if (!framebufferManager_->NotifyFramebufferCopy(dest, dest, size, true, gstate_c.skipDrawReason)) {
if (!framebufferManager_->NotifyFramebufferCopy(dest, dest, size, GPUCopyFlag::MEMSET, gstate_c.skipDrawReason)) {
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
}
return true;
@ -3093,20 +3094,16 @@ bool GPUCommon::PerformMemorySet(u32 dest, u8 v, int size) {
}
bool GPUCommon::PerformMemoryDownload(u32 dest, int size) {
// Cheat a bit to force a download of the framebuffer.
// VRAM + 0x00400000 is simply a VRAM mirror.
if (Memory::IsVRAMAddress(dest)) {
return PerformMemoryCopy(dest ^ 0x00400000, dest, size);
return PerformMemoryCopy(dest, dest, size, GPUCopyFlag::FORCE_DST_MEM);
}
return false;
}
bool GPUCommon::PerformMemoryUpload(u32 dest, int size) {
// Cheat a bit to force an upload of the framebuffer.
// VRAM + 0x00400000 is simply a VRAM mirror.
if (Memory::IsVRAMAddress(dest)) {
GPURecord::NotifyUpload(dest, size);
return PerformMemoryCopy(dest, dest ^ 0x00400000, size);
return PerformMemoryCopy(dest, dest, size, GPUCopyFlag::FORCE_SRC_MEM | GPUCopyFlag::DEBUG_NOTIFIED);
}
return false;
}

View File

@ -124,7 +124,7 @@ public:
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void CopyDisplayToOutput(bool reallyDirty) override = 0;
void InitClear() override = 0;
bool PerformMemoryCopy(u32 dest, u32 src, int size) override;
bool PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags = GPUCopyFlag::NONE) override;
bool PerformMemorySet(u32 dest, u8 v, int size) override;
bool PerformMemoryDownload(u32 dest, int size) override;
bool PerformMemoryUpload(u32 dest, int size) override;

View File

@ -114,6 +114,16 @@ enum class StencilUpload {
};
ENUM_CLASS_BITOPS(StencilUpload);
enum class GPUCopyFlag {
NONE = 0,
FORCE_SRC_MEM = 1,
FORCE_DST_MEM = 2,
// Note: implies src == dst and FORCE_SRC_MEM.
MEMSET = 4,
DEBUG_NOTIFIED = 8,
};
ENUM_CLASS_BITOPS(GPUCopyFlag);
// Used for debug
struct FramebufferInfo {
u32 fb_address;
@ -222,7 +232,7 @@ public:
virtual void InvalidateCache(u32 addr, int size, GPUInvalidationType type) = 0;
virtual void NotifyVideoUpload(u32 addr, int size, int width, int format) = 0;
// Update either RAM from VRAM, or VRAM from RAM... or even VRAM from VRAM.
virtual bool PerformMemoryCopy(u32 dest, u32 src, int size) = 0;
virtual bool PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags = GPUCopyFlag::NONE) = 0;
virtual bool PerformMemorySet(u32 dest, u8 v, int size) = 0;
virtual bool PerformMemoryDownload(u32 dest, int size) = 0;
virtual bool PerformMemoryUpload(u32 dest, int size) = 0;

View File

@ -1265,11 +1265,11 @@ void SoftGPU::NotifyVideoUpload(u32 addr, int size, int width, int format)
// Ignore.
}
bool SoftGPU::PerformMemoryCopy(u32 dest, u32 src, int size)
{
bool SoftGPU::PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags) {
// Nothing to update.
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
GPURecord::NotifyMemcpy(dest, src, size);
if (!(flags & GPUCopyFlag::DEBUG_NOTIFIED))
GPURecord::NotifyMemcpy(dest, src, size);
// Let's just be safe.
MarkDirty(dest, size, SoftGPUVRAMDirty::DIRTY | SoftGPUVRAMDirty::REALLY_DIRTY);
return false;

View File

@ -139,7 +139,7 @@ public:
void GetStats(char *buffer, size_t bufsize) override;
void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
void NotifyVideoUpload(u32 addr, int size, int width, int format) override;
bool PerformMemoryCopy(u32 dest, u32 src, int size) override;
bool PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags = GPUCopyFlag::NONE) override;
bool PerformMemorySet(u32 dest, u8 v, int size) override;
bool PerformMemoryDownload(u32 dest, int size) override;
bool PerformMemoryUpload(u32 dest, int size) override;