Compare commits

...

5 Commits

Author SHA1 Message Date
Hans-Kristian Arntzen 3d1de5dc6a vkd3d: Add full tracing of every submitted command list.
Replays relevant commands in submission order.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
2022-06-30 14:32:57 +02:00
Hans-Kristian Arntzen 0be0369ede vkd3d: Add breadcrumb for discard barriers.
Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
2022-06-30 14:32:37 +02:00
Hans-Kristian Arntzen 876447f254 vkd3d: Add more breadcrumb tracing around RTV/DSV/Indirect usage.
Report resource cookies so that it's easier to track down aliasing
issues.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
2022-06-30 14:32:37 +02:00
Hans-Kristian Arntzen 2c42c0da93 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>
2022-06-30 14:32:35 +02:00
Hans-Kristian Arntzen b1e735ee8f vkd3d: Do not perform initial layout transition for placed RTV / DSV.
Docs explicitly specify that placed RTV / DSV resource must be properly
initialized before use, either on first use or after aliasing barriers,
so there should be no need to perform initial layout transition.

Fixes spurious GPU hangs in Hitman III where application aliases
an indirect buffer and a DSV. The DSV is cleared after the indirect
buffer is consumed, but the initial_layout_transition is triggered and
HTILE init clobbered the buffer.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
2022-06-30 14:24:13 +02:00
7 changed files with 333 additions and 4 deletions

View File

@ -89,6 +89,7 @@ extern "C" {
#define VKD3D_CONFIG_FLAG_SHADER_CACHE_SYNC (1ull << 27)
#define VKD3D_CONFIG_FLAG_FORCE_RAW_VA_CBV (1ull << 28)
#define VKD3D_CONFIG_FLAG_ZERO_MEMORY_WORKAROUNDS_COMMITTED_BUFFER_UAV (1ull << 29)
#define VKD3D_CONFIG_FLAG_BREADCRUMBS_TRACE (1ull << 30)
typedef HRESULT (*PFN_vkd3d_signal_event)(HANDLE event);

View File

@ -82,6 +82,24 @@ static const char *vkd3d_breadcrumb_command_type_to_str(enum vkd3d_breadcrumb_co
return "root_desc";
case VKD3D_BREADCRUMB_COMMAND_ROOT_CONST:
return "root_const";
case VKD3D_BREADCRUMB_COMMAND_BIND_RTV:
return "bind_rtv";
case VKD3D_BREADCRUMB_COMMAND_BIND_DSV:
return "bind_dsv";
case VKD3D_BREADCRUMB_COMMAND_COOKIE:
return "cookie";
case VKD3D_BREADCRUMB_COMMAND_CLEAR_UAV_FLOAT:
return "clear_uav_float";
case VKD3D_BREADCRUMB_COMMAND_CLEAR_UAV_UINT:
return "clear_uav_uint";
case VKD3D_BREADCRUMB_COMMAND_CLEAR_UAV_FALLBACK:
return "clear_uav_fallback";
case VKD3D_BREADCRUMB_COMMAND_CLEAR_RTV:
return "clear_rtv";
case VKD3D_BREADCRUMB_COMMAND_CLEAR_DSV:
return "clear_dsv";
case VKD3D_BREADCRUMB_COMMAND_DISCARD:
return "discard";
default:
return "?";
@ -273,8 +291,11 @@ static void vkd3d_breadcrumb_tracer_report_command_list(
const struct vkd3d_breadcrumb_command *cmd;
bool observed_begin_cmd = false;
bool observed_end_cmd = false;
bool ignore_markers;
unsigned int i;
ignore_markers = begin_marker == UINT32_MAX && end_marker == UINT32_MAX;
if (end_marker == 0)
{
ERR(" ===== Potential crash region BEGIN (make sure RADV_DEBUG=syncshaders is used for maximum accuracy) =====\n");
@ -287,6 +308,12 @@ static void vkd3d_breadcrumb_tracer_report_command_list(
{
cmd = &context->commands[i];
if (ignore_markers && (cmd->type == VKD3D_BREADCRUMB_COMMAND_SET_TOP_MARKER ||
cmd->type == VKD3D_BREADCRUMB_COMMAND_SET_BOTTOM_MARKER))
{
continue;
}
/* If there is a command which sets TOP_OF_PIPE, but we haven't observed the marker yet,
* the command processor hasn't gotten there yet (most likely ...), so that should be the
* natural end-point. */
@ -306,6 +333,10 @@ static void vkd3d_breadcrumb_tracer_report_command_list(
{
ERR(" Set arg: %"PRIu64" (#%"PRIx64")\n", cmd->word_64bit, cmd->word_64bit);
}
else if (cmd->type == VKD3D_BREADCRUMB_COMMAND_COOKIE)
{
ERR(" Set resource cookie: %"PRIu64"\n", cmd->word_64bit);
}
else
{
ERR(" Command: %s\n", vkd3d_breadcrumb_command_type_to_str(cmd->type));
@ -338,6 +369,13 @@ static void vkd3d_breadcrumb_tracer_report_command_list(
}
}
void vkd3d_breadcrumb_tracer_dump_command_list(struct vkd3d_breadcrumb_tracer *tracer,
unsigned int index)
{
vkd3d_breadcrumb_tracer_report_command_list(&tracer->trace_contexts[index],
UINT32_MAX, UINT32_MAX);
}
static void vkd3d_breadcrumb_tracer_report_command_list_amd(struct vkd3d_breadcrumb_tracer *tracer,
unsigned int context_index)
{
@ -645,3 +683,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

@ -8173,6 +8173,10 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(d3d12_comman
rtv_desc = d3d12_rtv_desc_from_cpu_handle(render_target_descriptors[i]);
}
VKD3D_BREADCRUMB_COOKIE(rtv_desc && rtv_desc->resource ? rtv_desc->resource->res.cookie : 0);
VKD3D_BREADCRUMB_AUX32(i);
VKD3D_BREADCRUMB_COMMAND_STATE(BIND_RTV);
if (!rtv_desc || !rtv_desc->resource)
{
WARN("RTV descriptor %u is not initialized.\n", i);
@ -8204,6 +8208,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(d3d12_comman
{
WARN("DSV descriptor is not initialized.\n");
}
VKD3D_BREADCRUMB_COOKIE(rtv_desc && rtv_desc->resource ? rtv_desc->resource->res.cookie : 0);
VKD3D_BREADCRUMB_COMMAND_STATE(BIND_DSV);
}
if (d3d12_pipeline_state_is_graphics(list->state))
@ -8301,6 +8308,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(d3d12_com
d3d12_command_list_clear_attachment(list, dsv_desc->resource, dsv_desc->view,
clear_aspects, &clear_value, rect_count, rects);
VKD3D_BREADCRUMB_COOKIE(dsv_desc->resource->res.cookie);
VKD3D_BREADCRUMB_COMMAND(CLEAR_DSV);
}
static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(d3d12_command_list_iface *iface,
@ -8339,6 +8349,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(d3d12_com
d3d12_command_list_clear_attachment(list, rtv_desc->resource, rtv_desc->view,
VK_IMAGE_ASPECT_COLOR_BIT, &clear_value, rect_count, rects);
VKD3D_BREADCRUMB_COOKIE(rtv_desc->resource->res.cookie);
VKD3D_BREADCRUMB_COMMAND(CLEAR_RTV);
}
struct vkd3d_clear_uav_info
@ -8931,6 +8944,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(d3
{
d3d12_command_list_clear_uav_with_copy(list, &d, resource_impl,
&args, &color, uint_format, rect_count, rects);
VKD3D_BREADCRUMB_COMMAND(CLEAR_UAV_FALLBACK);
return;
}
}
@ -8968,6 +8982,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(d3
d3d12_command_allocator_add_view(list->allocator, inline_view);
vkd3d_view_decref(inline_view, list->device);
}
VKD3D_BREADCRUMB_COMMAND(CLEAR_UAV_UINT);
}
static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(d3d12_command_list_iface *iface,
@ -8994,6 +9010,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(d
color = vkd3d_fixup_clear_uav_swizzle(list->device, d.view->info.view->format->dxgi_format, color);
d3d12_command_list_clear_uav(list, &d, resource_impl, &args, &color, rect_count, rects);
VKD3D_BREADCRUMB_COMMAND(CLEAR_UAV_FLOAT);
}
static void STDMETHODCALLTYPE d3d12_command_list_DiscardResource(d3d12_command_list_iface *iface,
@ -9130,6 +9147,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_DiscardResource(d3d12_command_l
d3d12_command_list_discard_attachment_barrier(list, texture, &vk_subresource_range, is_bound);
}
}
VKD3D_BREADCRUMB_COOKIE(texture->res.cookie);
VKD3D_BREADCRUMB_COMMAND(DISCARD);
}
static inline bool d3d12_query_type_is_scoped(D3D12_QUERY_TYPE type)
@ -9879,6 +9899,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(d3d12_command_l
if (!max_command_count)
return;
VKD3D_BREADCRUMB_COOKIE(arg_impl ? arg_impl->res.cookie : 0);
VKD3D_BREADCRUMB_AUX64(arg_buffer_offset);
VKD3D_BREADCRUMB_COOKIE(count_impl ? count_impl->res.cookie : 0);
VKD3D_BREADCRUMB_AUX64(count_buffer_offset);
if ((count_buffer || list->predicate_va) && !list->device->vk_info.KHR_draw_indirect_count)
{
FIXME("Count buffers not supported by Vulkan implementation.\n");
@ -11230,6 +11255,9 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
size_t num_transitions, num_command_buffers;
struct d3d12_command_queue_submission sub;
struct d3d12_command_list *cmd_list;
#ifdef VKD3D_ENABLE_BREADCRUMBS
unsigned int *breadcrumb_indices;
#endif
VkCommandBuffer *buffers;
LONG **outstanding;
unsigned int i, j;
@ -11278,6 +11306,19 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
return;
}
#ifdef VKD3D_ENABLE_BREADCRUMBS
if (vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS_TRACE)
{
if (!(breadcrumb_indices = vkd3d_malloc(sizeof(unsigned int) * command_list_count)))
{
vkd3d_free(outstanding);
vkd3d_free(buffers);
}
}
else
breadcrumb_indices = NULL;
#endif
sub.execute.debug_capture = false;
num_transitions = 0;
@ -11292,6 +11333,9 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
"Command list %p is in recording state.\n", command_lists[i]);
vkd3d_free(outstanding);
vkd3d_free(buffers);
#ifdef VKD3D_ENABLE_BREADCRUMBS
vkd3d_free(breadcrumb_indices);
#endif
return;
}
@ -11305,6 +11349,11 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
buffers[j++] = cmd_list->vk_command_buffer;
if (cmd_list->debug_capture)
sub.execute.debug_capture = true;
#ifdef VKD3D_ENABLE_BREADCRUMBS
if (breadcrumb_indices)
breadcrumb_indices[i] = cmd_list->breadcrumb_context_index;
#endif
}
/* Append a full GPU barrier between submissions.
@ -11345,6 +11394,10 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
sub.execute.cmd_count = num_command_buffers;
sub.execute.outstanding_submissions_counters = outstanding;
sub.execute.outstanding_submissions_counter_count = command_list_count;
#ifdef VKD3D_ENABLE_BREADCRUMBS
sub.execute.breadcrumb_indices = breadcrumb_indices;
sub.execute.breadcrumb_indices_count = breadcrumb_indices ? command_list_count : 0;
#endif
d3d12_command_queue_add_submission(command_queue, &sub);
}
@ -12448,6 +12501,18 @@ static void *d3d12_command_queue_submission_worker_main(void *userdata)
for (i = 0; i < submission.execute.outstanding_submissions_counter_count; i++)
InterlockedDecrement(submission.execute.outstanding_submissions_counters[i]);
vkd3d_free(submission.execute.outstanding_submissions_counters);
#ifdef VKD3D_ENABLE_BREADCRUMBS
for (i = 0; i < submission.execute.breadcrumb_indices_count; i++)
{
INFO("=== Executing command list context %u on VkQueue %p, queue family %u ===\n",
submission.execute.breadcrumb_indices[i],
(void*)queue->vkd3d_queue->vk_queue, queue->vkd3d_queue->vk_family_index);
vkd3d_breadcrumb_tracer_dump_command_list(&queue->device->breadcrumb_tracer,
submission.execute.breadcrumb_indices[i]);
INFO("============================\n");
}
vkd3d_free(submission.execute.breadcrumb_indices);
#endif
VKD3D_REGION_END(queue_execute);
break;

View File

@ -664,6 +664,7 @@ static const struct vkd3d_debug_option vkd3d_config_options[] =
{"pipeline_library_app_cache", VKD3D_CONFIG_FLAG_PIPELINE_LIBRARY_APP_CACHE_ONLY},
{"shader_cache_sync", VKD3D_CONFIG_FLAG_SHADER_CACHE_SYNC},
{"force_raw_va_cbv", VKD3D_CONFIG_FLAG_FORCE_RAW_VA_CBV},
{"breadcrumbs_trace", VKD3D_CONFIG_FLAG_BREADCRUMBS | VKD3D_CONFIG_FLAG_BREADCRUMBS_TRACE},
};
static void vkd3d_config_flags_init_once(void)

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);
@ -2947,6 +2963,23 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE
goto fail;
}
/* Placed RTV and DSV *must* be explicitly initialized after alias barriers and first use,
* so there is no need to do initial layout transition ourselves.
* It is extremely dangerous to do so since the initialization will clobber other
* aliased buffers when clearing DCC/HTILE state.
* For details, see:
* https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createplacedresource#notes-on-the-required-resource-initialization. */
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,
@ -2353,6 +2373,12 @@ struct d3d12_command_queue_submission_execute
struct vkd3d_initial_transition *transitions;
size_t transition_count;
#ifdef VKD3D_ENABLE_BREADCRUMBS
/* Replays commands in submission order for heavy debug. */
unsigned int *breadcrumb_indices;
size_t breadcrumb_indices_count;
#endif
bool debug_capture;
};
@ -2552,6 +2578,15 @@ enum vkd3d_breadcrumb_command_type
VKD3D_BREADCRUMB_COMMAND_IBO,
VKD3D_BREADCRUMB_COMMAND_ROOT_DESC,
VKD3D_BREADCRUMB_COMMAND_ROOT_CONST,
VKD3D_BREADCRUMB_COMMAND_BIND_RTV,
VKD3D_BREADCRUMB_COMMAND_BIND_DSV,
VKD3D_BREADCRUMB_COMMAND_COOKIE,
VKD3D_BREADCRUMB_COMMAND_CLEAR_UAV_FLOAT,
VKD3D_BREADCRUMB_COMMAND_CLEAR_UAV_UINT,
VKD3D_BREADCRUMB_COMMAND_CLEAR_UAV_FALLBACK,
VKD3D_BREADCRUMB_COMMAND_CLEAR_RTV,
VKD3D_BREADCRUMB_COMMAND_CLEAR_DSV,
VKD3D_BREADCRUMB_COMMAND_DISCARD,
};
#ifdef VKD3D_ENABLE_BREADCRUMBS
@ -2622,6 +2657,14 @@ 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);
/* For heavy debug, replays the trace stream in submission order. */
void vkd3d_breadcrumb_tracer_dump_command_list(struct vkd3d_breadcrumb_tracer *tracer,
unsigned int index);
#define VKD3D_BREADCRUMB_COMMAND(cmd_type) do { \
if (vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS) { \
struct vkd3d_breadcrumb_command breadcrumb_cmd; \
@ -2658,6 +2701,15 @@ void vkd3d_breadcrumb_tracer_end_command_list(struct d3d12_command_list *list);
} \
} while(0)
#define VKD3D_BREADCRUMB_COOKIE(v) do { \
if (vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS) { \
struct vkd3d_breadcrumb_command breadcrumb_cmd; \
breadcrumb_cmd.type = VKD3D_BREADCRUMB_COMMAND_COOKIE; \
breadcrumb_cmd.word_64bit = v; \
vkd3d_breadcrumb_tracer_add_command(list, &breadcrumb_cmd); \
} \
} while(0)
/* Remember to kick debug ring as well. */
#define VKD3D_DEVICE_REPORT_BREADCRUMB_IF(device, cond) do { \
if ((vkd3d_config_flags & VKD3D_CONFIG_FLAG_BREADCRUMBS) && (cond)) { \
@ -2670,6 +2722,7 @@ void vkd3d_breadcrumb_tracer_end_command_list(struct d3d12_command_list *list);
#define VKD3D_BREADCRUMB_COMMAND_STATE(type) ((void)(VKD3D_BREADCRUMB_COMMAND_##type))
#define VKD3D_BREADCRUMB_AUX32(v) ((void)(v))
#define VKD3D_BREADCRUMB_AUX64(v) ((void)(v))
#define VKD3D_BREADCRUMB_COOKIE(v) ((void)(v))
#define VKD3D_DEVICE_REPORT_BREADCRUMB_IF(device, cond) ((void)(device), (void)(cond))
#endif /* VKD3D_ENABLE_BREADCRUMBS */