libs/vkd3d: Avoid vkCmdCopyQueryPoolResults() for not issued queries.

The Vulkan spec states:

  * "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."

  * "If queries will never finish (e.g. due to being reset but not
    issued), then vkGetQueryPoolResults may not return in finite time."
This commit is contained in:
Józef Kucia 2017-09-14 14:57:09 +02:00
parent 334c532401
commit 2ea8ffb554
4 changed files with 54 additions and 5 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -30,6 +30,7 @@
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#include <pthread.h>
#include <stdbool.h>
@ -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;