diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index ff139af723..6926d0cc67 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -123,7 +123,7 @@ inline u16 BGRA8888toRGBA4444(u32 px) { return ((px >> 20) & 0x000F) | ((px >> 8) & 0x00F0) | ((px << 4) & 0x0F00) | ((px >> 16) & 0xF000); } -void ConvertFromRGBA8888(u8 *dst, const u8 *src, u32 stride, u32 height, GEBufferFormat format); +void ConvertFromRGBA8888(u8 *dst, const u8 *src, u32 stride, u32 width, u32 height, GEBufferFormat format); void CenterRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH) { @@ -1562,49 +1562,83 @@ void FramebufferManager::BlitFramebuffer_(VirtualFramebuffer *dst, int dstX, int // TODO: SSE/NEON // Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :) -void ConvertFromRGBA8888(u8 *dst, const u8 *src, u32 stride, u32 height, GEBufferFormat format) { +void ConvertFromRGBA8888(u8 *dst, const u8 *src, u32 stride, u32 width, u32 height, GEBufferFormat format) { + // Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP. + const u32 *src32 = (const u32 *)src; + if (format == GE_FORMAT_8888) { + u32 *dst32 = (u32 *)dst; if (src == dst) { return; } else if (UseBGRA8888()) { - u32 numPixels = height * stride; - ConvertBGRA8888ToRGBA8888((u32 *)dst, (const u32 *)src, numPixels); + for (u32 y = 0; y < height; ++y) { + ConvertBGRA8888ToRGBA8888(dst32, src32, width); + src32 += stride; + dst32 += stride; + } } else { // Here let's assume they don't intersect - memcpy(dst, src, stride * height * 4); + for (u32 y = 0; y < height; ++y) { + memcpy(dst32, src32, width * 4); + src32 += stride; + dst32 += stride; + } } } else { // But here it shouldn't matter if they do intersect int size = height * stride; - const u32 *src32 = (const u32 *)src; u16 *dst16 = (u16 *)dst; switch (format) { case GE_FORMAT_565: // BGR 565 if (UseBGRA8888()) { - for (int i = 0; i < size; i++) { - dst16[i] = BGRA8888toRGB565(src32[i]); + for (u32 y = 0; y < height; ++y) { + for (u32 x = 0; x < width; ++x) { + dst16[x] = BGRA8888toRGB565(src32[x]); + } + src32 += stride; + dst16 += stride; } } else { - for (int i = 0; i < size; i++) { - dst16[i] = RGBA8888toRGB565(src32[i]); + for (u32 y = 0; y < height; ++y) { + for (u32 x = 0; x < width; ++x) { + dst16[x] = RGBA8888toRGB565(src32[x]); + } + src32 += stride; + dst16 += stride; } } break; case GE_FORMAT_5551: // ABGR 1555 if (UseBGRA8888()) { - ConvertBGRA8888ToRGBA5551(dst16, src32, size); + for (u32 y = 0; y < height; ++y) { + ConvertBGRA8888ToRGBA5551(dst16, src32, width); + src32 += stride; + dst16 += stride; + } } else { - ConvertRGBA8888ToRGBA5551(dst16, src32, size); + for (u32 y = 0; y < height; ++y) { + ConvertRGBA8888ToRGBA5551(dst16, src32, width); + src32 += stride; + dst16 += stride; + } } break; case GE_FORMAT_4444: // ABGR 4444 if (UseBGRA8888()) { - for (int i = 0; i < size; i++) { - dst16[i] = BGRA8888toRGBA4444(src32[i]); + for (u32 y = 0; y < height; ++y) { + for (u32 x = 0; x < width; ++x) { + dst16[x] = BGRA8888toRGBA4444(src32[x]); + } + src32 += stride; + dst16 += stride; } } else { - for (int i = 0; i < size; i++) { - dst16[i] = RGBA8888toRGBA4444(src32[i]); + for (u32 y = 0; y < height; ++y) { + for (u32 x = 0; x < width; ++x) { + dst16[x] = RGBA8888toRGBA4444(src32[x]); + } + src32 += stride; + dst16 += stride; } } break; @@ -1679,7 +1713,7 @@ void FramebufferManager::PackFramebufferAsync_(VirtualFramebuffer *vfb) { if (useCPU || (UseBGRA8888() && pbo.format == GE_FORMAT_8888)) { u8 *dst = Memory::GetPointer(pbo.fb_address); - ConvertFromRGBA8888(dst, packed, pbo.stride, pbo.height, pbo.format); + ConvertFromRGBA8888(dst, packed, pbo.stride, pbo.stride, pbo.height, pbo.format); } else { // We don't need to convert, GPU already did (or should have) Memory::Memcpy(pbo.fb_address, packed, pbo.size); @@ -1815,6 +1849,7 @@ void FramebufferManager::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, in GLubyte *packed = 0; bool convert = vfb->format != GE_FORMAT_8888 || UseBGRA8888(); + const int dstBpp = vfb->format == GE_FORMAT_8888 ? 4 : 2; if (!convert) { packed = (GLubyte *)Memory::GetPointer(fb_address); @@ -1843,7 +1878,8 @@ void FramebufferManager::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, in // LogReadPixelsError(glGetError()); if (convert) { - ConvertFromRGBA8888(Memory::GetPointer(fb_address + byteOffset), packed + byteOffset, vfb->fb_stride, h, vfb->format); + int dstByteOffset = y * vfb->fb_stride * dstBpp; + ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), packed + byteOffset, vfb->fb_stride, vfb->width, h, vfb->format); } }