mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	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
					
				
					 2 changed files with 94 additions and 2 deletions
				
			
		|  | @ -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:                                                                      \ | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue