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;
|
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);
|
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;
|
bool vfbFormatChanged = false;
|
||||||
|
|
||||||
// Find a matching framebuffer
|
// Find a matching framebuffer
|
||||||
VirtualFramebuffer *vfb = nullptr;
|
VirtualFramebuffer *vfb = nullptr;
|
||||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||||
VirtualFramebuffer *v = vfbs_[i];
|
VirtualFramebuffer *v = vfbs_[i];
|
||||||
|
|
||||||
|
const u32 bpp = v->format == GE_FORMAT_8888 ? 4 : 2;
|
||||||
|
|
||||||
if (v->fb_address == params.fb_address) {
|
if (v->fb_address == params.fb_address) {
|
||||||
vfb = v;
|
vfb = v;
|
||||||
// Update fb stride in case it changed
|
// Update fb stride in case it changed
|
||||||
|
@ -302,18 +305,36 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
||||||
vfb->height = drawing_height;
|
vfb->height = drawing_height;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if (v->fb_address < params.fb_address && v->fb_address + v->fb_stride * 4 > params.fb_address) {
|
} else if (v->fb_stride == params.fb_stride && v->format == params.fmt) {
|
||||||
// Possibly a render-to-offset.
|
u32 v_fb_first_line_end_ptr = v->fb_address + v->fb_stride * bpp;
|
||||||
const u32 bpp = v->format == GE_FORMAT_8888 ? 4 : 2;
|
u32 v_fb_end_ptr = v->fb_address + v->fb_stride * v->height * bpp;
|
||||||
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 (params.fb_address > v->fb_address && params.fb_address < v_fb_first_line_end_ptr) {
|
||||||
WARN_LOG_REPORT_ONCE(renderoffset, HLE, "Rendering to framebuffer offset: %08x +%dx%d", v->fb_address, x_offset, 0);
|
const int x_offset = (params.fb_address - v->fb_address) / bpp;
|
||||||
vfb = v;
|
if (x_offset < params.fb_stride && v->height >= drawing_height) {
|
||||||
gstate_c.SetCurRTOffsetX(x_offset);
|
// Pretty certainly a pure render-to-X-offset.
|
||||||
vfb->width = std::max((int)vfb->width, x_offset + drawing_width);
|
WARN_LOG_REPORT_ONCE(renderoffset, HLE, "Rendering to framebuffer offset: %08x +%dx%d", v->fb_address, x_offset, 0);
|
||||||
// To prevent the newSize code from being confused.
|
vfb = v;
|
||||||
drawing_width += x_offset;
|
gstate_c.SetCurRTOffset(x_offset, 0);
|
||||||
break;
|
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);
|
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;
|
vfb->last_frame_render = gpuStats.numFlips;
|
||||||
frameLastFramebufUsed_ = gpuStats.numFlips;
|
frameLastFramebufUsed_ = gpuStats.numFlips;
|
||||||
|
|
|
@ -584,6 +584,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
|
||||||
}
|
}
|
||||||
|
|
||||||
renderX = gstate_c.curRTOffsetX;
|
renderX = gstate_c.curRTOffsetX;
|
||||||
|
renderY = gstate_c.curRTOffsetY;
|
||||||
|
|
||||||
// Scissor
|
// Scissor
|
||||||
int scissorX1 = gstate.getScissorX1();
|
int scissorX1 = gstate.getScissorX1();
|
||||||
|
|
|
@ -633,8 +633,17 @@ std::vector<AttachCandidate> TextureCacheCommon::GetFramebufferCandidates(const
|
||||||
|
|
||||||
if (candidates.size() > 1) {
|
if (candidates.size() > 1) {
|
||||||
bool depth = channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH;
|
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;
|
return candidates;
|
||||||
|
@ -1996,3 +2005,7 @@ void TextureCacheCommon::InvalidateAll(GPUInvalidationType /*unused*/) {
|
||||||
void TextureCacheCommon::ClearNextFrame() {
|
void TextureCacheCommon::ClearNextFrame() {
|
||||||
clearCacheNextFrame_ = true;
|
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
|
#undef IGNORE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: Try to get rid of IGNORE, it doesn't match what we want to do
|
|
||||||
enum class FramebufferMatch {
|
enum class FramebufferMatch {
|
||||||
// Valid, exact match.
|
// Valid, exact match.
|
||||||
VALID = 0,
|
VALID = 0,
|
||||||
|
@ -224,6 +223,8 @@ struct AttachCandidate {
|
||||||
TextureDefinition entry;
|
TextureDefinition entry;
|
||||||
VirtualFramebuffer *fb;
|
VirtualFramebuffer *fb;
|
||||||
FramebufferNotificationChannel channel;
|
FramebufferNotificationChannel channel;
|
||||||
|
|
||||||
|
std::string ToString();
|
||||||
};
|
};
|
||||||
|
|
||||||
class FramebufferManagerCommon;
|
class FramebufferManagerCommon;
|
||||||
|
|
|
@ -606,13 +606,15 @@ struct GPUStateCache {
|
||||||
u32 curRTRenderWidth;
|
u32 curRTRenderWidth;
|
||||||
u32 curRTRenderHeight;
|
u32 curRTRenderHeight;
|
||||||
|
|
||||||
void SetCurRTOffsetX(int off) {
|
void SetCurRTOffset(u32 xoff, u32 yoff) {
|
||||||
if (off != curRTOffsetX) {
|
if (xoff != curRTOffsetX || yoff != curRTOffsetY) {
|
||||||
curRTOffsetX = off;
|
curRTOffsetX = xoff;
|
||||||
|
curRTOffsetY = yoff;
|
||||||
Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
u32 curRTOffsetX;
|
u32 curRTOffsetX;
|
||||||
|
u32 curRTOffsetY;
|
||||||
|
|
||||||
// Set if we are doing hardware bezier/spline.
|
// Set if we are doing hardware bezier/spline.
|
||||||
SubmitType submitType;
|
SubmitType submitType;
|
||||||
|
|
|
@ -1252,3 +1252,8 @@ ULKS46143 = true
|
||||||
ULES00981 = true
|
ULES00981 = true
|
||||||
ULES00982 = true
|
ULES00982 = true
|
||||||
LBSW10345 = true # Some modded version found in our report logs
|
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