diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 7f6980e982..a99b02c6b9 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -327,7 +327,8 @@ FramebufferManager::FramebufferManager() : shaderManager_(0), usePostShader_(false), postShaderAtOutputResolution_(false), - resized_(false) + resized_(false), + framebufRangeEnd_(0) #ifndef USING_GLES2 , pixelBufObj_(0), @@ -836,6 +837,11 @@ void FramebufferManager::DoSetRenderFrameBuffer() { glEnable(GL_DITHER); // why? currentRenderVfb_ = vfb; + u32 byteSize = vfb->fb_stride * vfb->height * (vfb->format == GE_FORMAT_8888 ? 4 : 2); + if (fb_address + byteSize > framebufRangeEnd_) { + framebufRangeEnd_ = ((fb_address + byteSize) & 0x3FFFFFFF) | 0x04000000; + } + INFO_LOG(SCEGE, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format); // Let's check for depth buffer overlap. Might be interesting. @@ -1798,6 +1804,11 @@ void FramebufferManager::UpdateFromMemory(u32 addr, int size, bool safe) { } void FramebufferManager::NotifyFramebufferCopy(u32 src, u32 dst, int size) { + if (!MayIntersectFramebuffer(src) && !MayIntersectFramebuffer(dst)) { + // Don't waste time looking if neither can be a framebuffer. + return; + } + // MotoGP workaround for (size_t i = 0; i < vfbs_.size(); i++) { int bpp = vfbs_[i]->format == GE_FORMAT_8888 ? 4 : 2; @@ -1867,6 +1878,11 @@ bool FramebufferManager::NotifyBlockTransferBefore(u32 dstBasePtr, int dstStride return false; } + // Skip checking if there's no framebuffers in that area. + if (!MayIntersectFramebuffer(srcBasePtr) && !MayIntersectFramebuffer(dstBasePtr)) { + return false; + } + VirtualFramebuffer *dstBuffer = 0; VirtualFramebuffer *srcBuffer = 0; FindTransferFramebuffers(dstBuffer, srcBuffer, dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, bpp); @@ -1903,7 +1919,8 @@ void FramebufferManager::NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, return; } - if (Memory::IsRAMAddress(srcBasePtr) && Memory::IsVRAMAddress(dstBasePtr)) { + // TODO: This can probably just be handled by a normal block transfer upload, no? + if (Memory::IsRAMAddress(srcBasePtr) && MayIntersectFramebuffer(dstBasePtr)) { // TODO: This causes glitches in Tactics Ogre if we don't implement both ways (which will probably be slow...) // The main thing this helps is videos, which will have a matching stride, and zero x/y. if (dstStride == srcStride && dstY == 0 && dstX == 0 && srcX == 0 && srcY == 0) { @@ -1917,6 +1934,7 @@ void FramebufferManager::NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, u32 backBuffer = PrevDisplayFramebufAddr(); u32 displayBuffer = DisplayFramebufAddr(); + // TODO: Is this not handled by upload? Should we check !dstBuffer to avoid a double copy? if (((backBuffer != 0 && dstBasePtr == backBuffer) || (displayBuffer != 0 && dstBasePtr == displayBuffer)) && dstStride == 512 && height == 272) { @@ -1924,15 +1942,17 @@ void FramebufferManager::NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, DrawFramebuffer(Memory::GetPointerUnchecked(dstBasePtr), GE_FORMAT_8888, 512, false); } - VirtualFramebuffer *dstBuffer = 0; - VirtualFramebuffer *srcBuffer = 0; - FindTransferFramebuffers(dstBuffer, srcBuffer, dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, bpp); + if (MayIntersectFramebuffer(srcBasePtr) || MayIntersectFramebuffer(dstBasePtr)) { + VirtualFramebuffer *dstBuffer = 0; + VirtualFramebuffer *srcBuffer = 0; + FindTransferFramebuffers(dstBuffer, srcBuffer, dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, bpp); - if (dstBuffer && !srcBuffer) { - WARN_LOG_REPORT_ONCE(btu, G3D, "Block transfer upload (not supported) %08x -> %08x", srcBasePtr, dstBasePtr); - if (g_Config.bBlockTransferGPU) { - u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp; - DrawPixels(dstBuffer, dstX, dstY, srcBase, dstBuffer->format, srcStride * bpp, width, height); + if (dstBuffer && !srcBuffer) { + WARN_LOG_REPORT_ONCE(btu, G3D, "Block transfer upload (not supported) %08x -> %08x", srcBasePtr, dstBasePtr); + if (g_Config.bBlockTransferGPU) { + u8 *srcBase = Memory::GetPointerUnchecked(srcBasePtr) + (srcX + srcY * srcStride) * bpp; + DrawPixels(dstBuffer, dstX, dstY, srcBase, dstBuffer->format, srcStride * bpp, width, height); + } } } } diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 1d58a118cc..c2ed32c8b5 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -200,6 +200,16 @@ public: } } + bool MayIntersectFramebuffer(u32 start) { + // Clear the cache/kernel bits. + start = start & 0x3FFFFFFF; + // Most games only have two framebuffers at the start. + if (start >= framebufRangeEnd_ || start < PSP_GetVidMemBase()) { + return false; + } + return true; + } + void NotifyFramebufferCopy(u32 src, u32 dest, int size); void DestroyFramebuf(VirtualFramebuffer *vfb); @@ -261,7 +271,10 @@ private: bool resized_; bool useBufferedRendering_; bool updateVRAM_; - + + // The range of PSP memory that may contain FBOs. So we can skip iterating. + u32 framebufRangeEnd_; + std::vector bvfbs_; // blitting FBOs std::map, FBO *> renderCopies_; diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index bdb4697fd4..f90a01deb8 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -1955,8 +1955,9 @@ void GLES_GPU::InvalidateCacheInternal(u32 addr, int size, GPUInvalidationType t else textureCache_.InvalidateAll(type); - if (type != GPU_INVALIDATE_ALL) + if (type != GPU_INVALIDATE_ALL && framebufferManager_.MayIntersectFramebuffer(addr)) { framebufferManager_.UpdateFromMemory(addr, size, type == GPU_INVALIDATE_SAFE); + } } void GLES_GPU::UpdateMemory(u32 dest, u32 src, int size) {