From 353d793622d74ff6f9c099e94e192bb2b8a88dee Mon Sep 17 00:00:00 2001 From: Ribbit Date: Sun, 12 Oct 2025 22:59:44 -0700 Subject: [PATCH] random fixes for random stuff --- .../renderer_vulkan/pipeline_helper.h | 6 +- .../renderer_vulkan/vk_compute_pass.cpp | 5 +- .../renderer_vulkan/vk_texture_cache.cpp | 69 +++++++++++++++---- .../renderer_vulkan/vk_texture_cache.h | 11 +++ 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 910e07a606..38fc8e6064 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -191,10 +191,8 @@ inline void PushImageDescriptors(TextureCache& texture_cache, ImageView& image_view{texture_cache.GetImageView(image_view_id)}; const VkImageView vk_image_view{image_view.Handle(desc.type)}; const Sampler& sampler{texture_cache.GetSampler(sampler_id)}; - const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && - !image_view.SupportsAnisotropy()}; - const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() - : sampler.Handle()}; + const VkSampler vk_sampler{sampler.HandleForView(image_view.SupportsLinearFiltering(), + image_view.SupportsAnisotropy())}; guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler); rescaling.PushTexture(texture_cache.IsRescaling(image_view)); } diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 5938de6100..e61ecd0ce1 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -503,6 +503,8 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT, }; + static constexpr VkPipelineStageFlags write_dest_stages = + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; // dstAccessMask spans many stages const QueriesPrefixScanPushConstants uniforms{ .min_accumulation_base = static_cast(min_accumulation_limit), .max_accumulation_base = static_cast(max_accumulation_limit), @@ -519,8 +521,7 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms); cmdbuf.Dispatch(1, 1, 1); cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, 0, - write_barrier); + write_dest_stages, 0, write_barrier); }); } } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 50a73ea76d..f8e6b42b8d 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -2030,6 +2030,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI "Image view format {} has different usage flags than image format {}", format, image.info.format); } + supports_linear_filtering = device->IsFormatSupported( + format_info.format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, FormatType::Optimal); const VkImageViewUsageCreateInfo image_view_usage{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, .pNext = nullptr, @@ -2100,7 +2102,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageInfo& info, const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) : VideoCommon::ImageViewBase{info, view_info, gpu_addr_}, - buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {} + buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)}, + supports_linear_filtering{false} {} ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params) : VideoCommon::ImageViewBase{params}, device{&runtime.device} { @@ -2161,20 +2164,31 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type, if (!image_handle) { return VK_NULL_HANDLE; } + if (!storage_views) { + storage_views = std::make_unique(); + } + + // For storage images, Vulkan requires identity-swizzled views regardless of sampling swizzles. + // - If the image is typeless in the shader, create an identity-swizzled view using the + // underlying image's format. if (image_format == Shader::ImageFormat::Typeless) { - return Handle(texture_type); + auto& view = storage_views->typeless[static_cast(texture_type)]; + if (!view) { + const auto format_info = + MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); + view = MakeView(format_info.format, VK_IMAGE_ASPECT_COLOR_BIT); + } + return *view; } + + // Otherwise, use a typed storage view with identity swizzle. const bool is_signed{image_format == Shader::ImageFormat::R8_SINT || image_format == Shader::ImageFormat::R16_SINT}; - if (!storage_views) { - storage_views = std::make_unique(); - } auto& views{is_signed ? storage_views->signeds : storage_views->unsigneds}; auto& view{views[static_cast(texture_type)]}; - if (view) { - return *view; + if (!view) { + view = MakeView(Format(image_format), VK_IMAGE_ASPECT_COLOR_BIT); } - view = MakeView(Format(image_format), VK_IMAGE_ASPECT_COLOR_BIT); return *view; } @@ -2234,14 +2248,19 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t // Some games have samplers with garbage. Sanitize them here. const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f); - const auto create_sampler = [&](const f32 anisotropy) { + const VkFilter mag_filter = MaxwellToVK::Sampler::Filter(tsc.mag_filter); + const VkFilter min_filter = MaxwellToVK::Sampler::Filter(tsc.min_filter); + const VkSamplerMipmapMode mipmap_mode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter); + + const auto create_sampler = [&](f32 anisotropy, VkFilter mag, VkFilter min, + VkSamplerMipmapMode mipmap) { return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .pNext = pnext, .flags = 0, - .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter), - .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter), - .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter), + .magFilter = mag, + .minFilter = min, + .mipmapMode = mipmap, .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter), .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter), .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter), @@ -2258,12 +2277,34 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t }); }; - sampler = create_sampler(max_anisotropy); + sampler = create_sampler(max_anisotropy, mag_filter, min_filter, mipmap_mode); const f32 max_anisotropy_default = static_cast(1U << tsc.max_anisotropy); if (max_anisotropy > max_anisotropy_default) { - sampler_default_anisotropy = create_sampler(max_anisotropy_default); + sampler_default_anisotropy = + create_sampler(max_anisotropy_default, mag_filter, min_filter, mipmap_mode); + } + + const bool needs_linear_fallback = (mag_filter == VK_FILTER_LINEAR) || + (min_filter == VK_FILTER_LINEAR) || + (mipmap_mode == VK_SAMPLER_MIPMAP_MODE_LINEAR) || + (max_anisotropy > 1.0f); + if (needs_linear_fallback) { + sampler_linear_fallback = + create_sampler(1.0f, VK_FILTER_NEAREST, VK_FILTER_NEAREST, + VK_SAMPLER_MIPMAP_MODE_NEAREST); + } +} + +VkSampler Sampler::HandleForView(bool supports_linear_filter, + bool supports_anisotropy) const noexcept { + if (!supports_linear_filter && sampler_linear_fallback) { + return *sampler_linear_fallback; + } + if (!supports_anisotropy && sampler_default_anisotropy) { + return *sampler_default_anisotropy; } + return *sampler; } Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span color_buffers, diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index cd11cc8fc7..bc33180254 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -258,6 +258,10 @@ public: return gpu_addr; } + [[nodiscard]] bool SupportsLinearFiltering() const noexcept { + return supports_linear_filtering; + } + [[nodiscard]] u32 BufferSize() const noexcept { return buffer_size; } @@ -266,6 +270,8 @@ private: struct StorageViews { std::array signeds; std::array unsigneds; + // Identity-swizzled views for typeless storage bindings + std::array typeless; }; [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask); @@ -283,6 +289,7 @@ private: VkImageView render_target = VK_NULL_HANDLE; VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; u32 buffer_size = 0; + bool supports_linear_filtering = true; }; class ImageAlloc : public VideoCommon::ImageAllocBase {}; @@ -303,9 +310,13 @@ public: return static_cast(sampler_default_anisotropy); } + [[nodiscard]] VkSampler HandleForView(bool supports_linear_filter, + bool supports_anisotropy) const noexcept; + private: vk::Sampler sampler; vk::Sampler sampler_default_anisotropy; + vk::Sampler sampler_linear_fallback; }; class Framebuffer {