Skip to content

Commit

Permalink
Merge pull request #15884 from unknownbrackets/texreplace-io-async
Browse files Browse the repository at this point in the history
Replacement: Read files only within time budget
  • Loading branch information
hrydgard committed Aug 22, 2022
2 parents 39cb2f1 + e473eb9 commit 3c307c9
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 30 deletions.
34 changes: 24 additions & 10 deletions Core/TextureReplacer.cpp
Expand Up @@ -49,7 +49,8 @@ static const int VERSION = 1;
static const int MAX_MIP_LEVELS = 12; // 12 should be plenty, 8 is the max mip levels supported by the PSP.

TextureReplacer::TextureReplacer() {
none_.alphaStatus_ = ReplacedTextureAlpha::UNKNOWN;
none_.initDone_ = true;
none_.prepareDone_ = true;
}

TextureReplacer::~TextureReplacer() {
Expand Down Expand Up @@ -373,7 +374,7 @@ u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureForm
}
}

ReplacedTexture &TextureReplacer::FindReplacement(u64 cachekey, u32 hash, int w, int h) {
ReplacedTexture &TextureReplacer::FindReplacement(u64 cachekey, u32 hash, int w, int h, double budget) {
// Only actually replace if we're replacing. We might just be saving.
if (!Enabled() || !g_Config.bReplaceTextures) {
return none_;
Expand All @@ -382,13 +383,18 @@ ReplacedTexture &TextureReplacer::FindReplacement(u64 cachekey, u32 hash, int w,
ReplacementCacheKey replacementKey(cachekey, hash);
auto it = cache_.find(replacementKey);
if (it != cache_.end()) {
if (!it->second.prepareDone_ && budget > 0.0) {
// We don't do this on a thread, but we only do it while within budget.
PopulateReplacement(&it->second, cachekey, hash, w, h);
}
return it->second;
}

// Okay, let's construct the result.
ReplacedTexture &result = cache_[replacementKey];
result.alphaStatus_ = ReplacedTextureAlpha::UNKNOWN;
PopulateReplacement(&result, cachekey, hash, w, h);
if (!g_Config.bReplaceTexturesAllowLate || budget > 0.0) {
PopulateReplacement(&result, cachekey, hash, w, h);
}
return result;
}

Expand Down Expand Up @@ -433,7 +439,7 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey,
break;
}

result->alphaStatus_ = ReplacedTextureAlpha::UNKNOWN;
result->prepareDone_ = true;
}

enum class ReplacedImageType {
Expand Down Expand Up @@ -815,11 +821,13 @@ bool ReplacedTexture::IsReady(double budget) {
}

// Loaded already, or not yet on a thread?
if (!levelData_.empty())
if (initDone_ && !levelData_.empty())
return true;
// Let's not even start a new texture if we're already behind.
if (budget < 0.0)
return false;
if (!prepareDone_)
return false;

if (g_Config.bReplaceTexturesAllowLate) {
if (threadWaitable_)
Expand All @@ -829,10 +837,11 @@ bool ReplacedTexture::IsReady(double budget) {

if (threadWaitable_->WaitFor(budget)) {
// If we finished all the levels, we're done.
return !levelData_.empty();
return initDone_ && !levelData_.empty();
}
} else {
Prepare();
_assert_(initDone_);
return true;
}

Expand All @@ -842,16 +851,19 @@ bool ReplacedTexture::IsReady(double budget) {

void ReplacedTexture::Prepare() {
std::unique_lock<std::mutex> lock(mutex_);
if (cancelPrepare_)
if (cancelPrepare_) {
initDone_ = true;
return;
}

levelData_.resize(NumLevels());
for (int i = 0; i < NumLevels(); ++i) {
levelData_.resize(levels_.size());
for (int i = 0; i < (int)levels_.size(); ++i) {
if (cancelPrepare_)
break;
PrepareData(i);
}

initDone_ = true;
if (!cancelPrepare_ && threadWaitable_)
threadWaitable_->Notify();
}
Expand Down Expand Up @@ -975,6 +987,8 @@ bool ReplacedTexture::Load(int level, void *out, int rowPitch) {
_assert_msg_((size_t)level < levels_.size(), "Invalid miplevel");
_assert_msg_(out != nullptr && rowPitch > 0, "Invalid out/pitch");

if (!initDone_)
return false;
if (levelData_.empty())
return false;

Expand Down
24 changes: 20 additions & 4 deletions Core/TextureReplacer.h
Expand Up @@ -118,10 +118,20 @@ struct ReplacedTexture {
~ReplacedTexture();

inline bool Valid() const {
if (!initDone_)
return false;
return !levels_.empty();
}

inline bool IsInvalid() const {
if (!initDone_)
return false;
return levels_.empty();
}

bool GetSize(int level, int &w, int &h) const {
if (!initDone_)
return false;
if ((size_t)level < levels_.size()) {
w = levels_[level].w;
h = levels_[level].h;
Expand All @@ -131,12 +141,16 @@ struct ReplacedTexture {
}

int NumLevels() const {
if (!initDone_)
return 0;
return (int)levels_.size();
}

Draw::DataFormat Format(int level) const {
if ((size_t)level < levels_.size()) {
return levels_[level].fmt;
if (initDone_) {
if ((size_t)level < levels_.size()) {
return levels_[level].fmt;
}
}
return Draw::DataFormat::R8G8B8A8_UNORM;
}
Expand All @@ -156,11 +170,13 @@ struct ReplacedTexture {

std::vector<ReplacedTextureLevel> levels_;
std::vector<std::vector<uint8_t>> levelData_;
ReplacedTextureAlpha alphaStatus_;
ReplacedTextureAlpha alphaStatus_ = ReplacedTextureAlpha::UNKNOWN;
double lastUsed_ = 0.0;
LimitedWaitable *threadWaitable_ = nullptr;
std::mutex mutex_;
bool cancelPrepare_ = false;
bool initDone_ = false;
bool prepareDone_ = false;

friend TextureReplacer;
friend ReplacedTextureTask;
Expand Down Expand Up @@ -196,7 +212,7 @@ class TextureReplacer {

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

ReplacedTexture &FindReplacement(u64 cachekey, u32 hash, int w, int h);
ReplacedTexture &FindReplacement(u64 cachekey, u32 hash, int w, int h, double budget);
bool FindFiltering(u64 cachekey, u32 hash, TextureFiltering *forceFiltering);
ReplacedTexture &FindNone() {
return none_;
Expand Down
29 changes: 18 additions & 11 deletions GPU/Common/TextureCacheCommon.cpp
Expand Up @@ -482,7 +482,14 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
int h0 = gstate.getTextureHeight(0);
int d0 = 1;
ReplacedTexture &replaced = FindReplacement(entry, w0, h0, d0);
if (replaced.Valid()) {
if (replaced.IsInvalid()) {
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
if (g_Config.bSaveNewTextures) {
// Load once more to actually save.
match = false;
reason = "replacing";
}
} else {
match = false;
reason = "replacing";
}
Expand Down Expand Up @@ -1303,22 +1310,22 @@ ReplacedTexture &TextureCacheCommon::FindReplacement(TexCacheEntry *entry, int &
constexpr double MAX_BUDGET_PER_TEX = 0.25 / 60.0;

double replaceStart = time_now_d();
double budget = std::min(MAX_BUDGET_PER_TEX, replacementFrameBudget_ - replacementTimeThisFrame_);
u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0;
ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h);
if (replaced.IsReady(std::min(MAX_BUDGET_PER_TEX, replacementFrameBudget_ - replacementTimeThisFrame_))) {
ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h, budget);
if (replaced.IsReady(budget)) {
if (replaced.GetSize(0, w, h)) {
replacementTimeThisFrame_ += time_now_d() - replaceStart;

// Consider it already "scaled" and remove any delayed replace flag.
// Consider it already "scaled."
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
return replaced;
}
} else if (replaced.Valid()) {

// Remove the flag, even if it was invalid.
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
} else if (!replaced.IsInvalid()) {
entry->status |= TexCacheEntry::STATUS_TO_REPLACE;
}
replacementTimeThisFrame_ += time_now_d() - replaceStart;
return replacer_.FindNone();
return replaced;
}

// This is only used in the GLES backend, where we don't point these to video memory.
Expand Down Expand Up @@ -2375,7 +2382,7 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, i
}
}

if (replacer_.Enabled()) {
if (replacer_.Enabled() && replaced.IsInvalid()) {
ReplacedTextureDecodeInfo replacedInfo;
replacedInfo.cachekey = entry.CacheKey();
replacedInfo.hash = entry.fullhash;
Expand Down
10 changes: 5 additions & 5 deletions GPU/Vulkan/TextureCacheVulkan.cpp
Expand Up @@ -464,7 +464,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
// Any texture scaling is gonna move away from the original 16-bit format, if any.
VkFormat actualFmt = plan.scaleFactor > 1 ? VULKAN_8888_FORMAT : dstFmt;
if (plan.replaced->Valid()) {
actualFmt = ToVulkanFormat(plan.replaced->Format(0));
actualFmt = ToVulkanFormat(plan.replaced->Format(plan.baseLevelSrc));
}

bool computeUpload = false;
Expand Down Expand Up @@ -536,7 +536,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {

ReplacedTextureDecodeInfo replacedInfo;
bool willSaveTex = false;
if (replacer_.Enabled() && !plan.replaced->Valid() && plan.depth == 1) {
if (replacer_.Enabled() && plan.replaced->IsInvalid() && plan.depth == 1) {
replacedInfo.cachekey = entry->CacheKey();
replacedInfo.hash = entry->fullhash;
replacedInfo.addr = entry->addr;
Expand Down Expand Up @@ -565,7 +565,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
int mipWidth = mipUnscaledWidth * plan.scaleFactor;
int mipHeight = mipUnscaledHeight * plan.scaleFactor;
if (plan.replaced->Valid()) {
plan.replaced->GetSize(i, mipWidth, mipHeight);
plan.replaced->GetSize(plan.baseLevelSrc + i, mipWidth, mipHeight);
}

int bpp = actualFmt == VULKAN_8888_FORMAT ? 4 : 2; // output bpp
Expand Down Expand Up @@ -595,7 +595,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
// Directly load the replaced image.
data = drawEngine_->GetPushBufferForTextureData()->PushAligned(size, &bufferOffset, &texBuf, pushAlignment);
double replaceStart = time_now_d();
plan.replaced->Load(i, data, stride); // if it fails, it'll just be garbage data... OK for now.
plan.replaced->Load(plan.baseLevelSrc + i, data, stride); // if it fails, it'll just be garbage data... OK for now.
replacementTimeThisFrame_ += time_now_d() - replaceStart;
VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT,
"Copy Upload (replaced): %dx%d", mipWidth, mipHeight);
Expand Down Expand Up @@ -636,7 +636,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
int w = dataScaled ? mipWidth : mipUnscaledWidth;
int h = dataScaled ? mipHeight : mipUnscaledHeight;
// At this point, data should be saveData, and not slow.
replacer_.NotifyTextureDecoded(replacedInfo, data, stride, i, w, h);
replacer_.NotifyTextureDecoded(replacedInfo, data, stride, plan.baseLevelSrc + i, w, h);
}
}
}
Expand Down

0 comments on commit 3c307c9

Please sign in to comment.