[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