Fix image leak bug when pausing and we're just displaying a framebuffer in memory

This commit is contained in:
Henrik Rydgård 2023-05-30 18:12:20 +02:00
parent 364c205d95
commit 49ecc01556
7 changed files with 45 additions and 7 deletions

View file

@ -131,7 +131,6 @@ public:
stencilDirty_ = true;
}
void EndFrame() override;
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
@ -139,6 +138,9 @@ public:
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
void BeginFrame() override;
void EndFrame() override;
int GetFrameCount() override { return frameCount_; }
std::string GetInfoString(InfoField info) const override {
switch (info) {
@ -221,6 +223,7 @@ private:
int nextIndexBufferOffset_ = 0;
InvalidationCallback invalidationCallback_;
int frameCount_ = 0;
// Dynamic state
float blendFactor_[4]{};
@ -423,6 +426,7 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1
void D3D11DrawContext::EndFrame() {
curPipeline_ = nullptr;
frameCount_++;
}
void D3D11DrawContext::SetViewport(const Viewport &viewport) {

View file

@ -580,6 +580,7 @@ public:
}
void EndFrame() override;
int GetFrameCount() override { return frameCount_; }
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
@ -640,6 +641,7 @@ private:
D3DCAPS9 d3dCaps_;
char shadeLangVersion_[64]{};
DeviceCaps caps_{};
int frameCount_ = 0;
// Bound state
AutoRef<D3D9Pipeline> curPipeline_;
@ -964,6 +966,7 @@ void D3D9Context::BindNativeTexture(int index, void *nativeTexture) {
void D3D9Context::EndFrame() {
curPipeline_ = nullptr;
frameCount_++;
}
static void SemanticToD3D9UsageAndIndex(int semantic, BYTE *usage, BYTE *index) {

View file

@ -370,6 +370,10 @@ public:
void BeginFrame() override;
void EndFrame() override;
int GetFrameCount() override {
return frameCount_;
}
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
@ -492,6 +496,7 @@ private:
void ApplySamplers();
GLRenderManager renderManager_;
int frameCount_ = 0;
DeviceCaps caps_{};
@ -795,6 +800,7 @@ void OpenGLContext::EndFrame() {
renderManager_.Finish();
Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
frameCount_++;
}
void OpenGLContext::Invalidate(InvalidationFlags flags) {

View file

@ -53,8 +53,11 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
return false;
case 1303270965:
// Benign perf warning, image blit using GENERAL layout.
// UNASSIGNED
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
// TODO: Oops, turns out we filtered out a bit too much here!
// We really need that performance flag check to sort out the stuff that matters.
// Will enable it soon, but it'll take some fixing.
//
//if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
return false;
break;
@ -79,6 +82,14 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
// Extended validation (ARM best practices)
// Non-fifo validation not recommended
return false;
case -564812795:
case 369680064:
case 307231540:
case 618171435: // SHADER_ACCESS_READ
case 1774732925: // same but different
case -1539028524: // image layout in draw
// wip
return false;
default:
break;
}

View file

@ -484,6 +484,10 @@ public:
void EndFrame() override;
void WipeQueue() override;
int GetFrameCount() override {
return frameCount_;
}
void FlushState() override {}
void ResetStats() override {
@ -528,6 +532,7 @@ private:
VulkanTexture *GetNullTexture();
VulkanContext *vulkan_ = nullptr;
int frameCount_ = 0;
VulkanRenderManager renderManager_;
VulkanTexture *nullTexture_ = nullptr;
@ -1105,6 +1110,8 @@ void VKContext::EndFrame() {
// Unbind stuff, to avoid accidentally relying on it across frames (and provide some protection against forgotten unbinds of deleted things).
Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
frameCount_++;
}
void VKContext::Invalidate(InvalidationFlags flags) {

View file

@ -841,6 +841,10 @@ public:
// Not very elegant, but more elegant than the old passId hack.
virtual void SetInvalidationCallback(InvalidationCallback callback) = 0;
// Total amount of frames rendered. Unaffected by game pause, so more robust than gpuStats.numFlips
virtual int GetFrameCount() = 0;
virtual int GetFramesInFlight() { return 3; }
protected:
ShaderModule *vsPresets_[VS_MAX_PRESET];
ShaderModule *fsPresets_[FS_MAX_PRESET];

View file

@ -1402,16 +1402,19 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
Draw::DataFormat texFormat = srcPixelFormat == GE_FORMAT_DEPTH16 ? depthFormat : preferredPixelsFormat_;
int frameNumber = draw_->GetFrameCount();
// Look for a matching texture we can re-use.
for (auto &iter : drawPixelsCache_) {
if (iter.frameNumber > gpuStats.numFlips - 3 || iter.tex->Width() != width || iter.tex->Height() != height || iter.tex->Format() != texFormat) {
if (iter.frameNumber >= frameNumber - 3 || iter.tex->Width() != width || iter.tex->Height() != height || iter.tex->Format() != texFormat) {
continue;
}
// OK, current one seems good, let's use it (and mark it used).
gpuStats.numDrawPixels++;
draw_->UpdateTextureLevels(iter.tex, &srcPixels, generateTexture, 1);
iter.frameNumber = gpuStats.numFlips;
// NOTE: numFlips is no good - this is called every frame when paused sometimes!
iter.frameNumber = frameNumber;
return iter.tex;
}
@ -1442,7 +1445,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
INFO_LOG(G3D, "Creating drawPixelsCache texture: %dx%d", tex->Width(), tex->Height());
DrawPixelsEntry entry{ tex, gpuStats.numFlips };
DrawPixelsEntry entry{ tex, frameNumber };
drawPixelsCache_.push_back(entry);
return tex;
}
@ -1695,7 +1698,7 @@ void FramebufferManagerCommon::DecimateFBOs() {
// And DrawPixels cached textures.
for (auto it = drawPixelsCache_.begin(); it != drawPixelsCache_.end(); ) {
int age = gpuStats.numFlips - it->frameNumber;
int age = draw_->GetFrameCount() - it->frameNumber;
if (age > 10) {
INFO_LOG(G3D, "Releasing drawPixelsCache texture: %dx%d", it->tex->Width(), it->tex->Height());
it->tex->Release();