diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index f5ea895bd5d2..03f6f370b653 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -266,13 +266,16 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame int drawing_width, drawing_height; EstimateDrawingSize(params.fb_address, params.fmt, params.viewportWidth, params.viewportHeight, params.regionWidth, params.regionHeight, params.scissorWidth, params.scissorHeight, std::max(params.fb_stride, 4), drawing_width, drawing_height); - gstate_c.SetCurRTOffsetX(0); + gstate_c.SetCurRTOffset(0, 0); bool vfbFormatChanged = false; // Find a matching framebuffer VirtualFramebuffer *vfb = nullptr; for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *v = vfbs_[i]; + + const u32 bpp = v->format == GE_FORMAT_8888 ? 4 : 2; + if (v->fb_address == params.fb_address) { vfb = v; // Update fb stride in case it changed @@ -302,18 +305,36 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->height = drawing_height; } break; - } else if (v->fb_address < params.fb_address && v->fb_address + v->fb_stride * 4 > params.fb_address) { - // Possibly a render-to-offset. - const u32 bpp = v->format == GE_FORMAT_8888 ? 4 : 2; - const int x_offset = (params.fb_address - v->fb_address) / bpp; - if (v->format == params.fmt && v->fb_stride == params.fb_stride && x_offset < params.fb_stride && v->height >= drawing_height) { - WARN_LOG_REPORT_ONCE(renderoffset, HLE, "Rendering to framebuffer offset: %08x +%dx%d", v->fb_address, x_offset, 0); - vfb = v; - gstate_c.SetCurRTOffsetX(x_offset); - vfb->width = std::max((int)vfb->width, x_offset + drawing_width); - // To prevent the newSize code from being confused. - drawing_width += x_offset; - break; + } else if (v->fb_stride == params.fb_stride && v->format == params.fmt) { + u32 v_fb_first_line_end_ptr = v->fb_address + v->fb_stride * bpp; + u32 v_fb_end_ptr = v->fb_address + v->fb_stride * v->height * bpp; + + if (params.fb_address > v->fb_address && params.fb_address < v_fb_first_line_end_ptr) { + const int x_offset = (params.fb_address - v->fb_address) / bpp; + if (x_offset < params.fb_stride && v->height >= drawing_height) { + // Pretty certainly a pure render-to-X-offset. + WARN_LOG_REPORT_ONCE(renderoffset, HLE, "Rendering to framebuffer offset: %08x +%dx%d", v->fb_address, x_offset, 0); + vfb = v; + gstate_c.SetCurRTOffset(x_offset, 0); + vfb->width = std::max((int)vfb->width, x_offset + drawing_width); + // To prevent the newSize code from being confused. + drawing_width += x_offset; + break; + } + } else if (params.fb_address > v->fb_address && params.fb_address < v_fb_end_ptr && PSP_CoreParameter().compat.flags().AllowLargeFBTextureOffsets) { + if (params.fb_address % params.fb_stride == v->fb_address % params.fb_stride) { + // Framebuffers are overlapping on the Y axis. + const int y_offset = (params.fb_address - v->fb_address) / (bpp * params.fb_stride); + + vfb = v; + gstate_c.SetCurRTOffset(0, y_offset); + // To prevent the newSize code from being confused. + drawing_height += y_offset; + break; + } + } else { + // We ignore this match. + // TODO: We can allow X/Y overlaps too, but haven't seen any so safer to not. } } } @@ -386,7 +407,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame SetColorUpdated(vfb, skipDrawReason); - INFO_LOG(FRAMEBUF, "Creating FBO for %08x (z: %08x) : %i x %i x %i", vfb->fb_address, vfb->z_address, vfb->width, vfb->height, vfb->format); + INFO_LOG(FRAMEBUF, "Creating FBO for %08x (z: %08x) : %d x %d x %s", vfb->fb_address, vfb->z_address, vfb->width, vfb->height, GeBufferFormatToString(vfb->format)); vfb->last_frame_render = gpuStats.numFlips; frameLastFramebufUsed_ = gpuStats.numFlips; diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 8b27be2d34b5..1f0841d84f88 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -584,6 +584,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo } renderX = gstate_c.curRTOffsetX; + renderY = gstate_c.curRTOffsetY; // Scissor int scissorX1 = gstate.getScissorX1(); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index b45ea56299cd..c4a03dfc0c22 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -633,8 +633,17 @@ std::vector TextureCacheCommon::GetFramebufferCandidates(const if (candidates.size() > 1) { bool depth = channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH; - WARN_LOG_REPORT_ONCE(multifbcandidate, G3D, "GetFramebufferCandidates(%s): Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s)", - depth ? "DEPTH" : "COLOR", (int)candidates.size(), entry.addr, texAddrOffset, dimWidth(entry.dim), dimHeight(entry.dim), entry.bufw, GeTextureFormatToString(entry.format)); + + std::string cands; + for (auto &candidate : candidates) { + cands += candidate.ToString() + " "; + } + + WARN_LOG_REPORT_ONCE(multifbcandidate, G3D, "GetFramebufferCandidates(%s): Multiple (%d) candidate framebuffers. First will be chosen. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", + depth ? "DEPTH" : "COLOR", (int)candidates.size(), + entry.addr, texAddrOffset, dimWidth(entry.dim), dimHeight(entry.dim), entry.bufw, GeTextureFormatToString(entry.format), + cands.c_str() + ); } return candidates; @@ -1996,3 +2005,7 @@ void TextureCacheCommon::InvalidateAll(GPUInvalidationType /*unused*/) { void TextureCacheCommon::ClearNextFrame() { clearCacheNextFrame_ = true; } + +std::string AttachCandidate::ToString() { + return StringFromFormat("[C:%08x/%d Z:%08x/%d X:%d Y:%d reint: %s]", this->fb->fb_address, this->fb->fb_stride, this->fb->z_address, this->fb->z_stride, this->match.xOffset, this->match.yOffset, this->match.reinterpret ? "true" : "false"); +} diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 7fb47e25caa2..3464a6784140 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -203,7 +203,6 @@ typedef std::map> TexCache; #undef IGNORE #endif -// TODO: Try to get rid of IGNORE, it doesn't match what we want to do enum class FramebufferMatch { // Valid, exact match. VALID = 0, @@ -224,6 +223,8 @@ struct AttachCandidate { TextureDefinition entry; VirtualFramebuffer *fb; FramebufferNotificationChannel channel; + + std::string ToString(); }; class FramebufferManagerCommon; diff --git a/GPU/GPUState.h b/GPU/GPUState.h index a4e157448d77..9026cfc24f18 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -606,13 +606,15 @@ struct GPUStateCache { u32 curRTRenderWidth; u32 curRTRenderHeight; - void SetCurRTOffsetX(int off) { - if (off != curRTOffsetX) { - curRTOffsetX = off; + void SetCurRTOffset(u32 xoff, u32 yoff) { + if (xoff != curRTOffsetX || yoff != curRTOffsetY) { + curRTOffsetX = xoff; + curRTOffsetY = yoff; Dirty(DIRTY_VIEWPORTSCISSOR_STATE); } } u32 curRTOffsetX; + u32 curRTOffsetY; // Set if we are doing hardware bezier/spline. SubmitType submitType; diff --git a/assets/compat.ini b/assets/compat.ini index 9d582ae1bdc5..24f5ecbf0e88 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1252,3 +1252,8 @@ ULKS46143 = true ULES00981 = true ULES00982 = true LBSW10345 = true # Some modded version found in our report logs + +# Juiced 2 bloom effect (see #7295) +ULES00928 = true +ULUS10312 = true +ULKS46154 = true