Skip to content

Commit

Permalink
Allows "merging" render targets that overlap on the Y access. Fixes #…
Browse files Browse the repository at this point in the history
…7295 (Juiced 2)

To be safe, gating this behind the related AllowLargeFBTextureOffsets,
which is also required for the effect to work.

Additionally, fixes the offset check for X offsets, which I guess is a
very small risk.
  • Loading branch information
hrydgard committed Jul 24, 2022
1 parent d2a3918 commit 04a85b1
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 20 deletions.
49 changes: 35 additions & 14 deletions GPU/Common/FramebufferManagerCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
}
}
}
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions GPU/Common/GPUStateUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
}

renderX = gstate_c.curRTOffsetX;
renderY = gstate_c.curRTOffsetY;

// Scissor
int scissorX1 = gstate.getScissorX1();
Expand Down
17 changes: 15 additions & 2 deletions GPU/Common/TextureCacheCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,17 @@ std::vector<AttachCandidate> 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;
Expand Down Expand Up @@ -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");
}
3 changes: 2 additions & 1 deletion GPU/Common/TextureCacheCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ typedef std::map<u64, std::unique_ptr<TexCacheEntry>> 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,
Expand All @@ -224,6 +223,8 @@ struct AttachCandidate {
TextureDefinition entry;
VirtualFramebuffer *fb;
FramebufferNotificationChannel channel;

std::string ToString();
};

class FramebufferManagerCommon;
Expand Down
8 changes: 5 additions & 3 deletions GPU/GPUState.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions assets/compat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 04a85b1

Please sign in to comment.