vkd3d: Add a crude form of alias debugging.

Report any placed aliases which could cause issues.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
Hans-Kristian Arntzen 2022-06-29 13:07:52 +02:00
parent b1e735ee8f
commit 2c42c0da93
4 changed files with 190 additions and 4 deletions

View File

@ -645,3 +645,116 @@ void vkd3d_breadcrumb_tracer_end_command_list(struct d3d12_command_list *list)
cmd.type = VKD3D_BREADCRUMB_COMMAND_SET_BOTTOM_MARKER;
vkd3d_breadcrumb_tracer_add_command(list, &cmd);
}
/* There is no obvious home for this code. It could be in heap.c, but this kind of
* debug is only really useful when doing crash debugging, i.e. breadcrumbs,
* so might as well have it here. */
static bool d3d12_resource_is_linear_placement(const struct d3d12_resource *resource)
{
return (resource->desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
!(resource->flags & VKD3D_RESOURCE_ACCELERATION_STRUCTURE)) ||
(resource->flags & VKD3D_RESOURCE_LINEAR_TILING);
}
static void d3d12_resource_report_parameters(char *buf, size_t buf_size, const struct d3d12_resource *resource)
{
if (resource->desc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER)
{
snprintf(buf, buf_size,
"IMAGE: format = %s, width = %"PRIu64", height = %u, depth/layers = %u, levels = %u, flags = #%x",
debug_dxgi_format(resource->desc.Format),
resource->desc.Width,
resource->desc.Height,
resource->desc.DepthOrArraySize,
resource->desc.MipLevels,
resource->desc.Flags);
}
else if (resource->flags & VKD3D_RESOURCE_ACCELERATION_STRUCTURE)
snprintf(buf, buf_size, "RTAS");
else
snprintf(buf, buf_size, "BUFFER");
}
void vkd3d_breadcrumb_tracer_register_placed_resource(struct d3d12_heap *heap,
struct d3d12_resource *resource,
VkDeviceSize heap_offset, VkDeviceSize required_size)
{
const struct d3d12_heap_resource_placement *placement;
bool candidate_resource_is_linear;
bool placed_resource_is_linear;
VkDeviceSize begin_overlap;
VkDeviceSize end_overlap;
char report_buffer[1024];
bool has_alias = false;
const char *msg;
size_t i;
/* Linear aliasing with other linear resources is fine.
* Image <-> Image, and Image <-> Buffer is far more dangerous however. */
placed_resource_is_linear = d3d12_resource_is_linear_placement(resource);
pthread_mutex_lock(&heap->placement_lock);
for (i = 0; i < heap->placements_count; i++)
{
placement = &heap->placements[i];
candidate_resource_is_linear = d3d12_resource_is_linear_placement(placement->resource);
begin_overlap = max(placement->heap_offset, heap_offset);
end_overlap = min(placement->heap_offset + placement->size, heap_offset + required_size);
if (begin_overlap < end_overlap && candidate_resource_is_linear != placed_resource_is_linear)
{
/* Overlap. */
/* Potentially problematic scenario, report this. */
if (!has_alias)
{
if (resource->desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
msg = "Attempting to place linear buffer resource on heap, placement aliases with non-linear layout.";
else
msg = "Attempting to place opaque resource on heap, placement aliases with other resources.";
d3d12_resource_report_parameters(report_buffer, sizeof(report_buffer), resource);
INFO("\n%s\n New placement: resource cookie = %"PRIu64", offset = %"PRIu64", size = %"PRIu64", VA = %"PRIx64"\n\t%s\n",
msg,
resource->res.cookie,
heap_offset, required_size, resource->res.va,
report_buffer);
has_alias = true;
}
d3d12_resource_report_parameters(report_buffer, sizeof(report_buffer), placement->resource);
INFO("\n Existing aliasing resource : cookie = %"PRIu64", offset = %"PRIu64", size = %"PRIu64".\n\t\t%s\n",
placement->resource->res.cookie, placement->heap_offset, placement->size,
report_buffer);
}
}
vkd3d_array_reserve((void**)&heap->placements, &heap->placements_size,
heap->placements_count + 1, sizeof(*heap->placements));
heap->placements[heap->placements_count].resource = resource;
heap->placements[heap->placements_count].heap_offset = heap_offset;
heap->placements[heap->placements_count].size = required_size;
heap->placements_count++;
pthread_mutex_unlock(&heap->placement_lock);
}
void vkd3d_breadcrumb_tracer_unregister_placed_resource(struct d3d12_heap *heap, struct d3d12_resource *resource)
{
size_t i;
pthread_mutex_lock(&heap->placement_lock);
for (i = 0; i < heap->placements_count; i++)
{
if (heap->placements[i].resource == resource)
{
heap->placements[i] = heap->placements[--heap->placements_count];
break;
}
}
pthread_mutex_unlock(&heap->placement_lock);
}

View File

@ -59,9 +59,13 @@ static void d3d12_heap_destroy(struct d3d12_heap *heap)
{
TRACE("Destroying heap %p.\n", heap);
#ifdef VKD3D_ENABLE_BREADCRUMBS
vkd3d_free(heap->placements);
pthread_mutex_destroy(&heap->placement_lock);
#endif
vkd3d_free_memory(heap->device, &heap->device->memory_allocator, &heap->allocation);
vkd3d_private_store_destroy(&heap->private_store);
d3d12_device_release(heap->device);
vkd3d_free(heap);
}
@ -72,6 +76,18 @@ static void d3d12_heap_set_name(struct d3d12_heap *heap, const char *name)
VK_OBJECT_TYPE_DEVICE_MEMORY, name);
}
void d3d12_heap_dec_ref(struct d3d12_heap *heap)
{
ULONG refcount = InterlockedDecrement(&heap->internal_refcount);
if (!refcount)
d3d12_heap_destroy(heap);
}
void d3d12_heap_inc_ref(struct d3d12_heap *heap)
{
InterlockedIncrement(&heap->internal_refcount);
}
static ULONG STDMETHODCALLTYPE d3d12_heap_Release(d3d12_heap_iface *iface)
{
struct d3d12_heap *heap = impl_from_ID3D12Heap1(iface);
@ -80,7 +96,11 @@ static ULONG STDMETHODCALLTYPE d3d12_heap_Release(d3d12_heap_iface *iface)
TRACE("%p decreasing refcount to %u.\n", heap, refcount);
if (!refcount)
d3d12_heap_destroy(heap);
{
struct d3d12_device *device = heap->device;
d3d12_heap_dec_ref(heap);
d3d12_device_release(device);
}
return refcount;
}
@ -225,6 +245,7 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap, struct d3d12_device *dev
memset(heap, 0, sizeof(*heap));
heap->ID3D12Heap_iface.lpVtbl = &d3d12_heap_vtbl;
heap->refcount = 1;
heap->internal_refcount = 1;
heap->desc = *desc;
heap->device = device;
@ -252,6 +273,10 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap, struct d3d12_device *dev
return hr;
}
#ifdef VKD3D_ENABLE_BREADCRUMBS
pthread_mutex_init(&heap->placement_lock, NULL);
#endif
d3d12_device_add_ref(heap->device);
return S_OK;
}

View File

@ -1419,7 +1419,14 @@ static ULONG d3d12_resource_decref(struct d3d12_resource *resource)
TRACE("%p decreasing refcount to %u.\n", resource, refcount);
if (!refcount)
{
VKD3D_UNUSED struct d3d12_heap *heap = resource->heap;
d3d12_resource_destroy(resource, resource->device);
#ifdef VKD3D_ENABLE_BREADCRUMBS
if (heap && (vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS))
d3d12_heap_dec_ref(heap);
#endif
}
return refcount;
}
@ -1511,7 +1518,6 @@ static ULONG STDMETHODCALLTYPE d3d12_resource_AddRef(d3d12_resource_iface *iface
if (refcount == 1)
{
struct d3d12_device *device = resource->device;
d3d12_device_add_ref(device);
d3d12_resource_incref(resource);
}
@ -2605,6 +2611,11 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12
if (resource->vrs_view)
VK_CALL(vkDestroyImageView(device->vk_device, resource->vrs_view, NULL));
#ifdef VKD3D_ENABLE_BREADCRUMBS
if ((vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS) && resource->heap)
vkd3d_breadcrumb_tracer_unregister_placed_resource(resource->heap, resource);
#endif
vkd3d_private_store_destroy(&resource->private_store);
d3d12_device_release(resource->device);
vkd3d_free(resource);
@ -2861,6 +2872,7 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
VkMemoryRequirements memory_requirements;
VKD3D_UNUSED VkDeviceSize required_size;
VkBindImageMemoryInfo bind_info;
struct d3d12_resource *object;
VkResult vr;
@ -2900,11 +2912,13 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE
if (heap_offset + memory_requirements.size > heap->allocation.resource.size)
{
ERR("Heap too small for the texture (heap=%"PRIu64", res=%"PRIu64".\n",
ERR("Heap too small for the texture (heap=%"PRIu64", res=%"PRIu64").\n",
heap->allocation.resource.size, heap_offset + memory_requirements.size);
hr = E_INVALIDARG;
goto fail;
}
required_size = memory_requirements.size;
}
else
{
@ -2915,6 +2929,8 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE
hr = E_INVALIDARG;
goto fail;
}
required_size = desc->Width;
}
vkd3d_memory_allocation_slice(&object->mem, &heap->allocation, heap_offset, 0);
@ -2956,6 +2972,14 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE
if (desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
object->initial_layout_transition = 0;
#ifdef VKD3D_ENABLE_BREADCRUMBS
if (vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS)
{
vkd3d_breadcrumb_tracer_register_placed_resource(heap, object, heap_offset, required_size);
d3d12_heap_inc_ref(heap);
}
#endif
*resource = object;
return S_OK;

View File

@ -740,18 +740,38 @@ HRESULT vkd3d_memory_allocator_flush_clears(struct vkd3d_memory_allocator *alloc
/* ID3D12Heap */
typedef ID3D12Heap1 d3d12_heap_iface;
#ifdef VKD3D_ENABLE_BREADCRUMBS
struct d3d12_heap_resource_placement
{
struct d3d12_resource *resource;
VkDeviceSize heap_offset;
VkDeviceSize size;
};
#endif
struct d3d12_heap
{
d3d12_heap_iface ID3D12Heap_iface;
LONG refcount;
LONG internal_refcount;
D3D12_HEAP_DESC desc;
struct vkd3d_memory_allocation allocation;
#ifdef VKD3D_ENABLE_BREADCRUMBS
struct d3d12_heap_resource_placement *placements;
size_t placements_count;
size_t placements_size;
pthread_mutex_t placement_lock;
#endif
struct d3d12_device *device;
struct vkd3d_private_store private_store;
};
void d3d12_heap_inc_ref(struct d3d12_heap *heap);
void d3d12_heap_dec_ref(struct d3d12_heap *heap);
HRESULT d3d12_heap_create(struct d3d12_device *device, const D3D12_HEAP_DESC *desc,
void *host_address, struct d3d12_heap **heap);
HRESULT d3d12_device_validate_custom_heap_type(struct d3d12_device *device,
@ -2622,6 +2642,10 @@ void vkd3d_breadcrumb_tracer_add_command(struct d3d12_command_list *list,
void vkd3d_breadcrumb_tracer_signal(struct d3d12_command_list *list);
void vkd3d_breadcrumb_tracer_end_command_list(struct d3d12_command_list *list);
void vkd3d_breadcrumb_tracer_register_placed_resource(struct d3d12_heap *heap, struct d3d12_resource *resource,
VkDeviceSize heap_offset, VkDeviceSize required_size);
void vkd3d_breadcrumb_tracer_unregister_placed_resource(struct d3d12_heap *heap, struct d3d12_resource *resource);
#define VKD3D_BREADCRUMB_COMMAND(cmd_type) do { \
if (vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS) { \
struct vkd3d_breadcrumb_command breadcrumb_cmd; \