aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan/vk_texture_cache.cpp
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-11-03 21:58:24 +0100
committercirakg <cirakg@cirakg.xyz>2026-11-03 21:58:24 +0100
commitcdfb1ae93444c0aa02dfe592af36d70ab36549fd (patch)
tree2fa8d7062d907d5ab8d85d64c66be87ea4cdf0d1 /src/video_core/renderer_vulkan/vk_texture_cache.cpp
parent51341ec09b25de1d9b01d0c00ee828dd5b861d5c (diff)
parent4383b9787afbf6c63291bf803c8330afb4f21a16 (diff)
Merge upstream Djihads80/Eglantine nx2 into nx2HEADnx2
# Conflicts: # .github/workflows/release-binaries.yml
Diffstat (limited to 'src/video_core/renderer_vulkan/vk_texture_cache.cpp')
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp122
1 files changed, 107 insertions, 15 deletions
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index e3f427dead..d7093997c4 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -39,6 +39,9 @@
#include "video_core/texture_cache/util.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
+#ifdef EGLANTINE_STREAMLINE
+#include "video_core/vulkan_common/streamline.h"
+#endif
#include "video_core/vulkan_common/vulkan_wrapper.h"
#include "video_core/textures/decoders.h"
@@ -1556,6 +1559,21 @@ bool TextureCacheRuntime::UpscaleWithFsr3(Framebuffer* dst_framebuffer, ImageVie
if (!WantsTemporalUpscaleDepth()) {
return false;
}
+ const VkExtent2D extent = dst_framebuffer->RenderArea();
+ // A gap in the evaluations (a menu, a movie, a load) starts the history again.
+ const auto now = std::chrono::steady_clock::now();
+ const f32 frame_time_ms =
+ fsr3_last_evaluation
+ ? std::chrono::duration<f32, std::milli>(now - *fsr3_last_evaluation).count()
+ : 1000.0f / 30.0f;
+ const bool reset = !fsr3_last_evaluation || frame_time_ms > 250.0f;
+ fsr3_last_evaluation = now;
+#ifdef EGLANTINE_STREAMLINE
+ if (UpscaleWithDlss(dst_framebuffer, input_color, motion_vectors, depth, render_size, jitter,
+ motion_scale, reset)) {
+ return true;
+ }
+#endif
if (!fsr3_upscaler) {
if (!Fsr3Upscaler::IsSupported(device)) {
LOG_WARNING(Render_Vulkan, "FSR 3.1 needs formats or features this device lacks; "
@@ -1574,15 +1592,6 @@ bool TextureCacheRuntime::UpscaleWithFsr3(Framebuffer* dst_framebuffer, ImageVie
return false;
}
}
- const VkExtent2D extent = dst_framebuffer->RenderArea();
- // A gap in the evaluations (a menu, a movie, a load) starts the history again.
- const auto now = std::chrono::steady_clock::now();
- const f32 frame_time_ms =
- fsr3_last_evaluation
- ? std::chrono::duration<f32, std::milli>(now - *fsr3_last_evaluation).count()
- : 1000.0f / 30.0f;
- const bool reset = !fsr3_last_evaluation || frame_time_ms > 250.0f;
- fsr3_last_evaluation = now;
// FSR's own RCAS, set by the sharpness slider: FSR takes 0-1 for 2 to 0 stops, and the slider
// stores stops x 100, so this is the percentage the slider shows; 0% (stored 200) is off.
// EDEN_NX2_TEMPORAL_SHARPEN=<stops>|off overrides the slider.
@@ -1608,15 +1617,28 @@ bool TextureCacheRuntime::UpscaleWithFsr3(Framebuffer* dst_framebuffer, ImageVie
.sharpen = sharpen,
.sharpness = 1.0f - stops / 2.0f,
});
- // Draw the result into the DLSS output, which keeps its own format; the blit leaves FSR's
- // output image in SHADER_READ_ONLY_OPTIMAL, so return it to GENERAL for the next frame.
+ DrawUpscaledOutput(dst_framebuffer, fsr3_upscaler->OutputView(), fsr3_upscaler->OutputImage(),
+ fsr3_upscaler->PointSampler());
+ static bool logged{};
+ if (!logged) {
+ logged = true;
+ LOG_INFO(Render_Vulkan, "DLSS replaced by FSR 3.1: {}x{} -> {}x{}", render_size[0],
+ render_size[1], extent.width, extent.height);
+ }
+ return true;
+}
+
+void TextureCacheRuntime::DrawUpscaledOutput(Framebuffer* dst_framebuffer, VkImageView view,
+ VkImage output, VkSampler sampler) {
+ // Draw the result into the DLSS output, which keeps its own format; the blit leaves the
+ // upscaler's output image in SHADER_READ_ONLY_OPTIMAL, so return it to GENERAL for the next
+ // frame.
+ const VkExtent2D extent = dst_framebuffer->RenderArea();
const Region2D region{
.start = {0, 0},
.end = {static_cast<s32>(extent.width), static_cast<s32>(extent.height)},
};
- const VkImage output = fsr3_upscaler->OutputImage();
- blit_image_helper.BlitColor(dst_framebuffer, fsr3_upscaler->OutputView(), output,
- fsr3_upscaler->PointSampler(), region, region,
+ blit_image_helper.BlitColor(dst_framebuffer, view, output, sampler, region, region,
{extent.width, extent.height, 1});
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([output](vk::CommandBuffer cmdbuf) {
@@ -1641,14 +1663,84 @@ bool TextureCacheRuntime::UpscaleWithFsr3(Framebuffer* dst_framebuffer, ImageVie
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, barrier);
});
+}
+
+#ifdef EGLANTINE_STREAMLINE
+bool TextureCacheRuntime::UpscaleWithDlss(Framebuffer* dst_framebuffer, ImageView& input_color,
+ ImageView& motion_vectors, ImageView& depth,
+ std::array<u32, 2> render_size,
+ std::array<f32, 2> jitter,
+ std::array<f32, 2> motion_scale, bool reset) {
+ // EDEN_NX2_DLSS_REPLACEMENT=fsr keeps FSR 3.1 for A/B runs.
+ static const bool force_fsr = [] {
+ const char* const value = std::getenv("EDEN_NX2_DLSS_REPLACEMENT");
+ return value && std::string_view{value} == "fsr";
+ }();
+ if (force_fsr || dlss_unsupported) {
+ return false;
+ }
+ if (!dlss_upscaler) {
+ // Off in the settings, or Streamline didn't start: it has said why.
+ if (!Streamline::IsDlssAvailable()) {
+ dlss_unsupported = true;
+ return false;
+ }
+ try {
+ dlss_upscaler =
+ std::make_unique<StreamlineDlssUpscaler>(device, scheduler, memory_allocator);
+ } catch (const vk::Exception& exception) {
+ LOG_WARNING(Render_Vulkan, "NVIDIA DLSS unavailable ({}); using FSR 3.1",
+ exception.what());
+ dlss_unsupported = true;
+ return false;
+ }
+ }
+ const auto image = [&](ImageView& view, VkImageView handle, VkImageAspectFlags aspect) {
+ return StreamlineDlssUpscaler::Image{
+ .view = handle,
+ .image = view.ImageHandle(),
+ .format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, view.format)
+ .format,
+ .range{
+ .aspectMask = aspect,
+ .baseMipLevel = static_cast<u32>(view.range.base.level),
+ .levelCount = 1,
+ .baseArrayLayer = static_cast<u32>(view.range.base.layer),
+ .layerCount = 1,
+ },
+ .barrier_aspect = ImageAspectMask(view.format),
+ };
+ };
+ const VkExtent2D extent = dst_framebuffer->RenderArea();
+ const bool upscaled = dlss_upscaler->Upscale({
+ .color = image(input_color, input_color.Handle(Shader::TextureType::Color2D),
+ VK_IMAGE_ASPECT_COLOR_BIT),
+ .depth = image(depth, depth.DepthView(), VK_IMAGE_ASPECT_DEPTH_BIT),
+ .motion_vectors = image(motion_vectors,
+ motion_vectors.Handle(Shader::TextureType::Color2D),
+ VK_IMAGE_ASPECT_COLOR_BIT),
+ .render_size = {render_size[0], render_size[1]},
+ .upscale_size = extent,
+ .jitter = jitter,
+ .motion_vector_scale = {motion_scale[0] * static_cast<f32>(render_size[0]),
+ motion_scale[1] * static_cast<f32>(render_size[1])},
+ .reset = reset,
+ });
+ if (!upscaled) {
+ dlss_unsupported = true;
+ return false;
+ }
+ DrawUpscaledOutput(dst_framebuffer, dlss_upscaler->OutputView(), dlss_upscaler->OutputImage(),
+ dlss_upscaler->PointSampler());
static bool logged{};
if (!logged) {
logged = true;
- LOG_INFO(Render_Vulkan, "DLSS replaced by FSR 3.1: {}x{} -> {}x{}", render_size[0],
+ LOG_INFO(Render_Vulkan, "DLSS replaced by NVIDIA DLSS: {}x{} -> {}x{}", render_size[0],
render_size[1], extent.width, extent.height);
}
return true;
}
+#endif
bool TextureCacheRuntime::TemporalUpscale(Framebuffer* dst_framebuffer, ImageView& dst,
ImageView& input_color, ImageView& motion_vectors,