citra_qt, video_core: Screenshot functionality
Allows capturing screenshot at the current internal resolution (native for software renderer), but a setting is available to capture it in other resolutions. The screenshot is saved to a single PNG in the current layout.
This commit is contained in:
parent
7e90abec78
commit
071b41cb61
14 changed files with 202 additions and 14 deletions
|
@ -24,7 +24,6 @@
|
|||
#include "common/vector_math.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/pica_state.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||
|
@ -78,12 +77,6 @@ constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
|||
return boost::make_iterator_range(map.equal_range(interval));
|
||||
}
|
||||
|
||||
static u16 GetResolutionScaleFactor() {
|
||||
return !Settings::values.resolution_factor
|
||||
? VideoCore::g_renderer->GetRenderWindow().GetFramebufferLayout().GetScalingRatio()
|
||||
: Settings::values.resolution_factor;
|
||||
}
|
||||
|
||||
template <bool morton_to_gl, PixelFormat format>
|
||||
static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
|
||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
|
||||
|
@ -1360,9 +1353,9 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
|||
const auto& config = regs.framebuffer.framebuffer;
|
||||
|
||||
// update resolution_scale_factor and reset cache if changed
|
||||
static u16 resolution_scale_factor = GetResolutionScaleFactor();
|
||||
if (resolution_scale_factor != GetResolutionScaleFactor()) {
|
||||
resolution_scale_factor = GetResolutionScaleFactor();
|
||||
static u16 resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||
if (resolution_scale_factor != VideoCore::GetResolutionScaleFactor()) {
|
||||
resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||
FlushAll();
|
||||
while (!surface_cache.empty())
|
||||
UnregisterSurface(*surface_cache.begin()->second.begin());
|
||||
|
|
|
@ -140,7 +140,39 @@ void RendererOpenGL::SwapBuffers() {
|
|||
}
|
||||
}
|
||||
|
||||
DrawScreens();
|
||||
if (VideoCore::g_renderer_screenshot_requested) {
|
||||
// Draw this frame to the screenshot framebuffer
|
||||
screenshot_framebuffer.Create();
|
||||
GLuint old_read_fb = state.draw.read_framebuffer;
|
||||
GLuint old_draw_fb = state.draw.draw_framebuffer;
|
||||
state.draw.read_framebuffer = state.draw.draw_framebuffer = screenshot_framebuffer.handle;
|
||||
state.Apply();
|
||||
|
||||
Layout::FramebufferLayout layout{VideoCore::g_screenshot_framebuffer_layout};
|
||||
|
||||
GLuint renderbuffer;
|
||||
glGenRenderbuffers(1, &renderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, layout.width, layout.height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
|
||||
renderbuffer);
|
||||
|
||||
DrawScreens(layout);
|
||||
|
||||
glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
VideoCore::g_screenshot_bits);
|
||||
|
||||
screenshot_framebuffer.Release();
|
||||
state.draw.read_framebuffer = old_read_fb;
|
||||
state.draw.draw_framebuffer = old_draw_fb;
|
||||
state.Apply();
|
||||
glDeleteRenderbuffers(1, &renderbuffer);
|
||||
|
||||
VideoCore::g_screenshot_complete_callback();
|
||||
VideoCore::g_renderer_screenshot_requested = false;
|
||||
}
|
||||
|
||||
DrawScreens(render_window.GetFramebufferLayout());
|
||||
|
||||
Core::System::GetInstance().perf_stats.EndSystemFrame();
|
||||
|
||||
|
@ -386,14 +418,13 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
|
|||
/**
|
||||
* Draws the emulated screens to the emulator window.
|
||||
*/
|
||||
void RendererOpenGL::DrawScreens() {
|
||||
void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) {
|
||||
if (VideoCore::g_renderer_bg_color_update_requested.exchange(false)) {
|
||||
// Update background color before drawing
|
||||
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
|
||||
0.0f);
|
||||
}
|
||||
|
||||
auto layout = render_window.GetFramebufferLayout();
|
||||
const auto& top_screen = layout.top_screen;
|
||||
const auto& bottom_screen = layout.bottom_screen;
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
|
||||
namespace Layout {
|
||||
class FramebufferLayout;
|
||||
}
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
/// Structure used for storing information about the textures for each 3DS screen
|
||||
|
@ -50,7 +54,7 @@ private:
|
|||
void InitOpenGLObjects();
|
||||
void ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
const GPU::Regs::FramebufferConfig& framebuffer);
|
||||
void DrawScreens();
|
||||
void DrawScreens(const Layout::FramebufferLayout& layout);
|
||||
void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h);
|
||||
void UpdateFramerate();
|
||||
|
||||
|
@ -66,6 +70,7 @@ private:
|
|||
OGLVertexArray vertex_array;
|
||||
OGLBuffer vertex_buffer;
|
||||
OGLProgram shader;
|
||||
OGLFramebuffer screenshot_framebuffer;
|
||||
|
||||
/// Display information for top and bottom screens respectively
|
||||
std::array<ScreenInfo, 3> screen_infos;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/pica.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||
|
@ -22,6 +23,11 @@ std::atomic<bool> g_hw_shader_enabled;
|
|||
std::atomic<bool> g_hw_shader_accurate_gs;
|
||||
std::atomic<bool> g_hw_shader_accurate_mul;
|
||||
std::atomic<bool> g_renderer_bg_color_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;
|
||||
|
||||
/// Initialize the video core
|
||||
Core::System::ResultStatus Init(EmuWindow& emu_window) {
|
||||
|
@ -48,4 +54,27 @@ void Shutdown() {
|
|||
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() {
|
||||
if (g_hw_renderer_enabled) {
|
||||
return !Settings::values.resolution_factor
|
||||
? g_renderer->GetRenderWindow().GetFramebufferLayout().GetScalingRatio()
|
||||
: Settings::values.resolution_factor;
|
||||
} else {
|
||||
// Software renderer always render at native resolution
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace VideoCore
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <atomic>
|
||||
#include <memory>
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
|
||||
class EmuWindow;
|
||||
class RendererBase;
|
||||
|
@ -26,6 +27,11 @@ extern std::atomic<bool> g_hw_shader_enabled;
|
|||
extern std::atomic<bool> g_hw_shader_accurate_gs;
|
||||
extern std::atomic<bool> g_hw_shader_accurate_mul;
|
||||
extern std::atomic<bool> g_renderer_bg_color_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;
|
||||
|
||||
/// Initialize the video core
|
||||
Core::System::ResultStatus Init(EmuWindow& emu_window);
|
||||
|
@ -33,4 +39,10 @@ Core::System::ResultStatus Init(EmuWindow& emu_window);
|
|||
/// Shutdown the video core
|
||||
void Shutdown();
|
||||
|
||||
/// Request a screenshot of the next frame
|
||||
void RequestScreenshot(void* data, std::function<void()> callback,
|
||||
const Layout::FramebufferLayout& layout);
|
||||
|
||||
u16 GetResolutionScaleFactor();
|
||||
|
||||
} // namespace VideoCore
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue