From 7956a381304d436a1db94537bee04508bee74806 Mon Sep 17 00:00:00 2001 From: butilly Date: Mon, 9 Nov 2026 13:52:16 +0000 Subject: [PATCH] KOTOR II: bounded Zink texture sampling diagnostics --- src/vulkan/wrapper/wrapper_device.c | 92 +++++++++++++- src/vulkan/wrapper/wrapper_private.h | 1 + src/vulkan/wrapper/wrapper_texture_diag.h | 140 ++++++++++++++++++++++ 3 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 src/vulkan/wrapper/wrapper_texture_diag.h diff --git a/src/vulkan/wrapper/wrapper_device.c b/src/vulkan/wrapper/wrapper_device.c index 2602532d383..a26a7dd7fd4 100644 --- a/src/vulkan/wrapper/wrapper_device.c +++ b/src/vulkan/wrapper/wrapper_device.c @@ -22,6 +22,8 @@ #include "vk_util.h" #include "util/list.h" #include "util/simple_mtx.h" +#include "util/u_atomic.h" +#include "wrapper_texture_diag.h" const struct vk_device_extension_table wrapper_device_extensions = { @@ -595,6 +597,43 @@ wrapper_create_device_queue(struct wrapper_device *device, return VK_SUCCESS; } +VKAPI_ATTR VkResult VKAPI_CALL +wrapper_CreateSampler(VkDevice _device, const VkSamplerCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) +{ + VK_FROM_HANDLE(wrapper_device, device, _device); + VkResult result = device->dispatch_table.CreateSampler(device->dispatch_handle, + pCreateInfo, pAllocator, pSampler); + static unsigned count; + if (texture_diag_budget(device, &count, 256, "sampler")) { + const VkSamplerCreateInfo *s = pCreateInfo; + fprintf(stderr, "[WRAPPER_SAMPLE] sampler dev=%p result=%d handle=%llx flags=%x filter=%d,%d mip=%d address=%d,%d,%d lod=%g,%g bias=%g anisotropy=%u,%g compare=%u,%d border=%d unnormalized=%u\n", + (void *)device, result, result == VK_SUCCESS ? (unsigned long long)*pSampler : 0, + s->flags, s->minFilter, s->magFilter, s->mipmapMode, + s->addressModeU, s->addressModeV, s->addressModeW, + s->minLod, s->maxLod, s->mipLodBias, s->anisotropyEnable, s->maxAnisotropy, + s->compareEnable, s->compareOp, s->borderColor, s->unnormalizedCoordinates); + const VkBaseInStructure *ext = s->pNext; + for (unsigned i = 0; ext && i < 8; i++, ext = ext->pNext) + fprintf(stderr, "[WRAPPER_SAMPLE] sampler=%llx pnext=%d\n", + result == VK_SUCCESS ? (unsigned long long)*pSampler : 0, ext->sType); + } + return result; +} + +VKAPI_ATTR void VKAPI_CALL +wrapper_UpdateDescriptorSetWithTemplate(VkDevice _device, VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplate descriptorUpdateTemplate, + const void *pData) +{ + VK_FROM_HANDLE(wrapper_device, device, _device); + texture_diag_template_update(device, descriptorUpdateTemplate, (uint64_t)descriptorSet, pData); + PFN_vkUpdateDescriptorSetWithTemplate update = device->dispatch_table.UpdateDescriptorSetWithTemplate + ? device->dispatch_table.UpdateDescriptorSetWithTemplate + : device->dispatch_table.UpdateDescriptorSetWithTemplateKHR; + update(device->dispatch_handle, descriptorSet, descriptorUpdateTemplate, pData); +} + static void wrapper_create_null_resources(struct wrapper_device *device) { @@ -674,6 +713,18 @@ wrapper_UpdateDescriptorSets(VkDevice _device, uint32_t descriptorWriteCount, { VK_FROM_HANDLE(wrapper_device, device, _device); VkWriteDescriptorSet *fold_writes = (VkWriteDescriptorSet *)pDescriptorWrites; + texture_diag_writes(device, "write", descriptorWriteCount, pDescriptorWrites); + static unsigned copy_count; + if (descriptorCopyCount && texture_diag_budget(device, ©_count, 128, "descriptor-copy")) { + for (uint32_t i = 0; i < MIN2(descriptorCopyCount, 32); i++) { + const VkCopyDescriptorSet *c = &pDescriptorCopies[i]; + fprintf(stderr, "[WRAPPER_SAMPLE] copy dev=%p src=%llx:%u:%u dst=%llx:%u:%u count=%u\n", + (void *)device, (unsigned long long)c->srcSet, c->srcBinding, c->srcArrayElement, + (unsigned long long)c->dstSet, c->dstBinding, c->dstArrayElement, c->descriptorCount); + } + if (descriptorCopyCount > 32) + fprintf(stderr, "[WRAPPER_SAMPLE] copies truncated to 32 of %u\n", descriptorCopyCount); + } VkCopyDescriptorSet *fold_copies = (VkCopyDescriptorSet *)pDescriptorCopies; if (device->fold_sets && wrapper_fold_remap_updates(device, &descriptorWriteCount, &fold_writes, @@ -741,6 +792,7 @@ wrapper_UpdateDescriptorSets(VkDevice _device, uint32_t descriptorWriteCount, device->dispatch_table.UpdateDescriptorSets(device->dispatch_handle, descriptorWriteCount, writes, descriptorCopyCount, pDescriptorCopies); + texture_diag_writes(device, "native-write", descriptorWriteCount, writes); for (uint32_t i = 0; i < descriptorWriteCount; i++) { if (writes[i].pBufferInfo != pDescriptorWrites[i].pBufferInfo) @@ -2227,6 +2279,20 @@ wrapper_CreateImageView(VkDevice _device, result = device->dispatch_table.CreateImageView(device->dispatch_handle, &create_info, pAllocator, pView); + static unsigned view_count; + if (texture_diag_budget(device, &view_count, 1024, "image-view")) { + const VkImageSubresourceRange *r = &create_info.subresourceRange; + fprintf(stderr, "[WRAPPER_SAMPLE] view dev=%p result=%d handle=%llx image=%llx type=%d fmt=%d->%d swizzle=%d,%d,%d,%d aspect=%x mip=%u+%u->%u+%u layer=%u+%u pnext=%d\n", + (void *)device, result, result == VK_SUCCESS ? (unsigned long long)*pView : 0, + (unsigned long long)create_info.image, create_info.viewType, + pCreateInfo->format, create_info.format, + create_info.components.r, create_info.components.g, + create_info.components.b, create_info.components.a, r->aspectMask, + pCreateInfo->subresourceRange.baseMipLevel, pCreateInfo->subresourceRange.levelCount, + r->baseMipLevel, r->levelCount, r->baseArrayLayer, r->layerCount, + create_info.pNext ? ((const VkBaseInStructure *)create_info.pNext)->sType : 0); + } + if (result != VK_SUCCESS) WRAPPER_LOG(error, "Failed to create image view, res %d", result); /* Only the lowering paths read this table, and populating it costs an @@ -2804,6 +2870,7 @@ wrapper_CmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, const VkWriteDescriptorSet *pDescriptorWrites) { VK_FROM_HANDLE(wrapper_command_buffer, wcb, commandBuffer); + texture_diag_writes(wcb->device, "push-write", descriptorWriteCount, pDescriptorWrites); if (!wcb->device->emulate_push_descriptor) { wcb->device->dispatch_table.CmdPushDescriptorSetKHR(wcb->dispatch_handle, pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites); @@ -2861,6 +2928,7 @@ wrapper_CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer, const void *pData) { VK_FROM_HANDLE(wrapper_command_buffer, wcb, commandBuffer); + texture_diag_template_update(wcb->device, descriptorUpdateTemplate, (uint64_t)layout, pData); if (!wcb->device->emulate_push_descriptor) { wcb->device->dispatch_table.CmdPushDescriptorSetWithTemplateKHR( wcb->dispatch_handle, descriptorUpdateTemplate, layout, set, pData); @@ -3110,6 +3178,16 @@ wrapper_CmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets) { VK_FROM_HANDLE(wrapper_command_buffer, wcb, commandBuffer); + static unsigned bind_count; + if (texture_diag_budget(wcb->device, &bind_count, 512, "bind")) { + for (uint32_t i = 0; i < MIN2(descriptorSetCount, 16); i++) + fprintf(stderr, "[WRAPPER_SAMPLE] bind dev=%p cmd=%p point=%d layout=%llx set=%u handle=%llx dynamicOffsets=%u folded=%d\n", + (void *)wcb->device, (void *)wcb, pipelineBindPoint, + (unsigned long long)layout, firstSet + i, + (unsigned long long)pDescriptorSets[i], dynamicOffsetCount, wcb->device->fold_sets); + if (descriptorSetCount > 16) + fprintf(stderr, "[WRAPPER_SAMPLE] bind truncated to 16 of %u\n", descriptorSetCount); + } if (wcb->device->fold_sets && wrapper_fold_bind(wcb, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets)) @@ -3169,8 +3247,11 @@ wrapper_CreateDescriptorUpdateTemplate(VkDevice _device, VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate) { VK_FROM_HANDLE(wrapper_device, device, _device); - return wrapper_create_update_template(device, pCreateInfo, pAllocator, - pDescriptorUpdateTemplate); + VkResult result = wrapper_create_update_template(device, pCreateInfo, pAllocator, + pDescriptorUpdateTemplate); + if (result == VK_SUCCESS) + texture_diag_template_create(device, *pDescriptorUpdateTemplate, pCreateInfo); + return result; } static void @@ -3179,6 +3260,7 @@ wrapper_destroy_update_template(struct wrapper_device *device, const VkAllocationCallbacks *pAllocator) { const struct vk_device_dispatch_table *dt = &device->dispatch_table; + texture_diag_template_destroy(device, descriptorUpdateTemplate); if (device->emulate_push_descriptor && descriptorUpdateTemplate) { simple_mtx_lock(&device->push_mutex); struct wrapper_push_template *rec = _mesa_hash_table_u64_search( @@ -6284,6 +6366,12 @@ wrapper_DestroyDevice(VkDevice _device, const VkAllocationCallbacks* pAllocator) { VK_FROM_HANDLE(wrapper_device, device, _device); + while (device->texture_diag_templates) { + struct wrapper_texture_template *r = device->texture_diag_templates; + device->texture_diag_templates = r->next; + free(r); + } + wrapper_query_reset_finish(device); simple_mtx_lock(&device->resource_mutex); diff --git a/src/vulkan/wrapper/wrapper_private.h b/src/vulkan/wrapper/wrapper_private.h index d87b019ba39..f54bc1c4b95 100644 --- a/src/vulkan/wrapper/wrapper_private.h +++ b/src/vulkan/wrapper/wrapper_private.h @@ -95,6 +95,7 @@ struct wrapper_device { struct hash_table_u64 *device_only_memory; /* allocations the host cannot map */ struct hash_table_u64 *image_table; struct hash_table_u64 *image_view_table; + struct wrapper_texture_template *texture_diag_templates; struct hash_table_u64 *imageless_fb_table; struct hash_table_u64 *dynamic_pipeline_table; struct hash_table_u64 *stride_pipeline_table; diff --git a/src/vulkan/wrapper/wrapper_texture_diag.h b/src/vulkan/wrapper/wrapper_texture_diag.h new file mode 100644 index 00000000000..6087abf2135 --- /dev/null +++ b/src/vulkan/wrapper/wrapper_texture_diag.h @@ -0,0 +1,140 @@ +/* Temporary, bounded Zink diagnostic; never changes rendering state. + * Metadata is device-owned and protected by resource_mutex. Unlogged state + * after a limit is unknown, not evidence that an operation was unused. */ +struct wrapper_texture_template { + struct wrapper_texture_template *next; + VkDescriptorUpdateTemplate handle; + uint32_t count; + VkDescriptorUpdateTemplateEntry entries[]; +}; + +static bool +texture_diag_enabled(struct wrapper_device *d) +{ + const char *e = d->physical->instance->vk.app_info.engine_name; + return e && !strcmp(e, "mesa zink"); +} + +static bool +texture_diag_budget(struct wrapper_device *d, unsigned *counter, + unsigned limit, const char *kind) +{ + if (!texture_diag_enabled(d)) return false; + unsigned n = p_atomic_inc_return(counter); + if (n == limit + 1) + fprintf(stderr, "[WRAPPER_SAMPLE] %s initial limit=%u; then every 4096th call up to call 262144; gaps are unknown\n", kind, limit); + return n <= limit || (n <= 262144 && n % 4096 == 0); +} + +static bool +texture_diag_image_type(VkDescriptorType t) +{ + return t == VK_DESCRIPTOR_TYPE_SAMPLER || + t == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + t == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + t == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + t == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; +} + +static void +texture_diag_image(struct wrapper_device *d, const char *path, uint64_t owner, + uint32_t binding, uint32_t element, VkDescriptorType t, + const VkDescriptorImageInfo *i) +{ + static unsigned count; + if (!texture_diag_budget(d, &count, 2048, "descriptor-image")) return; + /* Ignore fields not used by this descriptor type. */ + bool s = t == VK_DESCRIPTOR_TYPE_SAMPLER || t == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bool v = t != VK_DESCRIPTOR_TYPE_SAMPLER; + fprintf(stderr, "[WRAPPER_SAMPLE] %s dev=%p owner=%llx binding=%u element=%u type=%d sampler=%llx view=%llx layout=%d\n", + path, (void *)d, (unsigned long long)owner, binding, element, t, + s ? (unsigned long long)i->sampler : 0, + v ? (unsigned long long)i->imageView : 0, v ? i->imageLayout : 0); +} + +static void +texture_diag_writes(struct wrapper_device *d, const char *path, + uint32_t count, const VkWriteDescriptorSet *writes) +{ + static unsigned batches; + if (!texture_diag_budget(d, &batches, 512, "write-batch")) return; + for (uint32_t k = 0; k < MIN2(count, 64); k++) { + const VkWriteDescriptorSet *w = &writes[k]; + if (!texture_diag_image_type(w->descriptorType) || !w->pImageInfo) continue; + for (uint32_t j = 0; j < MIN2(w->descriptorCount, 32); j++) + texture_diag_image(d, path, !strcmp(path, "push-write") ? 0 : (uint64_t)w->dstSet, w->dstBinding, + w->dstArrayElement + j, w->descriptorType, &w->pImageInfo[j]); + if (w->descriptorCount > 32) + fprintf(stderr, "[WRAPPER_SAMPLE] array truncated to 32 of %u\n", w->descriptorCount); + } + if (count > 64) fprintf(stderr, "[WRAPPER_SAMPLE] writes truncated to 64 of %u\n", count); +} + +static void +texture_diag_template_create(struct wrapper_device *d, VkDescriptorUpdateTemplate h, + const VkDescriptorUpdateTemplateCreateInfo *i) +{ + static unsigned count; + if (!texture_diag_budget(d, &count, 128, "template-create")) return; + uint32_t n = MIN2(i->descriptorUpdateEntryCount, 64); + struct wrapper_texture_template *r = calloc(1, sizeof(*r) + n * sizeof(r->entries[0])); + if (!r) { + fprintf(stderr, "[WRAPPER_SAMPLE] metadata allocation failed; template unknown\n"); + return; + } + r->handle = h; r->count = n; + if (n) memcpy(r->entries, i->pDescriptorUpdateEntries, n * sizeof(r->entries[0])); + simple_mtx_lock(&d->resource_mutex); + r->next = d->texture_diag_templates; d->texture_diag_templates = r; + simple_mtx_unlock(&d->resource_mutex); + fprintf(stderr, "[WRAPPER_SAMPLE] template dev=%p handle=%llx type=%d entries=%u captured=%u\n", + (void *)d, (unsigned long long)h, i->templateType, i->descriptorUpdateEntryCount, n); +} + +static void +texture_diag_template_destroy(struct wrapper_device *d, VkDescriptorUpdateTemplate h) +{ + simple_mtx_lock(&d->resource_mutex); + struct wrapper_texture_template **p = &d->texture_diag_templates; + while (*p) { + if ((*p)->handle == h) { + struct wrapper_texture_template *r = *p; *p = r->next; free(r); break; + } + p = &(*p)->next; + } + simple_mtx_unlock(&d->resource_mutex); +} + +static void +texture_diag_template_update(struct wrapper_device *d, VkDescriptorUpdateTemplate h, + uint64_t owner, const void *data) +{ + static unsigned count; + if (!texture_diag_budget(d, &count, 512, "template-update")) return; + simple_mtx_lock(&d->resource_mutex); + struct wrapper_texture_template *r = d->texture_diag_templates; + while (r && r->handle != h) r = r->next; + fprintf(stderr, "[WRAPPER_SAMPLE] template-update dev=%p template=%llx owner=%llx tracked=%d\n", + (void *)d, (unsigned long long)h, (unsigned long long)owner, r != NULL); + if (r) for (uint32_t k = 0; k < r->count; k++) { + const VkDescriptorUpdateTemplateEntry *e = &r->entries[k]; + if (!texture_diag_image_type(e->descriptorType)) continue; + for (uint32_t j = 0; j < MIN2(e->descriptorCount, 32); j++) { + VkDescriptorImageInfo image = {0}; + const char *src = (const char *)data + e->offset + j * e->stride; + /* The caller need only provide the members used by the type. */ + if (e->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + e->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) + memcpy(&image.sampler, src + offsetof(VkDescriptorImageInfo, sampler), sizeof(image.sampler)); + if (e->descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) { + memcpy(&image.imageView, src + offsetof(VkDescriptorImageInfo, imageView), sizeof(image.imageView)); + memcpy(&image.imageLayout, src + offsetof(VkDescriptorImageInfo, imageLayout), sizeof(image.imageLayout)); + } + texture_diag_image(d, "template-image", owner, e->dstBinding, + e->dstArrayElement + j, e->descriptorType, &image); + } + if (e->descriptorCount > 32) + fprintf(stderr, "[WRAPPER_SAMPLE] template array truncated to 32 of %u\n", e->descriptorCount); + } + simple_mtx_unlock(&d->resource_mutex); +}