From 3e07b466ebd43f90ccfc4b2a79fe7fd62843f94a Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 23 Aug 2026 17:31:09 +0200 Subject: [vulkan] Adjustments on MSAA and BlitHelpers (#4287) PR/Commit Owner: CamilleLaVey This PR contains changes complementary to the MSAA refactor from some weeks ago, adds proper shader convert to depth, stencil for msaa and non msaa convertions; removes redundant helpers and unify paths on the resolve functions, just to make the readability and maintainability better; includes fixes for the blit operations on Nvidia, Intel/Windows (previously banned) and ensures Linux retain the fix without extra burden; fixes the QCOM driver bug on resolution upscaling on any games above x1 (includes turnip on A8xx series) and fixes crashes/ resolution upscaled bugs on certain games that used to have wrong viewporting effect on screen or directly device loss on Vulkan. Adds fixes for regressions caused by previous MSAA refactor on games as Fire Emblem: Engage. Special Thanks 1.- Big Smolio (@Gidoly) Co-authored-by: CamilleLaVey Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4287 Reviewed-by: CamilleLaVey Reviewed-by: Samuel --- src/video_core/texture_cache/image_base.cpp | 8 ++---- src/video_core/texture_cache/image_base.h | 5 +++- src/video_core/texture_cache/texture_cache.h | 34 ++++++++++++++++++----- src/video_core/texture_cache/texture_cache_base.h | 2 ++ 4 files changed, 35 insertions(+), 14 deletions(-) (limited to 'src/video_core/texture_cache') diff --git a/src/video_core/texture_cache/image_base.cpp b/src/video_core/texture_cache/image_base.cpp index 077df28fb3..9b0f33220d 100644 --- a/src/video_core/texture_cache/image_base.cpp +++ b/src/video_core/texture_cache/image_base.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project @@ -121,7 +121,7 @@ void ImageBase::InsertView(const ImageViewInfo& view_info, ImageViewId image_vie image_view_ids.push_back(image_view_id); } -bool ImageBase::IsSafeDownload() const noexcept { +bool ImageBase::IsSafeGpuCopy() const noexcept { // Skip images that were not modified from the GPU if (False(flags & ImageFlagBits::GpuModified)) { return false; @@ -131,10 +131,6 @@ bool ImageBase::IsSafeDownload() const noexcept { if (True(flags & ImageFlagBits::CpuModified)) { return false; } - if (info.num_samples > 1) { - LOG_WARNING(HW_GPU, "MSAA image downloads are not implemented"); - return false; - } return true; } diff --git a/src/video_core/texture_cache/image_base.h b/src/video_core/texture_cache/image_base.h index 0587d7b724..79fc8505d6 100644 --- a/src/video_core/texture_cache/image_base.h +++ b/src/video_core/texture_cache/image_base.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -64,7 +67,7 @@ struct ImageBase { void InsertView(const ImageViewInfo& view_info, ImageViewId image_view_id); - [[nodiscard]] bool IsSafeDownload() const noexcept; + [[nodiscard]] bool IsSafeGpuCopy() const noexcept; [[nodiscard]] bool Overlaps(VAddr overlap_cpu_addr, size_t overlap_size) const noexcept { const VAddr overlap_end = overlap_cpu_addr + overlap_size; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 98a5e053a7..bcc40afde0 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -134,7 +134,7 @@ void TextureCache

::RunGarbageCollector() { if (True(image.flags & ImageFlagBits::IsDecoding)) { return false; } - const bool must_download = image.IsSafeDownload() && False(image.flags & ImageFlagBits::BadOverlap); + const bool must_download = IsDownloadable(image) && False(image.flags & ImageFlagBits::BadOverlap); if ((!aggressive_mode && True(image.flags & ImageFlagBits::CostlyLoad)) || (!high_priority_mode && must_download)) { return false; } @@ -577,6 +577,7 @@ FramebufferId TextureCache

::GetFramebufferId(const RenderTargets& key) { return id ? &slot_image_views[id] : nullptr; }); ImageView* const depth_buffer = key.depth_buffer_id ? &slot_image_views[key.depth_buffer_id] : nullptr; + runtime.FlushDeferredClear(); framebuffer_id = slot_framebuffers.insert(runtime, color_buffers, depth_buffer, key); return framebuffer_id; } @@ -594,11 +595,26 @@ void TextureCache

::WriteMemory(DAddr cpu_addr, size_t size) { }); } +template +bool TextureCache

::IsDownloadable(const ImageBase& image) const noexcept { + if (!image.IsSafeGpuCopy()) { + return false; + } + if (image.info.num_samples == 1) { + return true; + } + if constexpr (P::HAS_MSAA_DOWNLOADS) { + return runtime.CanDownloadMsaa(image.info); + } else { + return false; + } +} + template void TextureCache

::DownloadMemory(DAddr cpu_addr, size_t size) { boost::container::small_vector images; - ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { - if (!image.IsSafeDownload()) { + ForEachImageInRegion(cpu_addr, size, [this, &images](ImageId image_id, ImageBase& image) { + if (!IsDownloadable(image)) { return; } image.flags &= ~ImageFlagBits::GpuModified; @@ -1476,12 +1492,12 @@ template bool TextureCache

::ScaleUp(Image& image) { const bool has_copy = image.HasScaled(); const bool rescaled = image.ScaleUp(); + if (!has_copy && image.HasScaled()) { + total_used_memory += GetScaledImageSizeBytes(image); + } if (!rescaled) { return false; } - if (!has_copy) { - total_used_memory += GetScaledImageSizeBytes(image); - } InvalidateScale(image); return true; } @@ -1691,7 +1707,10 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA for (const auto& copy_object : join_copies_to_do) { Image& overlap = slot_images[copy_object.id]; if (copy_object.is_alias) { - if (!overlap.IsSafeDownload()) { + if (!overlap.IsSafeGpuCopy()) { + continue; + } + if (overlap.info.num_samples != new_image.info.num_samples) { continue; } const auto alias_pointer = join_alias_indices.find(copy_object.id); @@ -2461,6 +2480,7 @@ void TextureCache

::RemoveImageViewReferences(std::span rem template void TextureCache

::RemoveFramebuffers(std::span removed_views) { + runtime.FlushDeferredClear(); auto it = framebuffers.begin(); while (it != framebuffers.end()) { if (it->first.Contains(removed_views)) { diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index fafc331ef7..77947e83c7 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -303,6 +303,8 @@ private: FramebufferId GetFramebufferId(const RenderTargets& key); /// Refresh the contents (pixel data) of an image + [[nodiscard]] bool IsDownloadable(const ImageBase& image) const noexcept; + void RefreshContents(Image& image, ImageId image_id); /// Upload data from guest to an image -- cgit v1.2.3