summaryrefslogtreecommitdiffstats
path: root/src/video_core
diff options
context:
space:
mode:
authorLiam <byteslice@airmail.cc>2024-01-15 21:08:21 +0100
committerLiam <byteslice@airmail.cc>2024-01-31 17:27:21 +0100
commitd4de04584f14f3ea8fde4cd79102b887c084fbc2 (patch)
tree72581b4240726f72d769319f3b5e1b2ece6c8e58 /src/video_core
parentrenderer_opengl: move out ownership of FSR resources (diff)
downloadyuzu-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')
-rw-r--r--src/video_core/CMakeLists.txt4
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.cpp272
-rw-r--r--src/video_core/renderer_opengl/gl_blit_screen.h26
-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
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp6
-rw-r--r--src/video_core/renderer_vulkan/present/window_adapt_pass.cpp6
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp3
13 files changed, 329 insertions, 229 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 9879c3ad7..c6b0d628d 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -116,6 +116,8 @@ add_library(video_core STATIC
renderer_null/null_rasterizer.h
renderer_null/renderer_null.cpp
renderer_null/renderer_null.h
+ renderer_opengl/present/filters.cpp
+ renderer_opengl/present/filters.h
renderer_opengl/present/fsr.cpp
renderer_opengl/present/fsr.h
renderer_opengl/present/fxaa.cpp
@@ -123,6 +125,8 @@ add_library(video_core STATIC
renderer_opengl/present/smaa.cpp
renderer_opengl/present/smaa.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.h
renderer_opengl/gl_blit_screen.cpp
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 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#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_rasterizer.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_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/fxaa.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"
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_,
Tegra::MaxwellDeviceMemoryManager& device_memory_,
StateTracker& state_tracker_, ProgramManager& program_manager_,
Device& device_)
: rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_),
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
framebuffer_texture.resource.Create(GL_TEXTURE_2D);
@@ -106,15 +32,6 @@ BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_,
const u8 framebuffer_data[4] = {0, 0, 0, 0};
glClearTexImage(framebuffer_texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE,
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;
@@ -219,18 +136,14 @@ void BlitScreen::ConfigureFramebufferTexture(const Tegra::FramebufferConfig& fra
glTextureStorage2D(framebuffer_texture.resource.handle, 1, internal_format,
framebuffer_texture.width, framebuffer_texture.height);
- fxaa = std::make_unique<FXAA>(
- Settings::values.resolution_info.ScaleUp(framebuffer_texture.width),
- 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));
+ fxaa.reset();
+ smaa.reset();
}
void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer,
const Layout::FramebufferLayout& layout) {
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
state_tracker.NotifyScreenDrawVertexArray();
@@ -267,15 +180,14 @@ void BlitScreen::DrawScreen(const Tegra::FramebufferConfig& framebuffer,
glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
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;
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) {
glEnablei(GL_SCISSOR_TEST, 0);
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);
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) {
- case Settings::AntiAliasing::Fxaa: {
+ case Settings::AntiAliasing::Fxaa:
+ CreateFXAA();
texture = fxaa->Draw(program_manager, info.display_texture);
- } break;
- case Settings::AntiAliasing::Smaa: {
- texture = smaa->Draw(program_manager, info.display_texture);
- } break;
+ break;
+ case Settings::AntiAliasing::Smaa:
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);
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)) {
fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight());
}
texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
+ crop = {0, 0, 1, 1};
}
- glBindTextureUnit(0, texture);
-
- const std::array ortho_matrix =
- MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
-
- 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());
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
- 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;
- }
+ CreateWindowAdapt();
+ window_adapt->DrawToFramebuffer(program_manager, texture, layout, crop);
- // 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));
- }
+ // TODO
+ // program_manager.RestoreGuestPipeline();
+}
- if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) {
- glBindSampler(0, present_sampler.handle);
- } else {
- glBindSampler(0, present_sampler_nn.handle);
+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));
}
+}
- // 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);
+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));
+ }
+}
- glClear(GL_COLOR_BUFFER_BIT);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+void BlitScreen::CreateWindowAdapt() {
+ if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) {
+ return;
+ }
- // TODO
- // program_manager.RestoreGuestPipeline();
+ 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
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 {
struct FramebufferConfig;
}
+namespace Settings {
+enum class ScalingFilter : u32;
+}
+
namespace OpenGL {
class Device;
@@ -27,6 +31,7 @@ class ProgramManager;
class RasterizerOpenGL;
class SMAA;
class StateTracker;
+class WindowAdaptPass;
/// Structure used for storing information about the textures for the Switch screen
struct TextureInfo {
@@ -61,29 +66,22 @@ public:
void DrawScreen(const Tegra::FramebufferConfig& framebuffer,
const Layout::FramebufferLayout& layout);
- void RenderScreenshot(const Tegra::FramebufferConfig& framebuffer);
-
/// Loads framebuffer from emulated memory into the active OpenGL texture.
FramebufferTextureInfo LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer);
FramebufferTextureInfo PrepareRenderTarget(const Tegra::FramebufferConfig& framebuffer);
private:
+ void CreateFXAA();
+ void CreateSMAA();
+ void CreateWindowAdapt();
+
RasterizerOpenGL& rasterizer;
Tegra::MaxwellDeviceMemoryManager& device_memory;
StateTracker& state_tracker;
ProgramManager& program_manager;
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
TextureInfo framebuffer_texture;
@@ -91,11 +89,11 @@ private:
std::unique_ptr<FXAA> fxaa;
std::unique_ptr<SMAA> smaa;
+ Settings::ScalingFilter current_window_adapt{};
+ std::unique_ptr<WindowAdaptPass> window_adapt;
+
/// OpenGL framebuffer data
std::vector<u8> gl_framebuffer_data;
-
- // GPU address of the vertex buffer
- GLuint64EXT vertex_buffer_address = 0;
};
} // 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 @@
+// 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
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_,
if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) {
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,
program_manager, device);
}
diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
index 7fd9ecd22..1d1828a4c 100644
--- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
+++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp
@@ -92,7 +92,9 @@ void WindowAdaptPass::Draw(Scheduler& scheduler, size_t image_index, VkImageView
const VkFramebuffer host_framebuffer{*dst->framebuffer};
const VkRenderPass renderpass{*render_pass};
const VkPipeline graphics_pipeline{*pipeline};
+ const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout};
const VkDescriptorSet descriptor_set{descriptor_sets[image_index]};
+ const VkBuffer vertex_buffer{*buffer};
const VkExtent2D render_area{
.width = dst->width,
.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.SetViewport(0, viewport);
cmdbuf.SetScissor(0, scissor);
- cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices));
- cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0,
+ cmdbuf.BindVertexBuffer(0, vertex_buffer, offsetof(BufferData, vertices));
+ cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0,
descriptor_set, {});
cmdbuf.Draw(4, 1, 0, 0);
cmdbuf.EndRenderPass();
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 2912aaff6..a99ef08a5 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -222,6 +222,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
.image = std::move(staging_image),
.image_view = std::move(dst_view),
.framebuffer = std::move(screenshot_fb),
+ .cmdbuf{},
+ .render_ready{},
+ .present_done{},
};
}();