Allows "merging" render targets that overlap on the Y access. Fixes #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.
This commit is contained in:
parent
d2a3918f5f
commit
04a85b1da0
6 changed files with 63 additions and 20 deletions
|
@ -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,19 +305,37 @@ 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;
|
||||
} 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 (v->format == params.fmt && v->fb_stride == params.fb_stride && x_offset < params.fb_stride && v->height >= drawing_height) {
|
||||
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.SetCurRTOffsetX(x_offset);
|
||||
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;
|
||||
|
|
|
@ -584,6 +584,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
|||
}
|
||||
|
||||
renderX = gstate_c.curRTOffsetX;
|
||||
renderY = gstate_c.curRTOffsetY;
|
||||
|
||||
// Scissor
|
||||
int scissorX1 = gstate.getScissorX1();
|
||||
|
|
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -224,6 +223,8 @@ struct AttachCandidate {
|
|||
TextureDefinition entry;
|
||||
VirtualFramebuffer *fb;
|
||||
FramebufferNotificationChannel channel;
|
||||
|
||||
std::string ToString();
|
||||
};
|
||||
|
||||
class FramebufferManagerCommon;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue