From 54c3d10b868806b4d79a919893c7626550244ef7 Mon Sep 17 00:00:00 2001 From: xbzk Date: Thu, 2 Jul 2026 03:23:08 +0200 Subject: [PATCH] [vk, renderdoc] (VUID-02997) avoid vk_image_view as VK_NULL_HANDLE when feature nullDescriptor is unavailable (#4056) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This minor change in src\video_core\renderer_vulkan\pipeline_helper.h allows renderdoc capture on mhr sunbreak. Maybe it sanitizes some crashes on old vulkan GPUs. Device log (nvidia kepler gpu vulkan 1.1.117): [ 17.605262] Render.Vulkan video_core\vulkan_common\vulkan_device.cpp:1041:GetSuitability: Device doesn't support feature nullDescriptor VUID-VkWriteDescriptorSet-descriptorType-02997 For sampled/combined/storage image descriptors, Khronos says imageView must be valid or VK_NULL_HANDLE (https://docs.vulkan.org/refpages/latest/refpages/source/VkPhysicalDeviceRobustness2FeaturesKHR.html) but then it says: if nullDescriptor is not enabled, imageView must not be VK_NULL_HANDLE. (https://docs.vulkan.org/spec/latest/chapters/descriptorsets.html) nullDescriptor is exactly the feature that allows descriptors to be written with null handles. The fix relies on conditionally replacing the null sampled view with Eden’s dummy null-image-view object (ImageView constructor checks HasNullDescriptor which checks features.robustness2.nullDescriptor. cheap checks, and only for null handles, so no notable cost). Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4056 Reviewed-by: MaranBr Reviewed-by: CamilleLaVey --- src/video_core/renderer_vulkan/pipeline_helper.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 35c9379987..fce1f2e252 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -203,7 +203,11 @@ inline void PushImageDescriptors(TextureCache& texture_cache, const VideoCommon::ImageViewId image_view_id{(views++)->id}; const VideoCommon::SamplerId sampler_id{*(samplers++)}; ImageView& image_view{texture_cache.GetImageView(image_view_id)}; - const VkImageView vk_image_view{image_view.Handle(desc.type)}; + VkImageView vk_image_view{image_view.Handle(desc.type)}; + if (vk_image_view == VK_NULL_HANDLE) { + const VkImageView null_image_view{texture_cache.GetImageView(VideoCommon::NULL_IMAGE_VIEW_ID).Handle(desc.type)}; + if (null_image_view != VK_NULL_HANDLE) vk_image_view = null_image_view; + } const Sampler& sampler{texture_cache.GetSampler(sampler_id)}; const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && !image_view.SupportsAnisotropy()};