diff options
| author | nowhere02 <140357165+nowhere02@users.noreply.github.com> | 2026-11-02 20:59:00 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-11-02 20:59:00 -0300 |
| commit | 3c499c582cfa27585b3acd4593ede3e9c9f3b5e1 (patch) | |
| tree | 2f19414a5e89a067ed9c3f600217ae408e8918fd /src/video_core/texture_cache/texture_cache.h | |
| parent | aae778edce69f18513e952d3d267518b0f7d3f72 (diff) | |
| parent | 9acd36eb9a291e0631346f5b17d69d0e8eb26cc5 (diff) | |
Merge pull request #346 from Duck912/fe-fsr31
FSR 3.1 implementation for DLSS games
Diffstat (limited to 'src/video_core/texture_cache/texture_cache.h')
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 63 |
1 files changed, 57 insertions, 6 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 4929c2df44..abb22b9bfb 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1098,6 +1098,7 @@ template <class P> bool TextureCache<P>::TemporalUpscale(const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, const Tegra::Engines::Fermi2D::Surface& motion_vectors, + const Tegra::Texture::TICEntry* depth, std::array<f32, 2> jitter, std::array<f32, 2> motion_scale) { if constexpr (FRAMEBUFFER_BLITS) { return false; @@ -1123,6 +1124,12 @@ bool TextureCache<P>::TemporalUpscale(const Tegra::Engines::Fermi2D::Surface& ds has_deleted_images = false; const ImageId motion_id = FindOrInsertImage(motion_info, motion_vectors.Address(), RelaxedOptions{}); + // The depth only feeds FSR 3.1 (looked up only when FSR can run); without it the stand-in + // runs. + ImageId depth_id{}; + if (depth && motion_id && runtime.WantsTemporalUpscaleDepth()) { + depth_id = FindOrInsertImage(ImageInfo(*depth), depth->Address(), RelaxedOptions{}); + } if (has_deleted_images || !motion_id) { return false; // the colour and output ids may be stale; the caller blits instead } @@ -1131,12 +1138,47 @@ bool TextureCache<P>::TemporalUpscale(const Tegra::Engines::Fermi2D::Surface& ds PrepareImage(src_id, false, false); PrepareImage(motion_id, false, false); PrepareImage(dst_id, true, false); + if (depth_id) { + PrepareImage(depth_id, false, false); + if (slot_images[depth_id].info.num_samples != 1 || + slot_images[depth_id].info.format != PixelFormat::D32_FLOAT) { + depth_id = {}; + } + } for (const ImageId id : {src_id, motion_id, dst_id}) { - if (True(slot_images[id].flags & ImageFlagBits::Rescaled) || - slot_images[id].info.num_samples != 1) { + if (slot_images[id].info.num_samples != 1) { return false; } } + // With resolution scaling, bring the images that can follow to the same scale, as BlitImage + // does; the stand-in reads each image at its own size, so any left behind still work. + const auto rescaled = [&](ImageId id) { + return True(slot_images[id].flags & ImageFlagBits::Rescaled); + }; + if (rescaled(src_id) || rescaled(motion_id) || rescaled(dst_id) || + (depth_id && rescaled(depth_id))) { + for (const ImageId id : {src_id, motion_id, dst_id, depth_id}) { + if (id && !rescaled(id) && ImageCanRescale(slot_images[id])) { + ScaleUp(slot_images[id]); + } + } + } + // FSR 3.1 reads colour, motion and depth texel for texel: all at the colour's scale. + if (depth_id && (rescaled(depth_id) != rescaled(src_id) || + rescaled(motion_id) != rescaled(src_id))) { + depth_id = {}; + } + const Extent3D src_size = slot_images[src_id].info.size; + const std::array<u32, 2> render_size = + rescaled(src_id) + ? std::array{Settings::values.resolution_info.ScaleUp(src_size.width), + Settings::values.resolution_info.ScaleUp(src_size.height)} + : std::array{src_size.width, src_size.height}; + // The jitter is in the input's guest pixels. + if (rescaled(src_id)) { + const f32 factor = Settings::values.resolution_info.up_factor; + jitter = {jitter[0] * factor, jitter[1] * factor}; + } const auto view = [&](ImageId id, const Tegra::Engines::Fermi2D::Surface& surface, PixelFormat format) -> std::optional<std::pair<FramebufferId, ImageViewId>> { const std::optional base = slot_images[id].TryFindBase(surface.Address()); @@ -1152,12 +1194,21 @@ bool TextureCache<P>::TemporalUpscale(const Tegra::Engines::Fermi2D::Surface& ds if (!src_view || !motion_view || !dst_view) { return false; } + ImageViewId depth_view{}; + if (depth_id) { + if (const std::optional base = slot_images[depth_id].TryFindBase(depth->Address())) { + const SubresourceRange range{.base = *base, .extent = {1, 1}}; + depth_view = FindOrEmplaceImageView( + depth_id, ImageViewInfo(ImageViewType::e2D, PixelFormat::D32_FLOAT, range)); + } + } // After the views: creating them may reallocate the framebuffer slots. Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_view->first]; - return runtime.TemporalUpscale(dst_framebuffer, slot_image_views[dst_view->second], - slot_image_views[src_view->second], - slot_image_views[motion_view->second], jitter, - motion_scale); + return runtime.TemporalUpscale( + dst_framebuffer, slot_image_views[dst_view->second], slot_image_views[src_view->second], + slot_image_views[motion_view->second], + depth_view ? &slot_image_views[depth_view] : nullptr, render_size, jitter, + motion_scale); } } |
