Replacement: Add structure for delayed loading.

This commit is contained in:
Unknown W. Brackets 2021-10-17 08:54:45 -07:00
parent 12215a3c60
commit 2356280a9c
8 changed files with 90 additions and 28 deletions

View file

@ -733,6 +733,10 @@ float TextureReplacer::LookupReduceHashRange(int& w, int& h) {
} }
} }
bool ReplacedTexture::IsReady(double budget) {
return true;
}
bool ReplacedTexture::Load(int level, void *out, int rowPitch) { bool ReplacedTexture::Load(int level, void *out, int rowPitch) {
_assert_msg_((size_t)level < levels_.size(), "Invalid miplevel"); _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel");
_assert_msg_(out != nullptr && rowPitch > 0, "Invalid out/pitch"); _assert_msg_(out != nullptr && rowPitch > 0, "Invalid out/pitch");

View file

@ -153,6 +153,8 @@ struct ReplacedTexture {
return (u8)alphaStatus_; return (u8)alphaStatus_;
} }
bool IsReady(double budget);
bool Load(int level, void *out, int rowPitch); bool Load(int level, void *out, int rowPitch);
protected: protected:

View file

@ -472,6 +472,10 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
reason = "scaling"; reason = "scaling";
} }
} }
if (match && (entry->status & TexCacheEntry::STATUS_TO_REPLACE) && replacementTimeThisFrame_ <= replacementFrameBudget_) {
match = false;
reason = "replacing";
}
if (match) { if (match) {
// got one! // got one!

View file

@ -123,16 +123,17 @@ struct TexCacheEntry {
STATUS_CLUT_RECHECK = 0x20, // Another texture with same addr had a hashfail. STATUS_CLUT_RECHECK = 0x20, // Another texture with same addr had a hashfail.
STATUS_TO_SCALE = 0x80, // Pending texture scaling in a later frame. STATUS_TO_SCALE = 0x80, // Pending texture scaling in a later frame.
STATUS_IS_SCALED = 0x100, // Has been scaled (can't be replaceImages'd.) STATUS_IS_SCALED = 0x100, // Has been scaled (can't be replaceImages'd.)
STATUS_TO_REPLACE = 0x0200, // Pending texture replacement.
// When hashing large textures, we optimize 512x512 down to 512x272 by default, since this // When hashing large textures, we optimize 512x512 down to 512x272 by default, since this
// is commonly the only part accessed. If access is made above 272, we hash the entire // is commonly the only part accessed. If access is made above 272, we hash the entire
// texture, and set this flag to allow scaling the texture just once for the new hash. // texture, and set this flag to allow scaling the texture just once for the new hash.
STATUS_FREE_CHANGE = 0x200, // Allow one change before marking "frequent". STATUS_FREE_CHANGE = 0x0400, // Allow one change before marking "frequent".
STATUS_BAD_MIPS = 0x400, // Has bad or unusable mipmap levels. STATUS_BAD_MIPS = 0x0800, // Has bad or unusable mipmap levels.
STATUS_FRAMEBUFFER_OVERLAP = 0x800, STATUS_FRAMEBUFFER_OVERLAP = 0x1000,
STATUS_FORCE_REBUILD = 0x1000, STATUS_FORCE_REBUILD = 0x2000,
}; };
// Status, but int so we can zero initialize. // Status, but int so we can zero initialize.
@ -334,6 +335,9 @@ protected:
int decimationCounter_; int decimationCounter_;
int texelsScaledThisFrame_ = 0; int texelsScaledThisFrame_ = 0;
int timesInvalidatedAllThisFrame_ = 0; int timesInvalidatedAllThisFrame_ = 0;
double replacementTimeThisFrame_ = 0;
// TODO: Maybe vary by FPS...
double replacementFrameBudget_ = 0.75 / 60.0;
TexCache cache_; TexCache cache_;
u32 cacheSizeEstimate_ = 0; u32 cacheSizeEstimate_ = 0;

View file

@ -21,6 +21,7 @@
#include <d3d11.h> #include <d3d11.h>
#include "Common/TimeUtil.h"
#include "Core/MemMap.h" #include "Core/MemMap.h"
#include "Core/Reporting.h" #include "Core/Reporting.h"
#include "GPU/ge_constants.h" #include "GPU/ge_constants.h"
@ -169,6 +170,7 @@ void TextureCacheD3D11::InvalidateLastTexture() {
void TextureCacheD3D11::StartFrame() { void TextureCacheD3D11::StartFrame() {
InvalidateLastTexture(); InvalidateLastTexture();
timesInvalidatedAllThisFrame_ = 0; timesInvalidatedAllThisFrame_ = 0;
replacementTimeThisFrame_ = 0.0;
if (texelsScaledThisFrame_) { if (texelsScaledThisFrame_) {
// INFO_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); // INFO_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_);
@ -486,13 +488,21 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0; u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0;
int w = gstate.getTextureWidth(0); int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0); int h = gstate.getTextureHeight(0);
double replaceStart = time_now_d();
ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h); ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h);
if (replaced.GetSize(0, w, h)) { if (replaced.IsReady(replacementFrameBudget_ - replacementTimeThisFrame_)) {
// We're replacing, so we won't scale. if (replaced.GetSize(0, w, h)) {
scaleFactor = 1; replacementTimeThisFrame_ += time_now_d() - replaceStart;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
maxLevel = replaced.MaxLevel(); // We're replacing, so we won't scale.
badMipSizes = false; scaleFactor = 1;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
maxLevel = replaced.MaxLevel();
badMipSizes = false;
}
} else if (replaced.MaxLevel() >= 0) {
entry->status |= TexCacheEntry::STATUS_TO_REPLACE;
} }
// Don't scale the PPGe texture. // Don't scale the PPGe texture.
@ -678,7 +688,9 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &
if (replaced.GetSize(level, w, h)) { if (replaced.GetSize(level, w, h)) {
mapData = (u32 *)AllocateAlignedMemory(w * h * sizeof(u32), 16); mapData = (u32 *)AllocateAlignedMemory(w * h * sizeof(u32), 16);
mapRowPitch = w * 4; mapRowPitch = w * 4;
double replaceStart = time_now_d();
replaced.Load(level, mapData, mapRowPitch); replaced.Load(level, mapData, mapRowPitch);
replacementTimeThisFrame_ += time_now_d() - replaceStart;
dstFmt = ToDXGIFormat(replaced.Format(level)); dstFmt = ToDXGIFormat(replaced.Format(level));
} else { } else {
GETextureFormat tfmt = (GETextureFormat)entry.format; GETextureFormat tfmt = (GETextureFormat)entry.format;

View file

@ -18,6 +18,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include "Common/TimeUtil.h"
#include "Core/MemMap.h" #include "Core/MemMap.h"
#include "Core/Reporting.h" #include "Core/Reporting.h"
#include "GPU/ge_constants.h" #include "GPU/ge_constants.h"
@ -134,6 +135,7 @@ void TextureCacheDX9::ApplySamplingParams(const SamplerCacheKey &key) {
void TextureCacheDX9::StartFrame() { void TextureCacheDX9::StartFrame() {
InvalidateLastTexture(); InvalidateLastTexture();
timesInvalidatedAllThisFrame_ = 0; timesInvalidatedAllThisFrame_ = 0;
replacementTimeThisFrame_ = 0.0;
if (texelsScaledThisFrame_) { if (texelsScaledThisFrame_) {
VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_);
@ -441,13 +443,21 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) {
u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0; u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0;
int w = gstate.getTextureWidth(0); int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0); int h = gstate.getTextureHeight(0);
double replaceStart = time_now_d();
ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h); ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h);
if (replaced.GetSize(0, w, h)) { if (replaced.IsReady(replacementFrameBudget_ - replacementTimeThisFrame_)) {
// We're replacing, so we won't scale. if (replaced.GetSize(0, w, h)) {
scaleFactor = 1; replacementTimeThisFrame_ += time_now_d() - replaceStart;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
maxLevel = replaced.MaxLevel(); // We're replacing, so we won't scale.
badMipSizes = false; scaleFactor = 1;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
maxLevel = replaced.MaxLevel();
badMipSizes = false;
}
} else if (replaced.MaxLevel() >= 0) {
entry->status |= TexCacheEntry::STATUS_TO_REPLACE;
} }
// Don't scale the PPGe texture. // Don't scale the PPGe texture.
@ -615,7 +625,9 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
gpuStats.numTexturesDecoded++; gpuStats.numTexturesDecoded++;
if (replaced.GetSize(level, w, h)) { if (replaced.GetSize(level, w, h)) {
double replaceStart = time_now_d();
replaced.Load(level, rect.pBits, rect.Pitch); replaced.Load(level, rect.pBits, rect.Pitch);
replacementTimeThisFrame_ += time_now_d() - replaceStart;
dstFmt = ToD3D9Format(replaced.Format(level)); dstFmt = ToD3D9Format(replaced.Format(level));
} else { } else {
GETextureFormat tfmt = (GETextureFormat)entry.format; GETextureFormat tfmt = (GETextureFormat)entry.format;

View file

@ -24,6 +24,7 @@
#include "Common/Math/math_util.h" #include "Common/Math/math_util.h"
#include "Common/Profiler/Profiler.h" #include "Common/Profiler/Profiler.h"
#include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/GPU/OpenGL/GLRenderManager.h"
#include "Common/TimeUtil.h"
#include "Core/Config.h" #include "Core/Config.h"
#include "Core/Host.h" #include "Core/Host.h"
@ -152,6 +153,7 @@ static void ConvertColors(void *dstBuf, const void *srcBuf, Draw::DataFormat dst
void TextureCacheGLES::StartFrame() { void TextureCacheGLES::StartFrame() {
InvalidateLastTexture(); InvalidateLastTexture();
timesInvalidatedAllThisFrame_ = 0; timesInvalidatedAllThisFrame_ = 0;
replacementTimeThisFrame_ = 0.0;
GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
if (!lowMemoryMode_ && renderManager->SawOutOfMemory()) { if (!lowMemoryMode_ && renderManager->SawOutOfMemory()) {
@ -505,13 +507,21 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) {
u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0; u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0;
int w = gstate.getTextureWidth(0); int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0); int h = gstate.getTextureHeight(0);
double replaceStart = time_now_d();
ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h); ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h);
if (replaced.GetSize(0, w, h)) { if (replaced.IsReady(replacementFrameBudget_ - replacementTimeThisFrame_)) {
// We're replacing, so we won't scale. if (replaced.GetSize(0, w, h)) {
scaleFactor = 1; replacementTimeThisFrame_ += time_now_d() - replaceStart;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
maxLevel = replaced.MaxLevel(); // We're replacing, so we won't scale.
badMipSizes = false; scaleFactor = 1;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
maxLevel = replaced.MaxLevel();
badMipSizes = false;
}
} else if (replaced.MaxLevel() >= 0) {
entry->status |= TexCacheEntry::STATUS_TO_REPLACE;
} }
// Don't scale the PPGe texture. // Don't scale the PPGe texture.
@ -658,7 +668,9 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
int bpp = replaced.Format(level) == ReplacedTextureFormat::F_8888 ? 4 : 2; int bpp = replaced.Format(level) == ReplacedTextureFormat::F_8888 ? 4 : 2;
decPitch = w * bpp; decPitch = w * bpp;
uint8_t *rearrange = (uint8_t *)AllocateAlignedMemory(decPitch * h, 16); uint8_t *rearrange = (uint8_t *)AllocateAlignedMemory(decPitch * h, 16);
double replaceStart = time_now_d();
replaced.Load(level, rearrange, decPitch); replaced.Load(level, rearrange, decPitch);
replacementTimeThisFrame_ += time_now_d() - replaceStart;
pixelData = rearrange; pixelData = rearrange;
dstFmt = ToDataFormat(replaced.Format(level)); dstFmt = ToDataFormat(replaced.Format(level));

View file

@ -28,6 +28,7 @@
#include "Common/Data/Convert/ColorConv.h" #include "Common/Data/Convert/ColorConv.h"
#include "Common/StringUtils.h" #include "Common/StringUtils.h"
#include "Common/TimeUtil.h"
#include "Core/Config.h" #include "Core/Config.h"
#include "Core/Host.h" #include "Core/Host.h"
#include "Core/MemMap.h" #include "Core/MemMap.h"
@ -442,6 +443,7 @@ void TextureCacheVulkan::StartFrame() {
timesInvalidatedAllThisFrame_ = 0; timesInvalidatedAllThisFrame_ = 0;
texelsScaledThisFrame_ = 0; texelsScaledThisFrame_ = 0;
replacementTimeThisFrame_ = 0.0;
if (clearCacheNextFrame_) { if (clearCacheNextFrame_) {
Clear(true); Clear(true);
@ -776,13 +778,21 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0; u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0;
int w = gstate.getTextureWidth(0); int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0); int h = gstate.getTextureHeight(0);
double replaceStart = time_now_d();
ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h); ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h);
if (replaced.GetSize(0, w, h)) { if (replaced.IsReady(replacementFrameBudget_ - replacementTimeThisFrame_)) {
// We're replacing, so we won't scale. if (replaced.GetSize(0, w, h)) {
scaleFactor = 1; replacementTimeThisFrame_ += time_now_d() - replaceStart;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
maxLevel = replaced.MaxLevel(); // We're replacing, so we won't scale.
badMipSizes = false; scaleFactor = 1;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
maxLevel = replaced.MaxLevel();
badMipSizes = false;
}
} else if (replaced.MaxLevel() >= 0) {
entry->status |= TexCacheEntry::STATUS_TO_REPLACE;
} }
bool hardwareScaling = g_Config.bTexHardwareScaling && (uploadCS_ != VK_NULL_HANDLE || copyCS_ != VK_NULL_HANDLE); bool hardwareScaling = g_Config.bTexHardwareScaling && (uploadCS_ != VK_NULL_HANDLE || copyCS_ != VK_NULL_HANDLE);
@ -934,7 +944,9 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
if (replaced.Valid()) { if (replaced.Valid()) {
// Directly load the replaced image. // Directly load the replaced image.
data = drawEngine_->GetPushBufferForTextureData()->PushAligned(size, &bufferOffset, &texBuf, pushAlignment); data = drawEngine_->GetPushBufferForTextureData()->PushAligned(size, &bufferOffset, &texBuf, pushAlignment);
replaceStart = time_now_d();
replaced.Load(i, data, stride); // if it fails, it'll just be garbage data... OK for now. replaced.Load(i, data, stride); // if it fails, it'll just be garbage data... OK for now.
replacementTimeThisFrame_ += time_now_d() - replaceStart;
entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp); entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
} else { } else {
auto dispatchCompute = [&](VkDescriptorSet descSet) { auto dispatchCompute = [&](VkDescriptorSet descSet) {