Split the framebuffer in Killzone, with a compatibility flag.

Greatly improves performance.

See issue #6207
This commit is contained in:
Henrik Rydgård 2022-08-30 19:36:08 +02:00
parent daa62beb39
commit 987bfc79ef
8 changed files with 56 additions and 21 deletions

View file

@ -96,6 +96,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "AllowLargeFBTextureOffsets", &flags_.AllowLargeFBTextureOffsets);
CheckSetting(iniFile, gameID, "AtracLoopHack", &flags_.AtracLoopHack);
CheckSetting(iniFile, gameID, "DeswizzleDepth", &flags_.DeswizzleDepth);
CheckSetting(iniFile, gameID, "SplitFramebufferMargin", &flags_.SplitFramebufferMargin);
}
void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {

View file

@ -86,6 +86,7 @@ struct CompatFlags {
bool AllowLargeFBTextureOffsets;
bool AtracLoopHack;
bool DeswizzleDepth;
bool SplitFramebufferMargin;
};
class IniFile;

View file

@ -341,7 +341,7 @@ void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPU
}
}
VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const FramebufferHeuristicParams &params, u32 skipDrawReason) {
VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(FramebufferHeuristicParams &params, u32 skipDrawReason) {
gstate_c.Clean(DIRTY_FRAMEBUF);
// Collect all parameters. This whole function has really become a cesspool of heuristics...
@ -360,6 +360,19 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
WARN_LOG_ONCE(color_equal_z, G3D, "Framebuffer bound with color addr == z addr, likely will not use Z in this pass: %08x", params.fb_address);
}
if (PSP_CoreParameter().compat.flags().SplitFramebufferMargin && params.fb_format == GE_FORMAT_8888) {
// Detect whether we're rendering to the margin.
if (params.scissorWidth == 32 || params.scissorWidth == 512) {
gstate_c.SetCurRTOffset(-480, 0);
// Modify the fb_address and z_address too to avoid matching below.
params.fb_address += 480 * 4;
params.z_address += 480 * 2;
drawing_width = 32;
} else if (params.scissorWidth == 480) {
drawing_width = 480;
}
}
// Find a matching framebuffer.
VirtualFramebuffer *vfb = nullptr;
for (auto v : vfbs_) {
@ -385,7 +398,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
vfb->height = drawing_height;
}
break;
} else if (v->fb_stride == params.fb_stride && v->fb_format == params.fb_format) {
} else if (v->fb_stride == params.fb_stride && v->fb_format == params.fb_format && !PSP_CoreParameter().compat.flags().SplitFramebufferMargin) {
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;

View file

@ -279,7 +279,7 @@ public:
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format);
void DestroyFramebuf(VirtualFramebuffer *v);
VirtualFramebuffer *DoSetRenderFrameBuffer(const FramebufferHeuristicParams &params, u32 skipDrawReason);
VirtualFramebuffer *DoSetRenderFrameBuffer(FramebufferHeuristicParams &params, u32 skipDrawReason);
VirtualFramebuffer *SetRenderFrameBuffer(bool framebufChanged, int skipDrawReason) {
// Inlining this part since it's so frequent.
if (!framebufChanged && currentRenderVfb_) {

View file

@ -636,16 +636,18 @@ std::vector<AttachCandidate> TextureCacheCommon::GetFramebufferCandidates(const
}
if (candidates.size() > 1) {
std::string cands;
for (auto &candidate : candidates) {
cands += candidate.ToString() + "\n";
}
if (Reporting::ShouldLogNTimes("multifbcandidate", 5)) {
std::string cands;
for (auto &candidate : candidates) {
cands += candidate.ToString() + "\n";
}
WARN_LOG_REPORT_ONCE(multifbcandidate, G3D, "GetFramebufferCandidates: Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s",
(int)candidates.size(),
entry.addr, texAddrOffset, dimWidth(entry.dim), dimHeight(entry.dim), entry.bufw, GeTextureFormatToString(entry.format),
cands.c_str()
);
WARN_LOG_N_TIMES(multifbcandidate, 5, G3D, "GetFramebufferCandidates: Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s",
(int)candidates.size(),
entry.addr, texAddrOffset, dimWidth(entry.dim), dimHeight(entry.dim), entry.bufw, GeTextureFormatToString(entry.format),
cands.c_str()
);
}
}
return candidates;
@ -675,6 +677,10 @@ int TextureCacheCommon::GetBestCandidateIndex(const std::vector<AttachCandidate>
relevancy -= 2;
}
if (candidate.fb == framebufferManager_->GetCurrentRenderVFB()) {
continue;
}
if (relevancy > bestRelevancy) {
bestRelevancy = relevancy;
bestIndex = i;
@ -928,12 +934,17 @@ bool TextureCacheCommon::MatchFramebuffer(
(fb_format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT32) ||
(fb_format != GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT16);
const u32 bitOffset = (texaddr - addr) * 8;
const int bitOffset = (texaddr - addr) * 8;
if (bitOffset != 0) {
const u32 pixelOffset = bitOffset / std::max(1U, (u32)textureBitsPerPixel[entry.format]);
const int pixelOffset = bitOffset / (int)std::max(1U, (u32)textureBitsPerPixel[entry.format]);
matchInfo->yOffset = entry.bufw == 0 ? 0 : pixelOffset / entry.bufw;
matchInfo->xOffset = entry.bufw == 0 ? 0 : pixelOffset % entry.bufw;
if (pixelOffset > 0) {
matchInfo->yOffset = entry.bufw == 0 ? 0 : pixelOffset / (int)entry.bufw;
matchInfo->xOffset = entry.bufw == 0 ? 0 : pixelOffset % (int)entry.bufw;
} else if (pixelOffset < 0) {
matchInfo->yOffset = entry.bufw == 0 ? 0 : pixelOffset / (int)entry.bufw;
matchInfo->xOffset = entry.bufw == 0 ? 0 : -(-pixelOffset % (int)entry.bufw);
}
}
if (matchInfo->yOffset + minSubareaHeight >= framebuffer->height) {

View file

@ -209,8 +209,8 @@ typedef std::map<u64, std::unique_ptr<TexCacheEntry>> TexCache;
#endif
struct FramebufferMatchInfo {
u32 xOffset;
u32 yOffset;
int xOffset;
int yOffset;
bool reinterpret;
GEBufferFormat reinterpretTo;
};

View file

@ -621,15 +621,15 @@ struct GPUStateCache {
u32 curRTRenderWidth;
u32 curRTRenderHeight;
void SetCurRTOffset(u32 xoff, u32 yoff) {
void SetCurRTOffset(int xoff, int yoff) {
if (xoff != curRTOffsetX || yoff != curRTOffsetY) {
curRTOffsetX = xoff;
curRTOffsetY = yoff;
Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
}
}
u32 curRTOffsetX;
u32 curRTOffsetY;
int curRTOffsetX;
int curRTOffsetY;
// Set if we are doing hardware bezier/spline.
SubmitType submitType;

View file

@ -1256,3 +1256,12 @@ UCKS45048 = true
UCJS18030 = true
UCJS18047 = true
NPJG00015 = true
[SplitFramebufferMargin]
# Killzone: Liberation (see issue #6207)
UCES00279 = true
UCKS45041 = true
UCUS98646 = true
UCET00278 = true
UCUS98670 = true
UCUS98646 = true