mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Stop stacking duplicate video entries, and stop hashing video textures
NotifyWriteFormattedFromMemory appends to videos_ unconditionally. A game blitting its decoded frame to the display buffer does that every displayed frame while it waits for the next one to decode, so the same two or three addresses come back over and over: Death Jr pushes 733 entries where there are two distinct buffers, Tekken 6 around 53,000 where there are three. IsVideo() walks that vector linearly on every texture. Refresh the matching entry instead of appending a new one - Death Jr now holds 2 entries and Tekken 6 holds 18, peak size 2 and 3. The other half is the two TODOs that were already sitting there. A video texture is new every frame by definition, so re-hashing it only confirms what the VIDEO flag already said, and the secondary cache has nothing to offer a frame that will never recur. Skip both, and with them the secondary lookup that would otherwise key off a hash we no longer compute. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
ffc32d02fe
commit
14bfd332dc
3 files changed
+28
-8
No files matched your search
@@ -153,6 +153,7 @@ void TextureCacheCommon::StartFrame() {
|
||||
gpuStats.perFrame.numReplacerTrackedTex = replacer_.GetNumTrackedTextures();
|
||||
gpuStats.perFrame.numCachedReplacedTextures = replacer_.GetNumCachedReplacedTextures();
|
||||
}
|
||||
gpuStats.perFrame.numVideoTextures = (int)videos_.size();
|
||||
|
||||
if (texelsScaledThisFrame_) {
|
||||
VERBOSE_LOG(Log::TexCache, "Scaled %d texels", texelsScaledThisFrame_);
|
||||
@@ -710,8 +711,12 @@ TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
_dbg_assert_(h == gstate.getTextureHeight(0));
|
||||
_dbg_assert_(entry->addr == texaddr);
|
||||
UpdateMaxSeenV(entry, gstate.isModeThrough());
|
||||
const u32 newFullHash = ComputeTextureHash(replacer_, entry->addr, entry->bufw, w, h, swizzled, entry);
|
||||
if (newFullHash != entry->fullhash) {
|
||||
// A video texture is new every frame by definition, so hashing it only confirms what the
|
||||
// VIDEO flag already said. The replacer is the one thing that still wants the hash, and
|
||||
// only when it has been told to replace video.
|
||||
const bool skipHash = isVideo && !(replacer_.Enabled() && replacer_.AllowVideo());
|
||||
const u32 newFullHash = skipHash ? 0 : ComputeTextureHash(replacer_, entry->addr, entry->bufw, w, h, swizzled, entry);
|
||||
if (skipHash || newFullHash != entry->fullhash) {
|
||||
// The texture changed. Throw it in the secondary cache. Then we'll create a new entry later.
|
||||
gpuStats.perFrame.numTexturesChanged++;
|
||||
if (!isVideo) {
|
||||
@@ -765,7 +770,9 @@ TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
// Now, look for the new hash in the secondary cache.
|
||||
// If we find it, we can use that instead of building a new texture. We then pull it out from
|
||||
// the secondary cache and move it to the main cache.
|
||||
TexCache::iterator secondIterNew = secondCache_.find(secondKeyNew);
|
||||
// Without a hash there is nothing to look up by, and a frame that will never recur has
|
||||
// nothing to gain from the secondary cache anyway.
|
||||
TexCache::iterator secondIterNew = skipHash ? secondCache_.end() : secondCache_.find(secondKeyNew);
|
||||
if (secondIterNew != secondCache_.end()) {
|
||||
// Found it, but does it match our current params? If not, abort.
|
||||
if (secondIterNew->second->MatchesProperties(dim, texFormat, maxLevel)) {
|
||||
@@ -904,7 +911,8 @@ TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
if (clutInShader) {
|
||||
entry->status |= TexStatus::CLUT8_INDEXED;
|
||||
}
|
||||
if (IsVideo(entry->addr)) {
|
||||
const bool isVideo = IsVideo(entry->addr);
|
||||
if (isVideo) {
|
||||
entry->status |= TexStatus::VIDEO;
|
||||
}
|
||||
|
||||
@@ -912,8 +920,8 @@ TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
gstate_c.curTextureHeight = h;
|
||||
UpdateMaxSeenV(entry, gstate.isModeThrough()); // Critical to update this before hashing! As it's used to decide the hash range.
|
||||
|
||||
// TODO: Avoid hashing known video textures.
|
||||
if (!(entry->status & TexStatus::IS_PPGE_ATLAS)) {
|
||||
const bool skipHash = isVideo && !(replacer_.Enabled() && replacer_.AllowVideo());
|
||||
if (!(entry->status & TexStatus::IS_PPGE_ATLAS) && !skipHash) {
|
||||
entry->fullhash = ComputeTextureHash(replacer_, entry->addr, entry->bufw, w, h, swizzled, entry);
|
||||
}
|
||||
|
||||
@@ -1501,6 +1509,16 @@ void TextureCacheCommon::NotifyConfigChanged() {
|
||||
|
||||
void TextureCacheCommon::NotifyWriteFormattedFromMemory(u32 addr, int size, int width, GEBufferFormat fmt) {
|
||||
addr &= 0x3FFFFFFF;
|
||||
// A game blits its video frame every displayed frame while waiting for the next one, so the
|
||||
// same few display buffers arrive over and over. Refresh the one we already have rather than
|
||||
// stacking a duplicate per frame - IsVideo() scans this linearly.
|
||||
for (VideoInfo &info : videos_) {
|
||||
if (info.addr == addr) {
|
||||
info.size = (u32)size;
|
||||
info.flips = gpuStats.totals.numFlips;
|
||||
return;
|
||||
}
|
||||
}
|
||||
videos_.push_back({ addr, (u32)size, gpuStats.totals.numFlips });
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ struct GPUStatsPerFrame {
|
||||
int numTexturesHashed;
|
||||
int numTextureDataBytesHashed;
|
||||
int numTexturesDecoded;
|
||||
int numVideoTextures;
|
||||
int numFramebufferEvaluations;
|
||||
int numFBOsCreated;
|
||||
int numBlockingReadbacks;
|
||||
|
||||
+3
-2
@@ -1748,8 +1748,8 @@ void GPUCommonHW::FormatGPUStatsCommon(StringWriter &w) {
|
||||
gpuStats.perFrame.vertexGPUCycles + gpuStats.perFrame.otherGPUCycles,
|
||||
vertexAverageCycles);
|
||||
w.F("FBOs active: %d (evaluations: %d, created %d)\n"
|
||||
"Textures: %d (s: %d), dec: %d, invalidated: %d, changed %d, hashed: %d kB, clut %d\n"
|
||||
"readbacks %d (%d non-block), upload %d (cached %d), depal %d\n"
|
||||
"Text: %d (s: %d), dec: %d, invalidated: %d, changed %d, hashed: %d kB, clut %d\n"
|
||||
"readbacks %d (%d non-block), upload %d (cached %d), depal %d, video %d\n"
|
||||
"block transfers: %d\n"
|
||||
"Cpy: depth %d, color %d, reint %d, blend %d, self %d\n",
|
||||
(int)framebufferManager_->NumVFBs(),
|
||||
@@ -1767,6 +1767,7 @@ void GPUCommonHW::FormatGPUStatsCommon(StringWriter &w) {
|
||||
gpuStats.perFrame.numUploads,
|
||||
gpuStats.perFrame.numCachedUploads,
|
||||
gpuStats.perFrame.numDepal,
|
||||
gpuStats.perFrame.numVideoTextures,
|
||||
gpuStats.perFrame.numBlockTransfers,
|
||||
gpuStats.perFrame.numDepthCopies,
|
||||
gpuStats.perFrame.numColorCopies,
|
||||
|
||||
Reference in new issue
Block a user