summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2024-01-18 20:47:50 -0500
committerGravatar Liam2024-01-31 11:27:21 -0500
commit10cf0585180bcf2eab38ebf65dc593fecc4ddf92 (patch)
treec0c7680fd2a17b32b0baab91b31f3c25c597ccfd /src
parentrenderer_vulkan: implement layer stack composition (diff)
downloadyuzu-10cf0585180bcf2eab38ebf65dc593fecc4ddf92.tar.gz
yuzu-10cf0585180bcf2eab38ebf65dc593fecc4ddf92.tar.xz
yuzu-10cf0585180bcf2eab38ebf65dc593fecc4ddf92.zip
renderer_opengl: implement layer stack composition
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt3
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.cpp198
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.h38
-rw-r--r--src/video_core/renderer_opengl/present/layer.cpp215
-rw-r--r--src/video_core/renderer_opengl/present/layer.h80
-rw-r--r--src/video_core/renderer_opengl/present/present_uniforms.h43
-rw-r--r--src/video_core/renderer_opengl/present/window_adapt_pass.cpp91
-rw-r--r--src/video_core/renderer_opengl/present/window_adapt_pass.h14
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h2
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
17namespace OpenGL { 11namespace 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
37BlitScreen::~BlitScreen() = default; 20BlitScreen::~BlitScreen() = default;
38 21
39FramebufferTextureInfo BlitScreen::PrepareRenderTarget( 22void 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
56FramebufferTextureInfo 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
102void 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
143void 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
235void 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
244void 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
253void BlitScreen::CreateWindowAdapt() { 69void 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;
25namespace OpenGL { 26namespace OpenGL {
26 27
27class Device; 28class Device;
28class FSR; 29class Layer;
29class FXAA;
30class ProgramManager; 30class ProgramManager;
31class RasterizerOpenGL; 31class RasterizerOpenGL;
32class SMAA;
33class StateTracker; 32class StateTracker;
34class WindowAdaptPass; 33class WindowAdaptPass;
35 34
36/// Structure used for storing information about the textures for the Switch screen
37struct 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
47struct FramebufferTextureInfo { 36struct 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
74private: 56private:
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
15namespace OpenGL {
16
17Layer::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
31Layer::~Layer() = default;
32
33GLuint 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
94FramebufferTextureInfo 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
110FramebufferTextureInfo 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
156void 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
197void 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
206void 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
12namespace Layout {
13struct FramebufferLayout;
14}
15
16namespace Service::android {
17enum class PixelFormat : u32;
18};
19
20namespace Tegra {
21struct FramebufferConfig;
22}
23
24namespace OpenGL {
25
26struct FramebufferTextureInfo;
27class FSR;
28class FXAA;
29class ProgramManager;
30class RasterizerOpenGL;
31class SMAA;
32
33/// Structure used for storing information about the textures for the Switch screen
34struct 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
43struct ScreenRectVertex;
44
45class Layer {
46public:
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
56private:
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
65private:
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
8namespace OpenGL {
9
10constexpr GLint PositionLocation = 0;
11constexpr GLint TexCoordLocation = 1;
12constexpr GLint ModelViewMatrixLocation = 0;
13
14struct 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 */
31static 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
11namespace OpenGL { 14namespace OpenGL {
12 15
13namespace {
14constexpr GLint PositionLocation = 0;
15constexpr GLint TexCoordLocation = 1;
16constexpr GLint ModelViewMatrixLocation = 0;
17
18struct 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 */
33std::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
46WindowAdaptPass::WindowAdaptPass(const Device& device_, OGLSampler&& sampler_, 16WindowAdaptPass::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
66WindowAdaptPass::~WindowAdaptPass() = default; 36WindowAdaptPass::~WindowAdaptPass() = default;
67 37
68void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, GLuint texture, 38void 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 {
10struct FramebufferLayout; 13struct FramebufferLayout;
11} 14}
12 15
16namespace Tegra {
17struct FramebufferConfig;
18}
19
13namespace OpenGL { 20namespace OpenGL {
14 21
15class Device; 22class Device;
23class Layer;
16class ProgramManager; 24class ProgramManager;
17 25
18class WindowAdaptPass final { 26class 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
28private: 36private:
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
162void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { 162void 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
53private: 53private:
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;