video_core: Remove global screenshot state
This commit is contained in:
@ -634,11 +634,13 @@ void GRenderWindow::ReleaseRenderTarget() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
|
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
|
||||||
if (res_scale == 0)
|
if (res_scale == 0) {
|
||||||
res_scale = VideoCore::GetResolutionScaleFactor();
|
res_scale = VideoCore::GetResolutionScaleFactor();
|
||||||
|
}
|
||||||
|
|
||||||
const auto layout{Layout::FrameLayoutFromResolutionScale(res_scale, is_secondary)};
|
const auto layout{Layout::FrameLayoutFromResolutionScale(res_scale, is_secondary)};
|
||||||
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
|
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
|
||||||
VideoCore::RequestScreenshot(
|
VideoCore::g_renderer->RequestScreenshot(
|
||||||
screenshot_image.bits(),
|
screenshot_image.bits(),
|
||||||
[this, screenshot_path] {
|
[this, screenshot_path] {
|
||||||
const std::string std_screenshot_path = screenshot_path.toStdString();
|
const std::string std_screenshot_path = screenshot_path.toStdString();
|
||||||
|
@ -11,6 +11,10 @@ RendererBase::RendererBase(Frontend::EmuWindow& window, Frontend::EmuWindow* sec
|
|||||||
|
|
||||||
RendererBase::~RendererBase() = default;
|
RendererBase::~RendererBase() = default;
|
||||||
|
|
||||||
|
void RendererBase::RefreshBaseSettings() {
|
||||||
|
UpdateCurrentFramebufferLayout();
|
||||||
|
}
|
||||||
|
|
||||||
void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) {
|
void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) {
|
||||||
const auto update_layout = [is_portrait_mode](Frontend::EmuWindow& window) {
|
const auto update_layout = [is_portrait_mode](Frontend::EmuWindow& window) {
|
||||||
const Layout::FramebufferLayout& layout = window.GetFramebufferLayout();
|
const Layout::FramebufferLayout& layout = window.GetFramebufferLayout();
|
||||||
@ -21,3 +25,19 @@ void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) {
|
|||||||
update_layout(*secondary_window);
|
update_layout(*secondary_window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RendererBase::IsScreenshotPending() const {
|
||||||
|
return renderer_settings.screenshot_requested;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererBase::RequestScreenshot(void* data, std::function<void()> 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;
|
||||||
|
}
|
||||||
|
@ -13,6 +13,14 @@ namespace Frontend {
|
|||||||
class EmuWindow;
|
class EmuWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RendererSettings {
|
||||||
|
// Screenshot
|
||||||
|
std::atomic<bool> screenshot_requested{false};
|
||||||
|
void* screenshot_bits{};
|
||||||
|
std::function<void()> screenshot_complete_callback;
|
||||||
|
Layout::FramebufferLayout screenshot_framebuffer_layout;
|
||||||
|
};
|
||||||
|
|
||||||
class RendererBase : NonCopyable {
|
class RendererBase : NonCopyable {
|
||||||
public:
|
public:
|
||||||
explicit RendererBase(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window);
|
explicit RendererBase(Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window);
|
||||||
@ -46,6 +54,7 @@ public:
|
|||||||
/// Cleans up after video dumping is ended
|
/// Cleans up after video dumping is ended
|
||||||
virtual void CleanupVideoDumping() = 0;
|
virtual void CleanupVideoDumping() = 0;
|
||||||
|
|
||||||
|
/// Synchronizes fixed function renderer state
|
||||||
virtual void Sync() = 0;
|
virtual void Sync() = 0;
|
||||||
|
|
||||||
/// Updates the framebuffer layout of the contained render window handle.
|
/// Updates the framebuffer layout of the contained render window handle.
|
||||||
@ -70,7 +79,26 @@ public:
|
|||||||
return render_window;
|
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<void()> callback,
|
||||||
|
const Layout::FramebufferLayout& layout);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
RendererSettings renderer_settings;
|
||||||
Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
|
Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
|
||||||
Frontend::EmuWindow* secondary_window; ///< Reference to the secondary 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
|
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
|
||||||
|
@ -354,7 +354,7 @@ void RendererOpenGL::SwapBuffers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::RenderScreenshot() {
|
void RendererOpenGL::RenderScreenshot() {
|
||||||
if (VideoCore::g_renderer_screenshot_requested) {
|
if (renderer_settings.screenshot_requested) {
|
||||||
// Draw this frame to the screenshot framebuffer
|
// Draw this frame to the screenshot framebuffer
|
||||||
screenshot_framebuffer.Create();
|
screenshot_framebuffer.Create();
|
||||||
GLuint old_read_fb = state.draw.read_framebuffer;
|
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.draw.read_framebuffer = state.draw.draw_framebuffer = screenshot_framebuffer.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
Layout::FramebufferLayout layout{VideoCore::g_screenshot_framebuffer_layout};
|
const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
|
||||||
|
|
||||||
GLuint renderbuffer;
|
GLuint renderbuffer;
|
||||||
glGenRenderbuffers(1, &renderbuffer);
|
glGenRenderbuffers(1, &renderbuffer);
|
||||||
@ -374,7 +374,7 @@ void RendererOpenGL::RenderScreenshot() {
|
|||||||
DrawScreens(layout, false);
|
DrawScreens(layout, false);
|
||||||
|
|
||||||
glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
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();
|
screenshot_framebuffer.Release();
|
||||||
state.draw.read_framebuffer = old_read_fb;
|
state.draw.read_framebuffer = old_read_fb;
|
||||||
@ -382,8 +382,8 @@ void RendererOpenGL::RenderScreenshot() {
|
|||||||
state.Apply();
|
state.Apply();
|
||||||
glDeleteRenderbuffers(1, &renderbuffer);
|
glDeleteRenderbuffers(1, &renderbuffer);
|
||||||
|
|
||||||
VideoCore::g_screenshot_complete_callback();
|
renderer_settings.screenshot_complete_callback();
|
||||||
VideoCore::g_renderer_screenshot_requested = false;
|
renderer_settings.screenshot_requested = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +277,8 @@ void RendererVulkan::BeginRendering() {
|
|||||||
present_textures[3].sampler = present_samplers[current_sampler];
|
present_textures[3].sampler = present_samplers[current_sampler];
|
||||||
|
|
||||||
vk::DescriptorSet set = desc_manager.AllocateSet(present_descriptor_layout);
|
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) {
|
scheduler.Record([this, set, pipeline_index = current_pipeline](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipelines[pipeline_index]);
|
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);
|
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::Format format = instance.GetTraits(pixel_format).native;
|
||||||
const vk::ImageCreateInfo image_info = {
|
const vk::ImageCreateInfo image_info = {
|
||||||
.imageType = vk::ImageType::e2D,
|
.imageType = vk::ImageType::e2D,
|
||||||
@ -1159,11 +1161,11 @@ void RendererVulkan::SwapBuffers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::RenderScreenshot() {
|
void RendererVulkan::RenderScreenshot() {
|
||||||
if (!VideoCore::g_renderer_screenshot_requested) {
|
if (!renderer_settings.screenshot_requested) {
|
||||||
return;
|
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 vk::Extent2D extent = swapchain.GetExtent();
|
||||||
const u32 width = std::min(layout.width, extent.width);
|
const u32 width = std::min(layout.width, extent.width);
|
||||||
const u32 height = std::min(layout.height, extent.height);
|
const u32 height = std::min(layout.height, extent.height);
|
||||||
@ -1354,19 +1356,18 @@ void RendererVulkan::RenderScreenshot() {
|
|||||||
const vk::SubresourceLayout subresource_layout =
|
const vk::SubresourceLayout subresource_layout =
|
||||||
device.getImageSubresourceLayout(staging_image, subresource);
|
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<const u8*>(alloc_info.pMappedData);
|
const u8* data = reinterpret_cast<const u8*>(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);
|
subresource_layout.size);
|
||||||
|
|
||||||
// Destroy allocated resources
|
// Destroy allocated resources
|
||||||
vmaDestroyImage(instance.GetAllocator(), unsafe_image, allocation);
|
|
||||||
vmaDestroyImage(instance.GetAllocator(), frame.image, frame.allocation);
|
vmaDestroyImage(instance.GetAllocator(), frame.image, frame.allocation);
|
||||||
device.destroyFramebuffer(frame.framebuffer);
|
device.destroyFramebuffer(frame.framebuffer);
|
||||||
device.destroyImageView(frame.image_view);
|
device.destroyImageView(frame.image_view);
|
||||||
|
|
||||||
VideoCore::g_screenshot_complete_callback();
|
renderer_settings.screenshot_complete_callback();
|
||||||
VideoCore::g_renderer_screenshot_requested = false;
|
renderer_settings.screenshot_requested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::NotifySurfaceChanged() {
|
void RendererVulkan::NotifySurfaceChanged() {
|
||||||
|
@ -31,11 +31,6 @@ std::atomic<bool> g_renderer_bg_color_update_requested;
|
|||||||
std::atomic<bool> g_renderer_sampler_update_requested;
|
std::atomic<bool> g_renderer_sampler_update_requested;
|
||||||
std::atomic<bool> g_renderer_shader_update_requested;
|
std::atomic<bool> g_renderer_shader_update_requested;
|
||||||
std::atomic<bool> g_texture_filter_update_requested;
|
std::atomic<bool> g_texture_filter_update_requested;
|
||||||
// Screenshot
|
|
||||||
std::atomic<bool> g_renderer_screenshot_requested;
|
|
||||||
void* g_screenshot_bits;
|
|
||||||
std::function<void()> g_screenshot_complete_callback;
|
|
||||||
Layout::FramebufferLayout g_screenshot_framebuffer_layout;
|
|
||||||
|
|
||||||
Memory::MemorySystem* g_memory;
|
Memory::MemorySystem* g_memory;
|
||||||
|
|
||||||
@ -80,18 +75,6 @@ void Shutdown() {
|
|||||||
LOG_DEBUG(Render, "shutdown OK");
|
LOG_DEBUG(Render, "shutdown OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestScreenshot(void* data, std::function<void()> 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() {
|
u16 GetResolutionScaleFactor() {
|
||||||
if (g_hw_renderer_enabled && g_renderer) {
|
if (g_hw_renderer_enabled && g_renderer) {
|
||||||
return Settings::values.resolution_factor.GetValue()
|
return Settings::values.resolution_factor.GetValue()
|
||||||
|
@ -39,11 +39,6 @@ extern std::atomic<bool> g_renderer_bg_color_update_requested;
|
|||||||
extern std::atomic<bool> g_renderer_sampler_update_requested;
|
extern std::atomic<bool> g_renderer_sampler_update_requested;
|
||||||
extern std::atomic<bool> g_renderer_shader_update_requested;
|
extern std::atomic<bool> g_renderer_shader_update_requested;
|
||||||
extern std::atomic<bool> g_texture_filter_update_requested;
|
extern std::atomic<bool> g_texture_filter_update_requested;
|
||||||
// Screenshot
|
|
||||||
extern std::atomic<bool> g_renderer_screenshot_requested;
|
|
||||||
extern void* g_screenshot_bits;
|
|
||||||
extern std::function<void()> g_screenshot_complete_callback;
|
|
||||||
extern Layout::FramebufferLayout g_screenshot_framebuffer_layout;
|
|
||||||
|
|
||||||
extern Memory::MemorySystem* g_memory;
|
extern Memory::MemorySystem* g_memory;
|
||||||
|
|
||||||
@ -56,10 +51,6 @@ ResultStatus Init(Frontend::EmuWindow& emu_window, Frontend::EmuWindow* secondar
|
|||||||
/// Shutdown the video core
|
/// Shutdown the video core
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
/// Request a screenshot of the next frame
|
|
||||||
void RequestScreenshot(void* data, std::function<void()> callback,
|
|
||||||
const Layout::FramebufferLayout& layout);
|
|
||||||
|
|
||||||
u16 GetResolutionScaleFactor();
|
u16 GetResolutionScaleFactor();
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
Reference in New Issue
Block a user