diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 04f081cf05..ae4cafc253 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2701,6 +2701,16 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst return true; // Skip the memory copy. } + // If the formats mismatch badly, we need a resolve. + if (srcRect.vfb && dstRect.vfb && srcRect.channel == RASTER_COLOR && dstRect.channel == RASTER_COLOR && srcRect.vfb->fb_format != dstRect.vfb->fb_format) { + WARN_LOG_N_TIMES(dstnotsrc, 5, Log::G3D, "Mismatched color format requiring reinterpret during block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d %s) -> %08x (x:%d y:%d stride:%d %s)", + width, height, bpp, + srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride, GeBufferFormatToString(srcRect.vfb->fb_format), + dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride, GeBufferFormatToString(dstRect.vfb->fb_format)); + // Seen in Silent Hill: Shattered Memories. + srcRect.vfb = ResolveFramebufferColorToFormat(srcRect.vfb, dstRect.vfb->fb_format); + } + // Straightforward blit between two same-format framebuffers. if (srcRect.vfb && srcRect.channel == dstRect.channel && srcRect.vfb->Format(srcRect.channel) == dstRect.vfb->Format(dstRect.channel)) { WARN_LOG_N_TIMES(dstnotsrc, 5, Log::G3D, "Inter-buffer %s block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d %s) -> %08x (x:%d y:%d stride:%d %s)", @@ -2728,6 +2738,40 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst WARN_LOG_N_TIMES(blockformat, 5, Log::G3D, "Mismatched buffer formats in block transfer: %s->%s (%dx%d)", GeBufferFormatToString(srcRect.vfb->Format(srcRect.channel)), GeBufferFormatToString(dstRect.vfb->Format(dstRect.channel)), width, height); + + VirtualFramebuffer *src = srcRect.vfb, *dst = dstRect.vfb; + float scaleFactorX = 1.0f; + Draw2DPipeline *pipeline = GetReinterpretPipeline(src->fb_format, dst->fb_format, &scaleFactorX); + + if (pipeline) { + const char *pass_name = reinterpretStrings[(int)src->fb_format][(int)dst->fb_format]; + + int srcWidth = width * src->renderScaleFactor; + int srcHeight = height * src->renderScaleFactor; + int dstWidth = width * dst->renderScaleFactor; + int dstHeight = height * dst->renderScaleFactor; + + int srcX1 = srcX * src->renderScaleFactor; + int srcY1 = srcY * src->renderScaleFactor; + int srcX2 = srcX1 + srcWidth; + int srcY2 = srcY1 + srcHeight; + + int dstX1 = dstX * dst->renderScaleFactor; + int dstY1 = dstY * dst->renderScaleFactor; + int dstX2 = dstX1 + dstWidth; + int dstY2 = dstY1 + dstHeight; + + srcX1 /= scaleFactorX; + srcX2 /= scaleFactorX; + + gpuStats.numReinterpretCopies++; + FlushBeforeCopy(); + BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, + dst->fbo, dstX1, dstY1, dstX2, dstY2, false, dst->renderScaleFactor, pipeline, pass_name); + RebindFramebuffer("RebindFramebuffer - Inter-buffer block transfer with mismatched formats"); + SetColorUpdated(dst, skipDrawReason); + return true; + } } // TODO diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 75e327b5b8..858246552b 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1135,8 +1135,17 @@ bool TextureCacheCommon::MatchFramebuffer( } return true; } - } else if (IsClutFormat((GETextureFormat)(entry.format)) || IsDXTFormat((GETextureFormat)(entry.format))) { - WARN_LOG_ONCE(fourEightBit, Log::G3D, "%s texture format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); + } else if (IsClutFormat((GETextureFormat)(entry.format))) { + WARN_LOG_ONCE(nomatch_clut, Log::G3D, "%s texture format not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); + // Seen in Silent Hill: Shattered Memories (#6265). + if (entry.format == GE_TFMT_CLUT32 && fb_format != GE_FORMAT_8888) { + matchInfo->reinterpret = true; + matchInfo->reinterpretTo = GE_FORMAT_8888; + return true; + } + return false; + } else if (IsDXTFormat((GETextureFormat)(entry.format))) { + WARN_LOG_ONCE(nomatch_dxt, Log::G3D, "%s texture format (DXT!) not matching framebuffer of format %s at %08x/%d", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address, fb_stride); return false; }