mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
GPU: Fix texture cache and framebuffer cache lifetime bugs
- Delete TexCacheEntry objects dropped on rehash instead of leaking them. - Don't leave a released null entry in cache_ when the framebuffer match returns before the slot is refilled. - Reset clutRenderAddress_ in Clear(), which releases the dynamic CLUT FBOs. - Don't cache a null texture in drawPixelsCache_ when creation fails. - Fix the reversed subtraction in the failed-FBO retry check. - Remove the never-taken buffered-rendering early-out in UpdateRenderSize. Taking it would leave existing VFBs without an fbo. - Include smoothedDepal in the depal shader cache key, and print/parse the debug IDs as 64-bit. - Release depal pipelines through Draw2DPipeline::Release so the shader source isn't leaked, and make that null-safe. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
b04d03615b
commit
b912b5823b
4 files changed
+18
-16
No files matched your search
+3
-1
@@ -49,7 +49,9 @@ struct Draw2DPipeline {
|
||||
Draw2DPipelineInfo info;
|
||||
char *code;
|
||||
void Release() {
|
||||
pipeline->Release();
|
||||
if (pipeline) {
|
||||
pipeline->Release();
|
||||
}
|
||||
delete[] code;
|
||||
delete this;
|
||||
}
|
||||
|
||||
@@ -103,10 +103,8 @@ bool FramebufferManagerCommon::UpdateRenderSize(int msaaLevel) {
|
||||
|
||||
presentation_->UpdateRenderSize(renderWidth_, renderHeight_);
|
||||
|
||||
// If just switching TO buffered rendering, no need to pause the threads. In fact this causes problems due to the open backbuffer renderpass.
|
||||
if (!useBufferedRendering_ && newBuffered) {
|
||||
return false;
|
||||
}
|
||||
// Switching to buffered rendering must also recreate the framebuffers: the existing VFBs have no fbo,
|
||||
// and nothing else gives them one.
|
||||
return newRender || newSettings;
|
||||
}
|
||||
|
||||
@@ -1531,6 +1529,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
|
||||
Draw::Texture *tex = draw_->CreateTexture(desc);
|
||||
if (!tex) {
|
||||
ERROR_LOG(Log::G3D, "Failed to create DrawPixels texture");
|
||||
return nullptr;
|
||||
}
|
||||
// We don't need to count here, already counted by numUploads by the caller.
|
||||
|
||||
@@ -1876,7 +1875,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!old.fbo && vfb->last_frame_failed != 0 && vfb->last_frame_failed - gpuStats.totals.numFlips < 63) {
|
||||
if (!old.fbo && vfb->last_frame_failed != 0 && gpuStats.totals.numFlips - vfb->last_frame_failed < 63) {
|
||||
// Don't constantly retry FBOs which failed to create.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -757,12 +757,14 @@ TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
DEBUG_LOG(Log::TexCache, "%08x: Second cache already had one with hash %08x (tex has addr %08x)! (%dx%d)", texaddr, entry->fullhash, entry->addr, w, h);
|
||||
// Just release the old entry, drop it on the ground.
|
||||
ReleaseTexture(entry, true);
|
||||
delete entry;
|
||||
entry = nullptr;
|
||||
}
|
||||
} else {
|
||||
// Just release the old video entry, drop it on the ground.
|
||||
VERBOSE_LOG(Log::TexCache, "%08x: Dropping old invalidated video image (%dx%d)", texaddr, w, h);
|
||||
ReleaseTexture(entry, true);
|
||||
delete entry;
|
||||
entry = nullptr;
|
||||
}
|
||||
|
||||
@@ -802,9 +804,9 @@ TextureApplyResult TextureCacheCommon::ApplyTexture(bool doBind) {
|
||||
// other stuff like Gran Turismo or Gods Eater font rendering unless there are hash collisions..
|
||||
DEBUG_LOG(Log::TexCache, "%08x: No entry for hash %08x in secondary cache, creating new in main cache.", texaddr, newFullHash);
|
||||
}
|
||||
// Well, not found, so we need to create a new entry.
|
||||
cache_.erase(entryIter);
|
||||
}
|
||||
// The slot was released above. Erase it, since the framebuffer match below can return before it's refilled.
|
||||
cache_.erase(entryIter);
|
||||
entry = nullptr;
|
||||
entryIter = cache_.end();
|
||||
} else {
|
||||
@@ -2740,6 +2742,8 @@ void TextureCacheCommon::Clear(bool delete_them) {
|
||||
dynamicClutTemp_->Release();
|
||||
dynamicClutTemp_ = nullptr;
|
||||
}
|
||||
// The dynamic CLUT lived in the framebuffers released above. Fall back to the RAM copy until the next LoadClut.
|
||||
clutRenderAddress_ = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
// One type of texture update can happen without the involvement of the CPU: Block transfers.
|
||||
|
||||
@@ -79,10 +79,7 @@ Draw::SamplerState *TextureShaderCache::GetSampler(bool linearFilter) {
|
||||
|
||||
void TextureShaderCache::Clear() {
|
||||
for (auto shader = pipelineCache_.begin(); shader != pipelineCache_.end(); ++shader) {
|
||||
if (shader->second->pipeline) {
|
||||
shader->second->pipeline->Release();
|
||||
}
|
||||
delete shader->second;
|
||||
shader->second->Release();
|
||||
}
|
||||
pipelineCache_.clear();
|
||||
if (nearestSampler_) {
|
||||
@@ -99,7 +96,7 @@ Draw2DPipeline *TextureShaderCache::GetDepalettizeShader(uint32_t clutMode, GETe
|
||||
using namespace Draw;
|
||||
|
||||
// Generate an ID for depal shaders.
|
||||
u64 id = ((u64)depthUpperBits << 32) | (clutMode & 0xFFFFFF) | (textureFormat << 24) | (bufferFormat << 28);
|
||||
u64 id = ((u64)smoothedDepal << 63) | ((u64)depthUpperBits << 32) | (clutMode & 0xFFFFFF) | (textureFormat << 24) | (bufferFormat << 28);
|
||||
|
||||
auto shader = pipelineCache_.find(id);
|
||||
if (shader != pipelineCache_.end()) {
|
||||
@@ -135,14 +132,14 @@ Draw2DPipeline *TextureShaderCache::GetDepalettizeShader(uint32_t clutMode, GETe
|
||||
std::vector<std::string> TextureShaderCache::DebugGetShaderIDs(DebugShaderType type) const {
|
||||
std::vector<std::string> ids;
|
||||
for (auto &entry : pipelineCache_) {
|
||||
ids.push_back(StringFromFormat("%08x", entry.first));
|
||||
ids.push_back(StringFromFormat("%016llx", (unsigned long long)entry.first));
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::string TextureShaderCache::DebugGetShaderString(const std::string &idstr, DebugShaderType type, DebugShaderStringType stringType) const {
|
||||
uint32_t id = 0;
|
||||
if (sscanf(idstr.c_str(), "%08x", &id) == 0) {
|
||||
unsigned long long id = 0;
|
||||
if (sscanf(idstr.c_str(), "%llx", &id) != 1) {
|
||||
return "";
|
||||
}
|
||||
auto iter = pipelineCache_.find(id);
|
||||
|
||||
Reference in new issue
Block a user