diff options
author | Liam <byteslice@airmail.cc> | 2024-01-15 21:08:21 +0100 |
---|---|---|
committer | Liam <byteslice@airmail.cc> | 2024-01-31 17:27:21 +0100 |
commit | d4de04584f14f3ea8fde4cd79102b887c084fbc2 (patch) | |
tree | 72581b4240726f72d769319f3b5e1b2ece6c8e58 /src/video_core/renderer_opengl/present | |
parent | renderer_opengl: move out ownership of FSR resources (diff) | |
download | yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar.gz yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar.bz2 yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar.lz yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar.xz yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.tar.zst yuzu-d4de04584f14f3ea8fde4cd79102b887c084fbc2.zip |
Diffstat (limited to 'src/video_core/renderer_opengl/present')
-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 |
7 files changed, 235 insertions, 6 deletions
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 @@ +// 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 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 @@ +// 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 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) { program_manager.BindPresentPrograms(vert_shader.handle, frag_shader.handle); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.handle); glBindTextureUnit(0, input_texture); + glBindSampler(0, sampler.handle); glDrawArrays(GL_TRIANGLES, 0, 3); glFrontFace(GL_CW); 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) { SmaaShader(HostShaders::SMAA_NEIGHBORHOOD_BLENDING_FRAG, GL_FRAGMENT_SHADER); 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_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); 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() { 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 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 @@ +// 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 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 @@ +// 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 |