Skip to content

Commit

Permalink
Merge pull request #15717 from hrydgard/render-target-y-offset
Browse files Browse the repository at this point in the history
Allows "merging" render targets that overlap on the Y axis. Fixes Juiced 2
  • Loading branch information
hrydgard authored Jul 24, 2022
2 parents c5d1d11 + 80f0f90 commit 3c88183
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 * 4; // This should be * bpp, but leaving like this until after 1.13 to be safe. The God of War games use this for shadows.
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 3c88183

Please sign in to comment.