summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.cpp519
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.h110
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp506
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h78
6 files changed, 639 insertions, 577 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 36aa7bb66..c158970f2 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -118,6 +118,8 @@ add_library(video_core STATIC
118 renderer_null/renderer_null.h 118 renderer_null/renderer_null.h
119 renderer_opengl/blit_image.cpp 119 renderer_opengl/blit_image.cpp
120 renderer_opengl/blit_image.h 120 renderer_opengl/blit_image.h
121 renderer_opengl/gl_blit_screen.cpp
122 renderer_opengl/gl_blit_screen.h
121 renderer_opengl/gl_buffer_cache_base.cpp 123 renderer_opengl/gl_buffer_cache_base.cpp
122 renderer_opengl/gl_buffer_cache.cpp 124 renderer_opengl/gl_buffer_cache.cpp
123 renderer_opengl/gl_buffer_cache.h 125 renderer_opengl/gl_buffer_cache.h
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp
new file mode 100644
index 000000000..88757ba38
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp
@@ -0,0 +1,519 @@
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/host_shaders/ffx_a_h.h"
6#include "video_core/host_shaders/ffx_fsr1_h.h"
7#include "video_core/host_shaders/full_screen_triangle_vert.h"
8#include "video_core/host_shaders/fxaa_frag.h"
9#include "video_core/host_shaders/fxaa_vert.h"
10#include "video_core/host_shaders/opengl_fidelityfx_fsr_easu_frag.h"
11#include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h"
12#include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h"
13#include "video_core/host_shaders/opengl_present_frag.h"
14#include "video_core/host_shaders/opengl_present_scaleforce_frag.h"
15#include "video_core/host_shaders/opengl_present_vert.h"
16#include "video_core/host_shaders/opengl_smaa_glsl.h"
17#include "video_core/host_shaders/present_bicubic_frag.h"
18#include "video_core/host_shaders/present_gaussian_frag.h"
19#include "video_core/host_shaders/smaa_blending_weight_calculation_frag.h"
20#include "video_core/host_shaders/smaa_blending_weight_calculation_vert.h"
21#include "video_core/host_shaders/smaa_edge_detection_frag.h"
22#include "video_core/host_shaders/smaa_edge_detection_vert.h"
23#include "video_core/host_shaders/smaa_neighborhood_blending_frag.h"
24#include "video_core/host_shaders/smaa_neighborhood_blending_vert.h"
25#include "video_core/renderer_opengl/gl_blit_screen.h"
26#include "video_core/renderer_opengl/gl_rasterizer.h"
27#include "video_core/renderer_opengl/gl_shader_manager.h"
28#include "video_core/renderer_opengl/gl_shader_util.h"
29#include "video_core/renderer_opengl/gl_state_tracker.h"
30#include "video_core/smaa_area_tex.h"
31#include "video_core/smaa_search_tex.h"
32#include "video_core/textures/decoders.h"
33
34namespace OpenGL {
35
36namespace {
37constexpr GLint PositionLocation = 0;
38constexpr GLint TexCoordLocation = 1;
39constexpr GLint ModelViewMatrixLocation = 0;
40
41struct ScreenRectVertex {
42 constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v)
43 : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {}
44
45 std::array<GLfloat, 2> position;
46 std::array<GLfloat, 2> tex_coord;
47};
48
49/**
50 * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
51 * corner and (width, height) on the lower-bottom.
52 *
53 * The projection part of the matrix is trivial, hence these operations are represented
54 * by a 3x2 matrix.
55 */
56std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) {
57 std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order
58
59 // clang-format off
60 matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
61 matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
62 // Last matrix row is implicitly assumed to be [0, 0, 1].
63 // clang-format on
64
65 return matrix;
66}
67} // namespace
68
69BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_,
70 Tegra::MaxwellDeviceMemoryManager& device_memory_,
71 StateTracker& state_tracker_, ProgramManager& program_manager_,
72 Device& device_)
73 : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_),
74 program_manager(program_manager_), device(device_) {
75 // Create shader programs
76 fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER);
77 fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER);
78
79 const auto replace_include = [](std::string& shader_source, std::string_view include_name,
80 std::string_view include_content) {
81 const std::string include_string = fmt::format("#include \"{}\"", include_name);
82 const std::size_t pos = shader_source.find(include_string);
83 ASSERT(pos != std::string::npos);
84 shader_source.replace(pos, include_string.size(), include_content);
85 };
86
87 const auto SmaaShader = [&](std::string_view specialized_source, GLenum stage) {
88 std::string shader_source{specialized_source};
89 replace_include(shader_source, "opengl_smaa.glsl", HostShaders::OPENGL_SMAA_GLSL);
90 return CreateProgram(shader_source, stage);
91 };
92
93 smaa_edge_detection_vert = SmaaShader(HostShaders::SMAA_EDGE_DETECTION_VERT, GL_VERTEX_SHADER);
94 smaa_edge_detection_frag =
95 SmaaShader(HostShaders::SMAA_EDGE_DETECTION_FRAG, GL_FRAGMENT_SHADER);
96 smaa_blending_weight_calculation_vert =
97 SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_VERT, GL_VERTEX_SHADER);
98 smaa_blending_weight_calculation_frag =
99 SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_FRAG, GL_FRAGMENT_SHADER);
100 smaa_neighborhood_blending_vert =
101 SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_VERT, GL_VERTEX_SHADER);
102 smaa_neighborhood_blending_frag =
103 SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER);
104
105 present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
106 present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
107 present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER);
108 present_gaussian_fragment =
109 CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER);
110 present_scaleforce_fragment =
111 CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG),
112 GL_FRAGMENT_SHADER);
113
114 std::string fsr_source{HostShaders::OPENGL_FIDELITYFX_FSR_FRAG};
115 replace_include(fsr_source, "ffx_a.h", HostShaders::FFX_A_H);
116 replace_include(fsr_source, "ffx_fsr1.h", HostShaders::FFX_FSR1_H);
117
118 std::string fsr_easu_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_EASU_FRAG};
119 std::string fsr_rcas_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_RCAS_FRAG};
120 replace_include(fsr_easu_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source);
121 replace_include(fsr_rcas_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source);
122
123 fsr = std::make_unique<FSR>(HostShaders::FULL_SCREEN_TRIANGLE_VERT, fsr_easu_frag_source,
124 fsr_rcas_frag_source);
125
126 // Generate presentation sampler
127 present_sampler.Create();
128 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
129 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
130 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
131 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
132 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
133
134 present_sampler_nn.Create();
135 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
136 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
137 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
138 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
139 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
140
141 // Generate VBO handle for drawing
142 vertex_buffer.Create();
143
144 // Attach vertex data to VAO
145 glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
146
147 // Allocate textures for the screen
148 framebuffer_texture.resource.Create(GL_TEXTURE_2D);
149
150 const GLuint texture = framebuffer_texture.resource.handle;
151 glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1);
152
153 // Clear screen to black
154 const u8 framebuffer_data[4] = {0, 0, 0, 0};
155 glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE,
156 framebuffer_data);
157
158 aa_framebuffer.Create();
159
160 smaa_area_tex.Create(GL_TEXTURE_2D);
161 glTextureStorage2D(smaa_area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT);
162 glTextureSubImage2D(smaa_area_tex.handle, 0, 0, 0, AREATEX_WIDTH, AREATEX_HEIGHT, GL_RG,
163 GL_UNSIGNED_BYTE, areaTexBytes);
164 smaa_search_tex.Create(GL_TEXTURE_2D);
165 glTextureStorage2D(smaa_search_tex.handle, 1, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT);
166 glTextureSubImage2D(smaa_search_tex.handle, 0, 0, 0, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, GL_RED,
167 GL_UNSIGNED_BYTE, searchTexBytes);
168
169 // Enable unified vertex attributes and query vertex buffer address when the driver supports it
170 if (device.HasVertexBufferUnifiedMemory()) {
171 glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV);
172 glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV);
173 glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY);
174 glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV,
175 &vertex_buffer_address);
176 }
177}
178
179FramebufferTextureInfo BlitScreen::PrepareRenderTarget(
180 const Tegra::FramebufferConfig& framebuffer) {
181 // If framebuffer is provided, reload it from memory to a texture
182 if (framebuffer_texture.width != static_cast<GLsizei>(framebuffer.width) ||
183 framebuffer_texture.height != static_cast<GLsizei>(framebuffer.height) ||
184 framebuffer_texture.pixel_format != framebuffer.pixel_format ||
185 gl_framebuffer_data.empty()) {
186 // Reallocate texture if the framebuffer size has changed.
187 // This is expected to not happen very often and hence should not be a
188 // performance problem.
189 ConfigureFramebufferTexture(framebuffer);
190 }
191
192 // Load the framebuffer from memory if needed
193 return LoadFBToScreenInfo(framebuffer);
194}
195
196FramebufferTextureInfo BlitScreen::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) {
197 const DAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
198 const auto accelerated_info =
199 rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride);
200 if (accelerated_info) {
201 return *accelerated_info;
202 }
203
204 // Reset the screen info's display texture to its own permanent texture
205 FramebufferTextureInfo info{};
206 info.display_texture = framebuffer_texture.resource.handle;
207 info.width = framebuffer.width;
208 info.height = framebuffer.height;
209 info.scaled_width = framebuffer.width;
210 info.scaled_height = framebuffer.height;
211
212 // TODO(Rodrigo): Read this from HLE
213 constexpr u32 block_height_log2 = 4;
214 const auto pixel_format{
215 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
216 const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
217 const u64 size_in_bytes{Tegra::Texture::CalculateSize(
218 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
219 const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
220 const std::span<const u8> input_data(host_ptr, size_in_bytes);
221 Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
222 framebuffer.width, framebuffer.height, 1, block_height_log2,
223 0);
224
225 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
226 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
227
228 // Update existing texture
229 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
230 // they differ from the LCD resolution.
231 // TODO: Applications could theoretically crash yuzu here by specifying too large
232 // framebuffer sizes. We should make sure that this cannot happen.
233 glTextureSubImage2D(framebuffer_texture.resource.handle, 0, 0, 0, framebuffer.width,
234 framebuffer.height, framebuffer_texture.gl_format,
235 framebuffer_texture.gl_type, gl_framebuffer_data.data());
236
237 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
238
239 return info;
240}
241
242void BlitScreen::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer) {
243 framebuffer_texture.width = framebuffer.width;
244 framebuffer_texture.height = framebuffer.height;
245 framebuffer_texture.pixel_format = framebuffer.pixel_format;
246
247 const auto pixel_format{
248 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
249 const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
250 gl_framebuffer_data.resize(framebuffer_texture.width * framebuffer_texture.height *
251 bytes_per_pixel);
252
253 GLint internal_format;
254 switch (framebuffer.pixel_format) {
255 case Service::android::PixelFormat::Rgba8888:
256 internal_format = GL_RGBA8;
257 framebuffer_texture.gl_format = GL_RGBA;
258 framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
259 break;
260 case Service::android::PixelFormat::Rgb565:
261 internal_format = GL_RGB565;
262 framebuffer_texture.gl_format = GL_RGB;
263 framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
264 break;
265 default:
266 internal_format = GL_RGBA8;
267 framebuffer_texture.gl_format = GL_RGBA;
268 framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
269 // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",
270 // static_cast<u32>(framebuffer.pixel_format));
271 break;
272 }
273
274 framebuffer_texture.resource.Release();
275 framebuffer_texture.resource.Create(GL_TEXTURE_2D);
276 glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format,
277 framebuffer_texture.width, framebuffer_texture.height);
278 aa_texture.Release();
279 aa_texture.Create(GL_TEXTURE_2D);
280 glTextureStorage2D(aa_texture.handle, 1, GL_RGBA16F,
281 Settings::values.resolution_info.ScaleUp(framebuffer_texture.width),
282 Settings::values.resolution_info.ScaleUp(framebuffer_texture.height));
283 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, aa_texture.handle, 0);
284 smaa_edges_tex.Release();
285 smaa_edges_tex.Create(GL_TEXTURE_2D);
286 glTextureStorage2D(smaa_edges_tex.handle, 1, GL_RG16F,
287 Settings::values.resolution_info.ScaleUp(framebuffer_texture.width),
288 Settings::values.resolution_info.ScaleUp(framebuffer_texture.height));
289 smaa_blend_tex.Release();
290 smaa_blend_tex.Create(GL_TEXTURE_2D);
291 glTextureStorage2D(smaa_blend_tex.handle, 1, GL_RGBA16F,
292 Settings::values.resolution_info.ScaleUp(framebuffer_texture.width),
293 Settings::values.resolution_info.ScaleUp(framebuffer_texture.height));
294}
295
296void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer,
297 const Layout::FramebufferLayout& layout) {
298 FramebufferTextureInfo info = PrepareRenderTarget(framebuffer);
299 const auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height);
300
301 // TODO: Signal state tracker about these changes
302 state_tracker.NotifyScreenDrawVertexArray();
303 state_tracker.NotifyPolygonModes();
304 state_tracker.NotifyViewport0();
305 state_tracker.NotifyScissor0();
306 state_tracker.NotifyColorMask(0);
307 state_tracker.NotifyBlend0();
308 state_tracker.NotifyFramebuffer();
309 state_tracker.NotifyFrontFace();
310 state_tracker.NotifyCullTest();
311 state_tracker.NotifyDepthTest();
312 state_tracker.NotifyStencilTest();
313 state_tracker.NotifyPolygonOffset();
314 state_tracker.NotifyRasterizeEnable();
315 state_tracker.NotifyFramebufferSRGB();
316 state_tracker.NotifyLogicOp();
317 state_tracker.NotifyClipControl();
318 state_tracker.NotifyAlphaTest();
319
320 state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
321
322 glEnable(GL_CULL_FACE);
323 glDisable(GL_COLOR_LOGIC_OP);
324 glDisable(GL_DEPTH_TEST);
325 glDisable(GL_STENCIL_TEST);
326 glDisable(GL_POLYGON_OFFSET_FILL);
327 glDisable(GL_RASTERIZER_DISCARD);
328 glDisable(GL_ALPHA_TEST);
329 glDisablei(GL_BLEND, 0);
330 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
331 glCullFace(GL_BACK);
332 glFrontFace(GL_CW);
333 glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
334 glDepthRangeIndexed(0, 0.0, 0.0);
335
336 glBindTextureUnit(0, info.display_texture);
337
338 auto anti_aliasing = Settings::values.anti_aliasing.GetValue();
339 if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) {
340 LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing);
341 anti_aliasing = Settings::AntiAliasing::None;
342 Settings::values.anti_aliasing.SetValue(anti_aliasing);
343 }
344
345 if (anti_aliasing != Settings::AntiAliasing::None) {
346 glEnablei(GL_SCISSOR_TEST, 0);
347 auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width);
348 auto viewport_width = static_cast<GLfloat>(scissor_width);
349 auto scissor_height = Settings::values.resolution_info.ScaleUp(framebuffer_texture.height);
350 auto viewport_height = static_cast<GLfloat>(scissor_height);
351
352 glScissorIndexed(0, 0, 0, scissor_width, scissor_height);
353 glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height);
354
355 glBindSampler(0, present_sampler.handle);
356 GLint old_read_fb;
357 GLint old_draw_fb;
358 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
359 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
360
361 switch (anti_aliasing) {
362 case Settings::AntiAliasing::Fxaa: {
363 program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle);
364 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle);
365 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
366 } break;
367 case Settings::AntiAliasing::Smaa: {
368 glClearColor(0, 0, 0, 0);
369 glFrontFace(GL_CCW);
370 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle);
371 glBindSampler(1, present_sampler.handle);
372 glBindSampler(2, present_sampler.handle);
373
374 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
375 smaa_edges_tex.handle, 0);
376 glClear(GL_COLOR_BUFFER_BIT);
377 program_manager.BindPresentPrograms(smaa_edge_detection_vert.handle,
378 smaa_edge_detection_frag.handle);
379 glDrawArrays(GL_TRIANGLES, 0, 3);
380
381 glBindTextureUnit(0, smaa_edges_tex.handle);
382 glBindTextureUnit(1, smaa_area_tex.handle);
383 glBindTextureUnit(2, smaa_search_tex.handle);
384 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
385 smaa_blend_tex.handle, 0);
386 glClear(GL_COLOR_BUFFER_BIT);
387 program_manager.BindPresentPrograms(smaa_blending_weight_calculation_vert.handle,
388 smaa_blending_weight_calculation_frag.handle);
389 glDrawArrays(GL_TRIANGLES, 0, 3);
390
391 glBindTextureUnit(0, info.display_texture);
392 glBindTextureUnit(1, smaa_blend_tex.handle);
393 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
394 aa_texture.handle, 0);
395 program_manager.BindPresentPrograms(smaa_neighborhood_blending_vert.handle,
396 smaa_neighborhood_blending_frag.handle);
397 glDrawArrays(GL_TRIANGLES, 0, 3);
398 glFrontFace(GL_CW);
399 } break;
400 default:
401 UNREACHABLE();
402 }
403
404 glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
405 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
406
407 glBindTextureUnit(0, aa_texture.handle);
408 }
409 glDisablei(GL_SCISSOR_TEST, 0);
410
411 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
412 if (!fsr->AreBuffersInitialized()) {
413 fsr->InitBuffers();
414 }
415
416 glBindSampler(0, present_sampler.handle);
417 fsr->Draw(program_manager, layout.screen, info.scaled_width, info.scaled_height, crop);
418 } else {
419 if (fsr->AreBuffersInitialized()) {
420 fsr->ReleaseBuffers();
421 }
422 }
423
424 const std::array ortho_matrix =
425 MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
426
427 const auto fragment_handle = [this]() {
428 switch (Settings::values.scaling_filter.GetValue()) {
429 case Settings::ScalingFilter::NearestNeighbor:
430 case Settings::ScalingFilter::Bilinear:
431 return present_bilinear_fragment.handle;
432 case Settings::ScalingFilter::Bicubic:
433 return present_bicubic_fragment.handle;
434 case Settings::ScalingFilter::Gaussian:
435 return present_gaussian_fragment.handle;
436 case Settings::ScalingFilter::ScaleForce:
437 return present_scaleforce_fragment.handle;
438 case Settings::ScalingFilter::Fsr:
439 return fsr->GetPresentFragmentProgram().handle;
440 default:
441 return present_bilinear_fragment.handle;
442 }
443 }();
444 program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle);
445 glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE,
446 ortho_matrix.data());
447
448 f32 left, top, right, bottom;
449 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
450 // FSR has already applied the crop, so we just want to render the image
451 // it has produced.
452 left = 0;
453 top = 0;
454 right = 1;
455 bottom = 1;
456 } else {
457 // Apply the precomputed crop.
458 left = crop.left;
459 top = crop.top;
460 right = crop.right;
461 bottom = crop.bottom;
462 }
463
464 // Map the coordinates to the screen.
465 const auto& screen = layout.screen;
466 const auto x = screen.left;
467 const auto y = screen.top;
468 const auto w = screen.GetWidth();
469 const auto h = screen.GetHeight();
470
471 const std::array vertices = {
472 ScreenRectVertex(x, y, left, top),
473 ScreenRectVertex(x + w, y, right, top),
474 ScreenRectVertex(x, y + h, left, bottom),
475 ScreenRectVertex(x + w, y + h, right, bottom),
476 };
477 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices));
478
479 glDisable(GL_FRAMEBUFFER_SRGB);
480 glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width),
481 static_cast<GLfloat>(layout.height));
482
483 glEnableVertexAttribArray(PositionLocation);
484 glEnableVertexAttribArray(TexCoordLocation);
485 glVertexAttribDivisor(PositionLocation, 0);
486 glVertexAttribDivisor(TexCoordLocation, 0);
487 glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE,
488 offsetof(ScreenRectVertex, position));
489 glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE,
490 offsetof(ScreenRectVertex, tex_coord));
491 glVertexAttribBinding(PositionLocation, 0);
492 glVertexAttribBinding(TexCoordLocation, 0);
493 if (device.HasVertexBufferUnifiedMemory()) {
494 glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex));
495 glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address,
496 sizeof(vertices));
497 } else {
498 glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
499 }
500
501 if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) {
502 glBindSampler(0, present_sampler.handle);
503 } else {
504 glBindSampler(0, present_sampler_nn.handle);
505 }
506
507 // Update background color before drawing
508 glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
509 Settings::values.bg_green.GetValue() / 255.0f,
510 Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
511
512 glClear(GL_COLOR_BUFFER_BIT);
513 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
514
515 // TODO
516 // program_manager.RestoreGuestPipeline();
517}
518
519} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.h b/src/video_core/renderer_opengl/gl_blit_screen.h
new file mode 100644
index 000000000..13d769958
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_blit_screen.h
@@ -0,0 +1,110 @@
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 "core/hle/service/nvnflinger/pixel_format.h"
10#include "video_core/host1x/gpu_device_memory_manager.h"
11#include "video_core/renderer_opengl/gl_fsr.h"
12#include "video_core/renderer_opengl/gl_resource_manager.h"
13
14namespace Layout {
15struct FramebufferLayout;
16}
17
18namespace Tegra {
19struct FramebufferConfig;
20}
21
22namespace OpenGL {
23
24class Device;
25class RasterizerOpenGL;
26class StateTracker;
27
28/// Structure used for storing information about the textures for the Switch screen
29struct TextureInfo {
30 OGLTexture resource;
31 GLsizei width;
32 GLsizei height;
33 GLenum gl_format;
34 GLenum gl_type;
35 Service::android::PixelFormat pixel_format;
36};
37
38/// Structure used for storing information about the display target for the Switch screen
39struct FramebufferTextureInfo {
40 GLuint display_texture{};
41 u32 width;
42 u32 height;
43 u32 scaled_width;
44 u32 scaled_height;
45};
46
47class BlitScreen {
48public:
49 explicit BlitScreen(RasterizerOpenGL& rasterizer,
50 Tegra::MaxwellDeviceMemoryManager& device_memory,
51 StateTracker& state_tracker, ProgramManager& program_manager,
52 Device& device);
53
54 void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer);
55
56 /// Draws the emulated screens to the emulator window.
57 void DrawScreen(const Tegra::FramebufferConfig& framebuffer,
58 const Layout::FramebufferLayout& layout);
59
60 void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer);
61
62 /// Loads framebuffer from emulated memory into the active OpenGL texture.
63 FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer);
64
65 FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer);
66
67private:
68 RasterizerOpenGL& rasterizer;
69 Tegra::MaxwellDeviceMemoryManager& device_memory;
70 StateTracker& state_tracker;
71 ProgramManager& program_manager;
72 Device& device;
73
74 OGLSampler present_sampler;
75 OGLSampler present_sampler_nn;
76 OGLBuffer vertex_buffer;
77 OGLProgram fxaa_vertex;
78 OGLProgram fxaa_fragment;
79 OGLProgram present_vertex;
80 OGLProgram present_bilinear_fragment;
81 OGLProgram present_bicubic_fragment;
82 OGLProgram present_gaussian_fragment;
83 OGLProgram present_scaleforce_fragment;
84
85 /// Display information for Switch screen
86 TextureInfo framebuffer_texture;
87 OGLTexture aa_texture;
88 OGLFramebuffer aa_framebuffer;
89
90 OGLProgram smaa_edge_detection_vert;
91 OGLProgram smaa_blending_weight_calculation_vert;
92 OGLProgram smaa_neighborhood_blending_vert;
93 OGLProgram smaa_edge_detection_frag;
94 OGLProgram smaa_blending_weight_calculation_frag;
95 OGLProgram smaa_neighborhood_blending_frag;
96 OGLTexture smaa_area_tex;
97 OGLTexture smaa_search_tex;
98 OGLTexture smaa_edges_tex;
99 OGLTexture smaa_blend_tex;
100
101 std::unique_ptr<FSR> fsr;
102
103 /// OpenGL framebuffer data
104 std::vector<u8> gl_framebuffer_data;
105
106 // GPU address of the vertex buffer
107 GLuint64EXT vertex_buffer_address = 0;
108};
109
110} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index ee82d9f3a..6eae51ff7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -16,6 +16,7 @@
16#include "video_core/engines/maxwell_dma.h" 16#include "video_core/engines/maxwell_dma.h"
17#include "video_core/rasterizer_interface.h" 17#include "video_core/rasterizer_interface.h"
18#include "video_core/renderer_opengl/blit_image.h" 18#include "video_core/renderer_opengl/blit_image.h"
19#include "video_core/renderer_opengl/gl_blit_screen.h"
19#include "video_core/renderer_opengl/gl_buffer_cache.h" 20#include "video_core/renderer_opengl/gl_buffer_cache.h"
20#include "video_core/renderer_opengl/gl_device.h" 21#include "video_core/renderer_opengl/gl_device.h"
21#include "video_core/renderer_opengl/gl_fence_manager.h" 22#include "video_core/renderer_opengl/gl_fence_manager.h"
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 2b9ebff92..38b0aacf4 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -16,68 +16,16 @@
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/frontend/emu_window.h" 17#include "core/frontend/emu_window.h"
18#include "core/telemetry_session.h" 18#include "core/telemetry_session.h"
19#include "video_core/host_shaders/ffx_a_h.h" 19#include "video_core/renderer_opengl/gl_blit_screen.h"
20#include "video_core/host_shaders/ffx_fsr1_h.h"
21#include "video_core/host_shaders/full_screen_triangle_vert.h"
22#include "video_core/host_shaders/fxaa_frag.h"
23#include "video_core/host_shaders/fxaa_vert.h"
24#include "video_core/host_shaders/opengl_fidelityfx_fsr_easu_frag.h"
25#include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h"
26#include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h"
27#include "video_core/host_shaders/opengl_present_frag.h"
28#include "video_core/host_shaders/opengl_present_scaleforce_frag.h"
29#include "video_core/host_shaders/opengl_present_vert.h"
30#include "video_core/host_shaders/opengl_smaa_glsl.h"
31#include "video_core/host_shaders/present_bicubic_frag.h"
32#include "video_core/host_shaders/present_gaussian_frag.h"
33#include "video_core/host_shaders/smaa_blending_weight_calculation_frag.h"
34#include "video_core/host_shaders/smaa_blending_weight_calculation_vert.h"
35#include "video_core/host_shaders/smaa_edge_detection_frag.h"
36#include "video_core/host_shaders/smaa_edge_detection_vert.h"
37#include "video_core/host_shaders/smaa_neighborhood_blending_frag.h"
38#include "video_core/host_shaders/smaa_neighborhood_blending_vert.h"
39#include "video_core/renderer_opengl/gl_fsr.h" 20#include "video_core/renderer_opengl/gl_fsr.h"
40#include "video_core/renderer_opengl/gl_rasterizer.h" 21#include "video_core/renderer_opengl/gl_rasterizer.h"
41#include "video_core/renderer_opengl/gl_shader_manager.h" 22#include "video_core/renderer_opengl/gl_shader_manager.h"
42#include "video_core/renderer_opengl/gl_shader_util.h" 23#include "video_core/renderer_opengl/gl_shader_util.h"
43#include "video_core/renderer_opengl/renderer_opengl.h" 24#include "video_core/renderer_opengl/renderer_opengl.h"
44#include "video_core/smaa_area_tex.h"
45#include "video_core/smaa_search_tex.h"
46#include "video_core/textures/decoders.h" 25#include "video_core/textures/decoders.h"
47 26
48namespace OpenGL { 27namespace OpenGL {
49namespace { 28namespace {
50constexpr GLint PositionLocation = 0;
51constexpr GLint TexCoordLocation = 1;
52constexpr GLint ModelViewMatrixLocation = 0;
53
54struct ScreenRectVertex {
55 constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v)
56 : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {}
57
58 std::array<GLfloat, 2> position;
59 std::array<GLfloat, 2> tex_coord;
60};
61
62/**
63 * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
64 * corner and (width, height) on the lower-bottom.
65 *
66 * The projection part of the matrix is trivial, hence these operations are represented
67 * by a 3x2 matrix.
68 */
69std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) {
70 std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order
71
72 // clang-format off
73 matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
74 matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
75 // Last matrix row is implicitly assumed to be [0, 0, 1].
76 // clang-format on
77
78 return matrix;
79}
80
81const char* GetSource(GLenum source) { 29const char* GetSource(GLenum source) {
82 switch (source) { 30 switch (source) {
83 case GL_DEBUG_SOURCE_API: 31 case GL_DEBUG_SOURCE_API:
@@ -155,7 +103,6 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
155 glDebugMessageCallback(DebugHandler, nullptr); 103 glDebugMessageCallback(DebugHandler, nullptr);
156 } 104 }
157 AddTelemetryFields(); 105 AddTelemetryFields();
158 InitOpenGLObjects();
159 106
160 // Initialize default attributes to match hardware's disabled attributes 107 // Initialize default attributes to match hardware's disabled attributes
161 GLint max_attribs{}; 108 GLint max_attribs{};
@@ -167,14 +114,8 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
167 if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) { 114 if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) {
168 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); 115 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
169 } 116 }
170 // Enable unified vertex attributes and query vertex buffer address when the driver supports it 117 blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker,
171 if (device.HasVertexBufferUnifiedMemory()) { 118 program_manager, device);
172 glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV);
173 glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV);
174 glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY);
175 glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV,
176 &vertex_buffer_address);
177 }
178} 119}
179 120
180RendererOpenGL::~RendererOpenGL() = default; 121RendererOpenGL::~RendererOpenGL() = default;
@@ -187,7 +128,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
187 RenderScreenshot(*framebuffer); 128 RenderScreenshot(*framebuffer);
188 129
189 state_tracker.BindFramebuffer(0); 130 state_tracker.BindFramebuffer(0);
190 DrawScreen(*framebuffer, emu_window.GetFramebufferLayout()); 131 blit_screen->DrawScreen(*framebuffer, emu_window.GetFramebufferLayout());
191 132
192 ++m_current_frame; 133 ++m_current_frame;
193 134
@@ -198,166 +139,6 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
198 render_window.OnFrameDisplayed(); 139 render_window.OnFrameDisplayed();
199} 140}
200 141
201FramebufferTextureInfo RendererOpenGL::PrepareRenderTarget(
202 const Tegra::FramebufferConfig& framebuffer) {
203 // If framebuffer is provided, reload it from memory to a texture
204 if (framebuffer_texture.width != static_cast<GLsizei>(framebuffer.width) ||
205 framebuffer_texture.height != static_cast<GLsizei>(framebuffer.height) ||
206 framebuffer_texture.pixel_format != framebuffer.pixel_format ||
207 gl_framebuffer_data.empty()) {
208 // Reallocate texture if the framebuffer size has changed.
209 // This is expected to not happen very often and hence should not be a
210 // performance problem.
211 ConfigureFramebufferTexture(framebuffer);
212 }
213
214 // Load the framebuffer from memory if needed
215 return LoadFBToScreenInfo(framebuffer);
216}
217
218FramebufferTextureInfo RendererOpenGL::LoadFBToScreenInfo(
219 const Tegra::FramebufferConfig& framebuffer) {
220 const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
221 const auto accelerated_info =
222 rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride);
223 if (accelerated_info) {
224 return *accelerated_info;
225 }
226
227 // Reset the screen info's display texture to its own permanent texture
228 FramebufferTextureInfo info{};
229 info.display_texture = framebuffer_texture.resource.handle;
230 info.width = framebuffer.width;
231 info.height = framebuffer.height;
232 info.scaled_width = framebuffer.width;
233 info.scaled_height = framebuffer.height;
234
235 // TODO(Rodrigo): Read this from HLE
236 constexpr u32 block_height_log2 = 4;
237 const auto pixel_format{
238 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
239 const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
240 const u64 size_in_bytes{Tegra::Texture::CalculateSize(
241 true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
242 const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
243 const std::span<const u8> input_data(host_ptr, size_in_bytes);
244 Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
245 framebuffer.width, framebuffer.height, 1, block_height_log2,
246 0);
247
248 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
249 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
250
251 // Update existing texture
252 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
253 // they differ from the LCD resolution.
254 // TODO: Applications could theoretically crash yuzu here by specifying too large
255 // framebuffer sizes. We should make sure that this cannot happen.
256 glTextureSubImage2D(framebuffer_texture.resource.handle, 0, 0, 0, framebuffer.width,
257 framebuffer.height, framebuffer_texture.gl_format,
258 framebuffer_texture.gl_type, gl_framebuffer_data.data());
259
260 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
261
262 return info;
263}
264
265void RendererOpenGL::InitOpenGLObjects() {
266 // Create shader programs
267 fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER);
268 fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER);
269
270 const auto replace_include = [](std::string& shader_source, std::string_view include_name,
271 std::string_view include_content) {
272 const std::string include_string = fmt::format("#include \"{}\"", include_name);
273 const std::size_t pos = shader_source.find(include_string);
274 ASSERT(pos != std::string::npos);
275 shader_source.replace(pos, include_string.size(), include_content);
276 };
277
278 const auto SmaaShader = [&](std::string_view specialized_source, GLenum stage) {
279 std::string shader_source{specialized_source};
280 replace_include(shader_source, "opengl_smaa.glsl", HostShaders::OPENGL_SMAA_GLSL);
281 return CreateProgram(shader_source, stage);
282 };
283
284 smaa_edge_detection_vert = SmaaShader(HostShaders::SMAA_EDGE_DETECTION_VERT, GL_VERTEX_SHADER);
285 smaa_edge_detection_frag =
286 SmaaShader(HostShaders::SMAA_EDGE_DETECTION_FRAG, GL_FRAGMENT_SHADER);
287 smaa_blending_weight_calculation_vert =
288 SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_VERT, GL_VERTEX_SHADER);
289 smaa_blending_weight_calculation_frag =
290 SmaaShader(HostShaders::SMAA_BLENDING_WEIGHT_CALCULATION_FRAG, GL_FRAGMENT_SHADER);
291 smaa_neighborhood_blending_vert =
292 SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_VERT, GL_VERTEX_SHADER);
293 smaa_neighborhood_blending_frag =
294 SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER);
295
296 present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
297 present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
298 present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER);
299 present_gaussian_fragment =
300 CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER);
301 present_scaleforce_fragment =
302 CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG),
303 GL_FRAGMENT_SHADER);
304
305 std::string fsr_source{HostShaders::OPENGL_FIDELITYFX_FSR_FRAG};
306 replace_include(fsr_source, "ffx_a.h", HostShaders::FFX_A_H);
307 replace_include(fsr_source, "ffx_fsr1.h", HostShaders::FFX_FSR1_H);
308
309 std::string fsr_easu_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_EASU_FRAG};
310 std::string fsr_rcas_frag_source{HostShaders::OPENGL_FIDELITYFX_FSR_RCAS_FRAG};
311 replace_include(fsr_easu_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source);
312 replace_include(fsr_rcas_frag_source, "opengl_fidelityfx_fsr.frag", fsr_source);
313
314 fsr = std::make_unique<FSR>(HostShaders::FULL_SCREEN_TRIANGLE_VERT, fsr_easu_frag_source,
315 fsr_rcas_frag_source);
316
317 // Generate presentation sampler
318 present_sampler.Create();
319 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
320 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
321 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
322 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
323 glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
324
325 present_sampler_nn.Create();
326 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
327 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
328 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
329 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
330 glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
331
332 // Generate VBO handle for drawing
333 vertex_buffer.Create();
334
335 // Attach vertex data to VAO
336 glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
337
338 // Allocate textures for the screen
339 framebuffer_texture.resource.Create(GL_TEXTURE_2D);
340
341 const GLuint texture = framebuffer_texture.resource.handle;
342 glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1);
343
344 // Clear screen to black
345 const u8 framebuffer_data[4] = {0, 0, 0, 0};
346 glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE,
347 framebuffer_data);
348
349 aa_framebuffer.Create();
350
351 smaa_area_tex.Create(GL_TEXTURE_2D);
352 glTextureStorage2D(smaa_area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT);
353 glTextureSubImage2D(smaa_area_tex.handle, 0, 0, 0, AREATEX_WIDTH, AREATEX_HEIGHT, GL_RG,
354 GL_UNSIGNED_BYTE, areaTexBytes);
355 smaa_search_tex.Create(GL_TEXTURE_2D);
356 glTextureStorage2D(smaa_search_tex.handle, 1, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT);
357 glTextureSubImage2D(smaa_search_tex.handle, 0, 0, 0, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, GL_RED,
358 GL_UNSIGNED_BYTE, searchTexBytes);
359}
360
361void RendererOpenGL::AddTelemetryFields() { 142void RendererOpenGL::AddTelemetryFields() {
362 const char* const gl_version{reinterpret_cast<char const*>(glGetString(GL_VERSION))}; 143 const char* const gl_version{reinterpret_cast<char const*>(glGetString(GL_VERSION))};
363 const char* const gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))}; 144 const char* const gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))};
@@ -373,283 +154,6 @@ void RendererOpenGL::AddTelemetryFields() {
373 telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); 154 telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version));
374} 155}
375 156
376void RendererOpenGL::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer) {
377 framebuffer_texture.width = framebuffer.width;
378 framebuffer_texture.height = framebuffer.height;
379 framebuffer_texture.pixel_format = framebuffer.pixel_format;
380
381 const auto pixel_format{
382 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
383 const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
384 gl_framebuffer_data.resize(framebuffer_texture.width * framebuffer_texture.height *
385 bytes_per_pixel);
386
387 GLint internal_format;
388 switch (framebuffer.pixel_format) {
389 case Service::android::PixelFormat::Rgba8888:
390 internal_format = GL_RGBA8;
391 framebuffer_texture.gl_format = GL_RGBA;
392 framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
393 break;
394 case Service::android::PixelFormat::Rgb565:
395 internal_format = GL_RGB565;
396 framebuffer_texture.gl_format = GL_RGB;
397 framebuffer_texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
398 break;
399 default:
400 internal_format = GL_RGBA8;
401 framebuffer_texture.gl_format = GL_RGBA;
402 framebuffer_texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
403 // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",
404 // static_cast<u32>(framebuffer.pixel_format));
405 break;
406 }
407
408 framebuffer_texture.resource.Release();
409 framebuffer_texture.resource.Create(GL_TEXTURE_2D);
410 glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format,
411 framebuffer_texture.width, framebuffer_texture.height);
412 aa_texture.Release();
413 aa_texture.Create(GL_TEXTURE_2D);
414 glTextureStorage2D(aa_texture.handle, 1, GL_RGBA16F,
415 Settings::values.resolution_info.ScaleUp(framebuffer_texture.width),
416 Settings::values.resolution_info.ScaleUp(framebuffer_texture.height));
417 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0, aa_texture.handle, 0);
418 smaa_edges_tex.Release();
419 smaa_edges_tex.Create(GL_TEXTURE_2D);
420 glTextureStorage2D(smaa_edges_tex.handle, 1, GL_RG16F,
421 Settings::values.resolution_info.ScaleUp(framebuffer_texture.width),
422 Settings::values.resolution_info.ScaleUp(framebuffer_texture.height));
423 smaa_blend_tex.Release();
424 smaa_blend_tex.Create(GL_TEXTURE_2D);
425 glTextureStorage2D(smaa_blend_tex.handle, 1, GL_RGBA16F,
426 Settings::values.resolution_info.ScaleUp(framebuffer_texture.width),
427 Settings::values.resolution_info.ScaleUp(framebuffer_texture.height));
428}
429
430void RendererOpenGL::DrawScreen(const Tegra::FramebufferConfig& framebuffer,
431 const Layout::FramebufferLayout& layout) {
432 FramebufferTextureInfo info = PrepareRenderTarget(framebuffer);
433 const auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height);
434
435 // TODO: Signal state tracker about these changes
436 state_tracker.NotifyScreenDrawVertexArray();
437 state_tracker.NotifyPolygonModes();
438 state_tracker.NotifyViewport0();
439 state_tracker.NotifyScissor0();
440 state_tracker.NotifyColorMask(0);
441 state_tracker.NotifyBlend0();
442 state_tracker.NotifyFramebuffer();
443 state_tracker.NotifyFrontFace();
444 state_tracker.NotifyCullTest();
445 state_tracker.NotifyDepthTest();
446 state_tracker.NotifyStencilTest();
447 state_tracker.NotifyPolygonOffset();
448 state_tracker.NotifyRasterizeEnable();
449 state_tracker.NotifyFramebufferSRGB();
450 state_tracker.NotifyLogicOp();
451 state_tracker.NotifyClipControl();
452 state_tracker.NotifyAlphaTest();
453
454 state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
455
456 glEnable(GL_CULL_FACE);
457 glDisable(GL_COLOR_LOGIC_OP);
458 glDisable(GL_DEPTH_TEST);
459 glDisable(GL_STENCIL_TEST);
460 glDisable(GL_POLYGON_OFFSET_FILL);
461 glDisable(GL_RASTERIZER_DISCARD);
462 glDisable(GL_ALPHA_TEST);
463 glDisablei(GL_BLEND, 0);
464 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
465 glCullFace(GL_BACK);
466 glFrontFace(GL_CW);
467 glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
468 glDepthRangeIndexed(0, 0.0, 0.0);
469
470 glBindTextureUnit(0, info.display_texture);
471
472 auto anti_aliasing = Settings::values.anti_aliasing.GetValue();
473 if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) {
474 LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing);
475 anti_aliasing = Settings::AntiAliasing::None;
476 Settings::values.anti_aliasing.SetValue(anti_aliasing);
477 }
478
479 if (anti_aliasing != Settings::AntiAliasing::None) {
480 glEnablei(GL_SCISSOR_TEST, 0);
481 auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width);
482 auto viewport_width = static_cast<GLfloat>(scissor_width);
483 auto scissor_height = Settings::values.resolution_info.ScaleUp(framebuffer_texture.height);
484 auto viewport_height = static_cast<GLfloat>(scissor_height);
485
486 glScissorIndexed(0, 0, 0, scissor_width, scissor_height);
487 glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height);
488
489 glBindSampler(0, present_sampler.handle);
490 GLint old_read_fb;
491 GLint old_draw_fb;
492 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
493 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
494
495 switch (anti_aliasing) {
496 case Settings::AntiAliasing::Fxaa: {
497 program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle);
498 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle);
499 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
500 } break;
501 case Settings::AntiAliasing::Smaa: {
502 glClearColor(0, 0, 0, 0);
503 glFrontFace(GL_CCW);
504 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, aa_framebuffer.handle);
505 glBindSampler(1, present_sampler.handle);
506 glBindSampler(2, present_sampler.handle);
507
508 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
509 smaa_edges_tex.handle, 0);
510 glClear(GL_COLOR_BUFFER_BIT);
511 program_manager.BindPresentPrograms(smaa_edge_detection_vert.handle,
512 smaa_edge_detection_frag.handle);
513 glDrawArrays(GL_TRIANGLES, 0, 3);
514
515 glBindTextureUnit(0, smaa_edges_tex.handle);
516 glBindTextureUnit(1, smaa_area_tex.handle);
517 glBindTextureUnit(2, smaa_search_tex.handle);
518 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
519 smaa_blend_tex.handle, 0);
520 glClear(GL_COLOR_BUFFER_BIT);
521 program_manager.BindPresentPrograms(smaa_blending_weight_calculation_vert.handle,
522 smaa_blending_weight_calculation_frag.handle);
523 glDrawArrays(GL_TRIANGLES, 0, 3);
524
525 glBindTextureUnit(0, info.display_texture);
526 glBindTextureUnit(1, smaa_blend_tex.handle);
527 glNamedFramebufferTexture(aa_framebuffer.handle, GL_COLOR_ATTACHMENT0,
528 aa_texture.handle, 0);
529 program_manager.BindPresentPrograms(smaa_neighborhood_blending_vert.handle,
530 smaa_neighborhood_blending_frag.handle);
531 glDrawArrays(GL_TRIANGLES, 0, 3);
532 glFrontFace(GL_CW);
533 } break;
534 default:
535 UNREACHABLE();
536 }
537
538 glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
539 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
540
541 glBindTextureUnit(0, aa_texture.handle);
542 }
543 glDisablei(GL_SCISSOR_TEST, 0);
544
545 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
546 if (!fsr->AreBuffersInitialized()) {
547 fsr->InitBuffers();
548 }
549
550 glBindSampler(0, present_sampler.handle);
551 fsr->Draw(program_manager, layout.screen, info.scaled_width, info.scaled_height, crop);
552 } else {
553 if (fsr->AreBuffersInitialized()) {
554 fsr->ReleaseBuffers();
555 }
556 }
557
558 const std::array ortho_matrix =
559 MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
560
561 const auto fragment_handle = [this]() {
562 switch (Settings::values.scaling_filter.GetValue()) {
563 case Settings::ScalingFilter::NearestNeighbor:
564 case Settings::ScalingFilter::Bilinear:
565 return present_bilinear_fragment.handle;
566 case Settings::ScalingFilter::Bicubic:
567 return present_bicubic_fragment.handle;
568 case Settings::ScalingFilter::Gaussian:
569 return present_gaussian_fragment.handle;
570 case Settings::ScalingFilter::ScaleForce:
571 return present_scaleforce_fragment.handle;
572 case Settings::ScalingFilter::Fsr:
573 return fsr->GetPresentFragmentProgram().handle;
574 default:
575 return present_bilinear_fragment.handle;
576 }
577 }();
578 program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle);
579 glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE,
580 ortho_matrix.data());
581
582 f32 left, top, right, bottom;
583 if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
584 // FSR has already applied the crop, so we just want to render the image
585 // it has produced.
586 left = 0;
587 top = 0;
588 right = 1;
589 bottom = 1;
590 } else {
591 // Apply the precomputed crop.
592 left = crop.left;
593 top = crop.top;
594 right = crop.right;
595 bottom = crop.bottom;
596 }
597
598 // Map the coordinates to the screen.
599 const auto& screen = layout.screen;
600 const auto x = screen.left;
601 const auto y = screen.top;
602 const auto w = screen.GetWidth();
603 const auto h = screen.GetHeight();
604
605 const std::array vertices = {
606 ScreenRectVertex(x, y, left, top),
607 ScreenRectVertex(x + w, y, right, top),
608 ScreenRectVertex(x, y + h, left, bottom),
609 ScreenRectVertex(x + w, y + h, right, bottom),
610 };
611 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices));
612
613 glDisable(GL_FRAMEBUFFER_SRGB);
614 glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width),
615 static_cast<GLfloat>(layout.height));
616
617 glEnableVertexAttribArray(PositionLocation);
618 glEnableVertexAttribArray(TexCoordLocation);
619 glVertexAttribDivisor(PositionLocation, 0);
620 glVertexAttribDivisor(TexCoordLocation, 0);
621 glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE,
622 offsetof(ScreenRectVertex, position));
623 glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE,
624 offsetof(ScreenRectVertex, tex_coord));
625 glVertexAttribBinding(PositionLocation, 0);
626 glVertexAttribBinding(TexCoordLocation, 0);
627 if (device.HasVertexBufferUnifiedMemory()) {
628 glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex));
629 glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address,
630 sizeof(vertices));
631 } else {
632 glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
633 }
634
635 if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) {
636 glBindSampler(0, present_sampler.handle);
637 } else {
638 glBindSampler(0, present_sampler_nn.handle);
639 }
640
641 // Update background color before drawing
642 glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
643 Settings::values.bg_green.GetValue() / 255.0f,
644 Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
645
646 glClear(GL_COLOR_BUFFER_BIT);
647 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
648
649 // TODO
650 // program_manager.RestoreGuestPipeline();
651}
652
653void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) { 157void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffer) {
654 if (!renderer_settings.screenshot_requested) { 158 if (!renderer_settings.screenshot_requested) {
655 return; 159 return;
@@ -672,7 +176,7 @@ void RendererOpenGL::RenderScreenshot(const Tegra::FramebufferConfig& framebuffe
672 glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); 176 glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height);
673 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); 177 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
674 178
675 DrawScreen(framebuffer, layout); 179 blit_screen->DrawScreen(framebuffer, layout);
676 180
677 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 181 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
678 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 182 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 3a83a9b78..23aff055a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -25,38 +25,13 @@ namespace Core::Frontend {
25class EmuWindow; 25class EmuWindow;
26} 26}
27 27
28namespace Core::Memory {
29class Memory;
30}
31
32namespace Layout {
33struct FramebufferLayout;
34}
35
36namespace Tegra { 28namespace Tegra {
37class GPU; 29class GPU;
38} 30}
39 31
40namespace OpenGL { 32namespace OpenGL {
41 33
42/// Structure used for storing information about the textures for the Switch screen 34class BlitScreen;
43struct TextureInfo {
44 OGLTexture resource;
45 GLsizei width;
46 GLsizei height;
47 GLenum gl_format;
48 GLenum gl_type;
49 Service::android::PixelFormat pixel_format;
50};
51
52/// Structure used for storing information about the display target for the Switch screen
53struct FramebufferTextureInfo {
54 GLuint display_texture{};
55 u32 width;
56 u32 height;
57 u32 scaled_width;
58 u32 scaled_height;
59};
60 35
61class RendererOpenGL final : public VideoCore::RendererBase { 36class RendererOpenGL final : public VideoCore::RendererBase {
62public: 37public:
@@ -77,24 +52,9 @@ public:
77 } 52 }
78 53
79private: 54private:
80 /// Initializes the OpenGL state and creates persistent objects.
81 void InitOpenGLObjects();
82
83 void AddTelemetryFields(); 55 void AddTelemetryFields();
84
85 void ConfigureFramebufferTexture(const Tegra::FramebufferConfig& framebuffer);
86
87 /// Draws the emulated screens to the emulator window.
88 void DrawScreen(const Tegra::FramebufferConfig& framebuffer,
89 const Layout::FramebufferLayout& layout);
90
91 void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); 56 void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer);
92 57
93 /// Loads framebuffer from emulated memory into the active OpenGL texture.
94 FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer);
95
96 FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer);
97
98 Core::TelemetrySession& telemetry_session; 58 Core::TelemetrySession& telemetry_session;
99 Core::Frontend::EmuWindow& emu_window; 59 Core::Frontend::EmuWindow& emu_window;
100 Tegra::MaxwellDeviceMemoryManager& device_memory; 60 Tegra::MaxwellDeviceMemoryManager& device_memory;
@@ -104,43 +64,9 @@ private:
104 StateTracker state_tracker; 64 StateTracker state_tracker;
105 ProgramManager program_manager; 65 ProgramManager program_manager;
106 RasterizerOpenGL rasterizer; 66 RasterizerOpenGL rasterizer;
107
108 // OpenGL object IDs
109 OGLSampler present_sampler;
110 OGLSampler present_sampler_nn;
111 OGLBuffer vertex_buffer;
112 OGLProgram fxaa_vertex;
113 OGLProgram fxaa_fragment;
114 OGLProgram present_vertex;
115 OGLProgram present_bilinear_fragment;
116 OGLProgram present_bicubic_fragment;
117 OGLProgram present_gaussian_fragment;
118 OGLProgram present_scaleforce_fragment;
119 OGLFramebuffer screenshot_framebuffer; 67 OGLFramebuffer screenshot_framebuffer;
120 68
121 // GPU address of the vertex buffer 69 std::unique_ptr<BlitScreen> blit_screen;
122 GLuint64EXT vertex_buffer_address = 0;
123
124 /// Display information for Switch screen
125 TextureInfo framebuffer_texture;
126 OGLTexture aa_texture;
127 OGLFramebuffer aa_framebuffer;
128
129 OGLProgram smaa_edge_detection_vert;
130 OGLProgram smaa_blending_weight_calculation_vert;
131 OGLProgram smaa_neighborhood_blending_vert;
132 OGLProgram smaa_edge_detection_frag;
133 OGLProgram smaa_blending_weight_calculation_frag;
134 OGLProgram smaa_neighborhood_blending_frag;
135 OGLTexture smaa_area_tex;
136 OGLTexture smaa_search_tex;
137 OGLTexture smaa_edges_tex;
138 OGLTexture smaa_blend_tex;
139
140 std::unique_ptr<FSR> fsr;
141
142 /// OpenGL framebuffer data
143 std::vector<u8> gl_framebuffer_data;
144}; 70};
145 71
146} // namespace OpenGL 72} // namespace OpenGL