From 1b1fc8de3e3d7ae1ee20efe2475e1150f7bde2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Thu, 2 Feb 2023 00:46:14 +0100 Subject: [PATCH] Save screenshot in separate thread to avoid lags Encoding the image as PNG and saving it to a file comprises the majority of the time when taking a screenshot. To avoid the client freezing while a screenshot is being saved, this task is moved to a separate background thread. --- src/engine/client/graphics_threaded.cpp | 76 ++++++++++++++++++------- src/engine/client/graphics_threaded.h | 3 +- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 0cbc07258..901ef68b0 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -11,11 +11,14 @@ #include #include +#include #include #include #include #include +#include #include + #include #include #include @@ -811,6 +814,55 @@ void CGraphics_Threaded::KickCommandBuffer() m_pCommandBuffer->Reset(); } +class CScreenshotSaveJob : public IJob +{ + IStorage *m_pStorage; + IConsole *m_pConsole; + char m_aName[IO_MAX_PATH_LENGTH]; + int m_Width; + int m_Height; + void *m_pData; + + void Run() override + { + char aWholePath[IO_MAX_PATH_LENGTH]; + char aBuf[64 + IO_MAX_PATH_LENGTH]; + IOHANDLE File = m_pStorage->OpenFile(m_aName, IOFLAG_WRITE, IStorage::TYPE_SAVE, aWholePath, sizeof(aWholePath)); + if(File) + { + TImageByteBuffer ByteBuffer; + SImageByteBuffer ImageByteBuffer(&ByteBuffer); + + if(SavePNG(IMAGE_FORMAT_RGBA, (const uint8_t *)m_pData, ImageByteBuffer, m_Width, m_Height)) + io_write(File, &ByteBuffer.front(), ByteBuffer.size()); + io_close(File); + + str_format(aBuf, sizeof(aBuf), "saved screenshot to '%s'", aWholePath); + } + else + { + str_format(aBuf, sizeof(aBuf), "failed to save screenshot to '%s'", aWholePath); + } + m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, ColorRGBA(1.0f, 0.6f, 0.3f, 1.0f)); + } + +public: + CScreenshotSaveJob(IStorage *pStorage, IConsole *pConsole, const char *pName, int Width, int Height, void *pData) : + m_pStorage(pStorage), + m_pConsole(pConsole), + m_Width(Width), + m_Height(Height), + m_pData(pData) + { + str_copy(m_aName, pName); + } + + virtual ~CScreenshotSaveJob() + { + free(m_pData); + } +}; + bool CGraphics_Threaded::ScreenshotDirect() { // add swap command @@ -831,28 +883,7 @@ bool CGraphics_Threaded::ScreenshotDirect() if(Image.m_pData) { - char aWholePath[IO_MAX_PATH_LENGTH]; - char aBuf[64 + IO_MAX_PATH_LENGTH]; - - IOHANDLE File = m_pStorage->OpenFile(m_aScreenshotName, IOFLAG_WRITE, IStorage::TYPE_SAVE, aWholePath, sizeof(aWholePath)); - if(File) - { - TImageByteBuffer ByteBuffer; - SImageByteBuffer ImageByteBuffer(&ByteBuffer); - - if(SavePNG(IMAGE_FORMAT_RGBA, (const uint8_t *)Image.m_pData, ImageByteBuffer, Image.m_Width, Image.m_Height)) - io_write(File, &ByteBuffer.front(), ByteBuffer.size()); - io_close(File); - - str_format(aBuf, sizeof(aBuf), "saved screenshot to '%s'", aWholePath); - } - else - { - str_format(aBuf, sizeof(aBuf), "failed to save screenshot to '%s'", aWholePath); - } - m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, ColorRGBA(1.0f, 0.6f, 0.3f, 1.0f)); - - free(Image.m_pData); + m_pEngine->AddJob(std::make_shared(m_pStorage, m_pConsole, m_aScreenshotName, Image.m_Width, Image.m_Height, Image.m_pData)); } return DidSwap; @@ -2836,6 +2867,7 @@ int CGraphics_Threaded::Init() // fetch pointers m_pStorage = Kernel()->RequestInterface(); m_pConsole = Kernel()->RequestInterface(); + m_pEngine = Kernel()->RequestInterface(); // init textures m_FirstFreeTexture = 0; diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index d060aa65b..3705df48c 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -802,6 +802,7 @@ class CGraphics_Threaded : public IEngineGraphics // class IStorage *m_pStorage; class IConsole *m_pConsole; + class IEngine *m_pEngine; int m_CurIndex; @@ -817,7 +818,7 @@ class CGraphics_Threaded : public IEngineGraphics float m_Rotation; int m_Drawing; bool m_DoScreenshot; - char m_aScreenshotName[128]; + char m_aScreenshotName[IO_MAX_PATH_LENGTH]; CTextureHandle m_InvalidTexture;