video_core: Implement frame dumping
Two PBOs are used to speed up pixel copying process. To avoid getting the wrong speed/FPS, a new parameter is added to DrawScreens about whether to increase the frame count.
This commit is contained in:
parent
778cc68114
commit
0224ae13c4
|
@ -12,7 +12,9 @@
|
|||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/dumping/backend.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/hw/lcd.h"
|
||||
|
@ -204,7 +206,38 @@ void RendererOpenGL::SwapBuffers() {
|
|||
VideoCore::g_renderer_screenshot_requested = false;
|
||||
}
|
||||
|
||||
if (cleanup_video_dumping.exchange(false)) {
|
||||
ReleaseVideoDumpingGLObjects();
|
||||
}
|
||||
|
||||
if (Core::System::GetInstance().VideoDumper().IsDumping()) {
|
||||
if (prepare_video_dumping.exchange(false)) {
|
||||
InitVideoDumpingGLObjects();
|
||||
}
|
||||
|
||||
const auto& layout = Core::System::GetInstance().VideoDumper().GetLayout();
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, frame_dumping_framebuffer.handle);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frame_dumping_framebuffer.handle);
|
||||
DrawScreens(layout);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, frame_dumping_pbos[current_pbo].handle);
|
||||
glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, frame_dumping_pbos[next_pbo].handle);
|
||||
|
||||
GLubyte* pixels = static_cast<GLubyte*>(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY));
|
||||
VideoDumper::VideoFrame frame_data{layout.width, layout.height, pixels};
|
||||
Core::System::GetInstance().VideoDumper().AddVideoFrame(frame_data);
|
||||
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
current_pbo = (current_pbo + 1) % 2;
|
||||
next_pbo = (current_pbo + 1) % 2;
|
||||
}
|
||||
|
||||
DrawScreens(render_window.GetFramebufferLayout());
|
||||
m_current_frame++;
|
||||
|
||||
Core::System::GetInstance().perf_stats.EndSystemFrame();
|
||||
|
||||
|
@ -634,13 +667,49 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) {
|
|||
(float)bottom_screen.GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
m_current_frame++;
|
||||
}
|
||||
|
||||
/// Updates the framerate
|
||||
void RendererOpenGL::UpdateFramerate() {}
|
||||
|
||||
void RendererOpenGL::PrepareVideoDumping() {
|
||||
prepare_video_dumping = true;
|
||||
}
|
||||
|
||||
void RendererOpenGL::CleanupVideoDumping() {
|
||||
cleanup_video_dumping = true;
|
||||
}
|
||||
|
||||
void RendererOpenGL::InitVideoDumpingGLObjects() {
|
||||
const auto& layout = Core::System::GetInstance().VideoDumper().GetLayout();
|
||||
|
||||
frame_dumping_framebuffer.Create();
|
||||
glGenRenderbuffers(1, &frame_dumping_renderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, frame_dumping_renderbuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, layout.width, layout.height);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frame_dumping_framebuffer.handle);
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
|
||||
frame_dumping_renderbuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
for (auto& buffer : frame_dumping_pbos) {
|
||||
buffer.Create();
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer.handle);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, layout.width * layout.height * 4, nullptr,
|
||||
GL_STREAM_READ);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void RendererOpenGL::ReleaseVideoDumpingGLObjects() {
|
||||
frame_dumping_framebuffer.Release();
|
||||
glDeleteRenderbuffers(1, &frame_dumping_renderbuffer);
|
||||
|
||||
for (auto& buffer : frame_dumping_pbos) {
|
||||
buffer.Release();
|
||||
}
|
||||
}
|
||||
|
||||
static const char* GetSource(GLenum source) {
|
||||
#define RET(s) \
|
||||
case GL_DEBUG_SOURCE_##s: \
|
||||
|
|
|
@ -50,6 +50,12 @@ public:
|
|||
/// Shutdown the renderer
|
||||
void ShutDown() override;
|
||||
|
||||
/// Prepares for video dumping (e.g. create necessary buffers, etc)
|
||||
void PrepareVideoDumping() override;
|
||||
|
||||
/// Cleans up after video dumping is ended
|
||||
void CleanupVideoDumping() override;
|
||||
|
||||
private:
|
||||
void InitOpenGLObjects();
|
||||
void ReloadSampler();
|
||||
|
@ -69,6 +75,9 @@ private:
|
|||
// Fills active OpenGL texture with the given RGB color.
|
||||
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
|
||||
|
||||
void InitVideoDumpingGLObjects();
|
||||
void ReleaseVideoDumpingGLObjects();
|
||||
|
||||
OpenGLState state;
|
||||
|
||||
// OpenGL object IDs
|
||||
|
@ -94,6 +103,20 @@ private:
|
|||
// Shader attribute input indices
|
||||
GLuint attrib_position;
|
||||
GLuint attrib_tex_coord;
|
||||
|
||||
// Frame dumping
|
||||
OGLFramebuffer frame_dumping_framebuffer;
|
||||
GLuint frame_dumping_renderbuffer;
|
||||
|
||||
// Whether prepare/cleanup video dumping has been requested.
|
||||
// They will be executed on next frame.
|
||||
std::atomic_bool prepare_video_dumping = false;
|
||||
std::atomic_bool cleanup_video_dumping = false;
|
||||
|
||||
// PBOs used to dump frames faster
|
||||
std::array<OGLBuffer, 2> frame_dumping_pbos;
|
||||
GLuint current_pbo = 1;
|
||||
GLuint next_pbo = 0;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
|
Reference in New Issue