diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index ac7a596874..2967686809 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -1330,6 +1330,11 @@ bool DIRECTX9_GPU::PerformMemoryDownload(u32 dest, int size) { return false; } +bool DIRECTX9_GPU::PerformMemoryUpload(u32 dest, int size) { + InvalidateCache(dest, size, GPU_INVALIDATE_HINT); + return false; +} + bool DIRECTX9_GPU::PerformStencilUpload(u32 dest, int size) { return false; } diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 35ff0dc4ba..33bd0bd19b 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -49,6 +49,7 @@ public: virtual bool PerformMemoryCopy(u32 dest, u32 src, int size); virtual bool PerformMemorySet(u32 dest, u8 v, int size); virtual bool PerformMemoryDownload(u32 dest, int size); + virtual bool PerformMemoryUpload(u32 dest, int size); virtual bool PerformStencilUpload(u32 dest, int size); virtual void ClearCacheNextFrame(); virtual void DeviceLost(); // Only happens on Android. Drop all textures and shaders. diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index 0b9b0b57bb..c251dba9b5 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -1997,7 +1997,11 @@ void GLES_GPU::InvalidateCacheInternal(u32 addr, int size, GPUInvalidationType t void GLES_GPU::PerformMemoryCopyInternal(u32 dest, u32 src, int size) { if (!framebufferManager_.NotifyFramebufferCopy(src, dest, size)) { - Memory::Memcpy(dest, Memory::GetPointer(src), size); + // We use a little hack for Download/Upload using a VRAM mirror. + // Since they're identical we don't need to copy. + if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) { + Memory::Memcpy(dest, Memory::GetPointer(src), size); + } } InvalidateCache(dest, size, GPU_INVALIDATE_HINT); } @@ -2064,6 +2068,12 @@ bool GLES_GPU::PerformMemoryDownload(u32 dest, int size) { return gpu->PerformMemoryCopy(dest ^ 0x00400000, dest, size); } +bool GLES_GPU::PerformMemoryUpload(u32 dest, int size) { + // Cheat a bit to force a download of the framebuffer. + // VRAM + 0x00400000 is simply a VRAM mirror. + return gpu->PerformMemoryCopy(dest, dest ^ 0x00400000, size); +} + bool GLES_GPU::PerformStencilUpload(u32 dest, int size) { if (framebufferManager_.MayIntersectFramebuffer(dest)) { if (IsOnSeparateCPUThread()) { diff --git a/GPU/GLES/GLES_GPU.h b/GPU/GLES/GLES_GPU.h index 85bcb032c1..3d3f7e07d9 100644 --- a/GPU/GLES/GLES_GPU.h +++ b/GPU/GLES/GLES_GPU.h @@ -48,6 +48,7 @@ public: virtual bool PerformMemoryCopy(u32 dest, u32 src, int size); virtual bool PerformMemorySet(u32 dest, u8 v, int size); virtual bool PerformMemoryDownload(u32 dest, int size); + virtual bool PerformMemoryUpload(u32 dest, int size); virtual bool PerformStencilUpload(u32 dest, int size); virtual void ClearCacheNextFrame(); virtual void DeviceLost(); // Only happens on Android. Drop all textures and shaders. diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index e8f6844514..b6b418ca4a 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -250,6 +250,7 @@ public: virtual bool PerformMemoryCopy(u32 dest, u32 src, int size) = 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; virtual bool PerformStencilUpload(u32 dest, int size) = 0; // Will cause the texture cache to be cleared at the start of the next frame. diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index f427b909d0..cfd358f929 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -675,6 +675,12 @@ bool NullGPU::PerformMemoryDownload(u32 dest, int size) { return false; } +bool NullGPU::PerformMemoryUpload(u32 dest, int size) { + // Nothing to update. + InvalidateCache(dest, size, GPU_INVALIDATE_HINT); + return false; +} + bool NullGPU::PerformStencilUpload(u32 dest, int size) { return false; } diff --git a/GPU/Null/NullGpu.h b/GPU/Null/NullGpu.h index a83b256e1e..aac1fb7124 100644 --- a/GPU/Null/NullGpu.h +++ b/GPU/Null/NullGpu.h @@ -37,6 +37,7 @@ public: virtual bool PerformMemoryCopy(u32 dest, u32 src, int size); virtual bool PerformMemorySet(u32 dest, u8 v, int size); virtual bool PerformMemoryDownload(u32 dest, int size); + virtual bool PerformMemoryUpload(u32 dest, int size); virtual bool PerformStencilUpload(u32 dest, int size); virtual void ClearCacheNextFrame() {}; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 2d3e38c522..e54e6082bb 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -876,6 +876,13 @@ bool SoftGPU::PerformMemoryDownload(u32 dest, int size) return false; } +bool SoftGPU::PerformMemoryUpload(u32 dest, int size) +{ + // Nothing to update. + InvalidateCache(dest, size, GPU_INVALIDATE_HINT); + return false; +} + bool SoftGPU::PerformStencilUpload(u32 dest, int size) { return false; diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 9ffe4509bd..4d028e4da8 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -62,6 +62,7 @@ public: virtual bool PerformMemoryCopy(u32 dest, u32 src, int size); virtual bool PerformMemorySet(u32 dest, u8 v, int size); virtual bool PerformMemoryDownload(u32 dest, int size); + virtual bool PerformMemoryUpload(u32 dest, int size); virtual bool PerformStencilUpload(u32 dest, int size); virtual void ClearCacheNextFrame() {};