Merge branch 'nvk/debug-no-compression' into 'main'

nvk: Compression cleanups and a debug flag

See merge request mesa/mesa!41397
This commit is contained in:
Faith Ekstrand 2026-05-08 00:09:27 +00:00
commit fca2f91145
4 changed files with 68 additions and 53 deletions

View file

@ -76,6 +76,8 @@ specific to NVK:
``coherent``
Forces all memory maps to be coherent with the CPU caches. This only
applies to Tegra devices.
``no_compression``
Disables image compression.
.. envvar:: NVK_I_WANT_A_BROKEN_VULKAN_DRIVER

View file

@ -42,6 +42,9 @@ enum nvk_debug {
/* Force all memory allocations to go to GART */
NVK_DEBUG_FORCE_COHERENT = 1ull << 8,
/* Disable image compression */
NVK_DEBUG_NO_COMPRESSION = 1ull << 9,
};
#endif /* NVK_DEBUG_H */

View file

@ -772,61 +772,68 @@ nvk_GetPhysicalDeviceSparseImageFormatProperties2(
}
}
/* To use compression and larger page sizes, we need to signal to the kernel
* that the memory requested is going to be VRAM resident. However, this
* comes with an issue where said memory can't be evicted to host RAM under
* pressure, so we work around this by going with a dedicated allocation for
* color, Z/S, and storage image targets which are the main types that would
* benefit from compression as they're heavy on writes. Additionally, they
* also aren't the majority of memory used, so they can be safely pinned in
* VRAM without worrying about eviction under high pressure.
*
* There are some additional restrictions we need to keep in mind, however:
* 1. We can only enable this for Turing onwards because prior architectures
* relied on firmware to manage the compression tags, and it's impossible to
* do this on nouveau. Additionally, since compression needs kernel changes,
* we can only enable it if the detected kernel supports it.
*
* 2. Given our approach depends on dedicated allocations, we can't enable
* compression for sparse images as dedicated allocations are not compatible
* with sparse.
*
* 3. In similar vein, we currently don't do multiplanar dedicated allocations
* so we can't do compression for multi-plane YCbCr images.
*
* 4. Host copies are a complete no-go for compression as the host doesn't know
* about the modified data layout nor the compression tags.
*
* 5. The API for VK_EXT_image_drm_format_modifier requires that we report the
* supported modifiers in GetPhysicalDeviceFormatProperties2(). However,
* since we can only know whether an image is compressed or not at bind time
* we can't actually expose any of the compressed modifiers in case the app
* chooses a compressed modifier for a non-compressed image. So for now, we
* have to disable compression for TILING_DRM_FORMAT_MODIFIER_EXT images.
*
* This helper enforces these restrictions and also makes sure to enable
* compression for storage, color, and Z/S targets only so as to avoid pinning
* too many things to VRAM.
*/
static bool
nvk_image_can_compress(const struct nvkmd_pdev *nvkmd_pdev,
nvk_image_can_compress(const struct nvk_physical_device *pdev,
const struct nvk_image *image)
{
if (nvkmd_pdev->kmd_info.has_compression) {
if (image->plane_count > 1 ||
image->vk.usage & (VK_IMAGE_USAGE_HOST_TRANSFER_BIT) ||
image->vk.create_flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT))
return false;
else if (image->vk.usage & (VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
image->vk.tiling == VK_IMAGE_TILING_OPTIMAL)
return true;
else
return false;
} else
if (pdev->debug_flags & NVK_DEBUG_NO_COMPRESSION)
return false;
if (!pdev->nvkmd->kmd_info.has_compression)
return false;
/* Our host copy code does not understand compression */
if (image->vk.usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT)
return false;
/* Our compression strategy depends on dedicated allocations, so we can't
* enable compression for sparse images as dedicated allocations are not
* compatible with sparse.
*/
if (image->vk.create_flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT))
return false;
/* In similar vein, we currently don't do multiplanar dedicated allocations
* so we can't do compression for multi-plane YCbCr images.
*/
if (image->plane_count > 1)
return false;
/* Linear images cannot be compressed. */
if (image->vk.tiling == VK_IMAGE_TILING_LINEAR)
return false;
/* The API for VK_EXT_image_drm_format_modifier requires that we report the
* supported modifiers in GetPhysicalDeviceFormatProperties2(). However,
* since we can only know whether an image is compressed or not at bind
* time we can't actually expose any of the compressed modifiers in case
* the app chooses a compressed modifier for a non-compressed image. So for
* now, we have to disable compression for TILING_DRM_FORMAT_MODIFIER_EXT
* images.
*/
if (image->vk.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
return false;
assert(image->vk.tiling == VK_IMAGE_TILING_OPTIMAL);
/* To use compression and larger page sizes, we need to signal to the
* kernel that the memory requested is going to be VRAM resident. However,
* this comes with an issue where said memory can't be evicted to host RAM
* under pressure.
*
* So we work around this by only allowing compression for color, Z/S, and
* storage image targets which are the main types that would benefit from
* compression as they're heavy on writes. Additionally, they also aren't
* the majority of memory used, so they can be safely pinned in VRAM
* without worrying about eviction under high pressure.
*/
if (!(image->vk.usage & (VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)))
return false;
return true;
}
static VkResult
@ -883,7 +890,7 @@ nvk_image_init(struct nvk_device *dev,
* in GetImageMemoryRequirements() we are able to detect it and specify that
* we prefer a dedicated allocation for it.
*/
image->can_compress = nvk_image_can_compress(dev->nvkmd->pdev, image);
image->can_compress = nvk_image_can_compress(pdev, image);
if (!image->can_compress)
usage |= NIL_IMAGE_USAGE_UNCOMPRESSED_BIT;
@ -1156,7 +1163,7 @@ nvk_image_init(struct nvk_device *dev,
image->image_align_B = MAX2(image->stencil_copy_temp.plane_align_B,
image->image_align_B);
}
return VK_SUCCESS;
}
@ -1165,6 +1172,7 @@ nvk_image_plane_alloc_va(struct nvk_device *dev,
const struct nvk_image *image,
struct nvk_image_plane *plane)
{
assert(plane->va == NULL);
VkResult result;
const bool sparse_bound =
@ -1610,6 +1618,7 @@ nvk_image_plane_bind(struct nvk_device *dev,
VkResult result = nvk_image_plane_alloc_va(dev, image, plane);
if (result != VK_SUCCESS)
return result;
result = nvkmd_va_bind_mem(plane->va, &image->vk.base, 0,
mem->mem, offset_B,
plane->va->size_B);

View file

@ -91,6 +91,7 @@ nvk_init_debug_flags(struct nvk_instance *instance)
{ "edb_bview", NVK_DEBUG_FORCE_EDB_BVIEW },
{ "gart", NVK_DEBUG_FORCE_GART },
{ "coherent", NVK_DEBUG_FORCE_COHERENT },
{ "no_compression", NVK_DEBUG_NO_COMPRESSION },
{ NULL, 0 },
};