diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
8 files changed, 145 insertions, 39 deletions
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp index 6ba8b214b..9260a4dc4 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.cpp +++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/settings.h" +#include "video_core/present.h" #include "video_core/renderer_opengl/gl_blit_screen.h" #include "video_core/renderer_opengl/gl_state_tracker.h" #include "video_core/renderer_opengl/present/filters.h" @@ -13,14 +14,14 @@ namespace OpenGL { BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_, StateTracker& state_tracker_, ProgramManager& program_manager_, - Device& device_) + Device& device_, const PresentFilters& filters_) : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), - program_manager(program_manager_), device(device_) {} + program_manager(program_manager_), device(device_), filters(filters_) {} BlitScreen::~BlitScreen() = default; void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers, - const Layout::FramebufferLayout& layout) { + const Layout::FramebufferLayout& layout, bool invert_y) { // TODO: Signal state tracker about these changes state_tracker.NotifyScreenDrawVertexArray(); state_tracker.NotifyPolygonModes(); @@ -56,22 +57,22 @@ void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffe glDepthRangeIndexed(0, 0.0, 0.0); while (layers.size() < framebuffers.size()) { - layers.emplace_back(rasterizer, device_memory); + layers.emplace_back(rasterizer, device_memory, filters); } CreateWindowAdapt(); - window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout); + window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout, invert_y); // TODO // program_manager.RestoreGuestPipeline(); } void BlitScreen::CreateWindowAdapt() { - if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) { + if (window_adapt && filters.get_scaling_filter() == current_window_adapt) { return; } - current_window_adapt = Settings::values.scaling_filter.GetValue(); + current_window_adapt = filters.get_scaling_filter(); switch (current_window_adapt) { case Settings::ScalingFilter::NearestNeighbor: window_adapt = MakeNearestNeighbor(device); diff --git a/src/video_core/renderer_opengl/gl_blit_screen.h b/src/video_core/renderer_opengl/gl_blit_screen.h index 0c3d838f1..df2da9424 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.h +++ b/src/video_core/renderer_opengl/gl_blit_screen.h @@ -15,6 +15,8 @@ namespace Layout { struct FramebufferLayout; } +struct PresentFilters; + namespace Tegra { struct FramebufferConfig; } @@ -46,12 +48,12 @@ public: explicit BlitScreen(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory, StateTracker& state_tracker, ProgramManager& program_manager, - Device& device); + Device& device, const PresentFilters& filters); ~BlitScreen(); /// Draws the emulated screens to the emulator window. void DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers, - const Layout::FramebufferLayout& layout); + const Layout::FramebufferLayout& layout, bool invert_y); private: void CreateWindowAdapt(); @@ -61,6 +63,7 @@ private: StateTracker& state_tracker; ProgramManager& program_manager; Device& device; + const PresentFilters& filters; Settings::ScalingFilter current_window_adapt{}; std::unique_ptr<WindowAdaptPass> window_adapt; diff --git a/src/video_core/renderer_opengl/present/layer.cpp b/src/video_core/renderer_opengl/present/layer.cpp index 8643e07c6..6c7092d22 100644 --- a/src/video_core/renderer_opengl/present/layer.cpp +++ b/src/video_core/renderer_opengl/present/layer.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "video_core/framebuffer_config.h" +#include "video_core/present.h" #include "video_core/renderer_opengl/gl_blit_screen.h" #include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/present/fsr.h" @@ -14,8 +15,9 @@ namespace OpenGL { -Layer::Layer(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_) - : rasterizer(rasterizer_), device_memory(device_memory_) { +Layer::Layer(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_, + const PresentFilters& filters_) + : rasterizer(rasterizer_), device_memory(device_memory_), filters(filters_) { // Allocate textures for the screen framebuffer_texture.resource.Create(GL_TEXTURE_2D); @@ -34,12 +36,12 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix, std::array<ScreenRectVertex, 4>& out_vertices, ProgramManager& program_manager, const Tegra::FramebufferConfig& framebuffer, - const Layout::FramebufferLayout& layout) { + const Layout::FramebufferLayout& layout, bool invert_y) { FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); GLuint texture = info.display_texture; - auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); + auto anti_aliasing = filters.get_anti_aliasing(); if (anti_aliasing != Settings::AntiAliasing::None) { glEnablei(GL_SCISSOR_TEST, 0); auto viewport_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); @@ -64,7 +66,7 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix, glDisablei(GL_SCISSOR_TEST, 0); - if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { + if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) { if (!fsr || fsr->NeedsRecreation(layout.screen)) { fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); } @@ -83,10 +85,15 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix, const auto w = screen.GetWidth(); const auto h = screen.GetHeight(); - out_vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); - out_vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); - out_vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); - out_vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); + const auto left = crop.left; + const auto right = crop.right; + const auto top = invert_y ? crop.bottom : crop.top; + const auto bottom = invert_y ? crop.top : crop.bottom; + + out_vertices[0] = ScreenRectVertex(x, y, left, top); + out_vertices[1] = ScreenRectVertex(x + w, y, right, top); + out_vertices[2] = ScreenRectVertex(x, y + h, left, bottom); + out_vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom); return texture; } @@ -131,10 +138,12 @@ FramebufferTextureInfo Layer::LoadFBToScreenInfo(const Tegra::FramebufferConfig& const u64 size_in_bytes{Tegra::Texture::CalculateSize( true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; - const std::span<const u8> input_data(host_ptr, size_in_bytes); - Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, - framebuffer.width, framebuffer.height, 1, block_height_log2, - 0); + if (host_ptr) { + const std::span<const u8> input_data(host_ptr, size_in_bytes); + Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, + framebuffer.width, framebuffer.height, 1, + block_height_log2, 0); + } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); diff --git a/src/video_core/renderer_opengl/present/layer.h b/src/video_core/renderer_opengl/present/layer.h index ef1055abf..5b15b730f 100644 --- a/src/video_core/renderer_opengl/present/layer.h +++ b/src/video_core/renderer_opengl/present/layer.h @@ -13,6 +13,8 @@ namespace Layout { struct FramebufferLayout; } +struct PresentFilters; + namespace Service::android { enum class PixelFormat : u32; }; @@ -44,14 +46,15 @@ struct ScreenRectVertex; class Layer { public: - explicit Layer(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory); + explicit Layer(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory, + const PresentFilters& filters); ~Layer(); GLuint ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix, std::array<ScreenRectVertex, 4>& out_vertices, ProgramManager& program_manager, const Tegra::FramebufferConfig& framebuffer, - const Layout::FramebufferLayout& layout); + const Layout::FramebufferLayout& layout, bool invert_y); private: /// Loads framebuffer from emulated memory into the active OpenGL texture. @@ -65,6 +68,7 @@ private: private: RasterizerOpenGL& rasterizer; Tegra::MaxwellDeviceMemoryManager& device_memory; + const PresentFilters& filters; /// OpenGL framebuffer data std::vector<u8> gl_framebuffer_data; diff --git a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp index 4d681606b..d8b6a11cb 100644 --- a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp @@ -37,7 +37,7 @@ WindowAdaptPass::~WindowAdaptPass() = default; void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers, std::span<const Tegra::FramebufferConfig> framebuffers, - const Layout::FramebufferLayout& layout) { + const Layout::FramebufferLayout& layout, bool invert_y) { GLint old_read_fb; GLint old_draw_fb; glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); @@ -51,7 +51,7 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li auto layer_it = layers.begin(); for (size_t i = 0; i < layer_count; i++) { textures[i] = layer_it->ConfigureDraw(matrices[i], vertices[i], program_manager, - framebuffers[i], layout); + framebuffers[i], layout, invert_y); layer_it++; } @@ -92,6 +92,21 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li glClear(GL_COLOR_BUFFER_BIT); for (size_t i = 0; i < layer_count; i++) { + switch (framebuffers[i].blending) { + case Tegra::BlendMode::Opaque: + default: + glDisablei(GL_BLEND, 0); + break; + case Tegra::BlendMode::Premultiplied: + glEnablei(GL_BLEND, 0); + glBlendFuncSeparatei(0, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + break; + case Tegra::BlendMode::Coverage: + glEnablei(GL_BLEND, 0); + glBlendFuncSeparatei(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + break; + } + glBindTextureUnit(0, textures[i]); glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE, matrices[i].data()); diff --git a/src/video_core/renderer_opengl/present/window_adapt_pass.h b/src/video_core/renderer_opengl/present/window_adapt_pass.h index 00975a9c6..0a8bcef2f 100644 --- a/src/video_core/renderer_opengl/present/window_adapt_pass.h +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.h @@ -31,7 +31,7 @@ public: void DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers, std::span<const Tegra::FramebufferConfig> framebuffers, - const Layout::FramebufferLayout& layout); + const Layout::FramebufferLayout& layout, bool invert_y); private: const Device& device; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index e33a32592..5fb54635d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -16,6 +16,8 @@ #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/telemetry_session.h" +#include "video_core/capture.h" +#include "video_core/present.h" #include "video_core/renderer_opengl/gl_blit_screen.h" #include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_shader_manager.h" @@ -120,7 +122,15 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); } blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, - program_manager, device); + program_manager, device, PresentFiltersForDisplay); + blit_applet = + std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, program_manager, + device, PresentFiltersForAppletCapture); + capture_framebuffer.Create(); + capture_renderbuffer.Create(); + glBindRenderbuffer(GL_RENDERBUFFER, capture_renderbuffer.handle); + glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, VideoCore::Capture::LinearWidth, + VideoCore::Capture::LinearHeight); } RendererOpenGL::~RendererOpenGL() = default; @@ -130,10 +140,11 @@ void RendererOpenGL::Composite(std::span<const Tegra::FramebufferConfig> framebu return; } + RenderAppletCaptureLayer(framebuffers); RenderScreenshot(framebuffers); state_tracker.BindFramebuffer(0); - blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout()); + blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout(), false); ++m_current_frame; @@ -159,11 +170,8 @@ void RendererOpenGL::AddTelemetryFields() { telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); } -void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) { - if (!renderer_settings.screenshot_requested) { - return; - } - +void RendererOpenGL::RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers, + const Layout::FramebufferLayout& layout, void* dst) { GLint old_read_fb; GLint old_draw_fb; glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); @@ -173,29 +181,86 @@ void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig> screenshot_framebuffer.Create(); glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle); - const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; - GLuint renderbuffer; glGenRenderbuffers(1, &renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); - blit_screen->DrawScreen(framebuffers, layout); + blit_screen->DrawScreen(framebuffers, layout, false); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - renderer_settings.screenshot_bits); + glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, dst); screenshot_framebuffer.Release(); glDeleteRenderbuffers(1, &renderbuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); +} + +void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) { + if (!renderer_settings.screenshot_requested) { + return; + } + + RenderToBuffer(framebuffers, renderer_settings.screenshot_framebuffer_layout, + renderer_settings.screenshot_bits); renderer_settings.screenshot_complete_callback(true); renderer_settings.screenshot_requested = false; } +void RendererOpenGL::RenderAppletCaptureLayer( + std::span<const Tegra::FramebufferConfig> framebuffers) { + GLint old_read_fb; + GLint old_draw_fb; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + capture_renderbuffer.handle); + + blit_applet->DrawScreen(framebuffers, VideoCore::Capture::Layout, true); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); +} + +std::vector<u8> RendererOpenGL::GetAppletCaptureBuffer() { + using namespace VideoCore::Capture; + + std::vector<u8> linear(TiledSize); + std::vector<u8> out(TiledSize); + + GLint old_read_fb; + GLint old_draw_fb; + GLint old_pixel_pack_buffer; + GLint old_pack_row_length; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); + glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &old_pixel_pack_buffer); + glGetIntegerv(GL_PACK_ROW_LENGTH, &old_pack_row_length); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + capture_renderbuffer.handle); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glReadPixels(0, 0, LinearWidth, LinearHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, + linear.data()); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); + glBindBuffer(GL_PIXEL_PACK_BUFFER, old_pixel_pack_buffer); + glPixelStorei(GL_PACK_ROW_LENGTH, old_pack_row_length); + + Tegra::Texture::SwizzleTexture(out, linear, BytesPerPixel, LinearWidth, LinearHeight, + LinearDepth, BlockHeight, BlockDepth); + + return out; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index c4625c96e..60d6a1477 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -42,6 +42,8 @@ public: void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override; + std::vector<u8> GetAppletCaptureBuffer() override; + VideoCore::RasterizerInterface* ReadRasterizer() override { return &rasterizer; } @@ -52,7 +54,11 @@ public: private: void AddTelemetryFields(); + + void RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers, + const Layout::FramebufferLayout& layout, void* dst); void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers); + void RenderAppletCaptureLayer(std::span<const Tegra::FramebufferConfig> framebuffers); Core::TelemetrySession& telemetry_session; Core::Frontend::EmuWindow& emu_window; @@ -64,8 +70,11 @@ private: ProgramManager program_manager; RasterizerOpenGL rasterizer; OGLFramebuffer screenshot_framebuffer; + OGLFramebuffer capture_framebuffer; + OGLRenderbuffer capture_renderbuffer; std::unique_ptr<BlitScreen> blit_screen; + std::unique_ptr<BlitScreen> blit_applet; }; } // namespace OpenGL |