diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index a1e243ccd534586f32b6f6aac7fe41f27f4b8cae..8d32825e419d62464095fb6e4ad0b4a9c809b5ba 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -1704,29 +1704,84 @@ static VkDescriptorSet d3d12_command_list_allocate_descriptor_set(struct d3d12_c
 }
 
 static void d3d12_command_list_copy_descriptors(struct d3d12_command_list *list,
-        const struct d3d12_root_signature *root_signature, VkDescriptorSet dst_set, VkDescriptorSet src_set)
+        const struct vkd3d_pipeline_bindings *bindings, VkDescriptorSet src_set)
 {
+    const struct d3d12_root_signature *root_signature = bindings->root_signature;
     const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
-    unsigned int count = root_signature->copy_descriptor_count;
+    const struct vkd3d_vulkan_info *vk_info = &list->device->vk_info;
+    const struct d3d12_root_descriptor_table *descriptor_table;
+    const struct d3d12_root_descriptor_table_range *range;
     VkDevice vk_device = list->device->vk_device;
     VkCopyDescriptorSet *descriptor_copies;
-    unsigned int i;
+    unsigned int i, j, count;
+    unsigned int idx;
+
+    count = 0;
+    if (!vk_info->KHR_push_descriptor)
+        count += root_signature->root_descriptor_count;
+    for (i = 0; i < root_signature->parameter_count; ++i)
+    {
+        if (root_signature->parameters[i].parameter_type != D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+            continue;
+        if (bindings->descriptor_table_dirty_mask & ((uint64_t)1 << i))
+            continue;
+
+        descriptor_table = &root_signature->parameters[i].u.descriptor_table;
+        count += descriptor_table->range_count;
+    }
+
+    if (!count)
+        return;
 
     if (!(descriptor_copies = vkd3d_calloc(count, sizeof(*descriptor_copies))))
         return;
 
-    for (i = 0; i < count; ++i)
+    idx = 0;
+    if (!vk_info->KHR_push_descriptor)
     {
-        descriptor_copies[i].sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET;
-        descriptor_copies[i].pNext = NULL;
-        descriptor_copies[i].srcSet = src_set;
-        descriptor_copies[i].srcBinding = i;
-        descriptor_copies[i].srcArrayElement = 0;
-        descriptor_copies[i].dstSet = dst_set;
-        descriptor_copies[i].dstBinding = i;
-        descriptor_copies[i].dstArrayElement = 0;
-        descriptor_copies[i].descriptorCount = 1;
+        for (i = 0; i < root_signature->root_descriptor_count; ++i)
+        {
+            descriptor_copies[idx].sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET;
+            descriptor_copies[idx].pNext = NULL;
+            descriptor_copies[idx].srcSet = src_set;
+            descriptor_copies[idx].srcBinding = i;
+            descriptor_copies[idx].srcArrayElement = 0;
+            descriptor_copies[idx].dstSet = bindings->descriptor_set;
+            descriptor_copies[idx].dstBinding = i;
+            descriptor_copies[idx].dstArrayElement = 0;
+            descriptor_copies[idx].descriptorCount = 1;
+            ++idx;
+        }
+    }
+    for (i = 0; i < root_signature->parameter_count; ++i)
+    {
+        if (root_signature->parameters[i].parameter_type != D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+            continue;
+        if (bindings->descriptor_table_dirty_mask & ((uint64_t)1 << i))
+            continue;
+
+        descriptor_table = &root_signature->parameters[i].u.descriptor_table;
+        for (j = 0; j < descriptor_table->range_count; ++j)
+        {
+            range = &descriptor_table->ranges[j];
+            descriptor_copies[idx].sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET;
+            descriptor_copies[idx].pNext = NULL;
+            descriptor_copies[idx].srcSet = src_set;
+            descriptor_copies[idx].srcBinding = range->binding;
+            descriptor_copies[idx].srcArrayElement = 0;
+            descriptor_copies[idx].dstSet = bindings->descriptor_set;
+            descriptor_copies[idx].dstBinding = range->binding;
+            descriptor_copies[idx].dstArrayElement = 0;
+            descriptor_copies[idx].descriptorCount = 1;
+            if (range->descriptor_magic == VKD3D_DESCRIPTOR_MAGIC_SRV
+                    || range->descriptor_magic == VKD3D_DESCRIPTOR_MAGIC_UAV)
+                descriptor_copies[idx].descriptorCount = 2 * range->descriptor_count;
+            else
+                descriptor_copies[idx].descriptorCount = range->descriptor_count;
+            ++idx;
+        }
     }
+    assert(count == idx);
     VK_CALL(vkUpdateDescriptorSets(vk_device, 0, NULL, count, descriptor_copies));
 
     vkd3d_free(descriptor_copies);
@@ -1759,8 +1814,7 @@ static void d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
     bindings->in_use = false;
 
     if (previous_descriptor_set)
-        d3d12_command_list_copy_descriptors(list, root_signature,
-                bindings->descriptor_set, previous_descriptor_set);
+        d3d12_command_list_copy_descriptors(list, bindings, previous_descriptor_set);
 }
 
 static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_descriptor_write,
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c
index a998a3b5a0dd6f4c01eabce1f250965d636ddcc5..3e8ea25cd7c30c416ba7fa0a060705cfa056e22c 100644
--- a/libs/vkd3d/state.c
+++ b/libs/vkd3d/state.c
@@ -323,8 +323,12 @@ struct d3d12_root_signature_info
     size_t buffer_srv_count;
     size_t srv_count;
     size_t sampler_count;
+
     size_t descriptor_count;
+
     size_t root_constant_count;
+    size_t root_descriptor_count;
+
     size_t cost;
 };
 
@@ -384,16 +388,19 @@ static HRESULT d3d12_root_signature_info_from_desc(struct d3d12_root_signature_i
                 break;
 
             case D3D12_ROOT_PARAMETER_TYPE_CBV:
+                ++info->root_descriptor_count;
                 ++info->cbv_count;
                 ++info->descriptor_count;
                 info->cost += 2;
                 break;
             case D3D12_ROOT_PARAMETER_TYPE_SRV:
+                ++info->root_descriptor_count;
                 ++info->buffer_srv_count;
                 ++info->descriptor_count;
                 info->cost += 2;
                 break;
             case D3D12_ROOT_PARAMETER_TYPE_UAV:
+                ++info->root_descriptor_count;
                 ++info->buffer_uav_count;
                 ++info->descriptor_count;
                 info->cost += 2;
@@ -916,6 +923,7 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
 
     root_signature->descriptor_count = info.descriptor_count;
     root_signature->static_sampler_count = desc->NumStaticSamplers;
+    root_signature->root_descriptor_count = info.root_descriptor_count;
 
     /* An additional sampler is created for SpvOpImageFetch. */
     if (info.srv_count || info.buffer_srv_count)
@@ -969,7 +977,6 @@ static HRESULT d3d12_root_signature_init(struct d3d12_root_signature *root_signa
         goto fail;
     if (FAILED(hr = d3d12_root_signature_init_root_descriptor_tables(root_signature, desc, &context)))
         goto fail;
-    root_signature->copy_descriptor_count = context.descriptor_binding;
     if (FAILED(hr = d3d12_root_signature_init_static_samplers(root_signature, device, desc, &context)))
         goto fail;
 
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index d0332e5f11dd0a395ed75d0601070bbb096e20d3..ca39503b8458d50282741a207f314ee69aa1a68a 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -355,8 +355,6 @@ struct d3d12_root_signature
     VkDescriptorSetLayout vk_push_set_layout;
     VkDescriptorSetLayout vk_set_layout;
 
-    unsigned int copy_descriptor_count;
-
     struct VkDescriptorPoolSize *pool_sizes;
     size_t pool_size_count;
 
@@ -371,6 +369,8 @@ struct d3d12_root_signature
     unsigned int root_constant_count;
     struct vkd3d_shader_push_constant_buffer *root_constants;
 
+    unsigned int root_descriptor_count;
+
     unsigned int push_constant_range_count;
     /* Only a single push constant range may include the same stage in Vulkan. */
     VkPushConstantRange push_constant_ranges[D3D12_SHADER_VISIBILITY_PIXEL + 1];