diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index ce2f219ba..fc925b575 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -1231,7 +1231,7 @@ void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool s } vfb->memoryUpdated = true; - BlitFramebuffer_(nvfb, x, y, vfb, x, y, w, h); + BlitFramebuffer_(nvfb, x, y, vfb, x, y, w, h, 0); // PackFramebufferSync_() - Synchronous pixel data transfer using glReadPixels // PackFramebufferAsync_() - Asynchronous pixel data transfer using glReadPixels with PBOs @@ -1254,7 +1254,7 @@ void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool s } // TODO: If dimensions are the same, we can use glCopyImageSubData. -void FramebufferManager::BlitFramebuffer_(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h) { +void FramebufferManager::BlitFramebuffer_(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) { if (!dst->fbo) { ERROR_LOG_REPORT_ONCE(dstfbozero, SCEGE, "BlitFramebuffer_: dst->fbo == 0"); fbo_unbind(); @@ -1278,17 +1278,37 @@ void FramebufferManager::BlitFramebuffer_(VirtualFramebuffer *dst, int dstX, int bool useNV = !gl_extensions.GLES3; #endif + float srcXFactor = (float)src->renderWidth / (float)src->bufferWidth; + float srcYFactor = (float)src->renderHeight / (float)src->bufferHeight; + int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; + if (srcBpp != bpp && bpp != 0) { + srcXFactor = (srcXFactor * bpp) / srcBpp; + } + int srcX1 = srcX * srcXFactor; + int srcX2 = (srcX + w) * srcXFactor; + int srcY2 = src->renderHeight - (h + srcY) * srcYFactor; + int srcY1 = srcY2 + h * srcYFactor; + + float dstXFactor = (float)dst->renderWidth / (float)dst->bufferWidth; + float dstYFactor = (float)dst->renderHeight / (float)dst->bufferHeight; + int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; + if (dstBpp != bpp && bpp != 0) { + dstXFactor = (dstXFactor * bpp) / dstBpp; + } + int dstX1 = dstX * dstXFactor; + int dstX2 = (dstX + w) * dstXFactor; + int dstY2 = dst->renderHeight - (h + dstY) * dstYFactor; + int dstY1 = dstY2 + h * dstYFactor; + #ifdef MAY_HAVE_GLES3 - fbo_bind_for_read(src->fbo); - if (!useNV) { - // Render buffer is upside down , swap srcY0 with srcY1 to flip it correct - glBlitFramebuffer(0, src->renderHeight, src->renderWidth, 0, 0, 0, dst->width, dst->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } + fbo_bind_for_read(src->fbo); + if (!useNV) { + glBlitFramebuffer(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } #if defined(ANDROID) // We only support this extension on Android, it's not even available on PC. - else if (gl_extensions.NV_framebuffer_blit) { - // Render buffer is upside down , swap srcY0 with srcY1 to flip it correct - glBlitFramebufferNV(0, src->renderHeight, src->renderWidth, 0, 0, 0, dst->width, dst->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } + else if (gl_extensions.NV_framebuffer_blit) { + glBlitFramebufferNV(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } #endif // defined(ANDROID) #endif // MAY_HAVE_GLES3 @@ -1803,7 +1823,7 @@ void FramebufferManager::NotifyFramebufferCopy(u32 src, u32 dst, int size) { // Just do the blit! // TODO: Possibly take bpp into account somehow if games are doing really crazy things? // if (g_Config.bBlockTransferGPU) { - // BlitFramebuffer_(dstBuffer, 0, 0, srcBuffer, 0, 0, srcBuffer->width, srcBuffer->height); + // BlitFramebuffer_(dstBuffer, 0, 0, srcBuffer, 0, 0, srcBuffer->width, srcBuffer->height, 0); // } } } else if (dstBuffer) { @@ -1841,6 +1861,7 @@ bool FramebufferManager::NotifyBlockTransfer(u32 dstBasePtr, int dstStride, int if (((backBuffer != 0 && dstBasePtr == backBuffer) || (displayBuffer != 0 && dstBasePtr == displayBuffer)) && dstStride == 512 && height == 272) { + // TODO: Use displayFormat_ instead of GE_FORMAT_8888? DrawFramebuffer(Memory::GetPointerUnchecked(dstBasePtr), GE_FORMAT_8888, 512, false); } @@ -1848,10 +1869,14 @@ bool FramebufferManager::NotifyBlockTransfer(u32 dstBasePtr, int dstStride, int VirtualFramebuffer *srcBuffer = 0; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - if (MaskedEqual(vfb->fb_address, dstBasePtr)) { + const u32 vfb_address = 0x04000000 | vfb->fb_address; + const u32 vfb_size = vfb->fb_stride * vfb->height * (vfb->format == GE_FORMAT_8888 ? 4 : 2); + if (vfb_address <= dstBasePtr && dstBasePtr < vfb_address + vfb_size) { + dstY += (dstBasePtr - vfb_address) / (dstStride * bpp); dstBuffer = vfb; } - if (MaskedEqual(vfb->fb_address, srcBasePtr)) { + if (vfb_address <= srcBasePtr && srcBasePtr < vfb_address + vfb_size) { + srcY += (srcBasePtr - vfb_address) / (srcStride * bpp); srcBuffer = vfb; } } @@ -1864,7 +1889,7 @@ bool FramebufferManager::NotifyBlockTransfer(u32 dstBasePtr, int dstStride, int // Just do the blit! // TODO: Possibly take bpp into account somehow if games are doing really crazy things? if (g_Config.bBlockTransferGPU) { - BlitFramebuffer_(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, width, height); + BlitFramebuffer_(dstBuffer, dstX, dstY, srcBuffer, srcX, srcY, width, height, bpp); return true; // No need to actually do the memory copy behind, probably. } } diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index dd11fdafe..a3ebf726c 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -227,7 +227,7 @@ private: VirtualFramebuffer *currentRenderVfb_; // Used by ReadFramebufferToMemory and later framebuffer block copies - void BlitFramebuffer_(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h); + void BlitFramebuffer_(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp); #ifndef USING_GLES2 void PackFramebufferAsync_(VirtualFramebuffer *vfb); #endif