[PATCH] vkd3d: Support RS 1.0 VOLATILE descriptors.

Sveinar Søpler cybermax at dexter.no
Sat Nov 2 12:44:07 CDT 2019


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