Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix frozen pitch meters in MLB series games - we were not hashing enough texture data #18484

Merged
merged 3 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Common/UI/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "Core/KeyMap.h"

void Screen::focusChanged(ScreenFocusChange focusChange) {
char *eventName = "";
const char *eventName = "";
switch (focusChange) {
case ScreenFocusChange::FOCUS_LOST_TOP: eventName = "FOCUS_LOST_TOP"; break;
case ScreenFocusChange::FOCUS_BECAME_TOP: eventName = "FOCUS_BECAME_TOP"; break;
Expand Down
7 changes: 5 additions & 2 deletions GPU/Common/TextureCacheCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
// Exponential backoff up to 512 frames. Textures are often reused.
if (entry->numFrames > 32) {
// Also, try to add some "randomness" to avoid rehashing several textures the same frame.
// textureName is unioned with texturePtr and vkTex so will work for the other backends.
entry->framesUntilNextFullHash = std::min(512, entry->numFrames) + (((intptr_t)(entry->textureName) >> 12) & 15);
} else {
entry->framesUntilNextFullHash = entry->numFrames;
Expand Down Expand Up @@ -2114,7 +2115,8 @@ void TextureCacheCommon::ApplyTexture() {
// Update the hash on the texture.
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
entry->fullhash = QuickTexHash(replacer_, entry->addr, entry->bufw, w, h, GETextureFormat(entry->format), entry);
bool swizzled = gstate.isTextureSwizzled();
entry->fullhash = QuickTexHash(replacer_, entry->addr, entry->bufw, w, h, swizzled, GETextureFormat(entry->format), entry);

// TODO: Here we could check the secondary cache; maybe the texture is in there?
// We would need to abort the build if so.
Expand Down Expand Up @@ -2535,6 +2537,7 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) {
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
bool isVideo = IsVideo(entry->addr);
bool swizzled = gstate.isTextureSwizzled();

// Don't even check the texture, just assume it has changed.
if (isVideo && g_Config.bTextureBackoffCache) {
Expand All @@ -2546,7 +2549,7 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) {
u32 fullhash;
{
PROFILE_THIS_SCOPE("texhash");
fullhash = QuickTexHash(replacer_, entry->addr, entry->bufw, w, h, GETextureFormat(entry->format), entry);
fullhash = QuickTexHash(replacer_, entry->addr, entry->bufw, w, h, swizzled, GETextureFormat(entry->format), entry);
}

if (fullhash == entry->fullhash) {
Expand Down
16 changes: 13 additions & 3 deletions GPU/Common/TextureCacheCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,16 +438,26 @@ class TextureCacheCommon {

static CheckAlphaResult CheckCLUTAlpha(const uint8_t *pixelData, GEPaletteFormat clutFmt, int w);

inline u32 QuickTexHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, GETextureFormat format, const TexCacheEntry *entry) const {
static inline u32 QuickTexHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, bool swizzled, GETextureFormat format, const TexCacheEntry *entry) {
if (replacer.Enabled()) {
return replacer.ComputeHash(addr, bufw, w, h, format, entry->maxSeenV);
return replacer.ComputeHash(addr, bufw, w, h, swizzled, format, entry->maxSeenV);
}

if (h == 512 && entry->maxSeenV < 512 && entry->maxSeenV != 0) {
h = (int)entry->maxSeenV;
}

const u32 sizeInRAM = (textureBitsPerPixel[format] * bufw * h) / 8;
u32 sizeInRAM;
if (swizzled) {
// In swizzle mode, textures are stored in rectangular blocks with the height 8.
// That means that for a 64x4 texture, like in issue #9308, we would only hash half of the texture!
// In theory, we should make sure to only hash half of each block, but in reality it's not likely that
// games are using that memory for anything else. So we'll just make sure to compute the full size to hash.
// To do that, we just use the same calculation but round the height upwards to the nearest multiple of 8.
sizeInRAM = (textureBitsPerPixel[format] * bufw * ((h + 7) & ~7)) >> 3;
} else {
sizeInRAM = (textureBitsPerPixel[format] * bufw * h) >> 3;
}
const u32 *checkp = (const u32 *)Memory::GetPointer(addr);

gpuStats.numTextureDataBytesHashed += sizeInRAM;
Expand Down
5 changes: 4 additions & 1 deletion GPU/Common/TextureReplacer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,12 @@ void TextureReplacer::ParseReduceHashRange(const std::string& key, const std::st
reducehashranges_[reducerangeKey] = rhashvalue;
}

u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV) {
u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, bool swizzled, GETextureFormat fmt, u16 maxSeenV) {
_dbg_assert_msg_(enabled_, "Replacement not enabled");

// TODO: Take swizzled into account, like in QuickTexHash().
// Note: Currently, only the MLB games are known to need this.

if (!LookupHashRange(addr, w, h, &w, &h)) {
// There wasn't any hash range, let's fall back to maxSeenV logic.
if (h == 512 && maxSeenV < 512 && maxSeenV != 0) {
Expand Down
2 changes: 1 addition & 1 deletion GPU/Common/TextureReplacer.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class TextureReplacer {
bool Enabled() const { return enabled_; }
bool AllowVideo() const { return allowVideo_; }

u32 ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV);
u32 ComputeHash(u32 addr, int bufw, int w, int h, bool swizzled, GETextureFormat fmt, u16 maxSeenV);

// Returns nullptr if not found.
ReplacedTexture *FindReplacement(u64 cachekey, u32 hash, int w, int h);
Expand Down
6 changes: 3 additions & 3 deletions GPU/Vulkan/TextureCacheVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,11 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
case VULKAN_4444_FORMAT: mapping = &VULKAN_4444_SWIZZLE; break;
case VULKAN_1555_FORMAT: mapping = &VULKAN_1555_SWIZZLE; break;
case VULKAN_565_FORMAT: mapping = &VULKAN_565_SWIZZLE; break;
default: mapping = &VULKAN_8888_SWIZZLE; break; // no swizzle
default: mapping = &VULKAN_8888_SWIZZLE; break; // no channel swizzle
}

char texName[64]{};
snprintf(texName, sizeof(texName), "tex_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format, gstate.getClutPaletteFormat()));
char texName[64];
snprintf(texName, sizeof(texName), "tex_%08x_%s_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format, gstate.getClutPaletteFormat()), gstate.isTextureSwizzled() ? "swz" : "lin");
entry->vkTex = new VulkanTexture(vulkan, texName);
VulkanTexture *image = entry->vkTex;
bool allocSuccess = image->CreateDirect(cmdInit, plan.createW, plan.createH, plan.depth, plan.levelsToCreate, actualFmt, imageLayout, usage, mapping);
Expand Down