mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-30 18:24:15 +01:00 
			
		
		
		
	renderer_opengl: split up blit screen resources into antialias and window adapt passes
This commit is contained in:
		
							parent
							
								
									dd2918efd8
								
							
						
					
					
						commit
						d4de04584f
					
				| @ -116,6 +116,8 @@ add_library(video_core STATIC | |||||||
|     renderer_null/null_rasterizer.h |     renderer_null/null_rasterizer.h | ||||||
|     renderer_null/renderer_null.cpp |     renderer_null/renderer_null.cpp | ||||||
|     renderer_null/renderer_null.h |     renderer_null/renderer_null.h | ||||||
|  |     renderer_opengl/present/filters.cpp | ||||||
|  |     renderer_opengl/present/filters.h | ||||||
|     renderer_opengl/present/fsr.cpp |     renderer_opengl/present/fsr.cpp | ||||||
|     renderer_opengl/present/fsr.h |     renderer_opengl/present/fsr.h | ||||||
|     renderer_opengl/present/fxaa.cpp |     renderer_opengl/present/fxaa.cpp | ||||||
| @ -123,6 +125,8 @@ add_library(video_core STATIC | |||||||
|     renderer_opengl/present/smaa.cpp |     renderer_opengl/present/smaa.cpp | ||||||
|     renderer_opengl/present/smaa.h |     renderer_opengl/present/smaa.h | ||||||
|     renderer_opengl/present/util.h |     renderer_opengl/present/util.h | ||||||
|  |     renderer_opengl/present/window_adapt_pass.cpp | ||||||
|  |     renderer_opengl/present/window_adapt_pass.h | ||||||
|     renderer_opengl/blit_image.cpp |     renderer_opengl/blit_image.cpp | ||||||
|     renderer_opengl/blit_image.h |     renderer_opengl/blit_image.h | ||||||
|     renderer_opengl/gl_blit_screen.cpp |     renderer_opengl/gl_blit_screen.cpp | ||||||
|  | |||||||
| @ -2,100 +2,26 @@ | |||||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
| 
 | 
 | ||||||
| #include "video_core/framebuffer_config.h" | #include "video_core/framebuffer_config.h" | ||||||
| #include "video_core/host_shaders/ffx_a_h.h" |  | ||||||
| #include "video_core/host_shaders/ffx_fsr1_h.h" |  | ||||||
| #include "video_core/host_shaders/full_screen_triangle_vert.h" |  | ||||||
| #include "video_core/host_shaders/opengl_fidelityfx_fsr_easu_frag.h" |  | ||||||
| #include "video_core/host_shaders/opengl_fidelityfx_fsr_frag.h" |  | ||||||
| #include "video_core/host_shaders/opengl_fidelityfx_fsr_rcas_frag.h" |  | ||||||
| #include "video_core/host_shaders/opengl_present_frag.h" |  | ||||||
| #include "video_core/host_shaders/opengl_present_scaleforce_frag.h" |  | ||||||
| #include "video_core/host_shaders/opengl_present_vert.h" |  | ||||||
| #include "video_core/host_shaders/present_bicubic_frag.h" |  | ||||||
| #include "video_core/host_shaders/present_gaussian_frag.h" |  | ||||||
| 
 |  | ||||||
| #include "video_core/renderer_opengl/gl_blit_screen.h" | #include "video_core/renderer_opengl/gl_blit_screen.h" | ||||||
| #include "video_core/renderer_opengl/gl_rasterizer.h" | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||||||
| #include "video_core/renderer_opengl/gl_shader_manager.h" | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||||||
| #include "video_core/renderer_opengl/gl_shader_util.h" | #include "video_core/renderer_opengl/gl_shader_util.h" | ||||||
| #include "video_core/renderer_opengl/gl_state_tracker.h" | #include "video_core/renderer_opengl/gl_state_tracker.h" | ||||||
|  | #include "video_core/renderer_opengl/present/filters.h" | ||||||
| #include "video_core/renderer_opengl/present/fsr.h" | #include "video_core/renderer_opengl/present/fsr.h" | ||||||
| #include "video_core/renderer_opengl/present/fxaa.h" | #include "video_core/renderer_opengl/present/fxaa.h" | ||||||
| #include "video_core/renderer_opengl/present/smaa.h" | #include "video_core/renderer_opengl/present/smaa.h" | ||||||
|  | #include "video_core/renderer_opengl/present/window_adapt_pass.h" | ||||||
| #include "video_core/textures/decoders.h" | #include "video_core/textures/decoders.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
| 
 | 
 | ||||||
| namespace { |  | ||||||
| constexpr GLint PositionLocation = 0; |  | ||||||
| constexpr GLint TexCoordLocation = 1; |  | ||||||
| constexpr GLint ModelViewMatrixLocation = 0; |  | ||||||
| 
 |  | ||||||
| struct ScreenRectVertex { |  | ||||||
|     constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) |  | ||||||
|         : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} |  | ||||||
| 
 |  | ||||||
|     std::array<GLfloat, 2> position; |  | ||||||
|     std::array<GLfloat, 2> tex_coord; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left |  | ||||||
|  * corner and (width, height) on the lower-bottom. |  | ||||||
|  * |  | ||||||
|  * The projection part of the matrix is trivial, hence these operations are represented |  | ||||||
|  * by a 3x2 matrix. |  | ||||||
|  */ |  | ||||||
| std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { |  | ||||||
|     std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order
 |  | ||||||
| 
 |  | ||||||
|     // clang-format off
 |  | ||||||
|     matrix[0] = 2.f / width; matrix[2] =  0.f;          matrix[4] = -1.f; |  | ||||||
|     matrix[1] = 0.f;         matrix[3] = -2.f / height; matrix[5] =  1.f; |  | ||||||
|     // Last matrix row is implicitly assumed to be [0, 0, 1].
 |  | ||||||
|     // clang-format on
 |  | ||||||
| 
 |  | ||||||
|     return matrix; |  | ||||||
| } |  | ||||||
| } // namespace
 |  | ||||||
| 
 |  | ||||||
| BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, | BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, | ||||||
|                        Tegra::MaxwellDeviceMemoryManager& device_memory_, |                        Tegra::MaxwellDeviceMemoryManager& device_memory_, | ||||||
|                        StateTracker& state_tracker_, ProgramManager& program_manager_, |                        StateTracker& state_tracker_, ProgramManager& program_manager_, | ||||||
|                        Device& device_) |                        Device& device_) | ||||||
|     : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), |     : rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_), | ||||||
|       program_manager(program_manager_), device(device_) { |       program_manager(program_manager_), device(device_) { | ||||||
|     // Create shader programs
 |  | ||||||
|     present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER); |  | ||||||
|     present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER); |  | ||||||
|     present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER); |  | ||||||
|     present_gaussian_fragment = |  | ||||||
|         CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER); |  | ||||||
|     present_scaleforce_fragment = |  | ||||||
|         CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG), |  | ||||||
|                       GL_FRAGMENT_SHADER); |  | ||||||
| 
 |  | ||||||
|     // Generate presentation sampler
 |  | ||||||
|     present_sampler.Create(); |  | ||||||
|     glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |  | ||||||
|     glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |  | ||||||
|     glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |  | ||||||
|     glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |  | ||||||
|     glSamplerParameteri(present_sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); |  | ||||||
| 
 |  | ||||||
|     present_sampler_nn.Create(); |  | ||||||
|     glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |  | ||||||
|     glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |  | ||||||
|     glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |  | ||||||
|     glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |  | ||||||
|     glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); |  | ||||||
| 
 |  | ||||||
|     // Generate VBO handle for drawing
 |  | ||||||
|     vertex_buffer.Create(); |  | ||||||
| 
 |  | ||||||
|     // Attach vertex data to VAO
 |  | ||||||
|     glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); |  | ||||||
| 
 |  | ||||||
|     // Allocate textures for the screen
 |     // Allocate textures for the screen
 | ||||||
|     framebuffer_texture.resource.Create(GL_TEXTURE_2D); |     framebuffer_texture.resource.Create(GL_TEXTURE_2D); | ||||||
| 
 | 
 | ||||||
| @ -106,15 +32,6 @@ BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_, | |||||||
|     const u8 framebuffer_data[4] = {0, 0, 0, 0}; |     const u8 framebuffer_data[4] = {0, 0, 0, 0}; | ||||||
|     glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, |     glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, | ||||||
|                     framebuffer_data); |                     framebuffer_data); | ||||||
| 
 |  | ||||||
|     // Enable unified vertex attributes and query vertex buffer address when the driver supports it
 |  | ||||||
|     if (device.HasVertexBufferUnifiedMemory()) { |  | ||||||
|         glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); |  | ||||||
|         glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); |  | ||||||
|         glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY); |  | ||||||
|         glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, |  | ||||||
|                                          &vertex_buffer_address); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BlitScreen::~BlitScreen() = default; | BlitScreen::~BlitScreen() = default; | ||||||
| @ -219,18 +136,14 @@ void BlitScreen::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& fra | |||||||
|     glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, |     glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format, | ||||||
|                        framebuffer_texture.width, framebuffer_texture.height); |                        framebuffer_texture.width, framebuffer_texture.height); | ||||||
| 
 | 
 | ||||||
|     fxaa = std::make_unique<FXAA>( |     fxaa.reset(); | ||||||
|         Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), |     smaa.reset(); | ||||||
|         Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); |  | ||||||
|     smaa = std::make_unique<SMAA>( |  | ||||||
|         Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), |  | ||||||
|         Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | ||||||
|                             const Layout::FramebufferLayout& layout) { |                             const Layout::FramebufferLayout& layout) { | ||||||
|     FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); |     FramebufferTextureInfo info = PrepareRenderTarget(framebuffer); | ||||||
|     const auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); |     auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height); | ||||||
| 
 | 
 | ||||||
|     // TODO: Signal state tracker about these changes
 |     // TODO: Signal state tracker about these changes
 | ||||||
|     state_tracker.NotifyScreenDrawVertexArray(); |     state_tracker.NotifyScreenDrawVertexArray(); | ||||||
| @ -267,15 +180,14 @@ void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | |||||||
|     glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |     glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | ||||||
|     glDepthRangeIndexed(0, 0.0, 0.0); |     glDepthRangeIndexed(0, 0.0, 0.0); | ||||||
| 
 | 
 | ||||||
|  |     GLint old_read_fb; | ||||||
|  |     GLint old_draw_fb; | ||||||
|  |     glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); | ||||||
|  |     glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); | ||||||
|  | 
 | ||||||
|     GLuint texture = info.display_texture; |     GLuint texture = info.display_texture; | ||||||
| 
 | 
 | ||||||
|     auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); |     auto anti_aliasing = Settings::values.anti_aliasing.GetValue(); | ||||||
|     if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) { |  | ||||||
|         LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing); |  | ||||||
|         anti_aliasing = Settings::AntiAliasing::None; |  | ||||||
|         Settings::values.anti_aliasing.SetValue(anti_aliasing); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (anti_aliasing != Settings::AntiAliasing::None) { |     if (anti_aliasing != Settings::AntiAliasing::None) { | ||||||
|         glEnablei(GL_SCISSOR_TEST, 0); |         glEnablei(GL_SCISSOR_TEST, 0); | ||||||
|         auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); |         auto scissor_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width); | ||||||
| @ -286,137 +198,83 @@ void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer, | |||||||
|         glScissorIndexed(0, 0, 0, scissor_width, scissor_height); |         glScissorIndexed(0, 0, 0, scissor_width, scissor_height); | ||||||
|         glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height); |         glViewportIndexedf(0, 0.0f, 0.0f, viewport_width, viewport_height); | ||||||
| 
 | 
 | ||||||
|         glBindSampler(0, present_sampler.handle); |  | ||||||
|         GLint old_read_fb; |  | ||||||
|         GLint old_draw_fb; |  | ||||||
|         glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); |  | ||||||
|         glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); |  | ||||||
| 
 |  | ||||||
|         switch (anti_aliasing) { |         switch (anti_aliasing) { | ||||||
|         case Settings::AntiAliasing::Fxaa: { |         case Settings::AntiAliasing::Fxaa: | ||||||
|  |             CreateFXAA(); | ||||||
|             texture = fxaa->Draw(program_manager, info.display_texture); |             texture = fxaa->Draw(program_manager, info.display_texture); | ||||||
|         } break; |             break; | ||||||
|         case Settings::AntiAliasing::Smaa: { |         case Settings::AntiAliasing::Smaa: | ||||||
|             texture = smaa->Draw(program_manager, info.display_texture); |  | ||||||
|         } break; |  | ||||||
|         default: |         default: | ||||||
|             UNREACHABLE(); |             CreateSMAA(); | ||||||
|  |             texture = smaa->Draw(program_manager, info.display_texture); | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); |  | ||||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     glDisablei(GL_SCISSOR_TEST, 0); |     glDisablei(GL_SCISSOR_TEST, 0); | ||||||
| 
 | 
 | ||||||
|     if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { |     if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { | ||||||
|         GLint old_read_fb; |  | ||||||
|         GLint old_draw_fb; |  | ||||||
|         glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb); |  | ||||||
|         glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb); |  | ||||||
| 
 |  | ||||||
|         if (!fsr || fsr->NeedsRecreation(layout.screen)) { |         if (!fsr || fsr->NeedsRecreation(layout.screen)) { | ||||||
|             fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); |             fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop); |         texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop); | ||||||
| 
 |         crop = {0, 0, 1, 1}; | ||||||
|         glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); |  | ||||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     glBindTextureUnit(0, texture); |     glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb); | ||||||
|  |     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb); | ||||||
| 
 | 
 | ||||||
|     const std::array ortho_matrix = |     CreateWindowAdapt(); | ||||||
|         MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); |     window_adapt->DrawToFramebuffer(program_manager, texture, layout, crop); | ||||||
| 
 |  | ||||||
|     const auto fragment_handle = [this]() { |  | ||||||
|         switch (Settings::values.scaling_filter.GetValue()) { |  | ||||||
|         case Settings::ScalingFilter::Bicubic: |  | ||||||
|             return present_bicubic_fragment.handle; |  | ||||||
|         case Settings::ScalingFilter::Gaussian: |  | ||||||
|             return present_gaussian_fragment.handle; |  | ||||||
|         case Settings::ScalingFilter::ScaleForce: |  | ||||||
|             return present_scaleforce_fragment.handle; |  | ||||||
|         case Settings::ScalingFilter::NearestNeighbor: |  | ||||||
|         case Settings::ScalingFilter::Bilinear: |  | ||||||
|         case Settings::ScalingFilter::Fsr: |  | ||||||
|         default: |  | ||||||
|             return present_bilinear_fragment.handle; |  | ||||||
|         } |  | ||||||
|     }(); |  | ||||||
|     program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle); |  | ||||||
|     glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, |  | ||||||
|                                 ortho_matrix.data()); |  | ||||||
| 
 |  | ||||||
|     f32 left, top, right, bottom; |  | ||||||
|     if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { |  | ||||||
|         // FSR has already applied the crop, so we just want to render the image
 |  | ||||||
|         // it has produced.
 |  | ||||||
|         left = 0; |  | ||||||
|         top = 0; |  | ||||||
|         right = 1; |  | ||||||
|         bottom = 1; |  | ||||||
|     } else { |  | ||||||
|         // Apply the precomputed crop.
 |  | ||||||
|         left = crop.left; |  | ||||||
|         top = crop.top; |  | ||||||
|         right = crop.right; |  | ||||||
|         bottom = crop.bottom; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Map the coordinates to the screen.
 |  | ||||||
|     const auto& screen = layout.screen; |  | ||||||
|     const auto x = screen.left; |  | ||||||
|     const auto y = screen.top; |  | ||||||
|     const auto w = screen.GetWidth(); |  | ||||||
|     const auto h = screen.GetHeight(); |  | ||||||
| 
 |  | ||||||
|     const std::array vertices = { |  | ||||||
|         ScreenRectVertex(x, y, left, top), |  | ||||||
|         ScreenRectVertex(x + w, y, right, top), |  | ||||||
|         ScreenRectVertex(x, y + h, left, bottom), |  | ||||||
|         ScreenRectVertex(x + w, y + h, right, bottom), |  | ||||||
|     }; |  | ||||||
|     glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); |  | ||||||
| 
 |  | ||||||
|     glDisable(GL_FRAMEBUFFER_SRGB); |  | ||||||
|     glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), |  | ||||||
|                        static_cast<GLfloat>(layout.height)); |  | ||||||
| 
 |  | ||||||
|     glEnableVertexAttribArray(PositionLocation); |  | ||||||
|     glEnableVertexAttribArray(TexCoordLocation); |  | ||||||
|     glVertexAttribDivisor(PositionLocation, 0); |  | ||||||
|     glVertexAttribDivisor(TexCoordLocation, 0); |  | ||||||
|     glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, |  | ||||||
|                          offsetof(ScreenRectVertex, position)); |  | ||||||
|     glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE, |  | ||||||
|                          offsetof(ScreenRectVertex, tex_coord)); |  | ||||||
|     glVertexAttribBinding(PositionLocation, 0); |  | ||||||
|     glVertexAttribBinding(TexCoordLocation, 0); |  | ||||||
|     if (device.HasVertexBufferUnifiedMemory()) { |  | ||||||
|         glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); |  | ||||||
|         glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, |  | ||||||
|                                sizeof(vertices)); |  | ||||||
|     } else { |  | ||||||
|         glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) { |  | ||||||
|         glBindSampler(0, present_sampler.handle); |  | ||||||
|     } else { |  | ||||||
|         glBindSampler(0, present_sampler_nn.handle); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Update background color before drawing
 |  | ||||||
|     glClearColor(Settings::values.bg_red.GetValue() / 255.0f, |  | ||||||
|                  Settings::values.bg_green.GetValue() / 255.0f, |  | ||||||
|                  Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); |  | ||||||
| 
 |  | ||||||
|     glClear(GL_COLOR_BUFFER_BIT); |  | ||||||
|     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |  | ||||||
| 
 | 
 | ||||||
|     // TODO
 |     // TODO
 | ||||||
|     // program_manager.RestoreGuestPipeline();
 |     // program_manager.RestoreGuestPipeline();
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void BlitScreen::CreateFXAA() { | ||||||
|  |     smaa.reset(); | ||||||
|  |     if (!fxaa) { | ||||||
|  |         fxaa = std::make_unique<FXAA>( | ||||||
|  |             Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||||||
|  |             Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void BlitScreen::CreateSMAA() { | ||||||
|  |     fxaa.reset(); | ||||||
|  |     if (!smaa) { | ||||||
|  |         smaa = std::make_unique<SMAA>( | ||||||
|  |             Settings::values.resolution_info.ScaleUp(framebuffer_texture.width), | ||||||
|  |             Settings::values.resolution_info.ScaleUp(framebuffer_texture.height)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void BlitScreen::CreateWindowAdapt() { | ||||||
|  |     if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     current_window_adapt = Settings::values.scaling_filter.GetValue(); | ||||||
|  |     switch (current_window_adapt) { | ||||||
|  |     case Settings::ScalingFilter::NearestNeighbor: | ||||||
|  |         window_adapt = MakeNearestNeighbor(device); | ||||||
|  |         break; | ||||||
|  |     case Settings::ScalingFilter::Bicubic: | ||||||
|  |         window_adapt = MakeBicubic(device); | ||||||
|  |         break; | ||||||
|  |     case Settings::ScalingFilter::Gaussian: | ||||||
|  |         window_adapt = MakeGaussian(device); | ||||||
|  |         break; | ||||||
|  |     case Settings::ScalingFilter::ScaleForce: | ||||||
|  |         window_adapt = MakeScaleForce(device); | ||||||
|  |         break; | ||||||
|  |     case Settings::ScalingFilter::Fsr: | ||||||
|  |     case Settings::ScalingFilter::Bilinear: | ||||||
|  |     default: | ||||||
|  |         window_adapt = MakeBilinear(device); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace OpenGL
 | } // namespace OpenGL
 | ||||||
|  | |||||||
| @ -18,6 +18,10 @@ namespace Tegra { | |||||||
| struct FramebufferConfig; | struct FramebufferConfig; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | namespace Settings { | ||||||
|  | enum class ScalingFilter : u32; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
| 
 | 
 | ||||||
| class Device; | class Device; | ||||||
| @ -27,6 +31,7 @@ class ProgramManager; | |||||||
| class RasterizerOpenGL; | class RasterizerOpenGL; | ||||||
| class SMAA; | class SMAA; | ||||||
| class StateTracker; | class StateTracker; | ||||||
|  | class WindowAdaptPass; | ||||||
| 
 | 
 | ||||||
| /// Structure used for storing information about the textures for the Switch screen
 | /// Structure used for storing information about the textures for the Switch screen
 | ||||||
| struct TextureInfo { | struct TextureInfo { | ||||||
| @ -61,29 +66,22 @@ public: | |||||||
|     void DrawScreen(const Tegra::FramebufferConfig& framebuffer, |     void DrawScreen(const Tegra::FramebufferConfig& framebuffer, | ||||||
|                     const Layout::FramebufferLayout& layout); |                     const Layout::FramebufferLayout& layout); | ||||||
| 
 | 
 | ||||||
|     void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer); |  | ||||||
| 
 |  | ||||||
|     /// Loads framebuffer from emulated memory into the active OpenGL texture.
 |     /// Loads framebuffer from emulated memory into the active OpenGL texture.
 | ||||||
|     FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); |     FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer); | ||||||
| 
 | 
 | ||||||
|     FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); |     FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     void CreateFXAA(); | ||||||
|  |     void CreateSMAA(); | ||||||
|  |     void CreateWindowAdapt(); | ||||||
|  | 
 | ||||||
|     RasterizerOpenGL& rasterizer; |     RasterizerOpenGL& rasterizer; | ||||||
|     Tegra::MaxwellDeviceMemoryManager& device_memory; |     Tegra::MaxwellDeviceMemoryManager& device_memory; | ||||||
|     StateTracker& state_tracker; |     StateTracker& state_tracker; | ||||||
|     ProgramManager& program_manager; |     ProgramManager& program_manager; | ||||||
|     Device& device; |     Device& device; | ||||||
| 
 | 
 | ||||||
|     OGLSampler present_sampler; |  | ||||||
|     OGLSampler present_sampler_nn; |  | ||||||
|     OGLBuffer vertex_buffer; |  | ||||||
|     OGLProgram present_vertex; |  | ||||||
|     OGLProgram present_bilinear_fragment; |  | ||||||
|     OGLProgram present_bicubic_fragment; |  | ||||||
|     OGLProgram present_gaussian_fragment; |  | ||||||
|     OGLProgram present_scaleforce_fragment; |  | ||||||
| 
 |  | ||||||
|     /// Display information for Switch screen
 |     /// Display information for Switch screen
 | ||||||
|     TextureInfo framebuffer_texture; |     TextureInfo framebuffer_texture; | ||||||
| 
 | 
 | ||||||
| @ -91,11 +89,11 @@ private: | |||||||
|     std::unique_ptr<FXAA> fxaa; |     std::unique_ptr<FXAA> fxaa; | ||||||
|     std::unique_ptr<SMAA> smaa; |     std::unique_ptr<SMAA> smaa; | ||||||
| 
 | 
 | ||||||
|  |     Settings::ScalingFilter current_window_adapt{}; | ||||||
|  |     std::unique_ptr<WindowAdaptPass> window_adapt; | ||||||
|  | 
 | ||||||
|     /// OpenGL framebuffer data
 |     /// OpenGL framebuffer data
 | ||||||
|     std::vector<u8> gl_framebuffer_data; |     std::vector<u8> gl_framebuffer_data; | ||||||
| 
 |  | ||||||
|     // GPU address of the vertex buffer
 |  | ||||||
|     GLuint64EXT vertex_buffer_address = 0; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace OpenGL
 | } // namespace OpenGL
 | ||||||
|  | |||||||
							
								
								
									
										39
									
								
								src/video_core/renderer_opengl/present/filters.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/video_core/renderer_opengl/present/filters.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #include "video_core/host_shaders/opengl_present_frag.h" | ||||||
|  | #include "video_core/host_shaders/opengl_present_scaleforce_frag.h" | ||||||
|  | #include "video_core/host_shaders/present_bicubic_frag.h" | ||||||
|  | #include "video_core/host_shaders/present_gaussian_frag.h" | ||||||
|  | #include "video_core/renderer_opengl/present/filters.h" | ||||||
|  | #include "video_core/renderer_opengl/present/util.h" | ||||||
|  | 
 | ||||||
|  | namespace OpenGL { | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device) { | ||||||
|  |     return std::make_unique<WindowAdaptPass>(device, CreateNearestNeighborSampler(), | ||||||
|  |                                              HostShaders::OPENGL_PRESENT_FRAG); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device) { | ||||||
|  |     return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(), | ||||||
|  |                                              HostShaders::OPENGL_PRESENT_FRAG); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device) { | ||||||
|  |     return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(), | ||||||
|  |                                              HostShaders::PRESENT_BICUBIC_FRAG); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device) { | ||||||
|  |     return std::make_unique<WindowAdaptPass>(device, CreateBilinearSampler(), | ||||||
|  |                                              HostShaders::PRESENT_GAUSSIAN_FRAG); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device) { | ||||||
|  |     return std::make_unique<WindowAdaptPass>( | ||||||
|  |         device, CreateBilinearSampler(), | ||||||
|  |         fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace OpenGL
 | ||||||
							
								
								
									
										17
									
								
								src/video_core/renderer_opengl/present/filters.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/video_core/renderer_opengl/present/filters.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include "video_core/renderer_opengl/present/window_adapt_pass.h" | ||||||
|  | 
 | ||||||
|  | namespace OpenGL { | ||||||
|  | 
 | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeNearestNeighbor(const Device& device); | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeBilinear(const Device& device); | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeBicubic(const Device& device); | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeGaussian(const Device& device); | ||||||
|  | std::unique_ptr<WindowAdaptPass> MakeScaleForce(const Device& device); | ||||||
|  | 
 | ||||||
|  | } // namespace OpenGL
 | ||||||
| @ -31,6 +31,7 @@ GLuint FXAA::Draw(ProgramManager& program_manager, GLuint input_texture) { | |||||||
|     program_manager.BindPresentPrograms(vert_shader.handle, frag_shader.handle); |     program_manager.BindPresentPrograms(vert_shader.handle, frag_shader.handle); | ||||||
|     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle); |     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle); | ||||||
|     glBindTextureUnit(0, input_texture); |     glBindTextureUnit(0, input_texture); | ||||||
|  |     glBindSampler(0, sampler.handle); | ||||||
|     glDrawArrays(GL_TRIANGLES, 0, 3); |     glDrawArrays(GL_TRIANGLES, 0, 3); | ||||||
|     glFrontFace(GL_CW); |     glFrontFace(GL_CW); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -36,13 +36,7 @@ SMAA::SMAA(u32 width, u32 height) { | |||||||
|         SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); |         SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); | ||||||
| 
 | 
 | ||||||
|     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | ||||||
|     glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); |  | ||||||
|     glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); |  | ||||||
|     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||||
|     glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); |  | ||||||
|     glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); |  | ||||||
|     glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); |  | ||||||
|     glPixelStorei(GL_UNPACK_ALIGNMENT, 4); |  | ||||||
| 
 | 
 | ||||||
|     area_tex.Create(GL_TEXTURE_2D); |     area_tex.Create(GL_TEXTURE_2D); | ||||||
|     glTextureStorage2D(area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT); |     glTextureStorage2D(area_tex.handle, 1, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT); | ||||||
|  | |||||||
| @ -29,4 +29,15 @@ static inline OGLSampler CreateBilinearSampler() { | |||||||
|     return sampler; |     return sampler; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline OGLSampler CreateNearestNeighborSampler() { | ||||||
|  |     OGLSampler sampler; | ||||||
|  |     sampler.Create(); | ||||||
|  |     glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||||
|  |     glSamplerParameteri(sampler.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||||
|  |     glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||||
|  |     glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||||
|  |     glSamplerParameteri(sampler.handle, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | ||||||
|  |     return sampler; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace OpenGL
 | } // namespace OpenGL
 | ||||||
|  | |||||||
							
								
								
									
										128
									
								
								src/video_core/renderer_opengl/present/window_adapt_pass.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/video_core/renderer_opengl/present/window_adapt_pass.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #include "common/settings.h" | ||||||
|  | #include "video_core/host_shaders/opengl_present_vert.h" | ||||||
|  | #include "video_core/renderer_opengl/gl_device.h" | ||||||
|  | #include "video_core/renderer_opengl/gl_shader_manager.h" | ||||||
|  | #include "video_core/renderer_opengl/gl_shader_util.h" | ||||||
|  | #include "video_core/renderer_opengl/present/window_adapt_pass.h" | ||||||
|  | 
 | ||||||
|  | namespace OpenGL { | ||||||
|  | 
 | ||||||
|  | namespace { | ||||||
|  | constexpr GLint PositionLocation = 0; | ||||||
|  | constexpr GLint TexCoordLocation = 1; | ||||||
|  | constexpr GLint ModelViewMatrixLocation = 0; | ||||||
|  | 
 | ||||||
|  | struct ScreenRectVertex { | ||||||
|  |     constexpr ScreenRectVertex(u32 x, u32 y, GLfloat u, GLfloat v) | ||||||
|  |         : position{{static_cast<GLfloat>(x), static_cast<GLfloat>(y)}}, tex_coord{{u, v}} {} | ||||||
|  | 
 | ||||||
|  |     std::array<GLfloat, 2> position; | ||||||
|  |     std::array<GLfloat, 2> tex_coord; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Defines a 1:1 pixel orthographic projection matrix with (0,0) on the top-left | ||||||
|  |  * corner and (width, height) on the lower-bottom. | ||||||
|  |  * | ||||||
|  |  * The projection part of the matrix is trivial, hence these operations are represented | ||||||
|  |  * by a 3x2 matrix. | ||||||
|  |  */ | ||||||
|  | std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(float width, float height) { | ||||||
|  |     std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order
 | ||||||
|  | 
 | ||||||
|  |     // clang-format off
 | ||||||
|  |     matrix[0] = 2.f / width; matrix[2] =  0.f;          matrix[4] = -1.f; | ||||||
|  |     matrix[1] = 0.f;         matrix[3] = -2.f / height; matrix[5] =  1.f; | ||||||
|  |     // Last matrix row is implicitly assumed to be [0, 0, 1].
 | ||||||
|  |     // clang-format on
 | ||||||
|  | 
 | ||||||
|  |     return matrix; | ||||||
|  | } | ||||||
|  | } // namespace
 | ||||||
|  | 
 | ||||||
|  | WindowAdaptPass::WindowAdaptPass(const Device& device_, OGLSampler&& sampler_, | ||||||
|  |                                  std::string_view frag_source) | ||||||
|  |     : device(device_), sampler(std::move(sampler_)) { | ||||||
|  |     vert = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER); | ||||||
|  |     frag = CreateProgram(frag_source, GL_FRAGMENT_SHADER); | ||||||
|  | 
 | ||||||
|  |     // Generate VBO handle for drawing
 | ||||||
|  |     vertex_buffer.Create(); | ||||||
|  | 
 | ||||||
|  |     // Attach vertex data to VAO
 | ||||||
|  |     glNamedBufferData(vertex_buffer.handle, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); | ||||||
|  | 
 | ||||||
|  |     // Query vertex buffer address when the driver supports unified vertex attributes
 | ||||||
|  |     if (device.HasVertexBufferUnifiedMemory()) { | ||||||
|  |         glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY); | ||||||
|  |         glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, | ||||||
|  |                                          &vertex_buffer_address); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | WindowAdaptPass::~WindowAdaptPass() = default; | ||||||
|  | 
 | ||||||
|  | void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, GLuint texture, | ||||||
|  |                                         const Layout::FramebufferLayout& layout, | ||||||
|  |                                         const Common::Rectangle<f32>& crop) { | ||||||
|  |     glBindTextureUnit(0, texture); | ||||||
|  | 
 | ||||||
|  |     const std::array ortho_matrix = | ||||||
|  |         MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | ||||||
|  | 
 | ||||||
|  |     program_manager.BindPresentPrograms(vert.handle, frag.handle); | ||||||
|  |     glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE, | ||||||
|  |                                 ortho_matrix.data()); | ||||||
|  | 
 | ||||||
|  |     // Map the coordinates to the screen.
 | ||||||
|  |     const auto& screen = layout.screen; | ||||||
|  |     const auto x = screen.left; | ||||||
|  |     const auto y = screen.top; | ||||||
|  |     const auto w = screen.GetWidth(); | ||||||
|  |     const auto h = screen.GetHeight(); | ||||||
|  | 
 | ||||||
|  |     const std::array vertices = { | ||||||
|  |         ScreenRectVertex(x, y, crop.left, crop.top), | ||||||
|  |         ScreenRectVertex(x + w, y, crop.right, crop.top), | ||||||
|  |         ScreenRectVertex(x, y + h, crop.left, crop.bottom), | ||||||
|  |         ScreenRectVertex(x + w, y + h, crop.right, crop.bottom), | ||||||
|  |     }; | ||||||
|  |     glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); | ||||||
|  | 
 | ||||||
|  |     glDisable(GL_FRAMEBUFFER_SRGB); | ||||||
|  |     glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), | ||||||
|  |                        static_cast<GLfloat>(layout.height)); | ||||||
|  | 
 | ||||||
|  |     glEnableVertexAttribArray(PositionLocation); | ||||||
|  |     glEnableVertexAttribArray(TexCoordLocation); | ||||||
|  |     glVertexAttribDivisor(PositionLocation, 0); | ||||||
|  |     glVertexAttribDivisor(TexCoordLocation, 0); | ||||||
|  |     glVertexAttribFormat(PositionLocation, 2, GL_FLOAT, GL_FALSE, | ||||||
|  |                          offsetof(ScreenRectVertex, position)); | ||||||
|  |     glVertexAttribFormat(TexCoordLocation, 2, GL_FLOAT, GL_FALSE, | ||||||
|  |                          offsetof(ScreenRectVertex, tex_coord)); | ||||||
|  |     glVertexAttribBinding(PositionLocation, 0); | ||||||
|  |     glVertexAttribBinding(TexCoordLocation, 0); | ||||||
|  |     if (device.HasVertexBufferUnifiedMemory()) { | ||||||
|  |         glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex)); | ||||||
|  |         glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address, | ||||||
|  |                                sizeof(vertices)); | ||||||
|  |     } else { | ||||||
|  |         glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     glBindSampler(0, sampler.handle); | ||||||
|  | 
 | ||||||
|  |     // Update background color before drawing
 | ||||||
|  |     glClearColor(Settings::values.bg_red.GetValue() / 255.0f, | ||||||
|  |                  Settings::values.bg_green.GetValue() / 255.0f, | ||||||
|  |                  Settings::values.bg_blue.GetValue() / 255.0f, 1.0f); | ||||||
|  | 
 | ||||||
|  |     glClear(GL_COLOR_BUFFER_BIT); | ||||||
|  |     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace OpenGL
 | ||||||
							
								
								
									
										39
									
								
								src/video_core/renderer_opengl/present/window_adapt_pass.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/video_core/renderer_opengl/present/window_adapt_pass.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common/math_util.h" | ||||||
|  | #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||||
|  | 
 | ||||||
|  | namespace Layout { | ||||||
|  | struct FramebufferLayout; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace OpenGL { | ||||||
|  | 
 | ||||||
|  | class Device; | ||||||
|  | class ProgramManager; | ||||||
|  | 
 | ||||||
|  | class WindowAdaptPass final { | ||||||
|  | public: | ||||||
|  |     explicit WindowAdaptPass(const Device& device, OGLSampler&& sampler, | ||||||
|  |                              std::string_view frag_source); | ||||||
|  |     ~WindowAdaptPass(); | ||||||
|  | 
 | ||||||
|  |     void DrawToFramebuffer(ProgramManager& program_manager, GLuint texture, | ||||||
|  |                            const Layout::FramebufferLayout& layout, | ||||||
|  |                            const Common::Rectangle<f32>& crop); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     const Device& device; | ||||||
|  |     OGLSampler sampler; | ||||||
|  |     OGLProgram vert; | ||||||
|  |     OGLProgram frag; | ||||||
|  |     OGLBuffer vertex_buffer; | ||||||
|  | 
 | ||||||
|  |     // GPU address of the vertex buffer
 | ||||||
|  |     GLuint64EXT vertex_buffer_address = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace OpenGL
 | ||||||
| @ -113,6 +113,12 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, | |||||||
|     if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) { |     if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) { | ||||||
|         glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); |         glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     // Enable unified vertex attributes when the driver supports it
 | ||||||
|  |     if (device.HasVertexBufferUnifiedMemory()) { | ||||||
|  |         glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); | ||||||
|  |         glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); | ||||||
|  |     } | ||||||
|     blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, |     blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, | ||||||
|                                                program_manager, device); |                                                program_manager, device); | ||||||
| } | } | ||||||
|  | |||||||
| @ -92,7 +92,9 @@ void WindowAdaptPass::Draw(Scheduler& scheduler, size_t image_index, VkImageView | |||||||
|     const VkFramebuffer host_framebuffer{*dst->framebuffer}; |     const VkFramebuffer host_framebuffer{*dst->framebuffer}; | ||||||
|     const VkRenderPass renderpass{*render_pass}; |     const VkRenderPass renderpass{*render_pass}; | ||||||
|     const VkPipeline graphics_pipeline{*pipeline}; |     const VkPipeline graphics_pipeline{*pipeline}; | ||||||
|  |     const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout}; | ||||||
|     const VkDescriptorSet descriptor_set{descriptor_sets[image_index]}; |     const VkDescriptorSet descriptor_set{descriptor_sets[image_index]}; | ||||||
|  |     const VkBuffer vertex_buffer{*buffer}; | ||||||
|     const VkExtent2D render_area{ |     const VkExtent2D render_area{ | ||||||
|         .width = dst->width, |         .width = dst->width, | ||||||
|         .height = dst->height, |         .height = dst->height, | ||||||
| @ -134,8 +136,8 @@ void WindowAdaptPass::Draw(Scheduler& scheduler, size_t image_index, VkImageView | |||||||
|         cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); |         cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); | ||||||
|         cmdbuf.SetViewport(0, viewport); |         cmdbuf.SetViewport(0, viewport); | ||||||
|         cmdbuf.SetScissor(0, scissor); |         cmdbuf.SetScissor(0, scissor); | ||||||
|         cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); |         cmdbuf.BindVertexBuffer(0, vertex_buffer, offsetof(BufferData, vertices)); | ||||||
|         cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, |         cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, | ||||||
|                                   descriptor_set, {}); |                                   descriptor_set, {}); | ||||||
|         cmdbuf.Draw(4, 1, 0, 0); |         cmdbuf.Draw(4, 1, 0, 0); | ||||||
|         cmdbuf.EndRenderPass(); |         cmdbuf.EndRenderPass(); | ||||||
|  | |||||||
| @ -222,6 +222,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||||||
|             .image = std::move(staging_image), |             .image = std::move(staging_image), | ||||||
|             .image_view = std::move(dst_view), |             .image_view = std::move(dst_view), | ||||||
|             .framebuffer = std::move(screenshot_fb), |             .framebuffer = std::move(screenshot_fb), | ||||||
|  |             .cmdbuf{}, | ||||||
|  |             .render_ready{}, | ||||||
|  |             .present_done{}, | ||||||
|         }; |         }; | ||||||
|     }(); |     }(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user