From fb832b482c6e74696271b70f484ae5184fb47f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sat, 27 Jul 2024 21:19:10 +0200 Subject: [PATCH] Fix memory leak of non-RGBA image data, clear all image info The image data was not being freed when `IGraphics::LoadTextureRawMove` is used with images that are not in RGBA format as this falls back to using `IGraphics::LoadTextureRaw` which requires manually freeing the image data. Also consistently clear all image info in `LoadTextureRawMove`. This makes it necessary to store the size of the preview image in the editor separately, as previously the width and height of the unloaded image info were being used to render the preview image. --- src/engine/client/graphics_threaded.cpp | 5 ++++- src/game/client/components/menus_browser.cpp | 1 - src/game/editor/editor.cpp | 16 +++++++++------- src/game/editor/editor.h | 3 ++- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 1e40d81a765..3f624be3295 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -474,7 +474,9 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRawMove(CImageInfo &Ima if(Image.m_Format != CImageInfo::FORMAT_RGBA) { // Moving not possible, texture needs to be converted - return LoadTextureRaw(Image, Flags, pTexName); + IGraphics::CTextureHandle TextureHandle = LoadTextureRaw(Image, Flags, pTexName); + Image.Free(); + return TextureHandle; } LoadTextureAddWarning(Image.m_Width, Image.m_Height, Flags, pTexName, m_vWarnings); @@ -486,6 +488,7 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRawMove(CImageInfo &Ima CCommandBuffer::SCommand_Texture_Create Cmd = LoadTextureCreateCommand(TextureHandle.Id(), Image.m_Width, Image.m_Height, Flags); Cmd.m_pData = Image.m_pData; Image.m_pData = nullptr; + Image.Free(); AddCmd(Cmd); return TextureHandle; diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 3bbb9f2fce7..a3d6898a6f5 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -2001,7 +2001,6 @@ void CMenus::LoadCommunityIconFinish(const char *pCommunityId, CImageInfo &Info, pData[i * Step + 2] = v; } CommunityIcon.m_GreyTexture = Graphics()->LoadTextureRawMove(Info, 0, pCommunityId); - Info.m_pData = nullptr; auto ExistingIcon = std::find_if(m_vCommunityIcons.begin(), m_vCommunityIcons.end(), [pCommunityId](const SCommunityIcon &Element) { return str_comp(Element.m_aCommunityId, pCommunityId) == 0; diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index f04d73f08a8..8aabc4f2046 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -5140,11 +5140,13 @@ void CEditor::RenderFileDialog() { char aBuffer[IO_MAX_PATH_LENGTH]; str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_pFileDialogPath, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename); - if(Graphics()->LoadPng(m_FilePreviewImageInfo, aBuffer, m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType)) + CImageInfo PreviewImageInfo; + if(Graphics()->LoadPng(PreviewImageInfo, aBuffer, m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType)) { Graphics()->UnloadTexture(&m_FilePreviewImage); - m_FilePreviewImage = Graphics()->LoadTextureRawMove(m_FilePreviewImageInfo, 0, aBuffer); - m_FilePreviewImageInfo.m_pData = nullptr; + m_FilePreviewImageWidth = PreviewImageInfo.m_Width; + m_FilePreviewImageHeight = PreviewImageInfo.m_Height; + m_FilePreviewImage = Graphics()->LoadTextureRawMove(PreviewImageInfo, 0, aBuffer); m_FilePreviewState = PREVIEW_LOADED; } else @@ -5167,11 +5169,11 @@ void CEditor::RenderFileDialog() Preview.Margin(10.0f, &Preview); if(m_FilePreviewState == PREVIEW_LOADED) { - int w = m_FilePreviewImageInfo.m_Width; - int h = m_FilePreviewImageInfo.m_Height; - if(m_FilePreviewImageInfo.m_Width > Preview.w) + int w = m_FilePreviewImageWidth; + int h = m_FilePreviewImageHeight; + if(m_FilePreviewImageWidth > Preview.w) { - h = m_FilePreviewImageInfo.m_Height * Preview.w / m_FilePreviewImageInfo.m_Width; + h = m_FilePreviewImageHeight * Preview.w / m_FilePreviewImageWidth; w = Preview.w; } if(h > Preview.h) diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 151fa36eaa4..bead2c2171a 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -610,7 +610,8 @@ class CEditor : public IEditor IGraphics::CTextureHandle m_FilePreviewImage; int m_FilePreviewSound; EPreviewState m_FilePreviewState; - CImageInfo m_FilePreviewImageInfo; + int m_FilePreviewImageWidth; + int m_FilePreviewImageHeight; bool m_FileDialogOpening; int m_ToolbarPreviewSound;