diff options
Diffstat (limited to 'src/video_core/renderer_opengl/renderer_opengl.cpp')
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 89 |
1 files changed, 56 insertions, 33 deletions
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 4fd0d66c5..e37b65b38 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -14,6 +14,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/frontend/scope_acquire_window_context.h" #include "core/memory.h" #include "core/perf_stats.h" #include "core/settings.h" @@ -97,18 +98,6 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons return matrix; } -ScopeAcquireGLContext::ScopeAcquireGLContext(Core::Frontend::EmuWindow& emu_window_) - : emu_window{emu_window_} { - if (Settings::values.use_multi_core) { - emu_window.MakeCurrent(); - } -} -ScopeAcquireGLContext::~ScopeAcquireGLContext() { - if (Settings::values.use_multi_core) { - emu_window.DoneCurrent(); - } -} - RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window) : VideoCore::RendererBase{window} {} @@ -117,7 +106,6 @@ RendererOpenGL::~RendererOpenGL() = default; /// Swap buffers (render frame) void RendererOpenGL::SwapBuffers( std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { - ScopeAcquireGLContext acquire_context{render_window}; Core::System::GetInstance().GetPerfStats().EndSystemFrame(); @@ -138,7 +126,12 @@ void RendererOpenGL::SwapBuffers( // Load the framebuffer from memory, draw it to the screen, and swap buffers LoadFBToScreenInfo(*framebuffer); - DrawScreen(); + + if (renderer_settings.screenshot_requested) + CaptureScreenshot(); + + DrawScreen(render_window.GetFramebufferLayout()); + render_window.SwapBuffers(); } @@ -240,20 +233,20 @@ void RendererOpenGL::InitOpenGLObjects() { // Generate VAO vertex_array.Create(); - state.draw.vertex_array = vertex_array.handle; - state.draw.vertex_buffer = vertex_buffer.handle; - state.draw.uniform_buffer = 0; - state.Apply(); // Attach vertex data to VAO - glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); - glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), - (GLvoid*)offsetof(ScreenRectVertex, position)); - glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), - (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); - glEnableVertexAttribArray(attrib_position); - glEnableVertexAttribArray(attrib_tex_coord); + glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); + glVertexArrayAttribFormat(vertex_array.handle, attrib_position, 2, GL_FLOAT, GL_FALSE, + offsetof(ScreenRectVertex, position)); + glVertexArrayAttribFormat(vertex_array.handle, attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, + offsetof(ScreenRectVertex, tex_coord)); + glVertexArrayAttribBinding(vertex_array.handle, attrib_position, 0); + glVertexArrayAttribBinding(vertex_array.handle, attrib_tex_coord, 0); + glEnableVertexArrayAttrib(vertex_array.handle, attrib_position); + glEnableVertexArrayAttrib(vertex_array.handle, attrib_tex_coord); + glVertexArrayVertexBuffer(vertex_array.handle, 0, vertex_buffer.handle, 0, + sizeof(ScreenRectVertex)); // Allocate textures for the screen screen_info.texture.resource.Create(); @@ -365,14 +358,12 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, state.texture_units[0].texture = screen_info.display_texture; state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; // Workaround brigthness problems in SMO by enabling sRGB in the final output - // if it has been used in the frame - // Needed because of this bug in QT - // QTBUG-50987 + // if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987 state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed(); state.Apply(); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); + glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), vertices.data()); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - // restore default state + // Restore default state state.framebuffer_srgb.enabled = false; state.texture_units[0].texture = 0; state.Apply(); @@ -383,14 +374,13 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, /** * Draws the emulated screens to the emulator window. */ -void RendererOpenGL::DrawScreen() { +void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { if (renderer_settings.set_background_color) { // Update background color before drawing glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); } - const auto& layout = render_window.GetFramebufferLayout(); const auto& screen = layout.screen; glViewport(0, 0, layout.width, layout.height); @@ -414,6 +404,37 @@ void RendererOpenGL::DrawScreen() { /// Updates the framerate void RendererOpenGL::UpdateFramerate() {} +void RendererOpenGL::CaptureScreenshot() { + // Draw the current 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{renderer_settings.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); + + DrawScreen(layout); + + glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + renderer_settings.screenshot_bits); + + screenshot_framebuffer.Release(); + state.draw.read_framebuffer = old_read_fb; + state.draw.draw_framebuffer = old_draw_fb; + state.Apply(); + glDeleteRenderbuffers(1, &renderbuffer); + + renderer_settings.screenshot_complete_callback(); + renderer_settings.screenshot_requested = false; +} + static const char* GetSource(GLenum source) { #define RET(s) \ case GL_DEBUG_SOURCE_##s: \ @@ -427,6 +448,7 @@ static const char* GetSource(GLenum source) { RET(OTHER); default: UNREACHABLE(); + return "Unknown source"; } #undef RET } @@ -445,6 +467,7 @@ static const char* GetType(GLenum type) { RET(MARKER); default: UNREACHABLE(); + return "Unknown type"; } #undef RET } @@ -471,7 +494,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum /// Initialize the renderer bool RendererOpenGL::Init() { - ScopeAcquireGLContext acquire_context{render_window}; + Core::Frontend::ScopeAcquireWindowContext acquire_context{render_window}; if (GLAD_GL_KHR_debug) { glEnable(GL_DEBUG_OUTPUT); |