diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 991c9ad95..fd34d084f 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -634,11 +634,13 @@ void GRenderWindow::ReleaseRenderTarget() { } void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) { - if (res_scale == 0) + if (res_scale == 0) { res_scale = VideoCore::GetResolutionScaleFactor(); + } + const auto layout{Layout::FrameLayoutFromResolutionScale(res_scale, is_secondary)}; screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); - VideoCore::RequestScreenshot( + VideoCore::g_renderer->RequestScreenshot( screenshot_image.bits(), [this, screenshot_path] { const std::string std_screenshot_path = screenshot_path.toStdString(); diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index 68d1e964e..8d457ce25 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp @@ -11,6 +11,10 @@ RendererBase::RendererBase(Frontend::EmuWindow& window, Frontend::EmuWindow* sec RendererBase::~RendererBase() = default; +void RendererBase::RefreshBaseSettings() { + UpdateCurrentFramebufferLayout(); +} + void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) { const auto update_layout = [is_portrait_mode](Frontend::EmuWindow& window) { const Layout::FramebufferLayout& layout = window.GetFramebufferLayout(); @@ -21,3 +25,19 @@ void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) { update_layout(*secondary_window); } } + +bool RendererBase::IsScreenshotPending() const { + return renderer_settings.screenshot_requested; +} + +void RendererBase::RequestScreenshot(void* data, std::function callback, + const Layout::FramebufferLayout& layout) { + if (renderer_settings.screenshot_requested) { + LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request"); + return; + } + renderer_settings.screenshot_bits = data; + renderer_settings.screenshot_complete_callback = callback; + renderer_settings.screenshot_framebuffer_layout = layout; + renderer_settings.screenshot_requested = true; +} diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 4c53995db..ff0268903 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -13,6 +13,14 @@ namespace Frontend { class EmuWindow; } +struct RendererSettings { + // Screenshot + std::atomic screenshot_requested{false}; + void* screenshot_bits{}; + std::function screenshot_complete_callback; + Layout::FramebufferLayout screenshot_framebuffer_layout; +}; + class RendererBase : NonCopyable { public: explicit RendererBase(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window); @@ -46,6 +54,7 @@ public: /// Cleans up after video dumping is ended virtual void CleanupVideoDumping() = 0; + /// Synchronizes fixed function renderer state virtual void Sync() = 0; /// Updates the framebuffer layout of the contained render window handle. @@ -70,7 +79,26 @@ public: return render_window; } + [[nodiscard]] RendererSettings& Settings() { + return renderer_settings; + } + + [[nodiscard]] const RendererSettings& Settings() const { + return renderer_settings; + } + + /// Refreshes the settings common to all renderers + void RefreshBaseSettings(); + + /// Returns true if a screenshot is being processed + bool IsScreenshotPending() const; + + /// Request a screenshot of the next frame + void RequestScreenshot(void* data, std::function callback, + const Layout::FramebufferLayout& layout); + protected: + RendererSettings renderer_settings; Frontend::EmuWindow& render_window; ///< Reference to the render window handle. Frontend::EmuWindow* secondary_window; ///< Reference to the secondary render window handle. f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index b91a26f80..1e226eff9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -354,7 +354,7 @@ void RendererOpenGL::SwapBuffers() { } void RendererOpenGL::RenderScreenshot() { - if (VideoCore::g_renderer_screenshot_requested) { + if (renderer_settings.screenshot_requested) { // Draw this frame to the screenshot framebuffer screenshot_framebuffer.Create(); GLuint old_read_fb = state.draw.read_framebuffer; @@ -362,7 +362,7 @@ void RendererOpenGL::RenderScreenshot() { state.draw.read_framebuffer = state.draw.draw_framebuffer = screenshot_framebuffer.handle; state.Apply(); - Layout::FramebufferLayout layout{VideoCore::g_screenshot_framebuffer_layout}; + const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; GLuint renderbuffer; glGenRenderbuffers(1, &renderbuffer); @@ -374,7 +374,7 @@ void RendererOpenGL::RenderScreenshot() { DrawScreens(layout, false); glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - VideoCore::g_screenshot_bits); + renderer_settings.screenshot_bits); screenshot_framebuffer.Release(); state.draw.read_framebuffer = old_read_fb; @@ -382,8 +382,8 @@ void RendererOpenGL::RenderScreenshot() { state.Apply(); glDeleteRenderbuffers(1, &renderbuffer); - VideoCore::g_screenshot_complete_callback(); - VideoCore::g_renderer_screenshot_requested = false; + renderer_settings.screenshot_complete_callback(); + renderer_settings.screenshot_requested = false; } } diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 0820af75e..589cc3f0b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -277,7 +277,8 @@ void RendererVulkan::BeginRendering() { present_textures[3].sampler = present_samplers[current_sampler]; vk::DescriptorSet set = desc_manager.AllocateSet(present_descriptor_layout); - instance.GetDevice().updateDescriptorSetWithTemplate(set, present_update_template, present_textures[0]); + instance.GetDevice().updateDescriptorSetWithTemplate(set, present_update_template, + present_textures[0]); scheduler.Record([this, set, pipeline_index = current_pipeline](vk::CommandBuffer cmdbuf) { cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipelines[pipeline_index]); @@ -550,7 +551,8 @@ void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture, vmaDestroyImage(instance.GetAllocator(), texture.image, texture.allocation); } - const VideoCore::PixelFormat pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format); + const VideoCore::PixelFormat pixel_format = + VideoCore::PixelFormatFromGPUPixelFormat(framebuffer.color_format); const vk::Format format = instance.GetTraits(pixel_format).native; const vk::ImageCreateInfo image_info = { .imageType = vk::ImageType::e2D, @@ -1159,11 +1161,11 @@ void RendererVulkan::SwapBuffers() { } void RendererVulkan::RenderScreenshot() { - if (!VideoCore::g_renderer_screenshot_requested) { + if (!renderer_settings.screenshot_requested) { return; } - const Layout::FramebufferLayout layout{VideoCore::g_screenshot_framebuffer_layout}; + const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; const vk::Extent2D extent = swapchain.GetExtent(); const u32 width = std::min(layout.width, extent.width); const u32 height = std::min(layout.height, extent.height); @@ -1354,19 +1356,18 @@ void RendererVulkan::RenderScreenshot() { const vk::SubresourceLayout subresource_layout = device.getImageSubresourceLayout(staging_image, subresource); - // Map image memory so we can start copying from it + // Copy backing image data to the QImage screenshot buffer const u8* data = reinterpret_cast(alloc_info.pMappedData); - std::memcpy(VideoCore::g_screenshot_bits, data + subresource_layout.offset, + std::memcpy(renderer_settings.screenshot_bits, data + subresource_layout.offset, subresource_layout.size); // Destroy allocated resources - vmaDestroyImage(instance.GetAllocator(), unsafe_image, allocation); vmaDestroyImage(instance.GetAllocator(), frame.image, frame.allocation); device.destroyFramebuffer(frame.framebuffer); device.destroyImageView(frame.image_view); - VideoCore::g_screenshot_complete_callback(); - VideoCore::g_renderer_screenshot_requested = false; + renderer_settings.screenshot_complete_callback(); + renderer_settings.screenshot_requested = false; } void RendererVulkan::NotifySurfaceChanged() { diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index a42bc5c0d..d35b42b74 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -31,11 +31,6 @@ std::atomic g_renderer_bg_color_update_requested; std::atomic g_renderer_sampler_update_requested; std::atomic g_renderer_shader_update_requested; std::atomic g_texture_filter_update_requested; -// Screenshot -std::atomic g_renderer_screenshot_requested; -void* g_screenshot_bits; -std::function g_screenshot_complete_callback; -Layout::FramebufferLayout g_screenshot_framebuffer_layout; Memory::MemorySystem* g_memory; @@ -80,18 +75,6 @@ void Shutdown() { LOG_DEBUG(Render, "shutdown OK"); } -void RequestScreenshot(void* data, std::function callback, - const Layout::FramebufferLayout& layout) { - if (g_renderer_screenshot_requested) { - LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request"); - return; - } - g_screenshot_bits = data; - g_screenshot_complete_callback = std::move(callback); - g_screenshot_framebuffer_layout = layout; - g_renderer_screenshot_requested = true; -} - u16 GetResolutionScaleFactor() { if (g_hw_renderer_enabled && g_renderer) { return Settings::values.resolution_factor.GetValue() diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index 04c0d94b5..90e366d39 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -39,11 +39,6 @@ extern std::atomic g_renderer_bg_color_update_requested; extern std::atomic g_renderer_sampler_update_requested; extern std::atomic g_renderer_shader_update_requested; extern std::atomic g_texture_filter_update_requested; -// Screenshot -extern std::atomic g_renderer_screenshot_requested; -extern void* g_screenshot_bits; -extern std::function g_screenshot_complete_callback; -extern Layout::FramebufferLayout g_screenshot_framebuffer_layout; extern Memory::MemorySystem* g_memory; @@ -56,10 +51,6 @@ ResultStatus Init(Frontend::EmuWindow& emu_window, Frontend::EmuWindow* secondar /// Shutdown the video core void Shutdown(); -/// Request a screenshot of the next frame -void RequestScreenshot(void* data, std::function callback, - const Layout::FramebufferLayout& layout); - u16 GetResolutionScaleFactor(); template