diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 7f6700e6..ce8f32e1 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -24,6 +24,8 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#define DIV_ROUND_UP(a, b) ((a) % (b) == 0 ? (a) / (b) : (a) / (b) + 1) + static inline size_t align(size_t addr, size_t alignment) { return (addr + (alignment - 1)) & ~(alignment - 1); diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index f06a31ce..a1e243cc 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -3305,6 +3305,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_EndQuery(ID3D12GraphicsCommandL TRACE("iface %p, heap %p, type %#x, index %u.\n", iface, heap, type, index); + d3d12_query_heap_mark_result_as_available(query_heap, index); + if (type == D3D12_QUERY_TYPE_TIMESTAMP) { VK_CALL(vkCmdResetQueryPool(list->vk_command_buffer, query_heap->vk_query_pool, index, 1)); @@ -3320,11 +3322,12 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResolveQueryData(ID3D12Graphics ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT start_index, UINT query_count, ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset) { + const struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap); struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList(iface); - struct d3d12_query_heap *query_heap = unsafe_impl_from_ID3D12QueryHeap(heap); struct d3d12_resource *buffer = unsafe_impl_from_ID3D12Resource(dst_buffer); const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; VkDeviceSize stride = sizeof(uint64_t); + unsigned int i; TRACE("iface %p, heap %p, type %#x, start_index %u, query_count %u, " "dst_buffer %p, aligned_dst_buffer_offset %#"PRIx64".\n", @@ -3350,9 +3353,28 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResolveQueryData(ID3D12Graphics if (type == D3D12_QUERY_TYPE_PIPELINE_STATISTICS) stride = sizeof(struct D3D12_QUERY_DATA_PIPELINE_STATISTICS); - VK_CALL(vkCmdCopyQueryPoolResults(list->vk_command_buffer, query_heap->vk_query_pool, - start_index, query_count, buffer->u.vk_buffer, aligned_dst_buffer_offset, - stride, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT)); + /* We cannot copy query results if a query was not issued: + * + * "If the query does not become available in a finite amount of time + * (e.g. due to not issuing a query since the last reset), + * a VK_ERROR_DEVICE_LOST error may occur." + */ + for (i = 0; i < query_count; ++i) + { + const UINT64 offset = aligned_dst_buffer_offset + i * stride; + const unsigned int query_index = start_index + i; + + if (!d3d12_query_heap_is_result_available(query_heap, query_index)) + { + VK_CALL(vkCmdFillBuffer(list->vk_command_buffer, + buffer->u.vk_buffer, offset, stride, 0x00000000)); + continue; + } + + VK_CALL(vkCmdCopyQueryPoolResults(list->vk_command_buffer, + query_heap->vk_query_pool, query_index, 1, buffer->u.vk_buffer, + offset, stride, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT)); + } } static void STDMETHODCALLTYPE d3d12_command_list_SetPredication(ID3D12GraphicsCommandList *iface, diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index be43af11..e2c1ac31 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -1871,14 +1871,17 @@ HRESULT d3d12_query_heap_create(struct d3d12_device *device, const D3D12_QUERY_H const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct d3d12_query_heap *object; VkQueryPoolCreateInfo pool_info; + unsigned int element_count; VkResult vr; - if (!(object = vkd3d_malloc(sizeof(*object)))) + element_count = DIV_ROUND_UP(desc->Count, sizeof(*object->availability_mask) * CHAR_BIT); + if (!(object = vkd3d_malloc(offsetof(struct d3d12_query_heap, availability_mask[element_count])))) return E_OUTOFMEMORY; object->ID3D12QueryHeap_iface.lpVtbl = &d3d12_query_heap_vtbl; object->refcount = 1; object->device = device; + memset(object->availability_mask, 0, element_count * sizeof(*object->availability_mask)); pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; pool_info.pNext = NULL; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 2e9ee29a..d0332e5f 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -279,12 +280,33 @@ struct d3d12_query_heap VkQueryPool vk_query_pool; struct d3d12_device *device; + + uint64_t availability_mask[]; }; HRESULT d3d12_query_heap_create(struct d3d12_device *device, const D3D12_QUERY_HEAP_DESC *desc, struct d3d12_query_heap **heap) DECLSPEC_HIDDEN; struct d3d12_query_heap *unsafe_impl_from_ID3D12QueryHeap(ID3D12QueryHeap *iface) DECLSPEC_HIDDEN; +/* A Vulkan query has to be issued at least one time before the result is + * available. In D3D12 it is legal to get query reults for not issued queries. + */ +static inline bool d3d12_query_heap_is_result_available(const struct d3d12_query_heap *heap, + unsigned int query_index) +{ + unsigned int index = query_index / (sizeof(*heap->availability_mask) * CHAR_BIT); + unsigned int shift = query_index % (sizeof(*heap->availability_mask) * CHAR_BIT); + return heap->availability_mask[index] & ((uint64_t)1 << shift); +} + +static inline void d3d12_query_heap_mark_result_as_available(struct d3d12_query_heap *heap, + unsigned int query_index) +{ + unsigned int index = query_index / (sizeof(*heap->availability_mask) * CHAR_BIT); + unsigned int shift = query_index % (sizeof(*heap->availability_mask) * CHAR_BIT); + heap->availability_mask[index] |= (uint64_t)1 << shift; +} + struct d3d12_root_descriptor_table_range { unsigned int offset;