diff options
| author | 2024-01-15 15:08:21 -0500 | |
|---|---|---|
| committer | 2024-01-31 11:27:21 -0500 | |
| commit | d4de04584f14f3ea8fde4cd79102b887c084fbc2 (patch) | |
| tree | 72581b4240726f72d769319f3b5e1b2ece6c8e58 /src/video_core/renderer_opengl | |
| parent | renderer_opengl: move out ownership of FSR resources (diff) | |
| download | yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar.gz yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar.xz yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.zip | |
renderer_opengl: split up blit screen resources into antialias and window adapt passes
Diffstat (limited to 'src/video_core/renderer_opengl')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_blit_screen.cpp | 272 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_blit_screen.h | 26 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/filters.cpp | 39 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/filters.h | 17 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/fxaa.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/smaa.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/util.h | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/window_adapt_pass.cpp | 128 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/present/window_adapt_pass.h | 39 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 6 |
10 files changed, 318 insertions, 227 deletions
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp index 5f6221b9b..f9dbef0fc 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.cpp +++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp | |||
| @@ -2,100 +2,26 @@ | |||
| 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 "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/opengl_fidelityfx_fsr_easu_frag.h" | ||
| 9 | #include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h" | ||
| 10 | #include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h" | ||
| 11 | #include "video_core/host_shaders/opengl_present_frag.h" | ||
| 12 | #include "video_core/host_shaders/opengl_present_scaleforce_frag.h" | ||
| 13 | #include "video_core/host_shaders/opengl_present_vert.h" | ||
| 14 | #include "video_core/host_shaders/present_bicubic_frag.h" | ||
| 15 | #include "video_core/host_shaders/present_gaussian_frag.h" | ||
| 16 | |||
| 17 | #include "video_core/renderer_opengl/gl_blit_screen.h" | 5 | #include "video_core/renderer_opengl/gl_blit_screen.h" |
| 18 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 6 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 19 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 7 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 20 | #include "video_core/renderer_opengl/gl_shader_util.h" | 8 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 21 | #include "video_core/renderer_opengl/gl_state_tracker.h" | 9 | #include "video_core/renderer_opengl/gl_state_tracker.h" |
| 10 | #include "video_core/renderer_opengl/present/filters.h" | ||
| 22 | #include "video_core/renderer_opengl/present/fsr.h" | 11 | #include "video_core/renderer_opengl/present/fsr.h" |
| 23 | #include "video_core/renderer_opengl/present/fxaa.h" | 12 | #include "video_core/renderer_opengl/present/fxaa.h" |
| 24 | #include "video_core/renderer_opengl/present/smaa.h" | 13 | #include "video_core/renderer_opengl/present/smaa.h" |
| 14 | #include "video_core/renderer_opengl/present/window_adapt_pass.h" | ||
| 25 | #include "video_core/textures/decoders.h" | 15 | #include "video_core/textures/decoders.h" |
| 26 | 16 | ||
| 27 | namespace OpenGL { | 17 | namespace OpenGL { |
| 28 | 18 | ||
| 29 | namespace { | ||
| 30 | constexpr GLint PositionLocation = 0; | ||
| 31 | constexpr GLint TexCoordLocation = 1; | ||
| 32 | constexpr GLint ModelViewMatrixLocation = 0; | ||
| 33 | |||
| 34 | struct ScreenRectVertex { | ||
| 35 | constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) | ||
| 36 | : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} | ||
| 37 | |||
| 38 | std::array<GLfloat, 2> position; | ||
| 39 | std::array<GLfloat, 2> tex_coord; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left | ||
| 44 | * corner and (width, height) on the lower-bottom. | ||
| 45 | * | ||
| 46 | * The projection part of the matrix is trivial, hence these operations are represented | ||
| 47 | * by a 3x2 matrix. | ||
| 48 | */ | ||
| 49 | std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { | ||
| 50 | std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order | ||
| 51 | |||
| 52 | // clang-format off | ||
| 53 | matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; | ||
| 54 | matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; | ||
| 55 | // Last matrix row is implicitly assumed to be [0, 0, 1]. | ||
| 56 | // clang-format on | ||
| 57 | |||
| 58 | return matrix; | ||
| 59 | } | ||
| 60 | } // namespace | ||
| 61 | |||
| 62 | BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, | 19 | BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, |
| 63 | Tegra::MaxwellDeviceMemoryManager& device_memory_, | 20 | Tegra::MaxwellDeviceMemoryManager& device_memory_, |
| 64 | StateTracker& state_tracker_, ProgramManager& program_manager_, | 21 | StateTracker& state_tracker_, ProgramManager& program_manager_, |
| 65 | Device& device_) | 22 | Device& device_) |
| 66 | : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), | 23 | : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), |
| 67 | program_manager(program_manager_), device(device_) { | 24 | program_manager(program_manager_), device(device_) { |
| 68 | // Create shader programs | ||
| 69 | present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER); | ||
| 70 | present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER); | ||
| 71 | present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER); | ||
| 72 | present_gaussian_fragment = | ||
| 73 | CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER); | ||
| 74 | present_scaleforce_fragment = | ||
| 75 | CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG), | ||
| 76 | GL_FRAGMENT_SHADER); | ||
| 77 | |||
| 78 | // Generate presentation sampler | ||
| 79 | present_sampler.Create(); | ||
| 80 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 81 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
| 82 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 83 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 84 | glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | ||
| 85 | |||
| 86 | present_sampler_nn.Create(); | ||
| 87 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
| 88 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
| 89 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 90 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 91 | glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | ||
| 92 | |||
| 93 | // Generate VBO handle for drawing | ||
| 94 | vertex_buffer.Create(); | ||
| 95 | |||
| 96 | // Attach vertex data to VAO | ||
| 97 | glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); | ||
| 98 | |||
| 99 | // Allocate textures for the screen | 25 | // Allocate textures for the screen |
| 100 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); | 26 | framebuffer_texture.resource.Create(GL_TEXTURE_2D); |
| 101 | 27 | ||
| @@ -106,15 +32,6 @@ BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, | |||
| 106 | const u8 framebuffer_data[4] = {0, 0, 0, 0}; | 32 | const u8 framebuffer_data[4] = {0, 0, 0, 0}; |
| 107 | glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, | 33 | glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| 108 | framebuffer_data); | 34 | framebuffer_data); |
| 109 | |||
| 110 | // Enable unified vertex attributes and query vertex buffer address when the driver supports it | ||
| 111 | if (device.HasVertexBufferUnifiedMemory()) { | ||
| 112 | glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); | ||
| 113 | glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); | ||
| 114 | glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY); | ||
| 115 | glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, | ||
| 116 | &vertex_buffer_address); | ||
| 117 | } | ||
| 118 | } | 35 | } |
| 119 | 36 | ||
| 120 | BlitScreen::~BlitScreen() = default; | 37 | BlitScreen::~BlitScreen() = default; |
| @@ -219,18 +136,14 @@ void BlitScreen::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& fra | |||
| 219 | glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, | 136 | glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, |
| 220 | framebuffer_texture.width, framebuffer_texture.height); | 137 | framebuffer_texture.width, framebuffer_texture.height); |
| 221 | 138 | ||
| 222 | fxaa = std::make_unique<FXAA>( | 139 | fxaa.reset(); |
| 223 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | 140 | smaa.reset(); |
| 224 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||
| 225 | smaa = std::make_unique<SMAA>( | ||
| 226 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||
| 227 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||
| 228 | } | 141 | } |
| 229 | 142 | ||
| 230 | void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | 143 | void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, |
| 231 | const Layout::FramebufferLayout& layout) { | 144 | const Layout::FramebufferLayout& layout) { |
| 232 | FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); | 145 | FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); |
| 233 | const auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); | 146 | auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); |
| 234 | 147 | ||
| 235 | // TODO: Signal state tracker about these changes | 148 | // TODO: Signal state tracker about these changes |
| 236 | state_tracker.NotifyScreenDrawVertexArray(); | 149 | state_tracker.NotifyScreenDrawVertexArray(); |
| @@ -267,15 +180,14 @@ void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | |||
| 267 | glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | 180 | glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| 268 | glDepthRangeIndexed(0, 0.0, 0.0); | 181 | glDepthRangeIndexed(0, 0.0, 0.0); |
| 269 | 182 | ||
| 183 | GLint old_read_fb; | ||
| 184 | GLint old_draw_fb; | ||
| 185 | glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); | ||
| 186 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||
| 187 | |||
| 270 | GLuint texture = info.display_texture; | 188 | GLuint texture = info.display_texture; |
| 271 | 189 | ||
| 272 | auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); | 190 | auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); |
| 273 | if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) { | ||
| 274 | LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing); | ||
| 275 | anti_aliasing = Settings::AntiAliasing::None; | ||
| 276 | Settings::values.anti_aliasing.SetValue(anti_aliasing); | ||
| 277 | } | ||
| 278 | |||
| 279 | if (anti_aliasing != Settings::AntiAliasing::None) { | 191 | if (anti_aliasing != Settings::AntiAliasing::None) { |
| 280 | glEnablei(GL_SCISSOR_TEST, 0); | 192 | glEnablei(GL_SCISSOR_TEST, 0); |
| 281 | auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); | 193 | auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); |
| @@ -286,137 +198,83 @@ void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | |||
| 286 | glScissorIndexed(0, 0, 0, scissor_width, scissor_height); | 198 | glScissorIndexed(0, 0, 0, scissor_width, scissor_height); |
| 287 | glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height); | 199 | glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height); |
| 288 | 200 | ||
| 289 | glBindSampler(0, present_sampler.handle); | ||
| 290 | GLint old_read_fb; | ||
| 291 | GLint old_draw_fb; | ||
| 292 | glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); | ||
| 293 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||
| 294 | |||
| 295 | switch (anti_aliasing) { | 201 | switch (anti_aliasing) { |
| 296 | case Settings::AntiAliasing::Fxaa: { | 202 | case Settings::AntiAliasing::Fxaa: |
| 203 | CreateFXAA(); | ||
| 297 | texture = fxaa->Draw(program_manager, info.display_texture); | 204 | texture = fxaa->Draw(program_manager, info.display_texture); |
| 298 | } break; | 205 | break; |
| 299 | case Settings::AntiAliasing::Smaa: { | 206 | case Settings::AntiAliasing::Smaa: |
| 300 | texture = smaa->Draw(program_manager, info.display_texture); | ||
| 301 | } break; | ||
| 302 | default: | 207 | default: |
| 303 | UNREACHABLE(); | 208 | CreateSMAA(); |
| 209 | texture = smaa->Draw(program_manager, info.display_texture); | ||
| 210 | break; | ||
| 304 | } | 211 | } |
| 305 | |||
| 306 | glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); | ||
| 307 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | ||
| 308 | } | 212 | } |
| 213 | |||
| 309 | glDisablei(GL_SCISSOR_TEST, 0); | 214 | glDisablei(GL_SCISSOR_TEST, 0); |
| 310 | 215 | ||
| 311 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | 216 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { |
| 312 | GLint old_read_fb; | ||
| 313 | GLint old_draw_fb; | ||
| 314 | glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); | ||
| 315 | glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||
| 316 | |||
| 317 | if (!fsr || fsr->NeedsRecreation(layout.screen)) { | 217 | if (!fsr || fsr->NeedsRecreation(layout.screen)) { |
| 318 | fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); | 218 | fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); |
| 319 | } | 219 | } |
| 320 | 220 | ||
| 321 | texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop); | 221 | texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop); |
| 322 | 222 | crop = {0, 0, 1, 1}; | |
| 323 | glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); | ||
| 324 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | ||
| 325 | } | 223 | } |
| 326 | 224 | ||
| 327 | glBindTextureUnit(0, texture); | 225 | glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); |
| 328 | 226 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | |
| 329 | const std::array ortho_matrix = | ||
| 330 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | ||
| 331 | |||
| 332 | const auto fragment_handle = [this]() { | ||
| 333 | switch (Settings::values.scaling_filter.GetValue()) { | ||
| 334 | case Settings::ScalingFilter::Bicubic: | ||
| 335 | return present_bicubic_fragment.handle; | ||
| 336 | case Settings::ScalingFilter::Gaussian: | ||
| 337 | return present_gaussian_fragment.handle; | ||
| 338 | case Settings::ScalingFilter::ScaleForce: | ||
| 339 | return present_scaleforce_fragment.handle; | ||
| 340 | case Settings::ScalingFilter::NearestNeighbor: | ||
| 341 | case Settings::ScalingFilter::Bilinear: | ||
| 342 | case Settings::ScalingFilter::Fsr: | ||
| 343 | default: | ||
| 344 | return present_bilinear_fragment.handle; | ||
| 345 | } | ||
| 346 | }(); | ||
| 347 | program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle); | ||
| 348 | glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, | ||
| 349 | ortho_matrix.data()); | ||
| 350 | 227 | ||
| 351 | f32 left, top, right, bottom; | 228 | CreateWindowAdapt(); |
| 352 | if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | 229 | window_adapt->DrawToFramebuffer(program_manager, texture, layout, crop); |
| 353 | // FSR has already applied the crop, so we just want to render the image | ||
| 354 | // it has produced. | ||
| 355 | left = 0; | ||
| 356 | top = 0; | ||
| 357 | right = 1; | ||
| 358 | bottom = 1; | ||
| 359 | } else { | ||
| 360 | // Apply the precomputed crop. | ||
| 361 | left = crop.left; | ||
| 362 | top = crop.top; | ||
| 363 | right = crop.right; | ||
| 364 | bottom = crop.bottom; | ||
| 365 | } | ||
| 366 | 230 | ||
| 367 | // Map the coordinates to the screen. | 231 | // TODO |
| 368 | const auto& screen = layout.screen; | 232 | // program_manager.RestoreGuestPipeline(); |
| 369 | const auto x = screen.left; | 233 | } |
| 370 | const auto y = screen.top; | ||
| 371 | const auto w = screen.GetWidth(); | ||
| 372 | const auto h = screen.GetHeight(); | ||
| 373 | |||
| 374 | const std::array vertices = { | ||
| 375 | ScreenRectVertex(x, y, left, top), | ||
| 376 | ScreenRectVertex(x + w, y, right, top), | ||
| 377 | ScreenRectVertex(x, y + h, left, bottom), | ||
| 378 | ScreenRectVertex(x + w, y + h, right, bottom), | ||
| 379 | }; | ||
| 380 | glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); | ||
| 381 | |||
| 382 | glDisable(GL_FRAMEBUFFER_SRGB); | ||
| 383 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), | ||
| 384 | static_cast<GLfloat>(layout.height)); | ||
| 385 | |||
| 386 | glEnableVertexAttribArray(PositionLocation); | ||
| 387 | glEnableVertexAttribArray(TexCoordLocation); | ||
| 388 | glVertexAttribDivisor(PositionLocation, 0); | ||
| 389 | glVertexAttribDivisor(TexCoordLocation, 0); | ||
| 390 | glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, | ||
| 391 | offsetof(ScreenRectVertex, position)); | ||
| 392 | glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE, | ||
| 393 | offsetof(ScreenRectVertex, tex_coord)); | ||
| 394 | glVertexAttribBinding(PositionLocation, 0); | ||
| 395 | glVertexAttribBinding(TexCoordLocation, 0); | ||
| 396 | if (device.HasVertexBufferUnifiedMemory()) { | ||
| 397 | glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); | ||
| 398 | glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, | ||
| 399 | sizeof(vertices)); | ||
| 400 | } else { | ||
| 401 | glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); | ||
| 402 | } | ||
| 403 | 234 | ||
| 404 | if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) { | 235 | void BlitScreen::CreateFXAA() { |
| 405 | glBindSampler(0, present_sampler.handle); | 236 | smaa.reset(); |
| 406 | } else { | 237 | if (!fxaa) { |
| 407 | glBindSampler(0, present_sampler_nn.handle); | 238 | fxaa = std::make_unique<FXAA>( |
| 239 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||
| 240 | Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||
| 408 | } | 241 | } |
| 242 | } | ||
| 409 | 243 | ||
| 410 | // Update background color before drawing | 244 | void BlitScreen::CreateSMAA() { |
| 411 | glClearColor(Settings::values.bg_red.GetValue() / 255.0f, | 245 | fxaa.reset(); |
| 412 | Settings::values.bg_green.GetValue() / 255.0f, | 246 | if (!smaa) { |
| 413 | Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); | 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 | } | ||
| 414 | 252 | ||
| 415 | glClear(GL_COLOR_BUFFER_BIT); | 253 | void BlitScreen::CreateWindowAdapt() { |
| 416 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 254 | if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) { |
| 255 | return; | ||
| 256 | } | ||
| 417 | 257 | ||
| 418 | // TODO | 258 | current_window_adapt = Settings::values.scaling_filter.GetValue(); |
| 419 | // program_manager.RestoreGuestPipeline(); | 259 | switch (current_window_adapt) { |
| 260 | case Settings::ScalingFilter::NearestNeighbor: | ||
| 261 | window_adapt = MakeNearestNeighbor(device); | ||
| 262 | break; | ||
| 263 | case Settings::ScalingFilter::Bicubic: | ||
| 264 | window_adapt = MakeBicubic(device); | ||
| 265 | break; | ||
| 266 | case Settings::ScalingFilter::Gaussian: | ||
| 267 | window_adapt = MakeGaussian(device); | ||
| 268 | break; | ||
| 269 | case Settings::ScalingFilter::ScaleForce: | ||
| 270 | window_adapt = MakeScaleForce(device); | ||
| 271 | break; | ||
| 272 | case Settings::ScalingFilter::Fsr: | ||
| 273 | case Settings::ScalingFilter::Bilinear: | ||
| 274 | default: | ||
| 275 | window_adapt = MakeBilinear(device); | ||
| 276 | break; | ||
| 277 | } | ||
| 420 | } | 278 | } |
| 421 | 279 | ||
| 422 | } // namespace OpenGL | 280 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_blit_screen.h b/src/video_core/renderer_opengl/gl_blit_screen.h index 2cb9a5015..f42f89dee 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.h +++ b/src/video_core/renderer_opengl/gl_blit_screen.h | |||
| @@ -18,6 +18,10 @@ namespace Tegra { | |||
| 18 | struct FramebufferConfig; | 18 | struct FramebufferConfig; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | namespace Settings { | ||
| 22 | enum class ScalingFilter : u32; | ||
| 23 | } | ||
| 24 | |||
| 21 | namespace OpenGL { | 25 | namespace OpenGL { |
| 22 | 26 | ||
| 23 | class Device; | 27 | class Device; |
| @@ -27,6 +31,7 @@ class ProgramManager; | |||
| 27 | class RasterizerOpenGL; | 31 | class RasterizerOpenGL; |
| 28 | class SMAA; | 32 | class SMAA; |
| 29 | class StateTracker; | 33 | class StateTracker; |
| 34 | class WindowAdaptPass; | ||
| 30 | 35 | ||
| 31 | /// Structure used for storing information about the textures for the Switch screen | 36 | /// Structure used for storing information about the textures for the Switch screen |
| 32 | struct TextureInfo { | 37 | struct TextureInfo { |
| @@ -61,29 +66,22 @@ public: | |||
| 61 | void DrawScreen(const Tegra::FramebufferConfig& framebuffer, | 66 | void DrawScreen(const Tegra::FramebufferConfig& framebuffer, |
| 62 | const Layout::FramebufferLayout& layout); | 67 | const Layout::FramebufferLayout& layout); |
| 63 | 68 | ||
| 64 | void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); | ||
| 65 | |||
| 66 | /// Loads framebuffer from emulated memory into the active OpenGL texture. | 69 | /// Loads framebuffer from emulated memory into the active OpenGL texture. |
| 67 | FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | 70 | FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); |
| 68 | 71 | ||
| 69 | FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); | 72 | FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); |
| 70 | 73 | ||
| 71 | private: | 74 | private: |
| 75 | void CreateFXAA(); | ||
| 76 | void CreateSMAA(); | ||
| 77 | void CreateWindowAdapt(); | ||
| 78 | |||
| 72 | RasterizerOpenGL& rasterizer; | 79 | RasterizerOpenGL& rasterizer; |
| 73 | Tegra::MaxwellDeviceMemoryManager& device_memory; | 80 | Tegra::MaxwellDeviceMemoryManager& device_memory; |
| 74 | StateTracker& state_tracker; | 81 | StateTracker& state_tracker; |
| 75 | ProgramManager& program_manager; | 82 | ProgramManager& program_manager; |
| 76 | Device& device; | 83 | Device& device; |
| 77 | 84 | ||
| 78 | OGLSampler present_sampler; | ||
| 79 | OGLSampler present_sampler_nn; | ||
| 80 | OGLBuffer vertex_buffer; | ||
| 81 | OGLProgram present_vertex; | ||
| 82 | OGLProgram present_bilinear_fragment; | ||
| 83 | OGLProgram present_bicubic_fragment; | ||
| 84 | OGLProgram present_gaussian_fragment; | ||
| 85 | OGLProgram present_scaleforce_fragment; | ||
| 86 | |||
| 87 | /// Display information for Switch screen | 85 | /// Display information for Switch screen |
| 88 | TextureInfo framebuffer_texture; | 86 | TextureInfo framebuffer_texture; |
| 89 | 87 | ||
| @@ -91,11 +89,11 @@ private: | |||
| 91 | std::unique_ptr<FXAA> fxaa; | 89 | std::unique_ptr<FXAA> fxaa; |
| 92 | std::unique_ptr<SMAA> smaa; | 90 | std::unique_ptr<SMAA> smaa; |
| 93 | 91 | ||
| 92 | Settings::ScalingFilter current_window_adapt{}; | ||
| 93 | std::unique_ptr<WindowAdaptPass> window_adapt; | ||
| 94 | |||
| 94 | /// OpenGL framebuffer data | 95 | /// OpenGL framebuffer data |
| 95 | std::vector<u8> gl_framebuffer_data; | 96 | std::vector<u8> gl_framebuffer_data; |
| 96 | |||
| 97 | // GPU address of the vertex buffer | ||
| 98 | GLuint64EXT vertex_buffer_address = 0; | ||
| 99 | }; | 97 | }; |
| 100 | 98 | ||
| 101 | } // namespace OpenGL | 99 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/present/filters.cpp b/src/video_core/renderer_opengl/present/filters.cpp new file mode 100644 index 000000000..819e5d77f --- /dev/null +++ b/src/video_core/renderer_opengl/present/filters.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/host_shaders/opengl_present_frag.h" | ||
| 5 | #include "video_core/host_shaders/opengl_present_scaleforce_frag.h" | ||
| 6 | #include "video_core/host_shaders/present_bicubic_frag.h" | ||
| 7 | #include "video_core/host_shaders/present_gaussian_frag.h" | ||
| 8 | #include "video_core/renderer_opengl/present/filters.h" | ||
| 9 | #include "video_core/renderer_opengl/present/util.h" | ||
| 10 | |||
| 11 | namespace OpenGL { | ||
| 12 | |||
| 13 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device) { | ||
| 14 | return std::make_unique<WindowAdaptPass>(device, CreateNearestNeighborSampler(), | ||
| 15 | HostShaders::OPENGL_PRESENT_FRAG); | ||
| 16 | } | ||
| 17 | |||
| 18 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device) { | ||
| 19 | return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(), | ||
| 20 | HostShaders::OPENGL_PRESENT_FRAG); | ||
| 21 | } | ||
| 22 | |||
| 23 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device) { | ||
| 24 | return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(), | ||
| 25 | HostShaders::PRESENT_BICUBIC_FRAG); | ||
| 26 | } | ||
| 27 | |||
| 28 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device) { | ||
| 29 | return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(), | ||
| 30 | HostShaders::PRESENT_GAUSSIAN_FRAG); | ||
| 31 | } | ||
| 32 | |||
| 33 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device) { | ||
| 34 | return std::make_unique<WindowAdaptPass>( | ||
| 35 | device, CreateBilinearSampler(), | ||
| 36 | fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG)); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/present/filters.h b/src/video_core/renderer_opengl/present/filters.h new file mode 100644 index 000000000..122ab7436 --- /dev/null +++ b/src/video_core/renderer_opengl/present/filters.h | |||
| @@ -0,0 +1,17 @@ | |||
| 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 "video_core/renderer_opengl/present/window_adapt_pass.h" | ||
| 8 | |||
| 9 | namespace OpenGL { | ||
| 10 | |||
| 11 | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device); | ||
| 12 | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device); | ||
| 13 | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device); | ||
| 14 | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device); | ||
| 15 | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device); | ||
| 16 | |||
| 17 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/present/fxaa.cpp b/src/video_core/renderer_opengl/present/fxaa.cpp index 9425c42fa..d9b58512d 100644 --- a/src/video_core/renderer_opengl/present/fxaa.cpp +++ b/src/video_core/renderer_opengl/present/fxaa.cpp | |||
| @@ -31,6 +31,7 @@ GLuint FXAA::Draw(ProgramManager& program_manager, GLuint input_texture) { | |||
| 31 | program_manager.BindPresentPrograms(vert_shader.handle, frag_shader.handle); | 31 | program_manager.BindPresentPrograms(vert_shader.handle, frag_shader.handle); |
| 32 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle); | 32 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle); |
| 33 | glBindTextureUnit(0, input_texture); | 33 | glBindTextureUnit(0, input_texture); |
| 34 | glBindSampler(0, sampler.handle); | ||
| 34 | glDrawArrays(GL_TRIANGLES, 0, 3); | 35 | glDrawArrays(GL_TRIANGLES, 0, 3); |
| 35 | glFrontFace(GL_CW); | 36 | glFrontFace(GL_CW); |
| 36 | 37 | ||
diff --git a/src/video_core/renderer_opengl/present/smaa.cpp b/src/video_core/renderer_opengl/present/smaa.cpp index a9a0eb6c6..de7f6e502 100644 --- a/src/video_core/renderer_opengl/present/smaa.cpp +++ b/src/video_core/renderer_opengl/present/smaa.cpp | |||
| @@ -36,13 +36,7 @@ SMAA::SMAA(u32 width, u32 height) { | |||
| 36 | SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); | 36 | SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); |
| 37 | 37 | ||
| 38 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | 38 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |
| 39 | glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); | ||
| 40 | glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); | ||
| 41 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 39 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| 42 | glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); | ||
| 43 | glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); | ||
| 44 | glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); | ||
| 45 | glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | ||
| 46 | 40 | ||
| 47 | area_tex.Create(GL_TEXTURE_2D); | 41 | area_tex.Create(GL_TEXTURE_2D); |
| 48 | glTextureStorage2D(area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT); | 42 | glTextureStorage2D(area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT); |
diff --git a/src/video_core/renderer_opengl/present/util.h b/src/video_core/renderer_opengl/present/util.h index 0aa8b110c..67f03aa27 100644 --- a/src/video_core/renderer_opengl/present/util.h +++ b/src/video_core/renderer_opengl/present/util.h | |||
| @@ -29,4 +29,15 @@ static inline OGLSampler CreateBilinearSampler() { | |||
| 29 | return sampler; | 29 | return sampler; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | static inline OGLSampler CreateNearestNeighborSampler() { | ||
| 33 | OGLSampler sampler; | ||
| 34 | sampler.Create(); | ||
| 35 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
| 36 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
| 37 | glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
| 38 | glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
| 39 | glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | ||
| 40 | return sampler; | ||
| 41 | } | ||
| 42 | |||
| 32 | } // namespace OpenGL | 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 new file mode 100644 index 000000000..168fa1aea --- /dev/null +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.cpp | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/settings.h" | ||
| 5 | #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_shader_manager.h" | ||
| 8 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 9 | #include "video_core/renderer_opengl/present/window_adapt_pass.h" | ||
| 10 | |||
| 11 | namespace OpenGL { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | constexpr GLint PositionLocation = 0; | ||
| 15 | constexpr GLint TexCoordLocation = 1; | ||
| 16 | constexpr GLint ModelViewMatrixLocation = 0; | ||
| 17 | |||
| 18 | struct ScreenRectVertex { | ||
| 19 | constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) | ||
| 20 | : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} | ||
| 21 | |||
| 22 | std::array<GLfloat, 2> position; | ||
| 23 | std::array<GLfloat, 2> tex_coord; | ||
| 24 | }; | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Defines a 1:1 pixel orthographic projection matrix with (0,0) on the top-left | ||
| 28 | * corner and (width, height) on the lower-bottom. | ||
| 29 | * | ||
| 30 | * The projection part of the matrix is trivial, hence these operations are represented | ||
| 31 | * by a 3x2 matrix. | ||
| 32 | */ | ||
| 33 | std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { | ||
| 34 | std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order | ||
| 35 | |||
| 36 | // clang-format off | ||
| 37 | matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; | ||
| 38 | matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; | ||
| 39 | // Last matrix row is implicitly assumed to be [0, 0, 1]. | ||
| 40 | // clang-format on | ||
| 41 | |||
| 42 | return matrix; | ||
| 43 | } | ||
| 44 | } // namespace | ||
| 45 | |||
| 46 | WindowAdaptPass::WindowAdaptPass(const Device& device_, OGLSampler&& sampler_, | ||
| 47 | std::string_view frag_source) | ||
| 48 | : device(device_), sampler(std::move(sampler_)) { | ||
| 49 | vert = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER); | ||
| 50 | frag = CreateProgram(frag_source, GL_FRAGMENT_SHADER); | ||
| 51 | |||
| 52 | // Generate VBO handle for drawing | ||
| 53 | vertex_buffer.Create(); | ||
| 54 | |||
| 55 | // Attach vertex data to VAO | ||
| 56 | glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); | ||
| 57 | |||
| 58 | // Query vertex buffer address when the driver supports unified vertex attributes | ||
| 59 | if (device.HasVertexBufferUnifiedMemory()) { | ||
| 60 | glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY); | ||
| 61 | glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, | ||
| 62 | &vertex_buffer_address); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | WindowAdaptPass::~WindowAdaptPass() = default; | ||
| 67 | |||
| 68 | void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, GLuint texture, | ||
| 69 | const Layout::FramebufferLayout& layout, | ||
| 70 | const Common::Rectangle<f32>& crop) { | ||
| 71 | glBindTextureUnit(0, texture); | ||
| 72 | |||
| 73 | const std::array ortho_matrix = | ||
| 74 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | ||
| 75 | |||
| 76 | 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 | |||
| 95 | glDisable(GL_FRAMEBUFFER_SRGB); | ||
| 96 | glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), | ||
| 97 | static_cast<GLfloat>(layout.height)); | ||
| 98 | |||
| 99 | glEnableVertexAttribArray(PositionLocation); | ||
| 100 | glEnableVertexAttribArray(TexCoordLocation); | ||
| 101 | glVertexAttribDivisor(PositionLocation, 0); | ||
| 102 | glVertexAttribDivisor(TexCoordLocation, 0); | ||
| 103 | glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, | ||
| 104 | offsetof(ScreenRectVertex, position)); | ||
| 105 | glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE, | ||
| 106 | offsetof(ScreenRectVertex, tex_coord)); | ||
| 107 | glVertexAttribBinding(PositionLocation, 0); | ||
| 108 | glVertexAttribBinding(TexCoordLocation, 0); | ||
| 109 | if (device.HasVertexBufferUnifiedMemory()) { | ||
| 110 | glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); | ||
| 111 | glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, | ||
| 112 | sizeof(vertices)); | ||
| 113 | } else { | ||
| 114 | glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); | ||
| 115 | } | ||
| 116 | |||
| 117 | glBindSampler(0, sampler.handle); | ||
| 118 | |||
| 119 | // Update background color before drawing | ||
| 120 | glClearColor(Settings::values.bg_red.GetValue() / 255.0f, | ||
| 121 | Settings::values.bg_green.GetValue() / 255.0f, | ||
| 122 | Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); | ||
| 123 | |||
| 124 | glClear(GL_COLOR_BUFFER_BIT); | ||
| 125 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
| 126 | } | ||
| 127 | |||
| 128 | } // 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 new file mode 100644 index 000000000..65dcd09ff --- /dev/null +++ b/src/video_core/renderer_opengl/present/window_adapt_pass.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/math_util.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||
| 8 | |||
| 9 | namespace Layout { | ||
| 10 | struct FramebufferLayout; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace OpenGL { | ||
| 14 | |||
| 15 | class Device; | ||
| 16 | class ProgramManager; | ||
| 17 | |||
| 18 | class WindowAdaptPass final { | ||
| 19 | public: | ||
| 20 | explicit WindowAdaptPass(const Device& device, OGLSampler&& sampler, | ||
| 21 | std::string_view frag_source); | ||
| 22 | ~WindowAdaptPass(); | ||
| 23 | |||
| 24 | void DrawToFramebuffer(ProgramManager& program_manager, GLuint texture, | ||
| 25 | const Layout::FramebufferLayout& layout, | ||
| 26 | const Common::Rectangle<f32>& crop); | ||
| 27 | |||
| 28 | private: | ||
| 29 | const Device& device; | ||
| 30 | OGLSampler sampler; | ||
| 31 | OGLProgram vert; | ||
| 32 | OGLProgram frag; | ||
| 33 | OGLBuffer vertex_buffer; | ||
| 34 | |||
| 35 | // GPU address of the vertex buffer | ||
| 36 | GLuint64EXT vertex_buffer_address = 0; | ||
| 37 | }; | ||
| 38 | |||
| 39 | } // namespace OpenGL | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 3d75fd17a..0d138c189 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -113,6 +113,12 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, | |||
| 113 | if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) { | 113 | if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) { |
| 114 | glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); | 114 | glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); |
| 115 | } | 115 | } |
| 116 | |||
| 117 | // Enable unified vertex attributes when the driver supports it | ||
| 118 | if (device.HasVertexBufferUnifiedMemory()) { | ||
| 119 | glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); | ||
| 120 | glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); | ||
| 121 | } | ||
| 116 | blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, | 122 | blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, |
| 117 | program_manager, device); | 123 | program_manager, device); |
| 118 | } | 124 | } |