panvk/v10+: Implement nullDescriptor support

Adds support for nullDescriptors in PanVK by memsetting the relevant
descriptors to zero. This is valid for v9+.

Note that vertex/index buffers require special handling in order to rely
on out-of-bounds behavior.
For index buffers specifically, the approach is only valid for v10+, as
v9 does not have a way to specify index buffer size.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35609>
This commit is contained in:
Lars-Ivar Hesselberg Simonsen 2025-06-17 12:25:16 +02:00 committed by Marge Bot
parent bbe3c7e1a3
commit a789867cb4
3 changed files with 109 additions and 46 deletions

View file

@ -311,7 +311,9 @@ prepare_vs_driver_set(struct panvk_cmd_buffer *cmdbuf,
emit_vs_attrib(cmdbuf, i, vb_offset,
(struct mali_attribute_packed *)(&descs[i]));
} else {
memset(&descs[i], 0, sizeof(descs[0]));
/* Write a NullDescriptor and rely on OOB behavior */
pan_cast_and_pack(&descs[i], NULL_DESCRIPTOR, cfg)
;
}
}
@ -326,15 +328,17 @@ prepare_vs_driver_set(struct panvk_cmd_buffer *cmdbuf,
for (uint32_t i = 0; i < vb_count; i++) {
const struct panvk_attrib_buf *vb = &cmdbuf->state.gfx.vb.bufs[i];
const bool nulldesc = (vb->address == 0 && vb->size == 0);
pan_cast_and_pack(&descs[vb_offset + i], BUFFER, cfg) {
if (vi->bindings_valid & BITFIELD_BIT(i)) {
if ((vi->bindings_valid & BITFIELD_BIT(i)) && !nulldesc) {
pan_cast_and_pack(&descs[vb_offset + i], BUFFER, cfg) {
cfg.address = vb->address;
cfg.size = vb->size;
} else {
cfg.address = 0;
cfg.size = 0;
}
} else {
/* Write a NullDescriptor and rely on OOB behavior */
pan_cast_and_pack(&descs[vb_offset + i], NULL_DESCRIPTOR, cfg)
;
}
}
@ -2634,7 +2638,7 @@ panvk_per_arch(CmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer,
VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
VK_FROM_HANDLE(panvk_buffer, buffer, _buffer);
if (drawCount == 0 || cmdbuf->state.gfx.ib.size == 0)
if (drawCount == 0)
return;
struct panvk_draw_info draw = {
@ -2687,7 +2691,7 @@ panvk_per_arch(CmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer,
VK_FROM_HANDLE(panvk_buffer, buffer, _buffer);
VK_FROM_HANDLE(panvk_buffer, count_buffer, countBuffer);
if (maxDrawCount == 0 || cmdbuf->state.gfx.ib.size == 0)
if (maxDrawCount == 0)
return;
struct panvk_draw_info draw = {

View file

@ -872,10 +872,15 @@ panvk_per_arch(CmdBindVertexBuffers2)(VkCommandBuffer commandBuffer,
for (uint32_t i = 0; i < bindingCount; i++) {
VK_FROM_HANDLE(panvk_buffer, buffer, pBuffers[i]);
cmdbuf->state.gfx.vb.bufs[firstBinding + i].address =
panvk_buffer_gpu_ptr(buffer, pOffsets[i]);
cmdbuf->state.gfx.vb.bufs[firstBinding + i].size = panvk_buffer_range(
buffer, pOffsets[i], pSizes ? pSizes[i] : VK_WHOLE_SIZE);
if (buffer) {
cmdbuf->state.gfx.vb.bufs[firstBinding + i].address =
panvk_buffer_gpu_ptr(buffer, pOffsets[i]);
cmdbuf->state.gfx.vb.bufs[firstBinding + i].size = panvk_buffer_range(
buffer, pOffsets[i], pSizes ? pSizes[i] : VK_WHOLE_SIZE);
} else {
cmdbuf->state.gfx.vb.bufs[firstBinding + i].address = 0;
cmdbuf->state.gfx.vb.bufs[firstBinding + i].size = 0;
}
}
cmdbuf->state.gfx.vb.count =
@ -899,15 +904,18 @@ panvk_per_arch(CmdBindIndexBuffer2)(VkCommandBuffer commandBuffer,
cmdbuf->state.gfx.ib.host_addr =
buf && buf->host_ptr ? buf->host_ptr + offset : NULL;
#endif
cmdbuf->state.gfx.ib.index_size = vk_index_type_to_bytes(indexType);
} else {
cmdbuf->state.gfx.ib.size = 0;
cmdbuf->state.gfx.ib.dev_addr = 0;
/* In case of NullDescriptors, we need to set a non-NULL address and rely
* on out-of-bounds behavior against the zero size of the buffer. Note
* that this only works for v10+, as v9 does not have a way to specify the
* index buffer size. */
cmdbuf->state.gfx.ib.dev_addr = PAN_ARCH >= 10 ? 0x1000 : 0;
#if PAN_ARCH < 9
cmdbuf->state.gfx.ib.host_addr = 0;
#endif
cmdbuf->state.gfx.ib.index_size = 0;
}
cmdbuf->state.gfx.ib.index_size = vk_index_type_to_bytes(indexType);
gfx_state_set_dirty(cmdbuf, IB);
}

View file

@ -55,6 +55,20 @@ get_desc_slot_ptr(struct panvk_descriptor_set *set, uint32_t binding,
memcpy(__dst, (desc), PANVK_DESCRIPTOR_SIZE); \
} while (0)
#if PAN_ARCH >= 9
#define write_nulldesc(set, binding, elem, subdesc) \
do { \
struct mali_null_descriptor_packed null_desc; \
pan_pack(&null_desc, NULL_DESCRIPTOR, cfg) \
; \
write_desc(set, binding, elem, &null_desc, (subdesc)); \
} while (0)
#else
#define write_nulldesc(set, binding, elem, subdesc) \
do { \
} while (0)
#endif
static void
write_sampler_desc(struct panvk_descriptor_set *set,
const VkDescriptorImageInfo *const pImageInfo,
@ -63,20 +77,25 @@ write_sampler_desc(struct panvk_descriptor_set *set,
const struct panvk_descriptor_set_binding_layout *binding_layout =
&set->layout->bindings[binding];
if (binding_layout->immutable_samplers && !write_immutable)
return;
struct panvk_sampler *sampler;
if (binding_layout->immutable_samplers) {
if (!write_immutable)
return;
sampler = binding_layout->immutable_samplers[elem];
} else {
sampler = panvk_sampler_from_handle(
pImageInfo ? pImageInfo->sampler : VK_NULL_HANDLE);
if (!pImageInfo)
return;
sampler = panvk_sampler_from_handle(pImageInfo->sampler);
}
if (!sampler)
if (!sampler) {
for (uint8_t plane = 0; plane < binding_layout->samplers_per_desc;
plane++)
write_nulldesc(set, binding, elem,
get_sampler_subdesc_info(binding_layout->type, plane));
return;
}
for (uint8_t plane = 0; plane < sampler->desc_count; plane++) {
write_desc(set, binding, elem, &sampler->descs[plane],
@ -89,26 +108,38 @@ write_image_view_desc(struct panvk_descriptor_set *set,
const VkDescriptorImageInfo *const pImageInfo,
uint32_t binding, uint32_t elem, VkDescriptorType type)
{
if (pImageInfo && pImageInfo->imageView != VK_NULL_HANDLE) {
VK_FROM_HANDLE(panvk_image_view, view, pImageInfo->imageView);
if (!pImageInfo)
return;
uint8_t plane_count = vk_format_get_plane_count(view->vk.format);
for (uint8_t plane = 0; plane < plane_count; plane++) {
struct panvk_subdesc_info subdesc = get_tex_subdesc_info(type, plane);
const struct panvk_descriptor_set_binding_layout *binding_layout =
&set->layout->bindings[binding];
if (pImageInfo->imageView == VK_NULL_HANDLE) {
for (uint8_t plane = 0; plane < binding_layout->textures_per_desc;
plane++)
write_nulldesc(set, binding, elem,
get_sampler_subdesc_info(binding_layout->type, plane));
return;
}
VK_FROM_HANDLE(panvk_image_view, view, pImageInfo->imageView);
uint8_t plane_count = vk_format_get_plane_count(view->vk.format);
for (uint8_t plane = 0; plane < plane_count; plane++) {
struct panvk_subdesc_info subdesc = get_tex_subdesc_info(type, plane);
#if PAN_ARCH >= 9
if (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
write_desc(set, binding, elem, &view->descs.storage_tex[plane],
subdesc);
else
write_desc(set, binding, elem, &view->descs.tex[plane], subdesc);
if (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
write_desc(set, binding, elem, &view->descs.storage_tex[plane],
subdesc);
else
write_desc(set, binding, elem, &view->descs.tex[plane], subdesc);
#else
if (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
write_desc(set, binding, elem, &view->descs.img_attrib_buf,
NO_SUBDESC);
else
write_desc(set, binding, elem, &view->descs.tex[plane], subdesc);
if (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
write_desc(set, binding, elem, &view->descs.img_attrib_buf,
NO_SUBDESC);
else
write_desc(set, binding, elem, &view->descs.tex[plane], subdesc);
#endif
}
}
}
@ -117,6 +148,11 @@ write_buffer_desc(struct panvk_descriptor_set *set,
const VkDescriptorBufferInfo *const info, uint32_t binding,
uint32_t elem, VkDescriptorType type)
{
if (info->buffer == VK_NULL_HANDLE) {
write_nulldesc(set, binding, elem, NO_SUBDESC);
return;
}
VK_FROM_HANDLE(panvk_buffer, buffer, info->buffer);
const uint64_t range = panvk_buffer_range(buffer, info->offset, info->range);
assert(range <= UINT32_MAX);
@ -158,6 +194,11 @@ write_dynamic_buffer_desc(struct panvk_descriptor_set *set,
const VkDescriptorBufferInfo *const info,
uint32_t binding, uint32_t elem)
{
if (info->buffer == VK_NULL_HANDLE) {
write_nulldesc(set, binding, elem, NO_SUBDESC);
return;
}
VK_FROM_HANDLE(panvk_buffer, buffer, info->buffer);
const struct panvk_descriptor_set_binding_layout *binding_layout =
&set->layout->bindings[binding];
@ -177,19 +218,21 @@ write_buffer_view_desc(struct panvk_descriptor_set *set,
const VkBufferView bufferView, uint32_t binding,
uint32_t elem, VkDescriptorType type)
{
if (bufferView != VK_NULL_HANDLE) {
VK_FROM_HANDLE(panvk_buffer_view, view, bufferView);
if (bufferView == VK_NULL_HANDLE) {
write_nulldesc(set, binding, elem, NO_SUBDESC);
return;
}
VK_FROM_HANDLE(panvk_buffer_view, view, bufferView);
#if PAN_ARCH < 9
if (type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
write_desc(set, binding, elem, &view->descs.img_attrib_buf,
NO_SUBDESC);
else
write_desc(set, binding, elem, &view->descs.tex, NO_SUBDESC);
#else
if (type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
write_desc(set, binding, elem, &view->descs.img_attrib_buf, NO_SUBDESC);
else
write_desc(set, binding, elem, &view->descs.tex, NO_SUBDESC);
#else
write_desc(set, binding, elem, &view->descs.tex, NO_SUBDESC);
#endif
}
}
static void
@ -340,6 +383,14 @@ desc_set_write_immutable_samplers(struct panvk_descriptor_set *set,
for (uint32_t j = 0; j < array_size; j++) {
struct panvk_sampler *sampler =
layout->bindings[b].immutable_samplers[j];
if (!sampler) {
for (uint8_t plane = 0;
plane < layout->bindings[b].samplers_per_desc; plane++)
write_nulldesc(
set, b, j,
get_sampler_subdesc_info(layout->bindings[b].type, plane));
continue;
}
for (uint8_t plane = 0; plane < sampler->desc_count; plane++) {
write_desc(set, b, j,
&sampler->descs[plane],