1
0
Fork 0

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:
zhupengfei 2019-01-26 22:34:55 +08:00
parent 778cc68114
commit 0224ae13c4
No known key found for this signature in database
GPG Key ID: DD129E108BD09378
2 changed files with 94 additions and 2 deletions

View File

@ -12,7 +12,9 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/dumping/backend.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/hw/gpu.h" #include "core/hw/gpu.h"
#include "core/hw/hw.h" #include "core/hw/hw.h"
#include "core/hw/lcd.h" #include "core/hw/lcd.h"
@ -204,7 +206,38 @@ void RendererOpenGL::SwapBuffers() {
VideoCore::g_renderer_screenshot_requested = false; 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()); DrawScreens(render_window.GetFramebufferLayout());
m_current_frame++;
Core::System::GetInstance().perf_stats.EndSystemFrame(); Core::System::GetInstance().perf_stats.EndSystemFrame();
@ -634,13 +667,49 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) {
(float)bottom_screen.GetHeight()); (float)bottom_screen.GetHeight());
} }
} }
m_current_frame++;
} }
/// Updates the framerate /// Updates the framerate
void RendererOpenGL::UpdateFramerate() {} 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) { static const char* GetSource(GLenum source) {
#define RET(s) \ #define RET(s) \
case GL_DEBUG_SOURCE_##s: \ case GL_DEBUG_SOURCE_##s: \

View File

@ -50,6 +50,12 @@ public:
/// Shutdown the renderer /// Shutdown the renderer
void ShutDown() override; 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: private:
void InitOpenGLObjects(); void InitOpenGLObjects();
void ReloadSampler(); void ReloadSampler();
@ -69,6 +75,9 @@ private:
// Fills active OpenGL texture with the given RGB color. // Fills active OpenGL texture with the given RGB color.
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture); void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
void InitVideoDumpingGLObjects();
void ReleaseVideoDumpingGLObjects();
OpenGLState state; OpenGLState state;
// OpenGL object IDs // OpenGL object IDs
@ -94,6 +103,20 @@ private:
// Shader attribute input indices // Shader attribute input indices
GLuint attrib_position; GLuint attrib_position;
GLuint attrib_tex_coord; 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 } // namespace OpenGL