From 8ffe0098be38000fdf1dc359fbda3f736821ba73 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Tue, 27 May 2025 17:02:54 -0400 Subject: [PATCH] nvk: Reserve a sampler for TXF on Kepler The SPIR-V spec says texelFetch and friends don't take a sampler. However, on Kepler and earlier hardware, the sampler is read even for tld. In particular, the hardware reads the sRGB conversion bit in the sampler and this can be in an inconsistent state if we haven't initialized samplers properly. On Kepler, we should just reserve a sampler at device creation time and always use that for tld. Part-of: --- src/nouveau/vulkan/nvk_device.c | 18 ++++++++++++++ .../vulkan/nvk_nir_lower_descriptors.c | 17 ++++++++++++- src/nouveau/vulkan/nvk_sampler.c | 24 +++++++++++++++++++ src/nouveau/vulkan/nvk_sampler.h | 8 +++---- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/nouveau/vulkan/nvk_device.c b/src/nouveau/vulkan/nvk_device.c index fb338ed2d4d..024677edc6d 100644 --- a/src/nouveau/vulkan/nvk_device.c +++ b/src/nouveau/vulkan/nvk_device.c @@ -8,6 +8,7 @@ #include "nvk_entrypoints.h" #include "nvk_instance.h" #include "nvk_physical_device.h" +#include "nvk_sampler.h" #include "nvk_shader.h" #include "nvkmd/nvkmd.h" @@ -200,6 +201,23 @@ nvk_CreateDevice(VkPhysicalDevice physicalDevice, if (result != VK_SUCCESS) goto fail_images; + /* On Kepler and earlier, TXF takes a sampler but SPIR-V defines it as not + * taking one so we need to reserve one at device create time. If we do so + * now then it will always have sampler index 0 so we can rely on that in + * the compiler lowering code (similar to null descriptors). + */ + if (pdev->info.cls_eng3d < MAXWELL_A) { + uint32_t txf_sampler[8] = {}; + nvk_fill_txf_sampler_header(pdev, txf_sampler); + + ASSERTED uint32_t txf_sampler_index; + result = nvk_descriptor_table_add(dev, &dev->samplers, + txf_sampler, sizeof(txf_sampler), + &txf_sampler_index); + assert(result == VK_SUCCESS); + assert(txf_sampler_index == 0); + } + if (dev->vk.enabled_features.descriptorBuffer || nvk_use_edb_buffer_views(pdev)) { result = nvk_edb_bview_cache_init(dev, &dev->edb_bview_cache); diff --git a/src/nouveau/vulkan/nvk_nir_lower_descriptors.c b/src/nouveau/vulkan/nvk_nir_lower_descriptors.c index ff24dab65a9..9193a39f953 100644 --- a/src/nouveau/vulkan/nvk_nir_lower_descriptors.c +++ b/src/nouveau/vulkan/nvk_nir_lower_descriptors.c @@ -12,6 +12,7 @@ #include "nir_builder.h" #include "nir_deref.h" +#include "clb097.h" #include "clc397.h" #include "clc597.h" @@ -1301,7 +1302,21 @@ lower_tex(nir_builder *b, nir_tex_instr *tex, load_resource_deref_desc(b, 1, 32, texture, plane_offset_B, ctx); nir_def *combined_handle; - if (texture == sampler || !nir_tex_instr_need_sampler(tex)) { + + if (!nir_tex_instr_need_sampler(tex)) { + combined_handle = texture_desc; + + /* On Kepler and earlier, TXF takes a sampler but SPIR-V defines it as + * not taking one so we can't trust the sampler from the client's image + * descriptor. Instead, mask off the top bits so we get a zero sampler + * index which we've conveniently reserved at device cration time for a + * special TXF sampler. + */ + if (ctx->dev_info->cls_eng3d < MAXWELL_A) { + combined_handle = nir_iand_imm(b, combined_handle, + NVK_IMAGE_DESCRIPTOR_IMAGE_INDEX_MASK); + } + } else if (texture == sampler) { combined_handle = texture_desc; } else { combined_handle = nir_iand_imm(b, texture_desc, diff --git a/src/nouveau/vulkan/nvk_sampler.c b/src/nouveau/vulkan/nvk_sampler.c index bc2e8c9ce14..3ee6b252f13 100644 --- a/src/nouveau/vulkan/nvk_sampler.c +++ b/src/nouveau/vulkan/nvk_sampler.c @@ -282,6 +282,30 @@ nvk_sampler_fill_header(const struct nvk_physical_device *pdev, SAMP_SET_U(samp, NV9097, 7, BORDER_COLOR_A, bc.uint32[3]); } +void +nvk_fill_txf_sampler_header(const struct nvk_physical_device *pdev, + uint32_t *samp) +{ + const VkSamplerCreateInfo sampler_info = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = VK_FILTER_NEAREST, + .minFilter = VK_FILTER_NEAREST, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, + .minLod = 0.0, + .maxLod = 16.0, + .unnormalizedCoordinates = true, + }; + + struct vk_sampler sampler; + vk_sampler_init(&sampler_info, &sampler); + + nvk_sampler_fill_header(pdev, &sampler_info, &sampler, samp); +} + VKAPI_ATTR VkResult VKAPI_CALL nvk_CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, diff --git a/src/nouveau/vulkan/nvk_sampler.h b/src/nouveau/vulkan/nvk_sampler.h index 06b44cf3a7e..e1337c82716 100644 --- a/src/nouveau/vulkan/nvk_sampler.h +++ b/src/nouveau/vulkan/nvk_sampler.h @@ -32,10 +32,8 @@ struct nvk_sampler_capture { } planes[NVK_MAX_SAMPLER_PLANES]; }; -static void -nvk_sampler_fill_header(const struct nvk_physical_device *pdev, - const struct VkSamplerCreateInfo *info, - const struct vk_sampler *vk_sampler, - uint32_t *samp); +void +nvk_fill_txf_sampler_header(const struct nvk_physical_device *pdev, + uint32_t *samp); #endif