[PATCH] vkd3d: Support RS 1.0 VOLATILE descriptors.

Hans-Kristian Arntzen post at arntzen-software.no
Sat Nov 2 14:47:14 CDT 2019


Thanks for testing. I had a hunch WoW would be fixed with this patch as 
it had stricter invalidation of UAV counters, but I didn't have retail 
client installed to test.

Cheers,
Hans-Kristian

On 11/2/19 6:44 PM, Sveinar Søpler wrote:
> You are absolutely right. My bad! I had some dirt in MY tree after 
> fiddling with the patch from this bug 
> https://bugs.winehq.org/show_bug.cgi?id=46410 , and by doing a fresh 
> clone it checks out AND compiles. Sorry for the noise :)
>
> I added the 3 patches you posted:
>
> https://source.winehq.org/patches/data/172721
>
> https://source.winehq.org/patches/data/172677
>
> https://source.winehq.org/patches/data/172679
>
> And doing this, without adding the patch posted on this bug, WoW seems 
> to work without flashing textures. Will do some more testing once this 
> is committed to GIT. Thanks :)
>
> Sveinar
>
> On 01.11.2019 22:03, Hans-Kristian Arntzen wrote:
>> The patch was made based on that parent commit and compiles fine for me.
>>
>> Cheers,
>> Hans-Kristian
>>
>> On 11/1/19 9:27 PM, Sveinar Søpler wrote:
>>> I am not sure what tree you are working on, but applying this patch 
>>> to GIT at 4576236199769eacadc6de49e03d05df999f9181 leads to a lot of:
>>>
>>> libs/vkd3d/command.c: In function 
>>> ‘d3d12_command_list_resolve_descriptor_table_normal’:
>>> libs/vkd3d/command.c:2815:13: error: invalid storage class for 
>>> function ‘d3d12_command_list_resolve_descriptor_table’
>>>  2815 | static void 
>>> d3d12_command_list_resolve_descriptor_table(struct 
>>> d3d12_command_list *list,
>>>       | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> libs/vkd3d/command.c:2815:1: warning: ISO C90 forbids mixed 
>>> declarations and code [-Wdeclaration-after-statement]
>>>  2815 | static void 
>>> d3d12_command_list_resolve_descriptor_table(struct 
>>> d3d12_command_list *list,
>>>       | ^~~~~~
>>> libs/vkd3d/command.c:2824:13: error: invalid storage class for 
>>> function ‘d3d12_command_list_resolve_descriptor_tables’
>>>  2824 | static void 
>>> d3d12_command_list_resolve_descriptor_tables(struct 
>>> d3d12_command_list *list)
>>>       | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>
>>> and subsequent errors.
>>>
>>> Does this patch depend on some other patch(set) to compile?
>>>
>>> From recent commits to vkd3d, it seems as some patches are picked, 
>>> and some not depending on some criteria. Working on a massively 
>>> changed git tree submitting patches that does not include its 
>>> dependencies is kinda hard for me to test :)
>>>
>>> If you have a git repo with a working tree i am willing to test stuff.
>>>
>>> Sorry if you feel i am stepping on some toes here tho...
>>>
>>> Sveinar
>>>
>>> On 01.11.2019 14:36, Hans-Kristian Arntzen wrote:
>>>> Use EXT_descriptor_indexing's UPDATE_AFTER_BIND feature to support
>>>> semantics required by RS 1.0 VOLATILE descriptors. We implement 
>>>> this by
>>>> deferring all updates of desciptor sets until Submit time.
>>>>
>>>> This is fine, as command buffers cannot be executed simultaneously on
>>>> D3D12, so at Submit time, we know that the command buffer is not being
>>>> executed on the GPU, and updating descriptors for multiple submissions
>>>> is correct.
>>>>
>>>> If EXT_descriptor_indexing is not available, the fallback is the older
>>>> method, which matches RS 1.1 STATIC descriptor model.
>>>>
>>>> Signed-off-by: Hans-Kristian Arntzen <post at arntzen-software.no>
>>>> ---
>>>>   libs/vkd3d/command.c       | 358 
>>>> +++++++++++++++++++++++++++++--------
>>>>   libs/vkd3d/device.c        |  20 ++-
>>>>   libs/vkd3d/state.c         |  22 +++
>>>>   libs/vkd3d/vkd3d_private.h |  19 +-
>>>>   tests/d3d12.c              |   2 +-
>>>>   5 files changed, 338 insertions(+), 83 deletions(-)
>>>>
>>>> diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
>>>> index 0532ec0..3f78d17 100644
>>>> --- a/libs/vkd3d/command.c
>>>> +++ b/libs/vkd3d/command.c
>>>> @@ -1341,7 +1341,7 @@ static VkDescriptorPool 
>>>> d3d12_command_allocator_allocate_descriptor_pool(
>>>>       {
>>>>           pool_desc.sType = 
>>>> VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
>>>>           pool_desc.pNext = NULL;
>>>> -        pool_desc.flags = 0;
>>>> +        pool_desc.flags = device->vk_info.EXT_descriptor_indexing 
>>>> ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT : 0;
>>>>           pool_desc.maxSets = 512;
>>>>           pool_desc.poolSizeCount = ARRAY_SIZE(pool_sizes);
>>>>           pool_desc.pPoolSizes = pool_sizes;
>>>> @@ -1865,6 +1865,10 @@ static void 
>>>> d3d12_command_list_invalidate_bindings(struct d3d12_command_list *li
>>>>       if (!state)
>>>>           return;
>>>>   +    /* Each pipeline state has its own set layout for UAV counters
>>>> +     * based on their implicit usage in the shader.
>>>> +     * Binding a different pipeline state means having to re-remit
>>>> +     * UAV counters in a new descriptor set (and layout). */
>>>>       if (state->uav_counter_mask)
>>>>       {
>>>>           struct vkd3d_pipeline_bindings *bindings = 
>>>> &list->pipeline_bindings[state->vk_bind_point];
>>>> @@ -2196,6 +2200,7 @@ static ULONG STDMETHODCALLTYPE 
>>>> d3d12_command_list_Release(ID3D12GraphicsCommandL
>>>>           if (list->allocator)
>>>> d3d12_command_allocator_free_command_buffer(list->allocator, list);
>>>>   +        vkd3d_free(list->descriptor_updates);
>>>>           vkd3d_free(list);
>>>>             d3d12_device_release(device);
>>>> @@ -2334,6 +2339,9 @@ static void 
>>>> d3d12_command_list_reset_state(struct d3d12_command_list *list,
>>>>         list->state = NULL;
>>>>   +    /* Recycle deferred descriptor update memory if possible. */
>>>> +    list->descriptor_updates_count = 0;
>>>> +
>>>>       memset(list->so_counter_buffers, 0, 
>>>> sizeof(list->so_counter_buffers));
>>>>       memset(list->so_counter_buffer_offsets, 0, 
>>>> sizeof(list->so_counter_buffer_offsets));
>>>>   @@ -2534,15 +2542,54 @@ static void 
>>>> d3d12_command_list_prepare_descriptors(struct d3d12_command_list *li
>>>>        *   time in between. Thus, the contents must not be altered 
>>>> (overwritten
>>>>        *   by an update command, or freed) between when the command 
>>>> is recorded
>>>>        *   and when the command completes executing on the queue."
>>>> +     *
>>>> +     * Even if we have descriptor indexing and UPDATE_AFTER_BIND,
>>>> +     * we need at the very least a new descriptor set.
>>>>        */
>>>>       bindings->descriptor_set = 
>>>> d3d12_command_allocator_allocate_descriptor_set(list->allocator,
>>>>               root_signature->vk_set_layout);
>>>> +
>>>>       bindings->in_use = false;
>>>>         bindings->descriptor_table_dirty_mask |= 
>>>> bindings->descriptor_table_active_mask & 
>>>> root_signature->descriptor_table_mask;
>>>>       bindings->push_descriptor_dirty_mask |= 
>>>> bindings->push_descriptor_active_mask & 
>>>> root_signature->push_descriptor_mask;
>>>>   }
>>>>   +static void 
>>>> d3d12_command_list_prepare_uav_counter_descriptors(struct 
>>>> d3d12_command_list *list,
>>>> +        VkPipelineBindPoint bind_point)
>>>> +{
>>>> +    struct vkd3d_pipeline_bindings *bindings = 
>>>> &list->pipeline_bindings[bind_point];
>>>> +
>>>> +    if (bindings->uav_counter_descriptor_set && 
>>>> !bindings->uav_counter_in_use)
>>>> +        return;
>>>> +
>>>> +    /* We cannot modify bound descriptor sets. We need a new 
>>>> descriptor set if
>>>> +     * we are about to update resource bindings.
>>>> +     *
>>>> +     * The Vulkan spec says:
>>>> +     *
>>>> +     *   "The descriptor set contents bound by a call to
>>>> +     *   vkCmdBindDescriptorSets may be consumed during host 
>>>> execution of the
>>>> +     *   command, or during shader execution of the resulting 
>>>> draws, or any
>>>> +     *   time in between. Thus, the contents must not be altered 
>>>> (overwritten
>>>> +     *   by an update command, or freed) between when the command 
>>>> is recorded
>>>> +     *   and when the command completes executing on the queue."
>>>> +     *
>>>> +     * Even if we have descriptor indexing and UPDATE_AFTER_BIND,
>>>> +     * we need at the very least a new descriptor set.
>>>> +     */
>>>> +
>>>> +    if (list->state->uav_counter_mask)
>>>> +    {
>>>> +        bindings->uav_counter_descriptor_set = 
>>>> d3d12_command_allocator_allocate_descriptor_set(list->allocator,
>>>> +                list->state->vk_set_layout);
>>>> +    }
>>>> +    else
>>>> +        bindings->uav_counter_descriptor_set = VK_NULL_HANDLE;
>>>> +
>>>> +    bindings->uav_counter_in_use = false;
>>>> +}
>>>> +
>>>>   static bool 
>>>> vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet 
>>>> *vk_descriptor_write,
>>>>           VkDescriptorImageInfo *vk_image_info, const struct 
>>>> d3d12_desc *descriptor,
>>>>           uint32_t descriptor_range_magic, VkDescriptorSet 
>>>> vk_descriptor_set,
>>>> @@ -2611,26 +2658,61 @@ static bool 
>>>> vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des
>>>>       return true;
>>>>   }
>>>>   -static void d3d12_command_list_update_descriptor_table(struct 
>>>> d3d12_command_list *list,
>>>> -        VkPipelineBindPoint bind_point, unsigned int index, struct 
>>>> d3d12_desc *base_descriptor)
>>>> +static void 
>>>> d3d12_command_list_defer_update_descriptor_table(struct 
>>>> d3d12_command_list *list,
>>>> +        VkPipelineBindPoint bind_point, uint64_t table_mask, bool 
>>>> uav)
>>>>   {
>>>> +    const struct d3d12_desc *base_descriptor;
>>>> +    unsigned i;
>>>> +    struct d3d12_deferred_descriptor_set_update *update;
>>>>       struct vkd3d_pipeline_bindings *bindings = 
>>>> &list->pipeline_bindings[bind_point];
>>>> -    struct VkWriteDescriptorSet descriptor_writes[24], 
>>>> *current_descriptor_write;
>>>> -    const struct d3d12_root_signature *root_signature = 
>>>> bindings->root_signature;
>>>> +
>>>> +    for (i = 0; i < ARRAY_SIZE(bindings->descriptor_tables); ++i)
>>>> +    {
>>>> +        if (table_mask & ((uint64_t)1 << i))
>>>> +        {
>>>> +            if ((base_descriptor = 
>>>> d3d12_desc_from_gpu_handle(bindings->descriptor_tables[i])))
>>>> +            {
>>>> +                vkd3d_array_reserve((void 
>>>> **)&list->descriptor_updates, &list->descriptor_updates_size,
>>>> + list->descriptor_updates_count + 1, 
>>>> sizeof(*list->descriptor_updates));
>>>> +                update = 
>>>> &list->descriptor_updates[list->descriptor_updates_count];
>>>> +
>>>> +                update->base_descriptor = base_descriptor;
>>>> +                update->index = i;
>>>> +                update->root_signature = bindings->root_signature;
>>>> +                update->descriptor_set = uav ? 
>>>> bindings->uav_counter_descriptor_set : bindings->descriptor_set;
>>>> +                update->uav = uav;
>>>> +                list->descriptor_updates_count++;
>>>> +            }
>>>> +            else
>>>> +                WARN("Descriptor table %u is not set.\n", i);
>>>> +        }
>>>> +    }
>>>> +}
>>>> +
>>>> +static void d3d12_command_list_resolve_descriptor_table_uav(struct 
>>>> d3d12_command_list *list,
>>>> + const struct d3d12_deferred_descriptor_set_update *update)
>>>> +{
>>>> +    const struct d3d12_root_signature *root_signature = 
>>>> update->root_signature;
>>>>       const struct vkd3d_vk_device_procs *vk_procs = 
>>>> &list->device->vk_procs;
>>>> -    struct VkDescriptorImageInfo image_infos[24], 
>>>> *current_image_info;
>>>>       const struct d3d12_root_descriptor_table *descriptor_table;
>>>>       const struct d3d12_root_descriptor_table_range *range;
>>>>       VkDevice vk_device = list->device->vk_device;
>>>> -    unsigned int i, j, descriptor_count;
>>>> -    struct d3d12_desc *descriptor;
>>>> -
>>>> -    descriptor_table = 
>>>> root_signature_get_descriptor_table(root_signature, index);
>>>> +    unsigned int i, j;
>>>> +    unsigned int uav_counter_count;
>>>> +    const struct d3d12_desc *descriptor;
>>>> +    VkWriteDescriptorSet 
>>>> vk_descriptor_writes[VKD3D_SHADER_MAX_UNORDERED_ACCESS_VIEWS];
>>>> +    VkBufferView 
>>>> vk_uav_counter_views[VKD3D_SHADER_MAX_UNORDERED_ACCESS_VIEWS];
>>>> +    VkDescriptorSet vk_descriptor_set;
>>>> +    const struct d3d12_desc *base_descriptor = 
>>>> update->base_descriptor;
>>>>   +    descriptor_table = 
>>>> root_signature_get_descriptor_table(root_signature, update->index);
>>>>       descriptor = base_descriptor;
>>>> -    descriptor_count = 0;
>>>> -    current_descriptor_write = descriptor_writes;
>>>> -    current_image_info = image_infos;
>>>> +
>>>> +    vk_descriptor_set = update->descriptor_set;
>>>> +    if (!vk_descriptor_set)
>>>> +        return;
>>>> +
>>>> +    /* FIXME: There should be a smarter way than scanning through 
>>>> all the descriptor table ranges for this. */
>>>>       for (i = 0; i < descriptor_table->range_count; ++i)
>>>>       {
>>>>           range = &descriptor_table->ranges[i];
>>>> @@ -2644,20 +2726,74 @@ static void 
>>>> d3d12_command_list_update_descriptor_table(struct d3d12_command_list
>>>>           {
>>>>               unsigned int register_idx = range->base_register_idx 
>>>> + j;
>>>>   -            /* Track UAV counters. */
>>>> +            /* Fish out UAV counters. */
>>>>               if (range->descriptor_magic == 
>>>> VKD3D_DESCRIPTOR_MAGIC_UAV
>>>> -                    && register_idx < 
>>>> ARRAY_SIZE(bindings->vk_uav_counter_views))
>>>> +                && register_idx < ARRAY_SIZE(vk_uav_counter_views))
>>>>               {
>>>>                   VkBufferView vk_counter_view = descriptor->magic 
>>>> == VKD3D_DESCRIPTOR_MAGIC_UAV
>>>> -                        ? descriptor->u.view->vk_counter_view : 
>>>> VK_NULL_HANDLE;
>>>> -                if (bindings->vk_uav_counter_views[register_idx] 
>>>> != vk_counter_view)
>>>> -                    bindings->uav_counter_dirty_mask |= 1u << 
>>>> register_idx;
>>>> - bindings->vk_uav_counter_views[register_idx] = vk_counter_view;
>>>> +                                               ? 
>>>> descriptor->u.view->vk_counter_view : VK_NULL_HANDLE;
>>>> +                vk_uav_counter_views[register_idx] = vk_counter_view;
>>>>               }
>>>> +        }
>>>> +    }
>>>> +
>>>> +    uav_counter_count = 
>>>> vkd3d_popcount(list->state->uav_counter_mask);
>>>> +    assert(uav_counter_count <= ARRAY_SIZE(vk_descriptor_writes));
>>>> +
>>>> +    for (i = 0; i < uav_counter_count; ++i)
>>>> +    {
>>>> +        const struct vkd3d_shader_uav_counter_binding *uav_counter 
>>>> = &list->state->uav_counters[i];
>>>> + assert(vk_uav_counter_views[uav_counter->register_index]);
>>>> +
>>>> +        vk_descriptor_writes[i].sType = 
>>>> VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
>>>> +        vk_descriptor_writes[i].pNext = NULL;
>>>> +        vk_descriptor_writes[i].dstSet = vk_descriptor_set;
>>>> +        vk_descriptor_writes[i].dstBinding = 
>>>> uav_counter->binding.binding;
>>>> +        vk_descriptor_writes[i].dstArrayElement = 0;
>>>> +        vk_descriptor_writes[i].descriptorCount = 1;
>>>> +        vk_descriptor_writes[i].descriptorType = 
>>>> VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
>>>> +        vk_descriptor_writes[i].pImageInfo = NULL;
>>>> +        vk_descriptor_writes[i].pBufferInfo = NULL;
>>>> +        vk_descriptor_writes[i].pTexelBufferView = 
>>>> &vk_uav_counter_views[uav_counter->register_index];
>>>> +    }
>>>> +
>>>> +    VK_CALL(vkUpdateDescriptorSets(vk_device, uav_counter_count, 
>>>> vk_descriptor_writes, 0, NULL));
>>>> +}
>>>> +
>>>> +static void 
>>>> d3d12_command_list_resolve_descriptor_table_normal(struct 
>>>> d3d12_command_list *list,
>>>> +        const struct d3d12_deferred_descriptor_set_update *update)
>>>> +{
>>>> +    const struct d3d12_root_descriptor_table *descriptor_table;
>>>> +    struct VkWriteDescriptorSet descriptor_writes[24], 
>>>> *current_descriptor_write;
>>>> +    struct VkDescriptorImageInfo image_infos[24], 
>>>> *current_image_info;
>>>> +    const struct d3d12_root_signature *root_signature = 
>>>> update->root_signature;
>>>> +    const struct vkd3d_vk_device_procs *vk_procs = 
>>>> &list->device->vk_procs;
>>>> +    const struct d3d12_root_descriptor_table_range *range;
>>>> +    VkDevice vk_device = list->device->vk_device;
>>>> +    unsigned int i, j, descriptor_count;
>>>> +    const struct d3d12_desc *descriptor;
>>>> +    const struct d3d12_desc *base_descriptor = 
>>>> update->base_descriptor;
>>>> +
>>>> +    descriptor_table = 
>>>> root_signature_get_descriptor_table(root_signature, update->index);
>>>> +
>>>> +    descriptor = update->base_descriptor;
>>>> +    descriptor_count = 0;
>>>> +    current_descriptor_write = descriptor_writes;
>>>> +    current_image_info = image_infos;
>>>> +    for (i = 0; i < descriptor_table->range_count; ++i)
>>>> +    {
>>>> +        range = &descriptor_table->ranges[i];
>>>>   +        if (range->offset != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
>>>> +        {
>>>> +            descriptor = base_descriptor + range->offset;
>>>> +        }
>>>> +
>>>> +        for (j = 0; j < range->descriptor_count; ++j, ++descriptor)
>>>> +        {
>>>>               if 
>>>> (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write,
>>>> -                    current_image_info, descriptor, 
>>>> range->descriptor_magic,
>>>> -                    bindings->descriptor_set, range->binding, j))
>>>> + current_image_info, descriptor, range->descriptor_magic,
>>>> + update->descriptor_set, range->binding, j))
>>>>                   continue;
>>>>                 ++descriptor_count;
>>>> @@ -2677,6 +2813,52 @@ static void 
>>>> d3d12_command_list_update_descriptor_table(struct d3d12_command_list
>>>>       VK_CALL(vkUpdateDescriptorSets(vk_device, descriptor_count, 
>>>> descriptor_writes, 0, NULL));
>>>>   }
>>>>   +static void d3d12_command_list_resolve_descriptor_table(struct 
>>>> d3d12_command_list *list,
>>>> + const struct d3d12_deferred_descriptor_set_update *update)
>>>> +{
>>>> +    if (update->uav)
>>>> + d3d12_command_list_resolve_descriptor_table_uav(list, update);
>>>> +    else
>>>> + d3d12_command_list_resolve_descriptor_table_normal(list, update);
>>>> +}
>>>> +
>>>> +static void d3d12_command_list_resolve_descriptor_tables(struct 
>>>> d3d12_command_list *list)
>>>> +{
>>>> +    unsigned i;
>>>> +    for (i = 0; i < list->descriptor_updates_count; i++)
>>>> +        d3d12_command_list_resolve_descriptor_table(list, 
>>>> &list->descriptor_updates[i]);
>>>> +}
>>>> +
>>>> +static void d3d12_command_list_update_descriptor_table(struct 
>>>> d3d12_command_list *list,
>>>> +        VkPipelineBindPoint bind_point, unsigned int index, struct 
>>>> d3d12_desc *base_descriptor)
>>>> +{
>>>> +    struct d3d12_deferred_descriptor_set_update update;
>>>> +    struct vkd3d_pipeline_bindings *bindings = 
>>>> &list->pipeline_bindings[bind_point];
>>>> +    const struct d3d12_root_signature *root_signature = 
>>>> bindings->root_signature;
>>>> +
>>>> +    update.descriptor_set = bindings->descriptor_set;
>>>> +    update.index = index;
>>>> +    update.root_signature = root_signature;
>>>> +    update.base_descriptor = base_descriptor;
>>>> +    update.uav = false;
>>>> + d3d12_command_list_resolve_descriptor_table_normal(list, &update);
>>>> +}
>>>> +
>>>> +static void 
>>>> d3d12_command_list_update_uav_counter_descriptor_table(struct 
>>>> d3d12_command_list *list,
>>>> +        VkPipelineBindPoint bind_point, unsigned int index, struct 
>>>> d3d12_desc *base_descriptor)
>>>> +{
>>>> +    struct d3d12_deferred_descriptor_set_update update;
>>>> +    struct vkd3d_pipeline_bindings *bindings = 
>>>> &list->pipeline_bindings[bind_point];
>>>> +    const struct d3d12_root_signature *root_signature = 
>>>> bindings->root_signature;
>>>> +
>>>> +    update.descriptor_set = bindings->uav_counter_descriptor_set;
>>>> +    update.index = index;
>>>> +    update.root_signature = root_signature;
>>>> +    update.base_descriptor = base_descriptor;
>>>> +    update.uav = true;
>>>> +    d3d12_command_list_resolve_descriptor_table_uav(list, &update);
>>>> +}
>>>> +
>>>>   static bool 
>>>> vk_write_descriptor_set_from_root_descriptor(VkWriteDescriptorSet 
>>>> *vk_descriptor_write,
>>>>           const struct d3d12_root_parameter *root_parameter, 
>>>> VkDescriptorSet vk_descriptor_set,
>>>>           VkBufferView *vk_buffer_view, const 
>>>> VkDescriptorBufferInfo *vk_buffer_info)
>>>> @@ -2781,55 +2963,6 @@ done:
>>>>       vkd3d_free(buffer_infos);
>>>>   }
>>>>   -static void 
>>>> d3d12_command_list_update_uav_counter_descriptors(struct 
>>>> d3d12_command_list *list,
>>>> -        VkPipelineBindPoint bind_point)
>>>> -{
>>>> -    VkWriteDescriptorSet 
>>>> vk_descriptor_writes[VKD3D_SHADER_MAX_UNORDERED_ACCESS_VIEWS];
>>>> -    struct vkd3d_pipeline_bindings *bindings = 
>>>> &list->pipeline_bindings[bind_point];
>>>> -    const struct vkd3d_vk_device_procs *vk_procs = 
>>>> &list->device->vk_procs;
>>>> -    const struct d3d12_pipeline_state *state = list->state;
>>>> -    VkDevice vk_device = list->device->vk_device;
>>>> -    VkDescriptorSet vk_descriptor_set;
>>>> -    unsigned int uav_counter_count;
>>>> -    unsigned int i;
>>>> -
>>>> -    if (!state || !(state->uav_counter_mask & 
>>>> bindings->uav_counter_dirty_mask))
>>>> -        return;
>>>> -
>>>> -    uav_counter_count = vkd3d_popcount(state->uav_counter_mask);
>>>> -    assert(uav_counter_count <= ARRAY_SIZE(vk_descriptor_writes));
>>>> -
>>>> -    vk_descriptor_set = 
>>>> d3d12_command_allocator_allocate_descriptor_set(list->allocator, 
>>>> state->vk_set_layout);
>>>> -    if (!vk_descriptor_set)
>>>> -        return;
>>>> -
>>>> -    for (i = 0; i < uav_counter_count; ++i)
>>>> -    {
>>>> -        const struct vkd3d_shader_uav_counter_binding *uav_counter 
>>>> = &state->uav_counters[i];
>>>> -        const VkBufferView *vk_uav_counter_views = 
>>>> bindings->vk_uav_counter_views;
>>>> -
>>>> - assert(vk_uav_counter_views[uav_counter->register_index]);
>>>> -
>>>> -        vk_descriptor_writes[i].sType = 
>>>> VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
>>>> -        vk_descriptor_writes[i].pNext = NULL;
>>>> -        vk_descriptor_writes[i].dstSet = vk_descriptor_set;
>>>> -        vk_descriptor_writes[i].dstBinding = 
>>>> uav_counter->binding.binding;
>>>> -        vk_descriptor_writes[i].dstArrayElement = 0;
>>>> -        vk_descriptor_writes[i].descriptorCount = 1;
>>>> -        vk_descriptor_writes[i].descriptorType = 
>>>> VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
>>>> -        vk_descriptor_writes[i].pImageInfo = NULL;
>>>> -        vk_descriptor_writes[i].pBufferInfo = NULL;
>>>> -        vk_descriptor_writes[i].pTexelBufferView = 
>>>> &vk_uav_counter_views[uav_counter->register_index];
>>>> -    }
>>>> -
>>>> -    VK_CALL(vkUpdateDescriptorSets(vk_device, uav_counter_count, 
>>>> vk_descriptor_writes, 0, NULL));
>>>> -
>>>> - VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bind_point,
>>>> -            state->vk_pipeline_layout, state->set_index, 1, 
>>>> &vk_descriptor_set, 0, NULL));
>>>> -
>>>> -    bindings->uav_counter_dirty_mask = 0;
>>>> -}
>>>> -
>>>>   static void d3d12_command_list_update_descriptors(struct 
>>>> d3d12_command_list *list,
>>>>           VkPipelineBindPoint bind_point)
>>>>   {
>>>> @@ -2842,31 +2975,86 @@ static void 
>>>> d3d12_command_list_update_descriptors(struct d3d12_command_list *lis
>>>>       if (!rs || !rs->vk_set_layout)
>>>>           return;
>>>>   +    if ((bindings->descriptor_table_active_mask | 
>>>> bindings->push_descriptor_dirty_mask |
>>>> +         (list->state->uav_counter_mask & 
>>>> bindings->uav_counter_dirty_mask)) == 0)
>>>> +    {
>>>> +        /* Nothing is dirty, so just return early. */
>>>> +        return;
>>>> +    }
>>>> +
>>>>       if (bindings->descriptor_table_dirty_mask || 
>>>> bindings->push_descriptor_dirty_mask)
>>>>           d3d12_command_list_prepare_descriptors(list, bind_point);
>>>> +    if (list->state->uav_counter_mask & 
>>>> bindings->uav_counter_dirty_mask)
>>>> + d3d12_command_list_prepare_uav_counter_descriptors(list, 
>>>> bind_point);
>>>>   -    for (i = 0; i < ARRAY_SIZE(bindings->descriptor_tables); ++i)
>>>> +    if (list->device->vk_info.EXT_descriptor_indexing)
>>>> +    {
>>>> + d3d12_command_list_defer_update_descriptor_table(list, 
>>>> bind_point, bindings->descriptor_table_dirty_mask,
>>>> + false);
>>>> +    }
>>>> +    else
>>>>       {
>>>> -        if (bindings->descriptor_table_dirty_mask & ((uint64_t)1 
>>>> << i))
>>>> +        /* FIXME: FOR_EACH_BIT */
>>>> +        for (i = 0; i < ARRAY_SIZE(bindings->descriptor_tables); ++i)
>>>>           {
>>>> -            if ((base_descriptor = 
>>>> d3d12_desc_from_gpu_handle(bindings->descriptor_tables[i])))
>>>> - d3d12_command_list_update_descriptor_table(list, bind_point, i, 
>>>> base_descriptor);
>>>> -            else
>>>> -                WARN("Descriptor table %u is not set.\n", i);
>>>> +            if (bindings->descriptor_table_dirty_mask & 
>>>> ((uint64_t) 1 << i))
>>>> +            {
>>>> +                if ((base_descriptor = 
>>>> d3d12_desc_from_gpu_handle(bindings->descriptor_tables[i])))
>>>> + d3d12_command_list_update_descriptor_table(list, bind_point, i, 
>>>> base_descriptor);
>>>> +                else
>>>> +                    WARN("Descriptor table %u is not set.\n", i);
>>>> +            }
>>>>           }
>>>>       }
>>>>       bindings->descriptor_table_dirty_mask = 0;
>>>>   +    /* Need to go through all descriptor tables here in the root 
>>>> signature,
>>>> +     * not just descriptor_table_dirty_mask. Binding a different 
>>>> shader may not invalidate descriptor tables,
>>>> +     * but it may invalidate the UAV counter set. */
>>>> +    if (bindings->uav_counter_dirty_mask)
>>>> +    {
>>>> +        if (list->device->vk_info.EXT_descriptor_indexing)
>>>> +        {
>>>> + d3d12_command_list_defer_update_descriptor_table(list, 
>>>> bind_point, bindings->descriptor_table_active_mask,
>>>> + true);
>>>> +        }
>>>> +        else
>>>> +        {
>>>> +            /* FIXME: FOR_EACH_BIT */
>>>> +            for (i = 0; i < 
>>>> ARRAY_SIZE(bindings->descriptor_tables); i++)
>>>> +            {
>>>> +                if (bindings->descriptor_table_active_mask & 
>>>> ((uint64_t) 1 << i))
>>>> +                {
>>>> +                    if ((base_descriptor = 
>>>> d3d12_desc_from_gpu_handle(bindings->descriptor_tables[i])))
>>>> + d3d12_command_list_update_uav_counter_descriptor_table(list, 
>>>> bind_point, i, base_descriptor);
>>>> +                    else
>>>> +                        WARN("Descriptor table %u is not set.\n", i);
>>>> +                }
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +    bindings->uav_counter_dirty_mask = 0;
>>>> +
>>>>       d3d12_command_list_update_push_descriptors(list, bind_point);
>>>>   -    if (bindings->descriptor_set)
>>>> +    /* Don't rebind the same descriptor set as long as we're in 
>>>> same pipeline layout. */
>>>> +    if (bindings->descriptor_set && bindings->descriptor_set != 
>>>> bindings->descriptor_set_bound)
>>>>       {
>>>> VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bind_point,
>>>>                   rs->vk_pipeline_layout, rs->main_set, 1, 
>>>> &bindings->descriptor_set, 0, NULL));
>>>>           bindings->in_use = true;
>>>> +        bindings->descriptor_set_bound = bindings->descriptor_set;
>>>>       }
>>>>   - d3d12_command_list_update_uav_counter_descriptors(list, 
>>>> bind_point);
>>>> +    /* Don't rebind the same descriptor set as long as we're in 
>>>> same pipeline layout. */
>>>> +    if (bindings->uav_counter_descriptor_set &&
>>>> +        bindings->uav_counter_descriptor_set != 
>>>> bindings->uav_counter_descriptor_set_bound)
>>>> +    {
>>>> + VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bind_point,
>>>> +                list->state->vk_pipeline_layout, 
>>>> list->state->set_index, 1, &bindings->uav_counter_descriptor_set, 
>>>> 0, NULL));
>>>> +        bindings->uav_counter_in_use = true;
>>>> +        bindings->uav_counter_descriptor_set_bound = 
>>>> bindings->uav_counter_descriptor_set;
>>>> +    }
>>>>   }
>>>>     static bool d3d12_command_list_begin_render_pass(struct 
>>>> d3d12_command_list *list)
>>>> @@ -4032,6 +4220,10 @@ static void 
>>>> d3d12_command_list_set_root_signature(struct d3d12_command_list *lis
>>>>       bindings->descriptor_set = VK_NULL_HANDLE;
>>>>       bindings->descriptor_table_dirty_mask = 
>>>> bindings->descriptor_table_active_mask & 
>>>> root_signature->descriptor_table_mask;
>>>>       bindings->push_descriptor_dirty_mask = 
>>>> bindings->push_descriptor_active_mask & 
>>>> root_signature->push_descriptor_mask;
>>>> +
>>>> +    bindings->uav_counter_descriptor_set = VK_NULL_HANDLE;
>>>> +    bindings->descriptor_set_bound = VK_NULL_HANDLE;
>>>> +    bindings->uav_counter_descriptor_set_bound = VK_NULL_HANDLE;
>>>>   }
>>>>     static void STDMETHODCALLTYPE 
>>>> d3d12_command_list_SetComputeRootSignature(ID3D12GraphicsCommandList1 
>>>> *iface,
>>>> @@ -5405,6 +5597,9 @@ static HRESULT d3d12_command_list_init(struct 
>>>> d3d12_command_list *list, struct d
>>>>       d3d12_device_add_ref(list->device = device);
>>>>         list->allocator = allocator;
>>>> +    list->descriptor_updates = NULL;
>>>> +    list->descriptor_updates_count = 0;
>>>> +    list->descriptor_updates_size = 0;
>>>>         if (SUCCEEDED(hr = 
>>>> d3d12_command_allocator_allocate_command_buffer(allocator, list)))
>>>>       {
>>>> @@ -5642,6 +5837,13 @@ static void STDMETHODCALLTYPE 
>>>> d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
>>>>               return;
>>>>           }
>>>>   +        /* Descriptors in root signature in 1.0 are VOLATILE by 
>>>> default, so
>>>> +         * the descriptor heap only need to be valid right before 
>>>> we submit them to the GPU.
>>>> +         * If we have EXT_descriptor_indexing enabled with 
>>>> UpdateAfterBind, we update
>>>> +         * descriptor sets here rather than while we're recording 
>>>> the command buffer.
>>>> +         * For each submission of the command buffer, we can 
>>>> modify the descriptor heap as we please. */
>>>> + d3d12_command_list_resolve_descriptor_tables(cmd_list);
>>>> +
>>>>           buffers[i] = cmd_list->vk_command_buffer;
>>>>       }
>>>>   diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
>>>> index 13ebc70..e159c1f 100644
>>>> --- a/libs/vkd3d/device.c
>>>> +++ b/libs/vkd3d/device.c
>>>> @@ -1436,11 +1436,25 @@ static HRESULT 
>>>> vkd3d_init_device_caps(struct d3d12_device *device,
>>>>       }
>>>>         if (vulkan_info->EXT_descriptor_indexing && 
>>>> descriptor_indexing
>>>> -            && 
>>>> (descriptor_indexing->descriptorBindingUniformBufferUpdateAfterBind
>>>> -            || 
>>>> descriptor_indexing->descriptorBindingStorageBufferUpdateAfterBind
>>>> +        && 
>>>> descriptor_indexing->descriptorBindingUniformBufferUpdateAfterBind
>>>> +        && 
>>>> descriptor_indexing->descriptorBindingSampledImageUpdateAfterBind
>>>> +        && 
>>>> descriptor_indexing->descriptorBindingStorageImageUpdateAfterBind
>>>> +        && 
>>>> descriptor_indexing->descriptorBindingUniformTexelBufferUpdateAfterBind)
>>>> +    {
>>>> +        TRACE("Enabling VK_EXT_descriptor_indexing for volatile 
>>>> descriptor updates.\n");
>>>> +    }
>>>> +    else
>>>> +    {
>>>> +        WARN("VK_EXT_descriptor indexing not supported in 
>>>> sufficient capacity. Volatile descriptor updates will not work.\n");
>>>> +        vulkan_info->EXT_descriptor_indexing = false;
>>>> +    }
>>>> +
>>>> +    if (vulkan_info->EXT_descriptor_indexing && descriptor_indexing
>>>> +        && 
>>>> (descriptor_indexing->descriptorBindingUniformBufferUpdateAfterBind
>>>>               || 
>>>> descriptor_indexing->descriptorBindingUniformTexelBufferUpdateAfterBind
>>>> +            || 
>>>> descriptor_indexing->descriptorBindingStorageBufferUpdateAfterBind
>>>>               || 
>>>> descriptor_indexing->descriptorBindingStorageTexelBufferUpdateAfterBind)
>>>> -            && 
>>>> !physical_device_info->descriptor_indexing_properties.robustBufferAccessUpdateAfterBind)
>>>> +        && 
>>>> !physical_device_info->descriptor_indexing_properties.robustBufferAccessUpdateAfterBind)
>>>>       {
>>>>           WARN("Disabling robust buffer access for the update after 
>>>> bind feature.\n");
>>>>           features->robustBufferAccess = VK_FALSE;
>>>> diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c
>>>> index a321fa4..50cff1f 100644
>>>> --- a/libs/vkd3d/state.c
>>>> +++ b/libs/vkd3d/state.c
>>>> @@ -745,21 +745,43 @@ static HRESULT 
>>>> vkd3d_create_descriptor_set_layout(struct d3d12_device *device,
>>>>           VkDescriptorSetLayoutCreateFlags flags, unsigned int 
>>>> binding_count,
>>>>           const VkDescriptorSetLayoutBinding *bindings, 
>>>> VkDescriptorSetLayout *set_layout)
>>>>   {
>>>> +    unsigned int i;
>>>>       const struct vkd3d_vk_device_procs *vk_procs = 
>>>> &device->vk_procs;
>>>>       VkDescriptorSetLayoutCreateInfo set_desc;
>>>>       VkResult vr;
>>>> +    VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_info;
>>>> +    VkDescriptorBindingFlagsEXT *binding_flags = NULL;
>>>>         set_desc.sType = 
>>>> VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
>>>>       set_desc.pNext = NULL;
>>>>       set_desc.flags = flags;
>>>>       set_desc.bindingCount = binding_count;
>>>>       set_desc.pBindings = bindings;
>>>> +
>>>> +    if (!(flags & 
>>>> VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR) && 
>>>> device->vk_info.EXT_descriptor_indexing)
>>>> +    {
>>>> +        set_desc.flags |= 
>>>> VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
>>>> +        flags_info.sType = 
>>>> VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
>>>> +        flags_info.pNext = NULL;
>>>> +        flags_info.bindingCount = binding_count;
>>>> +        binding_flags = vkd3d_malloc(sizeof(*binding_flags) * 
>>>> binding_count);
>>>> +        for (i = 0; i < binding_count; i++)
>>>> +        {
>>>> +            binding_flags[i] = 
>>>> VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT |
>>>> + VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT;
>>>> +        }
>>>> +        flags_info.pBindingFlags = binding_flags;
>>>> +        set_desc.pNext = &flags_info;
>>>> +    }
>>>> +
>>>>       if ((vr = 
>>>> VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, 
>>>> NULL, set_layout))) < 0)
>>>>       {
>>>>           WARN("Failed to create Vulkan descriptor set layout, vr 
>>>> %d.\n", vr);
>>>> +        vkd3d_free(binding_flags);
>>>>           return hresult_from_vk_result(vr);
>>>>       }
>>>>   +    vkd3d_free(binding_flags);
>>>>       return S_OK;
>>>>   }
>>>>   diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
>>>> index 2d62fda..58e9aa9 100644
>>>> --- a/libs/vkd3d/vkd3d_private.h
>>>> +++ b/libs/vkd3d/vkd3d_private.h
>>>> @@ -888,13 +888,16 @@ struct vkd3d_pipeline_bindings
>>>>       const struct d3d12_root_signature *root_signature;
>>>>         VkDescriptorSet descriptor_set;
>>>> +    VkDescriptorSet uav_counter_descriptor_set;
>>>> +    VkDescriptorSet descriptor_set_bound;
>>>> +    VkDescriptorSet uav_counter_descriptor_set_bound;
>>>>       bool in_use;
>>>> +    bool uav_counter_in_use;
>>>>         D3D12_GPU_DESCRIPTOR_HANDLE 
>>>> descriptor_tables[D3D12_MAX_ROOT_COST];
>>>>       uint64_t descriptor_table_dirty_mask;
>>>>       uint64_t descriptor_table_active_mask;
>>>>   -    VkBufferView 
>>>> vk_uav_counter_views[VKD3D_SHADER_MAX_UNORDERED_ACCESS_VIEWS];
>>>>       uint8_t uav_counter_dirty_mask;
>>>>         /* Needed when VK_KHR_push_descriptor is not available. */
>>>> @@ -903,6 +906,16 @@ struct vkd3d_pipeline_bindings
>>>>       uint32_t push_descriptor_active_mask;
>>>>   };
>>>>   +struct d3d12_deferred_descriptor_set_update
>>>> +{
>>>> +    const struct d3d12_desc *base_descriptor;
>>>> +    unsigned int index;
>>>> +
>>>> +    const struct d3d12_root_signature *root_signature;
>>>> +    VkDescriptorSet descriptor_set;
>>>> +    bool uav;
>>>> +};
>>>> +
>>>>   /* ID3D12CommandList */
>>>>   struct d3d12_command_list
>>>>   {
>>>> @@ -946,6 +959,10 @@ struct d3d12_command_list
>>>>       VkBuffer so_counter_buffers[D3D12_SO_BUFFER_SLOT_COUNT];
>>>>       VkDeviceSize 
>>>> so_counter_buffer_offsets[D3D12_SO_BUFFER_SLOT_COUNT];
>>>>   +    struct d3d12_deferred_descriptor_set_update 
>>>> *descriptor_updates;
>>>> +    size_t descriptor_updates_size;
>>>> +    size_t descriptor_updates_count;
>>>> +
>>>>       struct vkd3d_private_store private_store;
>>>>   };
>>>>   diff --git a/tests/d3d12.c b/tests/d3d12.c
>>>> index 858cf99..16a048c 100644
>>>> --- a/tests/d3d12.c
>>>> +++ b/tests/d3d12.c
>>>> @@ -15799,7 +15799,7 @@ static void 
>>>> test_update_descriptor_heap_after_closing_command_list(void)
>>>>               D3D12_RESOURCE_STATE_RENDER_TARGET, 
>>>> D3D12_RESOURCE_STATE_COPY_SOURCE);
>>>> get_texture_readback_with_command_list(context.render_target, 0, 
>>>> &rb, queue, command_list);
>>>>       value = get_readback_uint(&rb, 0, 0, 0);
>>>> -    todo ok(value == 0xff00ff00, "Got unexpected value %#x.\n", 
>>>> value);
>>>> +    ok(value == 0xff00ff00, "Got unexpected value %#x.\n", value);
>>>>       release_resource_readback(&rb);
>>>>         ID3D12DescriptorHeap_Release(cpu_heap);
>>>
>>
>



More information about the wine-devel mailing list