Break out the preparation part of BuildTexture from GLES

This commit is contained in:
Henrik Rydgård 2022-07-28 12:59:30 +02:00
parent c031f3085b
commit 167b837ed3
3 changed files with 136 additions and 113 deletions

View file

@ -2006,3 +2006,110 @@ void TextureCacheCommon::ClearNextFrame() {
std::string AttachCandidate::ToString() {
return StringFromFormat("[C:%08x/%d Z:%08x/%d X:%d Y:%d reint: %s]", this->fb->fb_address, this->fb->fb_stride, this->fb->z_address, this->fb->z_stride, this->match.xOffset, this->match.yOffset, this->match.reinterpret ? "true" : "false");
}
bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEntry *entry) {
entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK;
// For the estimate, we assume cluts always point to 8888 for simplicity.
cacheSizeEstimate_ += EstimateTexMemoryUsage(entry);
if ((entry->bufw == 0 || (gstate.texbufwidth[0] & 0xf800) != 0) && entry->addr >= PSP_GetKernelMemoryEnd()) {
ERROR_LOG_REPORT(G3D, "Texture with unexpected bufw (full=%d)", gstate.texbufwidth[0] & 0xffff);
// Proceeding here can cause a crash.
return false;
}
plan.badMipSizes = false;
// maxLevel here is the max level to upload. Not the count.
plan.canAutoGen = false;
plan.maxLevel = entry->maxLevel;
for (int i = 0; i <= plan.maxLevel; i++) {
// If encountering levels pointing to nothing, adjust max level.
u32 levelTexaddr = gstate.getTextureAddress(i);
if (!Memory::IsValidAddress(levelTexaddr)) {
plan.maxLevel = i - 1;
break;
}
// If size reaches 1, stop, and override maxlevel.
int tw = gstate.getTextureWidth(i);
int th = gstate.getTextureHeight(i);
if (tw == 1 || th == 1) {
plan.maxLevel = i;
break;
}
if (i > 0) {
int lastW = gstate.getTextureWidth(i - 1);
int lastH = gstate.getTextureHeight(i - 1);
if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) {
if (tw != 1 && tw != (lastW >> 1))
plan.badMipSizes = true;
else if (th != 1 && th != (lastH >> 1))
plan.badMipSizes = true;
}
if (lastW > tw || lastH > th)
plan.canAutoGen = true;
}
}
plan.scaleFactor = standardScaleFactor_;
// Rachet down scale factor in low-memory mode.
if (lowMemoryMode_) {
// Keep it even, though, just in case of npot troubles.
plan.scaleFactor = plan.scaleFactor > 4 ? 4 : (plan.scaleFactor > 2 ? 2 : 1);
}
plan.w = gstate.getTextureWidth(0);
plan.h = gstate.getTextureHeight(0);
plan.replaced = &FindReplacement(entry, plan.w, plan.h);
if (plan.replaced->Valid()) {
// We're replacing, so we won't scale.
plan.scaleFactor = 1;
plan.maxLevel = plan.replaced->MaxLevel();
plan.badMipSizes = false;
}
// Don't scale the PPGe texture.
if (entry->addr > 0x05000000 && entry->addr < PSP_GetKernelMemoryEnd())
plan.scaleFactor = 1;
if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) != 0 && plan.scaleFactor != 1) {
// Remember for later that we /wanted/ to scale this texture.
entry->status |= TexCacheEntry::STATUS_TO_SCALE;
plan.scaleFactor = 1;
}
if (plan.scaleFactor != 1) {
if (texelsScaledThisFrame_ >= TEXCACHE_MAX_TEXELS_SCALED) {
entry->status |= TexCacheEntry::STATUS_TO_SCALE;
plan.scaleFactor = 1;
} else {
entry->status &= ~TexCacheEntry::STATUS_TO_SCALE;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
texelsScaledThisFrame_ += plan.w * plan.h;
}
}
if (plan.badMipSizes) {
plan.maxLevel = 0;
}
// Always load base level texture here
plan.srcLevel = 0;
if (IsFakeMipmapChange()) {
// NOTE: Since the level is not part of the cache key, we assume it never changes.
plan.srcLevel = std::max(0, gstate.getTexLevelOffset16() / 16);
}
if (plan.maxLevel == 0) {
entry->status |= TexCacheEntry::STATUS_BAD_MIPS;
} else {
entry->status &= ~TexCacheEntry::STATUS_BAD_MIPS;
}
return true;
}

View file

@ -229,6 +229,17 @@ struct AttachCandidate {
class FramebufferManagerCommon;
struct BuildTexturePlan {
bool badMipSizes;
bool canAutoGen;
int maxLevel;
int srcLevel;
int scaleFactor;
int w;
int h;
ReplacedTexture *replaced;
};
class TextureCacheCommon {
public:
TextureCacheCommon(Draw::DrawContext *draw);
@ -270,6 +281,8 @@ public:
virtual bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) { return false; }
protected:
bool PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEntry *entry);
virtual void BindTexture(TexCacheEntry *entry) = 0;
virtual void Unbind() = 0;
virtual void ReleaseTexture(TexCacheEntry *entry, bool delete_them) = 0;

View file

@ -426,109 +426,12 @@ void TextureCacheGLES::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer,
}
void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) {
entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK;
// For the estimate, we assume cluts always point to 8888 for simplicity.
cacheSizeEstimate_ += EstimateTexMemoryUsage(entry);
if ((entry->bufw == 0 || (gstate.texbufwidth[0] & 0xf800) != 0) && entry->addr >= PSP_GetKernelMemoryEnd()) {
ERROR_LOG_REPORT(G3D, "Texture with unexpected bufw (full=%d)", gstate.texbufwidth[0] & 0xffff);
// Proceeding here can cause a crash.
BuildTexturePlan plan;
if (!PrepareBuildTexture(plan, entry)) {
// We're screwed?
return;
}
bool badMipSizes = false;
// maxLevel here is the max level to upload. Not the count.
bool canAutoGen = false;
int maxLevel = entry->maxLevel;
for (int i = 0; i <= maxLevel; i++) {
// If encountering levels pointing to nothing, adjust max level.
u32 levelTexaddr = gstate.getTextureAddress(i);
if (!Memory::IsValidAddress(levelTexaddr)) {
maxLevel = i - 1;
break;
}
// If size reaches 1, stop, and override maxlevel.
int tw = gstate.getTextureWidth(i);
int th = gstate.getTextureHeight(i);
if (tw == 1 || th == 1) {
maxLevel = i;
break;
}
if (i > 0) {
int lastW = gstate.getTextureWidth(i - 1);
int lastH = gstate.getTextureHeight(i - 1);
if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) {
if (tw != 1 && tw != (lastW >> 1))
badMipSizes = true;
else if (th != 1 && th != (lastH >> 1))
badMipSizes = true;
}
if (lastW > tw || lastH > th)
canAutoGen = true;
}
}
int scaleFactor = standardScaleFactor_;
// Rachet down scale factor in low-memory mode.
if (lowMemoryMode_) {
// Keep it even, though, just in case of npot troubles.
scaleFactor = scaleFactor > 4 ? 4 : (scaleFactor > 2 ? 2 : 1);
}
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
ReplacedTexture &replaced = FindReplacement(entry, w, h);
if (replaced.Valid()) {
// We're replacing, so we won't scale.
scaleFactor = 1;
maxLevel = replaced.MaxLevel();
badMipSizes = false;
}
// Don't scale the PPGe texture.
if (entry->addr > 0x05000000 && entry->addr < PSP_GetKernelMemoryEnd())
scaleFactor = 1;
if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) != 0 && scaleFactor != 1) {
// Remember for later that we /wanted/ to scale this texture.
entry->status |= TexCacheEntry::STATUS_TO_SCALE;
scaleFactor = 1;
}
if (scaleFactor != 1) {
if (texelsScaledThisFrame_ >= TEXCACHE_MAX_TEXELS_SCALED) {
entry->status |= TexCacheEntry::STATUS_TO_SCALE;
scaleFactor = 1;
} else {
entry->status &= ~TexCacheEntry::STATUS_TO_SCALE;
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
texelsScaledThisFrame_ += w * h;
}
}
if (badMipSizes) {
maxLevel = 0;
}
// Always load base level texture here
int srcLevel = 0;
if (IsFakeMipmapChange()) {
// NOTE: Since the level is not part of the cache key, we assume it never changes.
srcLevel = std::max(0, gstate.getTexLevelOffset16() / 16);
}
if (maxLevel == 0) {
entry->status |= TexCacheEntry::STATUS_BAD_MIPS;
} else {
entry->status &= ~TexCacheEntry::STATUS_BAD_MIPS;
}
_assert_(!entry->textureName);
// GLES2 doesn't have support for a "Max lod" which is critical as PSP games often
@ -544,34 +447,34 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) {
Draw::DataFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
LoadTextureLevel(*entry, replaced, srcLevel, 0, scaleFactor, dstFmt);
LoadTextureLevel(*entry, *plan.replaced, plan.srcLevel, 0, plan.scaleFactor, dstFmt);
// Mipmapping is only enabled when texture scaling is disabled.
int texMaxLevel = 0;
bool genMips = false;
if (maxLevel > 0 && scaleFactor == 1) {
if (plan.maxLevel > 0 && plan.scaleFactor == 1) {
if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) {
if (badMipSizes) {
if (plan.badMipSizes) {
// WARN_LOG(G3D, "Bad mipmap for texture sized %dx%dx%d - autogenerating", w, h, (int)format);
if (canAutoGen) {
if (plan.canAutoGen) {
genMips = true;
} else {
texMaxLevel = 0;
maxLevel = 0;
plan.maxLevel = 0;
}
} else {
for (int i = 1; i <= maxLevel; i++) {
LoadTextureLevel(*entry, replaced, i, i, scaleFactor, dstFmt);
for (int i = 1; i <= plan.maxLevel; i++) {
LoadTextureLevel(*entry, *plan.replaced, i, i, plan.scaleFactor, dstFmt);
}
texMaxLevel = maxLevel;
texMaxLevel = plan.maxLevel;
}
} else {
// Avoid PowerVR driver bug
if (canAutoGen && w > 1 && h > 1 && !(h > w && draw_->GetBugs().Has(Draw::Bugs::PVR_GENMIPMAP_HEIGHT_GREATER))) { // Really! only seems to fail if height > width
if (plan.canAutoGen && plan.w > 1 && plan.h > 1 && !(plan.h > plan.w && draw_->GetBugs().Has(Draw::Bugs::PVR_GENMIPMAP_HEIGHT_GREATER))) { // Really! only seems to fail if height > width
// NOTICE_LOG(G3D, "Generating mipmap for texture sized %dx%d%d", w, h, (int)format);
genMips = true;
} else {
maxLevel = 0;
plan.maxLevel = 0;
}
}
} else if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) {
@ -580,13 +483,13 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) {
render_->FinalizeTexture(entry->textureName, texMaxLevel, genMips);
if (maxLevel == 0) {
if (plan.maxLevel == 0) {
entry->status |= TexCacheEntry::STATUS_BAD_MIPS;
} else {
entry->status &= ~TexCacheEntry::STATUS_BAD_MIPS;
}
if (replaced.Valid()) {
entry->SetAlphaStatus(TexCacheEntry::TexStatus(replaced.AlphaStatus()));
if (plan.replaced->Valid()) {
entry->SetAlphaStatus(TexCacheEntry::TexStatus(plan.replaced->AlphaStatus()));
}
}