diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_blit_screen.cpp | 198 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_blit_screen.h | 38 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/layer.cpp | 215 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/layer.h | 80 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/present_uniforms.h | 43 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/window_adapt_pass.cpp | 91 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/window_adapt_pass.h | 14 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 2 |
10 files changed, 402 insertions, 290 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 7526de699..16c905db9 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -122,6 +122,9 @@ add_library(video_core STATIC | |||
| 122 | renderer_opengl/present/fsr.h | 122 | renderer_opengl/present/fsr.h |
| 123 | renderer_opengl/present/fxaa.cpp | 123 | renderer_opengl/present/fxaa.cpp |
| 124 | renderer_opengl/present/fxaa.h | 124 | renderer_opengl/present/fxaa.h |
| 125 | renderer_opengl/present/layer.cpp | ||
| 126 | renderer_opengl/present/layer.h | ||
| 127 | renderer_opengl/present/present_uniforms.h | ||
| 125 | renderer_opengl/present/smaa.cpp | 128 | renderer_opengl/present/smaa.cpp |
| 126 | renderer_opengl/present/smaa.h | 129 | renderer_opengl/present/smaa.h |
| 127 | renderer_opengl/present/util.h | 130 | renderer_opengl/present/util.h |
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp index f9dbef0fc..6ba8b214b 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.cpp +++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp | |||
| @@ -1,18 +1,12 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "video_core/framebuffer_config.h" | 4 | #include "common/settings.h" |
| 5 | #include "video_core/renderer_opengl/gl_blit_screen.h" | 5 | #include "video_core/renderer_opengl/gl_blit_screen.h" |
| 6 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||
| 8 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 9 | #include "video_core/renderer_opengl/gl_state_tracker.h" | 6 | #include "video_core/renderer_opengl/gl_state_tracker.h" |
| 10 | #include "video_core/renderer_opengl/present/filters.h" | 7 | #include "video_core/renderer_opengl/present/filters.h" |
| 11 | #include "video_core/renderer_opengl/present/fsr.h" | 8 | #include "video_core/renderer_opengl/present/layer.h" |
| 12 | #include "video_core/renderer_opengl/present/fxaa.h" | ||
| 13 | #include "video_core/renderer_opengl/present/smaa.h" | ||
| 14 | #include "video_core/renderer_opengl/present/window_adapt_pass.h" | 9 | #include "video_core/renderer_opengl/present/window_adapt_pass.h" |
| 15 | #include "video_core/textures/decoders.h" | ||
| 16 | 10 | ||
| 17 | namespace OpenGL { | 11 | namespace OpenGL { |
| 18 | 12 | ||
| @@ -21,130 +15,12 @@ BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, | |||
| 21 | StateTracker& state_tracker_, ProgramManager& program_manager_, | 15 | StateTracker& state_tracker_, ProgramManager& program_manager_, |
| 22 | Device& device_) | 16 | Device& device_) |
| 23 | : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), | 17 | : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), |
| 24 | program_manager(program_manager_), device(device_) { | 18 | program_manager(program_manager_), device(device_) {} |
| 25 | // Allocate textures for the screen | ||
| 26 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); | ||
| 27 | |||
| 28 | const GLuint texture = framebuffer_texture.resource.handle; | ||
| 29 | glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); | ||
| 30 | |||
| 31 | // Clear screen to black | ||
| 32 | const u8 framebuffer_data[4] = {0, 0, 0, 0}; | ||
| 33 | glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, | ||
| 34 | framebuffer_data); | ||
| 35 | } | ||
| 36 | 19 | ||
| 37 | BlitScreen::~BlitScreen() = default; | 20 | BlitScreen::~BlitScreen() = default; |
| 38 | 21 | ||
| 39 | FramebufferTextureInfo BlitScreen::PrepareRenderTarget( | 22 | void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers, |
| 40 | const Tegra::FramebufferConfig& framebuffer) { | ||
| 41 | // If framebuffer is provided, reload it from memory to a texture | ||
| 42 | if (framebuffer_texture.width != static_cast<GLsizei>(framebuffer.width) || | ||
| 43 | framebuffer_texture.height != static_cast<GLsizei>(framebuffer.height) || | ||
| 44 | framebuffer_texture.pixel_format != framebuffer.pixel_format || | ||
| 45 | gl_framebuffer_data.empty()) { | ||
| 46 | // Reallocate texture if the framebuffer size has changed. | ||
| 47 | // This is expected to not happen very often and hence should not be a | ||
| 48 | // performance problem. | ||
| 49 | ConfigureFramebufferTexture(framebuffer); | ||
| 50 | } | ||
| 51 | |||
| 52 | // Load the framebuffer from memory if needed | ||
| 53 | return LoadFBToScreenInfo(framebuffer); | ||
| 54 | } | ||
| 55 | |||
| 56 | FramebufferTextureInfo BlitScreen::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { | ||
| 57 | const DAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; | ||
| 58 | const auto accelerated_info = | ||
| 59 | rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride); | ||
| 60 | if (accelerated_info) { | ||
| 61 | return *accelerated_info; | ||
| 62 | } | ||
| 63 | |||
| 64 | // Reset the screen info's display texture to its own permanent texture | ||
| 65 | FramebufferTextureInfo info{}; | ||
| 66 | info.display_texture = framebuffer_texture.resource.handle; | ||
| 67 | info.width = framebuffer.width; | ||
| 68 | info.height = framebuffer.height; | ||
| 69 | info.scaled_width = framebuffer.width; | ||
| 70 | info.scaled_height = framebuffer.height; | ||
| 71 | |||
| 72 | // TODO(Rodrigo): Read this from HLE | ||
| 73 | constexpr u32 block_height_log2 = 4; | ||
| 74 | const auto pixel_format{ | ||
| 75 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; | ||
| 76 | const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; | ||
| 77 | const u64 size_in_bytes{Tegra::Texture::CalculateSize( | ||
| 78 | true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; | ||
| 79 | const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; | ||
| 80 | const std::span<const u8> input_data(host_ptr, size_in_bytes); | ||
| 81 | Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, | ||
| 82 | framebuffer.width, framebuffer.height, 1, block_height_log2, | ||
| 83 | 0); | ||
| 84 | |||
| 85 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | ||
| 86 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); | ||
| 87 | |||
| 88 | // Update existing texture | ||
| 89 | // TODO: Test what happens on hardware when you change the framebuffer dimensions so that | ||
| 90 | // they differ from the LCD resolution. | ||
| 91 | // TODO: Applications could theoretically crash yuzu here by specifying too large | ||
| 92 | // framebuffer sizes. We should make sure that this cannot happen. | ||
| 93 | glTextureSubImage2D(framebuffer_texture.resource.handle, 0, 0, 0, framebuffer.width, | ||
| 94 | framebuffer.height, framebuffer_texture.gl_format, | ||
| 95 | framebuffer_texture.gl_type, gl_framebuffer_data.data()); | ||
| 96 | |||
| 97 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||
| 98 | |||
| 99 | return info; | ||
| 100 | } | ||
| 101 | |||
| 102 | void BlitScreen::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer) { | ||
| 103 | framebuffer_texture.width = framebuffer.width; | ||
| 104 | framebuffer_texture.height = framebuffer.height; | ||
| 105 | framebuffer_texture.pixel_format = framebuffer.pixel_format; | ||
| 106 | |||
| 107 | const auto pixel_format{ | ||
| 108 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; | ||
| 109 | const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; | ||
| 110 | gl_framebuffer_data.resize(framebuffer_texture.width * framebuffer_texture.height * | ||
| 111 | bytes_per_pixel); | ||
| 112 | |||
| 113 | GLint internal_format; | ||
| 114 | switch (framebuffer.pixel_format) { | ||
| 115 | case Service::android::PixelFormat::Rgba8888: | ||
| 116 | internal_format = GL_RGBA8; | ||
| 117 | framebuffer_texture.gl_format = GL_RGBA; | ||
| 118 | framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | ||
| 119 | break; | ||
| 120 | case Service::android::PixelFormat::Rgb565: | ||
| 121 | internal_format = GL_RGB565; | ||
| 122 | framebuffer_texture.gl_format = GL_RGB; | ||
| 123 | framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; | ||
| 124 | break; | ||
| 125 | default: | ||
| 126 | internal_format = GL_RGBA8; | ||
| 127 | framebuffer_texture.gl_format = GL_RGBA; | ||
| 128 | framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | ||
| 129 | // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | ||
| 130 | // static_cast<u32>(framebuffer.pixel_format)); | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | |||
| 134 | framebuffer_texture.resource.Release(); | ||
| 135 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); | ||
| 136 | glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, | ||
| 137 | framebuffer_texture.width, framebuffer_texture.height); | ||
| 138 | |||
| 139 | fxaa.reset(); | ||
| 140 | smaa.reset(); | ||
| 141 | } | ||
| 142 | |||
| 143 | void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | ||
| 144 | const Layout::FramebufferLayout& layout) { | 23 | const Layout::FramebufferLayout& layout) { |
| 145 | FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); | ||
| 146 | auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); | ||
| 147 | |||
| 148 | // TODO: Signal state tracker about these changes | 24 | // TODO: Signal state tracker about these changes |
| 149 | state_tracker.NotifyScreenDrawVertexArray(); | 25 | state_tracker.NotifyScreenDrawVertexArray(); |
| 150 | state_tracker.NotifyPolygonModes(); | 26 | state_tracker.NotifyPolygonModes(); |
| @@ -163,7 +39,6 @@ void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | |||
| 163 | state_tracker.NotifyLogicOp(); | 39 | state_tracker.NotifyLogicOp(); |
| 164 | state_tracker.NotifyClipControl(); | 40 | state_tracker.NotifyClipControl(); |
| 165 | state_tracker.NotifyAlphaTest(); | 41 | state_tracker.NotifyAlphaTest(); |
| 166 | |||
| 167 | state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); | 42 | state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); |
| 168 | 43 | ||
| 169 | glEnable(GL_CULL_FACE); | 44 | glEnable(GL_CULL_FACE); |
| @@ -180,76 +55,17 @@ void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | |||
| 180 | glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | 55 | glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| 181 | glDepthRangeIndexed(0, 0.0, 0.0); | 56 | glDepthRangeIndexed(0, 0.0, 0.0); |
| 182 | 57 | ||
| 183 | GLint old_read_fb; | 58 | while (layers.size() < framebuffers.size()) { |
| 184 | GLint old_draw_fb; | 59 | layers.emplace_back(rasterizer, device_memory); |
| 185 | glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); | ||
| 186 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||
| 187 | |||
| 188 | GLuint texture = info.display_texture; | ||
| 189 | |||
| 190 | auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); | ||
| 191 | if (anti_aliasing != Settings::AntiAliasing::None) { | ||
| 192 | glEnablei(GL_SCISSOR_TEST, 0); | ||
| 193 | auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); | ||
| 194 | auto viewport_width = static_cast<GLfloat>(scissor_width); | ||
| 195 | auto scissor_height = Settings::values.resolution_info.ScaleUp(framebuffer_texture.height); | ||
| 196 | auto viewport_height = static_cast<GLfloat>(scissor_height); | ||
| 197 | |||
| 198 | glScissorIndexed(0, 0, 0, scissor_width, scissor_height); | ||
| 199 | glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height); | ||
| 200 | |||
| 201 | switch (anti_aliasing) { | ||
| 202 | case Settings::AntiAliasing::Fxaa: | ||
| 203 | CreateFXAA(); | ||
| 204 | texture = fxaa->Draw(program_manager, info.display_texture); | ||
| 205 | break; | ||
| 206 | case Settings::AntiAliasing::Smaa: | ||
| 207 | default: | ||
| 208 | CreateSMAA(); | ||
| 209 | texture = smaa->Draw(program_manager, info.display_texture); | ||
| 210 | break; | ||
| 211 | } | ||
| 212 | } | 60 | } |
| 213 | 61 | ||
| 214 | glDisablei(GL_SCISSOR_TEST, 0); | ||
| 215 | |||
| 216 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 217 | if (!fsr || fsr->NeedsRecreation(layout.screen)) { | ||
| 218 | fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); | ||
| 219 | } | ||
| 220 | |||
| 221 | texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop); | ||
| 222 | crop = {0, 0, 1, 1}; | ||
| 223 | } | ||
| 224 | |||
| 225 | glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); | ||
| 226 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | ||
| 227 | |||
| 228 | CreateWindowAdapt(); | 62 | CreateWindowAdapt(); |
| 229 | window_adapt->DrawToFramebuffer(program_manager, texture, layout, crop); | 63 | window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout); |
| 230 | 64 | ||
| 231 | // TODO | 65 | // TODO |
| 232 | // program_manager.RestoreGuestPipeline(); | 66 | // program_manager.RestoreGuestPipeline(); |
| 233 | } | 67 | } |
| 234 | 68 | ||
| 235 | void BlitScreen::CreateFXAA() { | ||
| 236 | smaa.reset(); | ||
| 237 | if (!fxaa) { | ||
| 238 | fxaa = std::make_unique<FXAA>( | ||
| 239 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||
| 240 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | void BlitScreen::CreateSMAA() { | ||
| 245 | fxaa.reset(); | ||
| 246 | if (!smaa) { | ||
| 247 | smaa = std::make_unique<SMAA>( | ||
| 248 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||
| 249 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | void BlitScreen::CreateWindowAdapt() { | 69 | void BlitScreen::CreateWindowAdapt() { |
| 254 | if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) { | 70 | if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) { |
| 255 | return; | 71 | return; |
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.h b/src/video_core/renderer_opengl/gl_blit_screen.h index f42f89dee..0c3d838f1 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.h +++ b/src/video_core/renderer_opengl/gl_blit_screen.h | |||
| @@ -3,8 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <list> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | #include <vector> | 8 | #include <span> |
| 8 | 9 | ||
| 9 | #include "core/hle/service/nvnflinger/pixel_format.h" | 10 | #include "core/hle/service/nvnflinger/pixel_format.h" |
| 10 | #include "video_core/host1x/gpu_device_memory_manager.h" | 11 | #include "video_core/host1x/gpu_device_memory_manager.h" |
| @@ -25,24 +26,12 @@ enum class ScalingFilter : u32; | |||
| 25 | namespace OpenGL { | 26 | namespace OpenGL { |
| 26 | 27 | ||
| 27 | class Device; | 28 | class Device; |
| 28 | class FSR; | 29 | class Layer; |
| 29 | class FXAA; | ||
| 30 | class ProgramManager; | 30 | class ProgramManager; |
| 31 | class RasterizerOpenGL; | 31 | class RasterizerOpenGL; |
| 32 | class SMAA; | ||
| 33 | class StateTracker; | 32 | class StateTracker; |
| 34 | class WindowAdaptPass; | 33 | class WindowAdaptPass; |
| 35 | 34 | ||
| 36 | /// Structure used for storing information about the textures for the Switch screen | ||
| 37 | struct TextureInfo { | ||
| 38 | OGLTexture resource; | ||
| 39 | GLsizei width; | ||
| 40 | GLsizei height; | ||
| 41 | GLenum gl_format; | ||
| 42 | GLenum gl_type; | ||
| 43 | Service::android::PixelFormat pixel_format; | ||
| 44 | }; | ||
| 45 | |||
| 46 | /// Structure used for storing information about the display target for the Switch screen | 35 | /// Structure used for storing information about the display target for the Switch screen |
| 47 | struct FramebufferTextureInfo { | 36 | struct FramebufferTextureInfo { |
| 48 | GLuint display_texture{}; | 37 | GLuint display_texture{}; |
| @@ -60,20 +49,11 @@ public: | |||
| 60 | Device& device); | 49 | Device& device); |
| 61 | ~BlitScreen(); | 50 | ~BlitScreen(); |
| 62 | 51 | ||
| 63 | void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer); | ||
| 64 | |||
| 65 | /// Draws the emulated screens to the emulator window. | 52 | /// Draws the emulated screens to the emulator window. |
| 66 | void DrawScreen(const Tegra::FramebufferConfig& framebuffer, | 53 | void DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers, |
| 67 | const Layout::FramebufferLayout& layout); | 54 | const Layout::FramebufferLayout& layout); |
| 68 | 55 | ||
| 69 | /// Loads framebuffer from emulated memory into the active OpenGL texture. | ||
| 70 | FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | ||
| 71 | |||
| 72 | FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); | ||
| 73 | |||
| 74 | private: | 56 | private: |
| 75 | void CreateFXAA(); | ||
| 76 | void CreateSMAA(); | ||
| 77 | void CreateWindowAdapt(); | 57 | void CreateWindowAdapt(); |
| 78 | 58 | ||
| 79 | RasterizerOpenGL& rasterizer; | 59 | RasterizerOpenGL& rasterizer; |
| @@ -82,18 +62,10 @@ private: | |||
| 82 | ProgramManager& program_manager; | 62 | ProgramManager& program_manager; |
| 83 | Device& device; | 63 | Device& device; |
| 84 | 64 | ||
| 85 | /// Display information for Switch screen | ||
| 86 | TextureInfo framebuffer_texture; | ||
| 87 | |||
| 88 | std::unique_ptr<FSR> fsr; | ||
| 89 | std::unique_ptr<FXAA> fxaa; | ||
| 90 | std::unique_ptr<SMAA> smaa; | ||
| 91 | |||
| 92 | Settings::ScalingFilter current_window_adapt{}; | 65 | Settings::ScalingFilter current_window_adapt{}; |
| 93 | std::unique_ptr<WindowAdaptPass> window_adapt; | 66 | std::unique_ptr<WindowAdaptPass> window_adapt; |
| 94 | 67 | ||
| 95 | /// OpenGL framebuffer data | 68 | std::list<Layer> layers; |
| 96 | std::vector<u8> gl_framebuffer_data; | ||
| 97 | }; | 69 | }; |
| 98 | 70 | ||
| 99 | } // namespace OpenGL | 71 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/present/layer.cpp b/src/video_core/renderer_opengl/present/layer.cpp new file mode 100644 index 000000000..8643e07c6 --- /dev/null +++ b/src/video_core/renderer_opengl/present/layer.cpp | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/framebuffer_config.h" | ||
| 5 | #include "video_core/renderer_opengl/gl_blit_screen.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 7 | #include "video_core/renderer_opengl/present/fsr.h" | ||
| 8 | #include "video_core/renderer_opengl/present/fxaa.h" | ||
| 9 | #include "video_core/renderer_opengl/present/layer.h" | ||
| 10 | #include "video_core/renderer_opengl/present/present_uniforms.h" | ||
| 11 | #include "video_core/renderer_opengl/present/smaa.h" | ||
| 12 | #include "video_core/surface.h" | ||
| 13 | #include "video_core/textures/decoders.h" | ||
| 14 | |||
| 15 | namespace OpenGL { | ||
| 16 | |||
| 17 | Layer::Layer(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_) | ||
| 18 | : rasterizer(rasterizer_), device_memory(device_memory_) { | ||
| 19 | // Allocate textures for the screen | ||
| 20 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); | ||
| 21 | |||
| 22 | const GLuint texture = framebuffer_texture.resource.handle; | ||
| 23 | glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1); | ||
| 24 | |||
| 25 | // Clear screen to black | ||
| 26 | const u8 framebuffer_data[4] = {0, 0, 0, 0}; | ||
| 27 | glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, | ||
| 28 | framebuffer_data); | ||
| 29 | } | ||
| 30 | |||
| 31 | Layer::~Layer() = default; | ||
| 32 | |||
| 33 | GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix, | ||
| 34 | std::array<ScreenRectVertex, 4>& out_vertices, | ||
| 35 | ProgramManager& program_manager, | ||
| 36 | const Tegra::FramebufferConfig& framebuffer, | ||
| 37 | const Layout::FramebufferLayout& layout) { | ||
| 38 | FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); | ||
| 39 | auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); | ||
| 40 | GLuint texture = info.display_texture; | ||
| 41 | |||
| 42 | auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); | ||
| 43 | if (anti_aliasing != Settings::AntiAliasing::None) { | ||
| 44 | glEnablei(GL_SCISSOR_TEST, 0); | ||
| 45 | auto viewport_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); | ||
| 46 | auto viewport_height = Settings::values.resolution_info.ScaleUp(framebuffer_texture.height); | ||
| 47 | |||
| 48 | glScissorIndexed(0, 0, 0, viewport_width, viewport_height); | ||
| 49 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(viewport_width), | ||
| 50 | static_cast<GLfloat>(viewport_height)); | ||
| 51 | |||
| 52 | switch (anti_aliasing) { | ||
| 53 | case Settings::AntiAliasing::Fxaa: | ||
| 54 | CreateFXAA(); | ||
| 55 | texture = fxaa->Draw(program_manager, info.display_texture); | ||
| 56 | break; | ||
| 57 | case Settings::AntiAliasing::Smaa: | ||
| 58 | default: | ||
| 59 | CreateSMAA(); | ||
| 60 | texture = smaa->Draw(program_manager, info.display_texture); | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | glDisablei(GL_SCISSOR_TEST, 0); | ||
| 66 | |||
| 67 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||
| 68 | if (!fsr || fsr->NeedsRecreation(layout.screen)) { | ||
| 69 | fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); | ||
| 70 | } | ||
| 71 | |||
| 72 | texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop); | ||
| 73 | crop = {0, 0, 1, 1}; | ||
| 74 | } | ||
| 75 | |||
| 76 | out_matrix = | ||
| 77 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | ||
| 78 | |||
| 79 | // Map the coordinates to the screen. | ||
| 80 | const auto& screen = layout.screen; | ||
| 81 | const auto x = screen.left; | ||
| 82 | const auto y = screen.top; | ||
| 83 | const auto w = screen.GetWidth(); | ||
| 84 | const auto h = screen.GetHeight(); | ||
| 85 | |||
| 86 | out_vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top); | ||
| 87 | out_vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top); | ||
| 88 | out_vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom); | ||
| 89 | out_vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom); | ||
| 90 | |||
| 91 | return texture; | ||
| 92 | } | ||
| 93 | |||
| 94 | FramebufferTextureInfo Layer::PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer) { | ||
| 95 | // If framebuffer is provided, reload it from memory to a texture | ||
| 96 | if (framebuffer_texture.width != static_cast<GLsizei>(framebuffer.width) || | ||
| 97 | framebuffer_texture.height != static_cast<GLsizei>(framebuffer.height) || | ||
| 98 | framebuffer_texture.pixel_format != framebuffer.pixel_format || | ||
| 99 | gl_framebuffer_data.empty()) { | ||
| 100 | // Reallocate texture if the framebuffer size has changed. | ||
| 101 | // This is expected to not happen very often and hence should not be a | ||
| 102 | // performance problem. | ||
| 103 | ConfigureFramebufferTexture(framebuffer); | ||
| 104 | } | ||
| 105 | |||
| 106 | // Load the framebuffer from memory if needed | ||
| 107 | return LoadFBToScreenInfo(framebuffer); | ||
| 108 | } | ||
| 109 | |||
| 110 | FramebufferTextureInfo Layer::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { | ||
| 111 | const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; | ||
| 112 | const auto accelerated_info = | ||
| 113 | rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride); | ||
| 114 | if (accelerated_info) { | ||
| 115 | return *accelerated_info; | ||
| 116 | } | ||
| 117 | |||
| 118 | // Reset the screen info's display texture to its own permanent texture | ||
| 119 | FramebufferTextureInfo info{}; | ||
| 120 | info.display_texture = framebuffer_texture.resource.handle; | ||
| 121 | info.width = framebuffer.width; | ||
| 122 | info.height = framebuffer.height; | ||
| 123 | info.scaled_width = framebuffer.width; | ||
| 124 | info.scaled_height = framebuffer.height; | ||
| 125 | |||
| 126 | // TODO(Rodrigo): Read this from HLE | ||
| 127 | constexpr u32 block_height_log2 = 4; | ||
| 128 | const auto pixel_format{ | ||
| 129 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; | ||
| 130 | const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; | ||
| 131 | const u64 size_in_bytes{Tegra::Texture::CalculateSize( | ||
| 132 | true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; | ||
| 133 | const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; | ||
| 134 | const std::span<const u8> input_data(host_ptr, size_in_bytes); | ||
| 135 | Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, | ||
| 136 | framebuffer.width, framebuffer.height, 1, block_height_log2, | ||
| 137 | 0); | ||
| 138 | |||
| 139 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | ||
| 140 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); | ||
| 141 | |||
| 142 | // Update existing texture | ||
| 143 | // TODO: Test what happens on hardware when you change the framebuffer dimensions so that | ||
| 144 | // they differ from the LCD resolution. | ||
| 145 | // TODO: Applications could theoretically crash yuzu here by specifying too large | ||
| 146 | // framebuffer sizes. We should make sure that this cannot happen. | ||
| 147 | glTextureSubImage2D(framebuffer_texture.resource.handle, 0, 0, 0, framebuffer.width, | ||
| 148 | framebuffer.height, framebuffer_texture.gl_format, | ||
| 149 | framebuffer_texture.gl_type, gl_framebuffer_data.data()); | ||
| 150 | |||
| 151 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||
| 152 | |||
| 153 | return info; | ||
| 154 | } | ||
| 155 | |||
| 156 | void Layer::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer) { | ||
| 157 | framebuffer_texture.width = framebuffer.width; | ||
| 158 | framebuffer_texture.height = framebuffer.height; | ||
| 159 | framebuffer_texture.pixel_format = framebuffer.pixel_format; | ||
| 160 | |||
| 161 | const auto pixel_format{ | ||
| 162 | VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; | ||
| 163 | const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)}; | ||
| 164 | gl_framebuffer_data.resize(framebuffer_texture.width * framebuffer_texture.height * | ||
| 165 | bytes_per_pixel); | ||
| 166 | |||
| 167 | GLint internal_format; | ||
| 168 | switch (framebuffer.pixel_format) { | ||
| 169 | case Service::android::PixelFormat::Rgba8888: | ||
| 170 | internal_format = GL_RGBA8; | ||
| 171 | framebuffer_texture.gl_format = GL_RGBA; | ||
| 172 | framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | ||
| 173 | break; | ||
| 174 | case Service::android::PixelFormat::Rgb565: | ||
| 175 | internal_format = GL_RGB565; | ||
| 176 | framebuffer_texture.gl_format = GL_RGB; | ||
| 177 | framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; | ||
| 178 | break; | ||
| 179 | default: | ||
| 180 | internal_format = GL_RGBA8; | ||
| 181 | framebuffer_texture.gl_format = GL_RGBA; | ||
| 182 | framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; | ||
| 183 | // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", | ||
| 184 | // static_cast<u32>(framebuffer.pixel_format)); | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | |||
| 188 | framebuffer_texture.resource.Release(); | ||
| 189 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); | ||
| 190 | glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, | ||
| 191 | framebuffer_texture.width, framebuffer_texture.height); | ||
| 192 | |||
| 193 | fxaa.reset(); | ||
| 194 | smaa.reset(); | ||
| 195 | } | ||
| 196 | |||
| 197 | void Layer::CreateFXAA() { | ||
| 198 | smaa.reset(); | ||
| 199 | if (!fxaa) { | ||
| 200 | fxaa = std::make_unique<FXAA>( | ||
| 201 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||
| 202 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | void Layer::CreateSMAA() { | ||
| 207 | fxaa.reset(); | ||
| 208 | if (!smaa) { | ||
| 209 | smaa = std::make_unique<SMAA>( | ||
| 210 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||
| 211 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/present/layer.h b/src/video_core/renderer_opengl/present/layer.h new file mode 100644 index 000000000..ef1055abf --- /dev/null +++ b/src/video_core/renderer_opengl/present/layer.h | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "video_core/host1x/gpu_device_memory_manager.h" | ||
| 10 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 11 | |||
| 12 | namespace Layout { | ||
| 13 | struct FramebufferLayout; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::android { | ||
| 17 | enum class PixelFormat : u32; | ||
| 18 | }; | ||
| 19 | |||
| 20 | namespace Tegra { | ||
| 21 | struct FramebufferConfig; | ||
| 22 | } | ||
| 23 | |||
| 24 | namespace OpenGL { | ||
| 25 | |||
| 26 | struct FramebufferTextureInfo; | ||
| 27 | class FSR; | ||
| 28 | class FXAA; | ||
| 29 | class ProgramManager; | ||
| 30 | class RasterizerOpenGL; | ||
| 31 | class SMAA; | ||
| 32 | |||
| 33 | /// Structure used for storing information about the textures for the Switch screen | ||
| 34 | struct TextureInfo { | ||
| 35 | OGLTexture resource; | ||
| 36 | GLsizei width; | ||
| 37 | GLsizei height; | ||
| 38 | GLenum gl_format; | ||
| 39 | GLenum gl_type; | ||
| 40 | Service::android::PixelFormat pixel_format; | ||
| 41 | }; | ||
| 42 | |||
| 43 | struct ScreenRectVertex; | ||
| 44 | |||
| 45 | class Layer { | ||
| 46 | public: | ||
| 47 | explicit Layer(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory); | ||
| 48 | ~Layer(); | ||
| 49 | |||
| 50 | GLuint ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix, | ||
| 51 | std::array<ScreenRectVertex, 4>& out_vertices, | ||
| 52 | ProgramManager& program_manager, | ||
| 53 | const Tegra::FramebufferConfig& framebuffer, | ||
| 54 | const Layout::FramebufferLayout& layout); | ||
| 55 | |||
| 56 | private: | ||
| 57 | /// Loads framebuffer from emulated memory into the active OpenGL texture. | ||
| 58 | FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | ||
| 59 | FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); | ||
| 60 | void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer); | ||
| 61 | |||
| 62 | void CreateFXAA(); | ||
| 63 | void CreateSMAA(); | ||
| 64 | |||
| 65 | private: | ||
| 66 | RasterizerOpenGL& rasterizer; | ||
| 67 | Tegra::MaxwellDeviceMemoryManager& device_memory; | ||
| 68 | |||
| 69 | /// OpenGL framebuffer data | ||
| 70 | std::vector<u8> gl_framebuffer_data; | ||
| 71 | |||
| 72 | /// Display information for Switch screen | ||
| 73 | TextureInfo framebuffer_texture; | ||
| 74 | |||
| 75 | std::unique_ptr<FSR> fsr; | ||
| 76 | std::unique_ptr<FXAA> fxaa; | ||
| 77 | std::unique_ptr<SMAA> smaa; | ||
| 78 | }; | ||
| 79 | |||
| 80 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/present/present_uniforms.h b/src/video_core/renderer_opengl/present/present_uniforms.h new file mode 100644 index 000000000..3a19f05c7 --- /dev/null +++ b/src/video_core/renderer_opengl/present/present_uniforms.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 7 | |||
| 8 | namespace OpenGL { | ||
| 9 | |||
| 10 | constexpr GLint PositionLocation = 0; | ||
| 11 | constexpr GLint TexCoordLocation = 1; | ||
| 12 | constexpr GLint ModelViewMatrixLocation = 0; | ||
| 13 | |||
| 14 | struct ScreenRectVertex { | ||
| 15 | constexpr ScreenRectVertex() = default; | ||
| 16 | |||
| 17 | constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) | ||
| 18 | : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} | ||
| 19 | |||
| 20 | std::array<GLfloat, 2> position{}; | ||
| 21 | std::array<GLfloat, 2> tex_coord{}; | ||
| 22 | }; | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Defines a 1:1 pixel orthographic projection matrix with (0,0) on the top-left | ||
| 26 | * corner and (width, height) on the lower-bottom. | ||
| 27 | * | ||
| 28 | * The projection part of the matrix is trivial, hence these operations are represented | ||
| 29 | * by a 3x2 matrix. | ||
| 30 | */ | ||
| 31 | static inline std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { | ||
| 32 | std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order | ||
| 33 | |||
| 34 | // clang-format off | ||
| 35 | matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; | ||
| 36 | matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; | ||
| 37 | // Last matrix row is implicitly assumed to be [0, 0, 1]. | ||
| 38 | // clang-format on | ||
| 39 | |||
| 40 | return matrix; | ||
| 41 | } | ||
| 42 | |||
| 43 | } // namespace OpenGL | ||
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 168fa1aea..4d681606b 100644 --- a/src/video_core/renderer_opengl/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp | |||
| @@ -2,47 +2,17 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/settings.h" | 4 | #include "common/settings.h" |
| 5 | #include "video_core/framebuffer_config.h" | ||
| 5 | #include "video_core/host_shaders/opengl_present_vert.h" | 6 | #include "video_core/host_shaders/opengl_present_vert.h" |
| 6 | #include "video_core/renderer_opengl/gl_device.h" | 7 | #include "video_core/renderer_opengl/gl_device.h" |
| 7 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 8 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 8 | #include "video_core/renderer_opengl/gl_shader_util.h" | 9 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 10 | #include "video_core/renderer_opengl/present/layer.h" | ||
| 11 | #include "video_core/renderer_opengl/present/present_uniforms.h" | ||
| 9 | #include "video_core/renderer_opengl/present/window_adapt_pass.h" | 12 | #include "video_core/renderer_opengl/present/window_adapt_pass.h" |
| 10 | 13 | ||
| 11 | namespace OpenGL { | 14 | namespace OpenGL { |
| 12 | 15 | ||
| 13 | namespace { | ||
| 14 | constexpr GLint PositionLocation = 0; | ||
| 15 | constexpr GLint TexCoordLocation = 1; | ||
| 16 | constexpr GLint ModelViewMatrixLocation = 0; | ||
| 17 | |||
| 18 | struct ScreenRectVertex { | ||
| 19 | constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) | ||
| 20 | : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} | ||
| 21 | |||
| 22 | std::array<GLfloat, 2> position; | ||
| 23 | std::array<GLfloat, 2> tex_coord; | ||
| 24 | }; | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Defines a 1:1 pixel orthographic projection matrix with (0,0) on the top-left | ||
| 28 | * corner and (width, height) on the lower-bottom. | ||
| 29 | * | ||
| 30 | * The projection part of the matrix is trivial, hence these operations are represented | ||
| 31 | * by a 3x2 matrix. | ||
| 32 | */ | ||
| 33 | std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { | ||
| 34 | std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order | ||
| 35 | |||
| 36 | // clang-format off | ||
| 37 | matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; | ||
| 38 | matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; | ||
| 39 | // Last matrix row is implicitly assumed to be [0, 0, 1]. | ||
| 40 | // clang-format on | ||
| 41 | |||
| 42 | return matrix; | ||
| 43 | } | ||
| 44 | } // namespace | ||
| 45 | |||
| 46 | WindowAdaptPass::WindowAdaptPass(const Device& device_, OGLSampler&& sampler_, | 16 | WindowAdaptPass::WindowAdaptPass(const Device& device_, OGLSampler&& sampler_, |
| 47 | std::string_view frag_source) | 17 | std::string_view frag_source) |
| 48 | : device(device_), sampler(std::move(sampler_)) { | 18 | : device(device_), sampler(std::move(sampler_)) { |
| @@ -65,32 +35,30 @@ WindowAdaptPass::WindowAdaptPass(const Device& device_, OGLSampler&& sampler_, | |||
| 65 | 35 | ||
| 66 | WindowAdaptPass::~WindowAdaptPass() = default; | 36 | WindowAdaptPass::~WindowAdaptPass() = default; |
| 67 | 37 | ||
| 68 | void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, GLuint texture, | 38 | void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers, |
| 69 | const Layout::FramebufferLayout& layout, | 39 | std::span<const Tegra::FramebufferConfig> framebuffers, |
| 70 | const Common::Rectangle<f32>& crop) { | 40 | const Layout::FramebufferLayout& layout) { |
| 71 | glBindTextureUnit(0, texture); | 41 | GLint old_read_fb; |
| 42 | GLint old_draw_fb; | ||
| 43 | glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); | ||
| 44 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||
| 45 | |||
| 46 | const size_t layer_count = framebuffers.size(); | ||
| 47 | std::vector<GLuint> textures(layer_count); | ||
| 48 | std::vector<std::array<GLfloat, 3 * 2>> matrices(layer_count); | ||
| 49 | std::vector<std::array<ScreenRectVertex, 4>> vertices(layer_count); | ||
| 50 | |||
| 51 | auto layer_it = layers.begin(); | ||
| 52 | for (size_t i = 0; i < layer_count; i++) { | ||
| 53 | textures[i] = layer_it->ConfigureDraw(matrices[i], vertices[i], program_manager, | ||
| 54 | framebuffers[i], layout); | ||
| 55 | layer_it++; | ||
| 56 | } | ||
| 72 | 57 | ||
| 73 | const std::array ortho_matrix = | 58 | glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); |
| 74 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | 59 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); |
| 75 | 60 | ||
| 76 | program_manager.BindPresentPrograms(vert.handle, frag.handle); | 61 | program_manager.BindPresentPrograms(vert.handle, frag.handle); |
| 77 | glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE, | ||
| 78 | ortho_matrix.data()); | ||
| 79 | |||
| 80 | // Map the coordinates to the screen. | ||
| 81 | const auto& screen = layout.screen; | ||
| 82 | const auto x = screen.left; | ||
| 83 | const auto y = screen.top; | ||
| 84 | const auto w = screen.GetWidth(); | ||
| 85 | const auto h = screen.GetHeight(); | ||
| 86 | |||
| 87 | const std::array vertices = { | ||
| 88 | ScreenRectVertex(x, y, crop.left, crop.top), | ||
| 89 | ScreenRectVertex(x + w, y, crop.right, crop.top), | ||
| 90 | ScreenRectVertex(x, y + h, crop.left, crop.bottom), | ||
| 91 | ScreenRectVertex(x + w, y + h, crop.right, crop.bottom), | ||
| 92 | }; | ||
| 93 | glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); | ||
| 94 | 62 | ||
| 95 | glDisable(GL_FRAMEBUFFER_SRGB); | 63 | glDisable(GL_FRAMEBUFFER_SRGB); |
| 96 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), | 64 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), |
| @@ -109,7 +77,7 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, GLuint | |||
| 109 | if (device.HasVertexBufferUnifiedMemory()) { | 77 | if (device.HasVertexBufferUnifiedMemory()) { |
| 110 | glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); | 78 | glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); |
| 111 | glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, | 79 | glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, |
| 112 | sizeof(vertices)); | 80 | sizeof(decltype(vertices)::value_type)); |
| 113 | } else { | 81 | } else { |
| 114 | glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); | 82 | glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); |
| 115 | } | 83 | } |
| @@ -122,7 +90,14 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, GLuint | |||
| 122 | Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); | 90 | Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); |
| 123 | 91 | ||
| 124 | glClear(GL_COLOR_BUFFER_BIT); | 92 | glClear(GL_COLOR_BUFFER_BIT); |
| 125 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 93 | |
| 94 | for (size_t i = 0; i < layer_count; i++) { | ||
| 95 | glBindTextureUnit(0, textures[i]); | ||
| 96 | glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE, | ||
| 97 | matrices[i].data()); | ||
| 98 | glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices[i]), std::data(vertices[i])); | ||
| 99 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
| 100 | } | ||
| 126 | } | 101 | } |
| 127 | 102 | ||
| 128 | } // namespace OpenGL | 103 | } // namespace OpenGL |
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 65dcd09ff..00975a9c6 100644 --- a/src/video_core/renderer_opengl/present/window_adapt_pass.h +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.h | |||
| @@ -3,6 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <list> | ||
| 7 | #include <span> | ||
| 8 | |||
| 6 | #include "common/math_util.h" | 9 | #include "common/math_util.h" |
| 7 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 10 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 8 | 11 | ||
| @@ -10,9 +13,14 @@ namespace Layout { | |||
| 10 | struct FramebufferLayout; | 13 | struct FramebufferLayout; |
| 11 | } | 14 | } |
| 12 | 15 | ||
| 16 | namespace Tegra { | ||
| 17 | struct FramebufferConfig; | ||
| 18 | } | ||
| 19 | |||
| 13 | namespace OpenGL { | 20 | namespace OpenGL { |
| 14 | 21 | ||
| 15 | class Device; | 22 | class Device; |
| 23 | class Layer; | ||
| 16 | class ProgramManager; | 24 | class ProgramManager; |
| 17 | 25 | ||
| 18 | class WindowAdaptPass final { | 26 | class WindowAdaptPass final { |
| @@ -21,9 +29,9 @@ public: | |||
| 21 | std::string_view frag_source); | 29 | std::string_view frag_source); |
| 22 | ~WindowAdaptPass(); | 30 | ~WindowAdaptPass(); |
| 23 | 31 | ||
| 24 | void DrawToFramebuffer(ProgramManager& program_manager, GLuint texture, | 32 | void DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers, |
| 25 | const Layout::FramebufferLayout& layout, | 33 | std::span<const Tegra::FramebufferConfig> framebuffers, |
| 26 | const Common::Rectangle<f32>& crop); | 34 | const Layout::FramebufferLayout& layout); |
| 27 | 35 | ||
| 28 | private: | 36 | private: |
| 29 | const Device& device; | 37 | const Device& device; |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 0d138c189..10a9f973c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -130,10 +130,10 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 130 | return; | 130 | return; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | RenderScreenshot(*framebuffer); | 133 | RenderScreenshot(framebuffer); |
| 134 | 134 | ||
| 135 | state_tracker.BindFramebuffer(0); | 135 | state_tracker.BindFramebuffer(0); |
| 136 | blit_screen->DrawScreen(*framebuffer, emu_window.GetFramebufferLayout()); | 136 | blit_screen->DrawScreen(std::span(framebuffer, 1), emu_window.GetFramebufferLayout()); |
| 137 | 137 | ||
| 138 | ++m_current_frame; | 138 | ++m_current_frame; |
| 139 | 139 | ||
| @@ -159,7 +159,7 @@ void RendererOpenGL::AddTelemetryFields() { | |||
| 159 | telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); | 159 | telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { | 162 | void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig* framebuffer) { |
| 163 | if (!renderer_settings.screenshot_requested) { | 163 | if (!renderer_settings.screenshot_requested) { |
| 164 | return; | 164 | return; |
| 165 | } | 165 | } |
| @@ -181,7 +181,7 @@ void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffe | |||
| 181 | glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); | 181 | glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); |
| 182 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); | 182 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); |
| 183 | 183 | ||
| 184 | blit_screen->DrawScreen(framebuffer, layout); | 184 | blit_screen->DrawScreen(std::span(framebuffer, 1), layout); |
| 185 | 185 | ||
| 186 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | 186 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); |
| 187 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 187 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 7ab163372..df76d3d05 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -52,7 +52,7 @@ public: | |||
| 52 | 52 | ||
| 53 | private: | 53 | private: |
| 54 | void AddTelemetryFields(); | 54 | void AddTelemetryFields(); |
| 55 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); | 55 | void RenderScreenshot(const Tegra::FramebufferConfig* framebuffer); |
| 56 | 56 | ||
| 57 | Core::TelemetrySession& telemetry_session; | 57 | Core::TelemetrySession& telemetry_session; |
| 58 | Core::Frontend::EmuWindow& emu_window; | 58 | Core::Frontend::EmuWindow& emu_window; |