diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h
index 7f6700e63900c9f8b1dcb9c9342722a81e9c43f8..ce8f32e1b1aa32a2c69bb8fc009f9a7363aa477b 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 f06a31ce273765b3bd61d0f7a9971afb845e05da..a1e243ccd534586f32b6f6aac7fe41f27f4b8cae 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 be43af11cfdfcb46ae19eb1c768836989085b51c..e2c1ac31d86e35b0e2ccb08b49fd10ea2658a232 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 2e9ee29ae31c955cfd15568dbd3e58ec0ff76fb8..d0332e5f11dd0a395ed75d0601070bbb096e20d3 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -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;