mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-30 19:24:23 +01:00
Merge pull request #21931 from hrydgard/merge-set-texture-apply-texture
Code cleanup: Merge the SetTexture and ApplyTexture functions
This commit is contained in:
5 files changed
+183
-241
No files matched your search
+157
-218
@@ -386,6 +386,39 @@ SamplerCacheKey GetFramebufferSamplingParams(const GEState &gstate, u16 bufferWi
|
||||
return key;
|
||||
}
|
||||
|
||||
static u32 ComputeTextureHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, bool swizzled, const TexCacheEntry *entry) {
|
||||
const GETextureFormat format = entry->format;
|
||||
if (replacer.Enabled()) {
|
||||
return replacer.ComputeHash(addr, bufw, w, h, swizzled, format, entry->maxSeenV);
|
||||
}
|
||||
|
||||
if (h == 512 && entry->maxSeenV < 512 && entry->maxSeenV != 0) {
|
||||
h = (int)entry->maxSeenV;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (Memory::IsValidAddress(addr + sizeInRAM)) {
|
||||
gpuStats.perFrame.numTextureDataBytesHashed += sizeInRAM;
|
||||
|
||||
// return XXH64(checkp, sizeInRAM, 0xBACD7814);
|
||||
return StableQuickTexHash(checkp, sizeInRAM);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this is overridden in TextureCacheGLES, with some extra color conversion.
|
||||
void TextureCacheCommon::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) {
|
||||
const u32 clutBaseBytes = clutFormat == GE_CMODE_32BIT_ABGR8888 ? (clutBase * sizeof(u32)) : (clutBase * sizeof(u16));
|
||||
@@ -475,7 +508,7 @@ void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode)
|
||||
}
|
||||
}
|
||||
|
||||
TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
u8 level = 0;
|
||||
if (IsFakeMipmapChange()) {
|
||||
level = std::max(0, gstate.getTexLevelOffset16() / 16);
|
||||
@@ -483,13 +516,14 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
u32 texaddr = gstate.getTextureAddress(level);
|
||||
if (!Memory::IsValidAddress(texaddr)) {
|
||||
// Bind a null texture and return.
|
||||
nextTexture_ = nullptr;
|
||||
Unbind();
|
||||
gstate_c.SetTextureIsVideo(false);
|
||||
gstate_c.SetTextureIs3D(false);
|
||||
gstate_c.SetTextureIsArray(false);
|
||||
gstate_c.SetTextureIsFramebuffer(false);
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::OFF);
|
||||
return nullptr;
|
||||
return TextureApplyResult();
|
||||
}
|
||||
|
||||
const u16 dim = gstate.getTextureDimension(level);
|
||||
@@ -502,11 +536,11 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
texFormat = GE_TFMT_5650;
|
||||
}
|
||||
|
||||
bool hasClut = gstate.isTextureFormatIndexed();
|
||||
bool hasClutGPU = false;
|
||||
bool clutInShader = false;
|
||||
u32 cluthash;
|
||||
if (hasClut) {
|
||||
if (gstate.isTextureFormatIndexed()) {
|
||||
// Check if we should use dynamic CLUT in shader or some other tricks.
|
||||
if (PSP_CoreParameter().compat.flags().TextureCLUTInShader && !replacer_.Enabled() && (texFormat == GE_TFMT_CLUT8 || texFormat == GE_TFMT_CLUT4)) {
|
||||
if (clutLastFormat_ != gstate.clutformat) {
|
||||
// We update here because the clut format can be specified after the load.
|
||||
@@ -532,7 +566,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
} else {
|
||||
cluthash = 0;
|
||||
}
|
||||
u64 cachekey = TexCacheEntry::CacheKey(texaddr, texFormat, dim, cluthash);
|
||||
const u64 cachekey = TexCacheEntry::CacheKey(texaddr, texFormat, dim, cluthash);
|
||||
|
||||
int bufw = GetTextureBufw(0, texaddr, texFormat);
|
||||
u8 maxLevel = gstate.getTextureMaxLevel();
|
||||
@@ -584,12 +618,6 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
entry->status &= ~(TexStatus::HASH_RECHECK | TexStatus::CLUT_RECHECK);
|
||||
}
|
||||
|
||||
// Do we need to recreate?
|
||||
if (entry->status & TexStatus::FORCE_REBUILD) {
|
||||
match = false;
|
||||
entry->status &= ~TexStatus::FORCE_REBUILD;
|
||||
}
|
||||
|
||||
if (match && (entry->status & TexStatus::TO_SCALE) && (standardScaleFactor_ > 1 || shaderScaleFactor_ > 1) && texelsScaledThisFrame_ < TEXCACHE_MAX_TEXELS_SCALED) {
|
||||
// INFO_LOG(Log::G3D, "Reloading texture to do the scaling we skipped..");
|
||||
match = false;
|
||||
@@ -632,16 +660,6 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
// got one!
|
||||
gstate_c.curTextureWidth = w;
|
||||
gstate_c.curTextureHeight = h;
|
||||
gstate_c.SetTextureIsVideo(false);
|
||||
gstate_c.SetTextureIs3D(entry->status & TexStatus::IS_3D);
|
||||
gstate_c.SetTextureIsArray(false);
|
||||
gstate_c.SetTextureIsFramebuffer(false);
|
||||
if (entry->status & TexStatus::CLUT8_INDEXED) {
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::NORMAL, GE_FORMAT_CLUT8);
|
||||
} else {
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::OFF, GE_FORMAT_INVALID);
|
||||
}
|
||||
|
||||
if (rehash) {
|
||||
// Update in case any of these changed.
|
||||
entry->bufw = bufw;
|
||||
@@ -655,7 +673,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
nextNeedsRebuild_ = false;
|
||||
failedTexture_ = false;
|
||||
VERBOSE_LOG(Log::G3D, "Texture at %08x found in cache, applying", texaddr);
|
||||
return entry; //Done!
|
||||
return ApplyTextureFinish(entry, doBind); //Done!
|
||||
} else {
|
||||
// Wasn't a match, we will rebuild.
|
||||
nextChangeReason_ = reason;
|
||||
@@ -683,8 +701,8 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
nextTexture_ = nullptr;
|
||||
nextNeedsRebuild_ = false;
|
||||
|
||||
SetTextureFramebuffer(bestCandidate); // sets curTexture3D
|
||||
return nullptr;
|
||||
VirtualFramebuffer *framebuffer = SetTextureFramebuffer(bestCandidate); // sets curTexture3D
|
||||
return ApplyTextureFinishFramebuffer(framebuffer, doBind);
|
||||
}
|
||||
|
||||
// Didn't match a framebuffer, keep going.
|
||||
@@ -704,7 +722,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
entry->status |= TexStatus::CLUT_GPU | TexStatus::CLUT8_INDEXED;
|
||||
}
|
||||
|
||||
if (hasClut && clutRenderAddress_ == 0xFFFFFFFF) {
|
||||
if (gstate.isTextureFormatIndexed() && clutRenderAddress_ == 0xFFFFFFFF) {
|
||||
const u64 cachekeyMin = (u64)(texaddr & 0x3FFFFFFF) << 32;
|
||||
const u64 cachekeyMax = cachekeyMin + (1ULL << 32);
|
||||
|
||||
@@ -743,22 +761,117 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
|
||||
gstate_c.curTextureWidth = w;
|
||||
gstate_c.curTextureHeight = h;
|
||||
gstate_c.SetTextureIsVideo((entry->status & TexStatus::VIDEO) != 0);
|
||||
gstate_c.SetTextureIs3D((entry->status & TexStatus::IS_3D) != 0);
|
||||
gstate_c.SetTextureIsArray(false); // Ordinary 2D textures still aren't used by array view in VK. We probably might as well, though, at this point..
|
||||
gstate_c.SetTextureIsFramebuffer(false);
|
||||
if (entry->status & TexStatus::CLUT8_INDEXED) {
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::NORMAL, GE_FORMAT_CLUT8);
|
||||
} else {
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::OFF, GE_FORMAT_INVALID);
|
||||
}
|
||||
|
||||
failedTexture_ = false;
|
||||
nextTexture_ = entry;
|
||||
nextFramebufferTexture_ = nullptr;
|
||||
nextNeedsRehash_ = true;
|
||||
nextNeedsRebuild_ = true;
|
||||
return entry;
|
||||
return ApplyTextureFinish(entry, doBind);
|
||||
}
|
||||
|
||||
TextureApplyResult TextureCacheCommon::ApplyTextureFinishFramebuffer(VirtualFramebuffer *framebuffer, bool doBind) {
|
||||
TextureApplyResult result;
|
||||
// Maybe we bound a framebuffer?
|
||||
ForgetLastTexture();
|
||||
if (failedTexture_) {
|
||||
// Backends should handle this by binding a black texture with 0 alpha.
|
||||
BindTexture(nullptr);
|
||||
} else if (framebuffer) {
|
||||
// ApplyTextureFramebuffer is responsible for setting SetTextureFullAlpha.
|
||||
ApplyTextureFramebuffer(framebuffer, gstate.getTextureFormat(), nextFramebufferTextureChannel_);
|
||||
result.framebuffer = framebuffer;
|
||||
framebuffer = nullptr;
|
||||
}
|
||||
// We don't set the 3D texture state here or anything else, on some backends (?)
|
||||
// a nextTexture_ of nullptr means keep the current texture.
|
||||
return result;
|
||||
}
|
||||
|
||||
TextureApplyResult TextureCacheCommon::ApplyTextureFinish(TexCacheEntry *entry, bool doBind) {
|
||||
_dbg_assert_(entry);
|
||||
|
||||
TextureApplyResult result;
|
||||
nextTexture_ = nullptr;
|
||||
|
||||
UpdateMaxSeenV(entry, gstate.isModeThrough());
|
||||
|
||||
if (nextNeedsRebuild_) {
|
||||
// Regardless of hash fails or otherwise, if this is a video, mark it frequently changing.
|
||||
// This prevents temporary scaling perf hits on the first second of video.
|
||||
if (IsVideo(entry->addr)) {
|
||||
entry->status |= TexStatus::VIDEO;
|
||||
} else {
|
||||
entry->status &= ~TexStatus::VIDEO;
|
||||
}
|
||||
|
||||
if (nextNeedsRehash_) {
|
||||
PROFILE_THIS_SCOPE("texhash");
|
||||
// Update the hash on the texture.
|
||||
int w = gstate.getTextureWidth(0);
|
||||
int h = gstate.getTextureHeight(0);
|
||||
const bool swizzled = gstate.isTextureSwizzled();
|
||||
entry->fullhash = ComputeTextureHash(replacer_, entry->addr, entry->bufw, w, h, swizzled, entry);
|
||||
|
||||
// TODO: Here we could check the secondary cache; maybe the texture is in there?
|
||||
// We would need to abort the build if so.
|
||||
}
|
||||
if (nextNeedsChange_) {
|
||||
// This texture existed previously, let's handle the change.
|
||||
HandleTextureChange(entry, nextChangeReason_, false, true);
|
||||
}
|
||||
// We actually build afterward (shared with rehash rebuild.)
|
||||
} else if (nextNeedsRehash_) {
|
||||
// Okay, this matched and didn't change - but let's check the hash. Maybe it will change.
|
||||
bool doDelete = true;
|
||||
if (!CheckFullHash(entry, doDelete)) {
|
||||
HandleTextureChange(entry, "hash fail", true, doDelete);
|
||||
nextNeedsRebuild_ = true;
|
||||
} else if (nextTexture_ != nullptr) {
|
||||
// The secondary cache may choose an entry from its storage by setting nextTexture_.
|
||||
// This means we should set that, instead of our previous entry.
|
||||
entry = nextTexture_;
|
||||
nextTexture_ = nullptr;
|
||||
UpdateMaxSeenV(entry, gstate.isModeThrough());
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, now actually rebuild the texture if needed.
|
||||
if (nextNeedsRebuild_) {
|
||||
_assert_(!entry->texturePtr);
|
||||
BuildTexture(entry);
|
||||
ForgetLastTexture();
|
||||
}
|
||||
|
||||
gstate_c.SetTextureIsVideo((entry->status & TexStatus::VIDEO) != 0);
|
||||
gstate_c.SetTextureIsArray(false); // Ordinary 2D textures still aren't used by array view in VK. We probably might as well, though, at this point..
|
||||
gstate_c.SetTextureIsFramebuffer(false);
|
||||
entry->lastFrame = gpuStats.totals.numFlips;
|
||||
if (entry->status & TexStatus::CLUT_GPU) {
|
||||
_dbg_assert_(entry->status & TexStatus::CLUT8_INDEXED);
|
||||
// Special process.
|
||||
if (doBind) {
|
||||
ApplyTextureDepalFramebufferCLUT(entry);
|
||||
}
|
||||
gstate_c.SetTextureSolidAlpha(false);
|
||||
gstate_c.SetTextureIs3D(false);
|
||||
return TextureApplyResult{};
|
||||
} else {
|
||||
if (doBind) {
|
||||
BindTexture(entry);
|
||||
}
|
||||
gstate_c.SetTextureSolidAlpha((entry->status & TexStatus::ALPHA_SOLID) != 0);
|
||||
gstate_c.SetTextureIs3D((entry->status & TexStatus::IS_3D) != 0);
|
||||
if (entry->status & TexStatus::CLUT8_INDEXED) {
|
||||
bool smoothedDepal = false;
|
||||
u32 depthUpperBits = 0;
|
||||
ClutTexture clutTexture = clutTextureCache_.GetClutTexture(gstate.getClutPaletteFormat(), clutHash_, clutBuf_);
|
||||
BindAsClutTexture(clutTexture.texture, false);
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::NORMAL, GE_FORMAT_CLUT8);
|
||||
} else {
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::OFF, GE_FORMAT_INVALID);
|
||||
}
|
||||
}
|
||||
return TextureApplyResult{entry, nullptr};
|
||||
}
|
||||
|
||||
static bool GetBestFramebufferCandidate(FramebufferManagerCommon *fbManager, const TextureDefinition &entry, u32 texAddrOffset, AttachCandidate *bestCandidate, const char *context) {
|
||||
@@ -1201,7 +1314,7 @@ static bool MatchFramebuffer(const TextureDefinition &entry,
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) {
|
||||
VirtualFramebuffer *TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) {
|
||||
VirtualFramebuffer *framebuffer = candidate.fb;
|
||||
RasterChannel channel = candidate.channel;
|
||||
|
||||
@@ -1259,10 +1372,9 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate)
|
||||
WARN_LOG_ONCE(ndepthtex, Log::G3D, "Depth textures not supported, not binding");
|
||||
// Flag to bind a null texture if we can't support depth textures.
|
||||
// Should only happen on old OpenGL.
|
||||
nextFramebufferTexture_ = nullptr;
|
||||
framebuffer = nullptr;
|
||||
failedTexture_ = true;
|
||||
} else {
|
||||
nextFramebufferTexture_ = framebuffer;
|
||||
nextFramebufferTextureChannel_ = channel;
|
||||
}
|
||||
nextTexture_ = nullptr;
|
||||
@@ -1273,7 +1385,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate)
|
||||
}
|
||||
Unbind();
|
||||
gstate_c.SetNeedShaderTexclamp(false);
|
||||
nextFramebufferTexture_ = nullptr;
|
||||
framebuffer = nullptr;
|
||||
nextTexture_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -1285,44 +1397,10 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate)
|
||||
nextNeedsRehash_ = false;
|
||||
nextNeedsChange_ = false;
|
||||
nextNeedsRebuild_ = false;
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
// Only looks for framebuffers.
|
||||
bool TextureCacheCommon::SetOffsetTexture(u32 yOffset) {
|
||||
if (!framebufferManager_->UseBufferedRendering()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 texaddr = gstate.getTextureAddress(0);
|
||||
GETextureFormat fmt = gstate.getTextureFormat();
|
||||
const u32 bpp = fmt == GE_TFMT_8888 ? 4 : 2;
|
||||
const u32 texaddrOffset = yOffset * gstate.getTextureWidth(0) * bpp;
|
||||
|
||||
if (!Memory::IsValidAddress(texaddr) || !Memory::IsValidAddress(texaddr + texaddrOffset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextureDefinition def;
|
||||
def.addr = texaddr;
|
||||
def.format = fmt;
|
||||
def.bufw = GetTextureBufw(0, texaddr, fmt);
|
||||
def.dim = gstate.getTextureDimension(0);
|
||||
|
||||
AttachCandidate bestCandidate;
|
||||
if (GetBestFramebufferCandidate(framebufferManager_, def, texaddrOffset, &bestCandidate, "offsetTexture")) {
|
||||
SetTextureFramebuffer(bestCandidate);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureCacheCommon::GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffer, bool *isFramebuffer) {
|
||||
if (!nextFramebufferTexture_)
|
||||
return false;
|
||||
*isFramebuffer = true;
|
||||
|
||||
VirtualFramebuffer *vfb = nextFramebufferTexture_;
|
||||
bool TextureCacheCommon::GetFramebufferTextureDebug(const VirtualFramebuffer *vfb, GPUDebugBuffer &buffer) {
|
||||
u8 sf = vfb->renderScaleFactor;
|
||||
int x = gstate_c.curTextureXOffset * sf;
|
||||
int y = gstate_c.curTextureYOffset * sf;
|
||||
@@ -2178,144 +2256,6 @@ TextureAlpha TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ComputeTextureHash(TextureReplacer &replacer, u32 addr, int bufw, int w, int h, bool swizzled, const TexCacheEntry *entry) {
|
||||
const GETextureFormat format = entry->format;
|
||||
if (replacer.Enabled()) {
|
||||
return replacer.ComputeHash(addr, bufw, w, h, swizzled, format, entry->maxSeenV);
|
||||
}
|
||||
|
||||
if (h == 512 && entry->maxSeenV < 512 && entry->maxSeenV != 0) {
|
||||
h = (int)entry->maxSeenV;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (Memory::IsValidAddress(addr + sizeInRAM)) {
|
||||
gpuStats.perFrame.numTextureDataBytesHashed += sizeInRAM;
|
||||
|
||||
// return XXH64(checkp, sizeInRAM, 0xBACD7814);
|
||||
return StableQuickTexHash(checkp, sizeInRAM);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
SetTexture();
|
||||
|
||||
TextureApplyResult result;
|
||||
TexCacheEntry *entry = nextTexture_;
|
||||
if (!entry) {
|
||||
// Maybe we bound a framebuffer?
|
||||
ForgetLastTexture();
|
||||
if (failedTexture_) {
|
||||
// Backends should handle this by binding a black texture with 0 alpha.
|
||||
BindTexture(nullptr);
|
||||
} else if (nextFramebufferTexture_) {
|
||||
// ApplyTextureFramebuffer is responsible for setting SetTextureFullAlpha.
|
||||
ApplyTextureFramebuffer(nextFramebufferTexture_, gstate.getTextureFormat(), nextFramebufferTextureChannel_);
|
||||
result.framebuffer = nextFramebufferTexture_;
|
||||
nextFramebufferTexture_ = nullptr;
|
||||
}
|
||||
// We don't set the 3D texture state here or anything else, on some backends (?)
|
||||
// a nextTexture_ of nullptr means keep the current texture.
|
||||
return result;
|
||||
}
|
||||
|
||||
nextTexture_ = nullptr;
|
||||
|
||||
UpdateMaxSeenV(entry, gstate.isModeThrough());
|
||||
|
||||
if (nextNeedsRebuild_) {
|
||||
// Regardless of hash fails or otherwise, if this is a video, mark it frequently changing.
|
||||
// This prevents temporary scaling perf hits on the first second of video.
|
||||
if (IsVideo(entry->addr)) {
|
||||
entry->status |= TexStatus::VIDEO;
|
||||
} else {
|
||||
entry->status &= ~TexStatus::VIDEO;
|
||||
}
|
||||
|
||||
if (nextNeedsRehash_) {
|
||||
PROFILE_THIS_SCOPE("texhash");
|
||||
// Update the hash on the texture.
|
||||
int w = gstate.getTextureWidth(0);
|
||||
int h = gstate.getTextureHeight(0);
|
||||
const bool swizzled = gstate.isTextureSwizzled();
|
||||
entry->fullhash = ComputeTextureHash(replacer_, entry->addr, entry->bufw, w, h, swizzled, entry);
|
||||
|
||||
// TODO: Here we could check the secondary cache; maybe the texture is in there?
|
||||
// We would need to abort the build if so.
|
||||
}
|
||||
if (nextNeedsChange_) {
|
||||
// This texture existed previously, let's handle the change.
|
||||
HandleTextureChange(entry, nextChangeReason_, false, true);
|
||||
}
|
||||
// We actually build afterward (shared with rehash rebuild.)
|
||||
} else if (nextNeedsRehash_) {
|
||||
// Okay, this matched and didn't change - but let's check the hash. Maybe it will change.
|
||||
bool doDelete = true;
|
||||
if (!CheckFullHash(entry, doDelete)) {
|
||||
HandleTextureChange(entry, "hash fail", true, doDelete);
|
||||
nextNeedsRebuild_ = true;
|
||||
} else if (nextTexture_ != nullptr) {
|
||||
// The secondary cache may choose an entry from its storage by setting nextTexture_.
|
||||
// This means we should set that, instead of our previous entry.
|
||||
entry = nextTexture_;
|
||||
nextTexture_ = nullptr;
|
||||
UpdateMaxSeenV(entry, gstate.isModeThrough());
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, now actually rebuild the texture if needed.
|
||||
if (nextNeedsRebuild_) {
|
||||
_assert_(!entry->texturePtr);
|
||||
BuildTexture(entry);
|
||||
ForgetLastTexture();
|
||||
}
|
||||
|
||||
gstate_c.SetTextureIsVideo((entry->status & TexStatus::VIDEO) != 0);
|
||||
entry->lastFrame = gpuStats.totals.numFlips;
|
||||
if (entry->status & TexStatus::CLUT_GPU) {
|
||||
_dbg_assert_(entry->status & TexStatus::CLUT8_INDEXED);
|
||||
// Special process.
|
||||
if (doBind) {
|
||||
ApplyTextureDepalFramebufferCLUT(entry);
|
||||
}
|
||||
gstate_c.SetTextureSolidAlpha(false);
|
||||
gstate_c.SetTextureIs3D(false);
|
||||
gstate_c.SetTextureIsArray(false);
|
||||
return TextureApplyResult{};
|
||||
} else {
|
||||
if (doBind) {
|
||||
BindTexture(entry);
|
||||
}
|
||||
gstate_c.SetTextureSolidAlpha((entry->status & TexStatus::ALPHA_SOLID) != 0);
|
||||
gstate_c.SetTextureIs3D((entry->status & TexStatus::IS_3D) != 0);
|
||||
gstate_c.SetTextureIsArray(false);
|
||||
if (entry->status & TexStatus::CLUT8_INDEXED) {
|
||||
bool smoothedDepal = false;
|
||||
u32 depthUpperBits = 0;
|
||||
ClutTexture clutTexture = clutTextureCache_.GetClutTexture(gstate.getClutPaletteFormat(), clutHash_, clutBuf_);
|
||||
BindAsClutTexture(clutTexture.texture, false);
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::NORMAL, GE_FORMAT_CLUT8);
|
||||
} else {
|
||||
gstate_c.SetShaderDepal(ShaderDepalMode::OFF);
|
||||
}
|
||||
}
|
||||
return TextureApplyResult{entry, nullptr};
|
||||
}
|
||||
|
||||
void TextureCacheCommon::ApplySampler(const TextureApplyResult &result, bool flatZ, bool pixelMapped) {
|
||||
SamplerCacheKey samplerKey;
|
||||
if (result.texCacheEntry) {
|
||||
@@ -2562,7 +2502,8 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
|
||||
}
|
||||
|
||||
// Applies depal to a normal (non-framebuffer) texture, pre-decoded to CLUT8 format.
|
||||
// TODO: Merge this function with the above.
|
||||
// TODO: Merge this function with the above. Or rather, we should try to eliminate this in favor
|
||||
// of in-shader depal.
|
||||
void TextureCacheCommon::ApplyTextureDepalFramebufferCLUT(const TexCacheEntry *const entry) {
|
||||
uint32_t clutMode = gstate.clutformat & 0xFFFFFF;
|
||||
|
||||
@@ -2920,6 +2861,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
|
||||
plan.w = gstate.getTextureWidth(0);
|
||||
plan.h = gstate.getTextureHeight(0);
|
||||
|
||||
// TODO: We should move the PPGE texture entirely out from the PSP's memory space, so we don't save it in every save state.
|
||||
const bool isPPGETexture = entry->addr >= PSP_GetKernelMemoryBase() && entry->addr < PSP_GetKernelMemoryEnd();
|
||||
|
||||
// Don't scale the PPGe texture.
|
||||
@@ -3170,9 +3112,6 @@ std::string TexStatusToString(TexStatus status) {
|
||||
if (status & TexStatus::CLUT8_INDEXED) {
|
||||
result += "CLUT8_INDEXED ";
|
||||
}
|
||||
if (status & TexStatus::FORCE_REBUILD) {
|
||||
result += "FORCE_REBUILD ";
|
||||
}
|
||||
if (status & TexStatus::IS_3D) {
|
||||
result += "3D ";
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ enum class TexStatus : u16 {
|
||||
IS_3D = (1 << 10),
|
||||
NO_MIPS = (1 << 11), // Has bad or unusable mipmap levels.
|
||||
FRAMEBUFFER_OVERLAP = (1 << 12),
|
||||
FORCE_REBUILD = (1 << 13),
|
||||
// Free bit 13
|
||||
CLUT8_INDEXED = (1 << 14), // Decoded as plain CLUT8 indices instead of all the way to colors.
|
||||
CLUT_GPU = (1 << 15),
|
||||
};
|
||||
@@ -329,6 +329,7 @@ struct TextureApplyResult {
|
||||
// At most one of these will be set.
|
||||
TexCacheEntry *texCacheEntry = nullptr;
|
||||
VirtualFramebuffer *framebuffer = nullptr;
|
||||
bool otherTexture = false;
|
||||
};
|
||||
|
||||
class TextureCacheCommon {
|
||||
@@ -346,7 +347,6 @@ public:
|
||||
TextureApplyResult ApplyTexture(bool doBind);
|
||||
void ApplySampler(const TextureApplyResult &result, bool flatZ, bool pixelMapped); // Should follow ApplyTexture
|
||||
|
||||
bool SetOffsetTexture(u32 yOffset);
|
||||
void Invalidate(u32 addr, int size, GPUInvalidationType type);
|
||||
void InvalidateAll(GPUInvalidationType type);
|
||||
void ClearNextFrame();
|
||||
@@ -405,10 +405,13 @@ protected:
|
||||
|
||||
// This updates nextTexture_ / nextFramebufferTexture_, which is then used by ApplyTexture.
|
||||
// TODO: Return stuff directly instead of keeping state.
|
||||
TexCacheEntry *SetTexture();
|
||||
TextureApplyResult ApplyTextureFinish(TexCacheEntry *entry, bool doBind);
|
||||
TextureApplyResult ApplyTextureFinishFramebuffer(VirtualFramebuffer *framebuffer, bool doBind);
|
||||
virtual void BindTexture(TexCacheEntry *entry) = 0;
|
||||
virtual void Unbind() = 0;
|
||||
virtual void BuildTexture(TexCacheEntry *const entry) = 0;
|
||||
virtual void ReleaseTexture(TexCacheEntry *entry, bool delete_them) = 0;
|
||||
VirtualFramebuffer *SetTextureFramebuffer(const AttachCandidate &candidate);
|
||||
void DeleteTexture(TexCache::iterator it);
|
||||
void Decimate(const TexCacheEntry *const exceptThisOne, bool forcePressure); // forcePressure defaults to false.
|
||||
|
||||
@@ -417,7 +420,6 @@ protected:
|
||||
virtual void ApplySamplerByKey(const SamplerCacheKey &key) = 0;
|
||||
|
||||
void HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete);
|
||||
virtual void BuildTexture(TexCacheEntry *const entry) = 0;
|
||||
virtual void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple); // only overridden in GLES
|
||||
bool CheckFullHash(TexCacheEntry *entry, bool &doDelete);
|
||||
|
||||
@@ -437,8 +439,7 @@ protected:
|
||||
|
||||
void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode);
|
||||
|
||||
void SetTextureFramebuffer(const AttachCandidate &candidate);
|
||||
bool GetCurrentFramebufferTextureDebug(GPUDebugBuffer &buffer, bool *isFramebuffer);
|
||||
bool GetFramebufferTextureDebug(const VirtualFramebuffer *vfb, GPUDebugBuffer &buffer);
|
||||
|
||||
virtual void BoundFramebufferTexture() {}
|
||||
|
||||
@@ -476,7 +477,6 @@ protected:
|
||||
|
||||
TexCacheEntry *nextTexture_ = nullptr;
|
||||
bool failedTexture_ = false;
|
||||
VirtualFramebuffer *nextFramebufferTexture_ = nullptr;
|
||||
RasterChannel nextFramebufferTextureChannel_ = RASTER_COLOR;
|
||||
|
||||
u32 clutHash_ = 0;
|
||||
|
||||
@@ -444,21 +444,23 @@ DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFo
|
||||
}
|
||||
|
||||
bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
|
||||
SetTexture();
|
||||
if (!nextTexture_) {
|
||||
return GetCurrentFramebufferTextureDebug(buffer, isFramebuffer);
|
||||
}
|
||||
|
||||
// Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer.
|
||||
TextureApplyResult textureResult = ApplyTexture(true);
|
||||
TexCacheEntry *entry = textureResult.texCacheEntry;
|
||||
if (textureResult.framebuffer) {
|
||||
*isFramebuffer = true;
|
||||
return GetFramebufferTextureDebug(textureResult.framebuffer, buffer);
|
||||
}
|
||||
|
||||
const TexCacheEntry *entry = textureResult.texCacheEntry;
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ID3D11Texture2D *texture = (ID3D11Texture2D *)entry->texturePtr;
|
||||
if (!texture)
|
||||
if (!texture) {
|
||||
// Hm.
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture->GetDesc(&desc);
|
||||
|
||||
@@ -361,15 +361,16 @@ Draw::DataFormat TextureCacheGLES::GetDestFormat(GETextureFormat format, GEPalet
|
||||
|
||||
bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
|
||||
ForgetLastTexture();
|
||||
SetTexture();
|
||||
if (!nextTexture_) {
|
||||
return GetCurrentFramebufferTextureDebug(buffer, isFramebuffer);
|
||||
}
|
||||
|
||||
// Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer.
|
||||
// We might need a render pass to set the sampling params, unfortunately. Otherwise BuildTexture may crash.
|
||||
framebufferManagerGL_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug");
|
||||
TextureApplyResult textureResult = ApplyTexture(false);
|
||||
if (textureResult.framebuffer) {
|
||||
*isFramebuffer = true;
|
||||
return GetFramebufferTextureDebug(textureResult.framebuffer, buffer);
|
||||
}
|
||||
|
||||
TexCacheEntry *entry = textureResult.texCacheEntry;
|
||||
if (!entry) {
|
||||
return false;
|
||||
|
||||
@@ -1002,13 +1002,13 @@ void TextureCacheVulkan::BoundFramebufferTexture() {
|
||||
}
|
||||
|
||||
bool TextureCacheVulkan::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
|
||||
SetTexture();
|
||||
if (!nextTexture_) {
|
||||
return GetCurrentFramebufferTextureDebug(buffer, isFramebuffer);
|
||||
}
|
||||
|
||||
// Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer.
|
||||
TextureApplyResult textureResult = ApplyTexture(true);
|
||||
if (textureResult.framebuffer) {
|
||||
*isFramebuffer = true;
|
||||
return GetFramebufferTextureDebug(textureResult.framebuffer, buffer);
|
||||
}
|
||||
|
||||
TexCacheEntry *entry = textureResult.texCacheEntry;
|
||||
if (!entry || !entry->vkTex) {
|
||||
return false;
|
||||
|
||||
Reference in new issue
Block a user