summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl/present
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl/present')
-rw-r--r--src/video_core/renderer_opengl/present/filters.cpp39
-rw-r--r--src/video_core/renderer_opengl/present/filters.h17
-rw-r--r--src/video_core/renderer_opengl/present/fxaa.cpp1
-rw-r--r--src/video_core/renderer_opengl/present/smaa.cpp6
-rw-r--r--src/video_core/renderer_opengl/present/util.h11
-rw-r--r--src/video_core/renderer_opengl/present/window_adapt_pass.cpp128
-rw-r--r--src/video_core/renderer_opengl/present/window_adapt_pass.h39
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