Latte: Serialize screenshot requests

This commit is contained in:
fooly 2026-07-15 20:12:12 +09:00
parent f613dc6b22
commit 78367c9aca
6 changed files with 77 additions and 13 deletions

View File

@ -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<LatteTextureMtl*>(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,

View File

@ -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)

View File

@ -109,24 +109,70 @@ uint8 Renderer::RGBComponentToSRGB(uint8 cli)
return (uint8)(cs * 255.0f);
}
void Renderer::RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot)
std::optional<Renderer::ScreenshotRequestId> Renderer::RequestScreenshot(
ScreenshotSaveFunction onSaveScreenshot, std::optional<bool> 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<uint8>& 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<uint8>& 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())

View File

@ -68,7 +68,10 @@ public:
virtual void SwapBuffers(bool swapTV, bool swapDRC) = 0;
using ScreenshotSaveFunction = std::function<std::optional<std::string>(const std::vector<uint8>&, int, int, bool)>;
void RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot);
using ScreenshotRequestId = uint64;
[[nodiscard]] std::optional<ScreenshotRequestId> RequestScreenshot(
ScreenshotSaveFunction onSaveScreenshot, std::optional<bool> 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<ScreenshotState> 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<bool> m_screenshot_main_window;
void SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow);
[[nodiscard]] ScreenshotRequestId GetActiveScreenshotRequestId();
void SaveScreenshot(ScreenshotRequestId requestId, const std::vector<uint8>& rgb_data,
int width, int height, bool mainWindow);
ImFontAtlas* imguiFontAtlas{};

View File

@ -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;

View File

@ -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);