diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 4cfdde33..3be934f8 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -413,6 +413,9 @@ void MetalRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padV } else m_screenshot_state = ScreenshotState::None; + const auto screenshotRequestId = GetActiveScreenshotRequestId(); + if (screenshotRequestId == 0) + return; auto texMtl = static_cast(texView->baseTexture); @@ -460,7 +463,7 @@ void MetalRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padV } if (formatValid) - SaveScreenshot(rgb_data, width, height, !padView); + SaveScreenshot(screenshotRequestId, rgb_data, width, height, !padView); } void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp index 9d30da31..4f8365a3 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp @@ -536,6 +536,9 @@ void OpenGLRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad } else m_screenshot_state = ScreenshotState::None; + const auto screenshotRequestId = GetActiveScreenshotRequestId(); + if (screenshotRequestId == 0) + return; int screenshotWidth, screenshotHeight; glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); @@ -577,7 +580,7 @@ void OpenGLRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad } } - SaveScreenshot(rgb_data, screenshotWidth, screenshotHeight, !padView); + SaveScreenshot(screenshotRequestId, rgb_data, screenshotWidth, screenshotHeight, !padView); } void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground) diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.cpp b/src/Cafe/HW/Latte/Renderer/Renderer.cpp index 35991cde..e8c5f42d 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Renderer.cpp @@ -109,24 +109,70 @@ uint8 Renderer::RGBComponentToSRGB(uint8 cli) return (uint8)(cs * 255.0f); } -void Renderer::RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot) +std::optional Renderer::RequestScreenshot( + ScreenshotSaveFunction onSaveScreenshot, std::optional mainWindow) { + std::lock_guard lock(m_screenshot_mutex); + if (!onSaveScreenshot || m_screenshot_active_request_id != 0 || + m_screenshot_requested.load(std::memory_order_acquire) || + m_screenshot_state.load(std::memory_order_acquire) != ScreenshotState::None) + return std::nullopt; + auto requestId = m_screenshot_next_request_id++; + if (requestId == 0) + requestId = m_screenshot_next_request_id++; + m_screenshot_active_request_id = requestId; + m_on_save_screenshot = std::move(onSaveScreenshot); + m_screenshot_main_window = mainWindow; m_screenshot_requested = true; - m_on_save_screenshot = onSaveScreenshot; + return requestId; +} + +bool Renderer::CancelScreenshotRequest(ScreenshotRequestId requestId) +{ + std::lock_guard lock(m_screenshot_mutex); + if (requestId == 0 || m_screenshot_active_request_id != requestId) + return false; + m_screenshot_requested = false; + m_on_save_screenshot = {}; + m_screenshot_main_window.reset(); + m_screenshot_active_request_id = 0; + return true; } void Renderer::CancelScreenshotRequest() { + std::lock_guard lock(m_screenshot_mutex); m_screenshot_requested = false; m_on_save_screenshot = {}; + m_screenshot_main_window.reset(); + m_screenshot_active_request_id = 0; } -void Renderer::SaveScreenshot(const std::vector& rgb_data, int width, int height, bool mainWindow) +Renderer::ScreenshotRequestId Renderer::GetActiveScreenshotRequestId() { + std::lock_guard lock(m_screenshot_mutex); + return m_screenshot_active_request_id; +} + +void Renderer::SaveScreenshot(ScreenshotRequestId requestId, const std::vector& rgb_data, + int width, int height, bool mainWindow) +{ + ScreenshotSaveFunction onSaveScreenshot; + { + std::lock_guard lock(m_screenshot_mutex); + if (requestId == 0 || requestId != m_screenshot_active_request_id) + return; + if (m_screenshot_main_window.has_value() && m_screenshot_main_window.value() != mainWindow) + return; + m_screenshot_main_window.reset(); + m_screenshot_requested = false; + onSaveScreenshot = std::move(m_on_save_screenshot); + m_screenshot_active_request_id = 0; + } std::thread( - [=, screenshotRequested = std::exchange(m_screenshot_requested, false), onSaveScreenshot = std::exchange(m_on_save_screenshot, {})]() { - if (screenshotRequested && onSaveScreenshot) + [=, onSaveScreenshot = std::move(onSaveScreenshot)]() { + if (onSaveScreenshot) { auto notificationMessage = onSaveScreenshot(rgb_data, width, height, mainWindow); if (notificationMessage.has_value()) diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.h b/src/Cafe/HW/Latte/Renderer/Renderer.h index 6482f37a..517ecc21 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.h +++ b/src/Cafe/HW/Latte/Renderer/Renderer.h @@ -68,7 +68,10 @@ public: virtual void SwapBuffers(bool swapTV, bool swapDRC) = 0; using ScreenshotSaveFunction = std::function(const std::vector&, int, int, bool)>; - void RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot); + using ScreenshotRequestId = uint64; + [[nodiscard]] std::optional RequestScreenshot( + ScreenshotSaveFunction onSaveScreenshot, std::optional mainWindow = {}); + bool CancelScreenshotRequest(ScreenshotRequestId requestId); void CancelScreenshotRequest(); virtual void HandleScreenshotRequest(LatteTextureView* texView, bool padView){} @@ -175,11 +178,17 @@ protected: Main, Pad, }; - ScreenshotState m_screenshot_state = ScreenshotState::None; - bool m_screenshot_requested = false; + std::atomic m_screenshot_state{ScreenshotState::None}; + std::atomic_bool m_screenshot_requested{false}; + std::mutex m_screenshot_mutex; + ScreenshotRequestId m_screenshot_next_request_id{1}; + ScreenshotRequestId m_screenshot_active_request_id{}; ScreenshotSaveFunction m_on_save_screenshot; + std::optional m_screenshot_main_window; - void SaveScreenshot(const std::vector& rgb_data, int width, int height, bool mainWindow); + [[nodiscard]] ScreenshotRequestId GetActiveScreenshotRequestId(); + void SaveScreenshot(ScreenshotRequestId requestId, const std::vector& rgb_data, + int width, int height, bool mainWindow); ImFontAtlas* imguiFontAtlas{}; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index c700fbc2..da8ac9a9 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -1022,6 +1022,9 @@ void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad } else m_screenshot_state = ScreenshotState::None; + const auto screenshotRequestId = GetActiveScreenshotRequestId(); + if (screenshotRequestId == 0) + return; auto texViewVk = (LatteTextureViewVk*)texView; auto baseImageTex = texViewVk->GetBaseImage(); @@ -1268,7 +1271,7 @@ void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad vkFreeMemory(m_logicalDevice, imageMemory, nullptr); if (formatValid) - SaveScreenshot(rgb_data, width, height, !padView); + SaveScreenshot(screenshotRequestId, rgb_data, width, height, !padView); } static const float kQueuePriority = 1.0f; diff --git a/src/gui/wxgui/input/HotkeySettings.cpp b/src/gui/wxgui/input/HotkeySettings.cpp index d84ffa1b..2a08d481 100644 --- a/src/gui/wxgui/input/HotkeySettings.cpp +++ b/src/gui/wxgui/input/HotkeySettings.cpp @@ -192,7 +192,7 @@ void HotkeySettings::Init(MainWindow* mainWindowFrame) }}, {&s_cfgHotkeys.takeScreenshot, [](void) { if (g_renderer) - g_renderer->RequestScreenshot(SaveScreenshot); + (void)g_renderer->RequestScreenshot(SaveScreenshot); }}, {&s_cfgHotkeys.toggleFastForward, [](void) { ActiveSettings::SetTimerShiftFactor((ActiveSettings::GetTimerShiftFactor() < 3) ? 3 : 1);