History

vulkan: add support for regular descriptor pools

This permits: - The use of Vulkan filtering on many more devices - Better debugging due to lack of descriptor buffer support in layers Much of the changes here are due to a requirement that updates to descriptors must happen between the command buffer being waited on, and the pipeline not being bound. We routinely did it the other way around, by updating only after we bind the pipeline.

Lynne committed 2 years ago

Commit 8a7af4a1 parent 3d75ba77 files · +394 −232Browse files

Unified · Split

7 files
  1. libavfilter/vf_gblur_vulkan.c +1 −1
  2. libavfilter/vf_nlmeans_vulkan.c +9 −12
  3. libavfilter/vulkan_filter.c +55 −65
  4. libavutil/hwcontext_vulkan.c +6 −0
  5. libavutil/vulkan.c +271 −114
  6. libavutil/vulkan.h +49 −40
  7. libavutil/vulkan_functions.h +3 −0
libavfilter/vf_gblur_vulkan.c+1−1
@@ -189,7 +189,7 @@ static int init_gblur_pipeline(GBlurVulkanContext *s, FFVulkanPipeline *pl, · 188 unmodified lines
189189 RET(ff_vk_unmap_buffer(&s->vkctx, params_buf, 1));
190190
191191 RET(ff_vk_set_descriptor_buffer(&s->vkctx, pl, NULL, 1, 0, 0,
192− params_buf->address, params_buf->size,
192+ params_buf, 0, params_buf->size,
193193 VK_FORMAT_UNDEFINED));
194194
195195 fail:
libavfilter/vf_nlmeans_vulkan.c+9−12
@@ -657,7 +657,7 @@ static av_cold int init_filter(AVFilterContext *ctx) · 656 unmodified lines
657657 spv, desc, planes));
658658
659659 RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_weights, NULL, 1, 0, 0,
660− s->xyoffsets_buf.address, s->xyoffsets_buf.size,
660+ &s->xyoffsets_buf, 0, s->xyoffsets_buf.size,
661661 VK_FORMAT_UNDEFINED));
662662
663663 do {
@@ -751,8 +751,8 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) · 87 unmodified lines
751751 /* Weights/sums */
752752 AVBufferRef *ws_buf = NULL;
753753 FFVkBuffer *ws_vk;
754− VkDeviceAddress weights_addr[4];
755− VkDeviceAddress sums_addr[4];
754+ VkDeviceSize weights_addr[4];
755+ VkDeviceSize sums_addr[4];
756756 uint32_t ws_stride[4];
757757 size_t ws_size[4];
758758 size_t ws_total_size = 0;
@@ -810,8 +810,8 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) · 51 unmodified lines
810810 return err;
811811 ws_vk = (FFVkBuffer *)ws_buf->data;
812812
813− weights_addr[0] = ws_vk->address;
814− sums_addr[0] = ws_vk->address + ws_total_size;
813+ weights_addr[0] = 0;
814+ sums_addr[0] = ws_total_size;
815815 for (int i = 1; i < desc->nb_components; i++) {
816816 weights_addr[i] = weights_addr[i - 1] + ws_size[i - 1];
817817 sums_addr[i] = sums_addr[i - 1] + ws_size[i - 1];
@@ -844,9 +844,6 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) · 26 unmodified lines
844844
845845 /* Input frame prep */
846846 RET(ff_vk_create_imageviews(vkctx, exec, in_views, in));
847− ff_vk_update_descriptor_img_array(vkctx, &s->pl_weights, exec, in, in_views, 0, 0,
848− VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
849− s->sampler);
850847 ff_vk_frame_barrier(vkctx, exec, in, img_bar, &nb_img_bar,
851848 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
852849 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
@@ -934,10 +931,10 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) · 81 unmodified lines
934931 s->sampler);
935932 for (int i = 0; i < desc->nb_components; i++) {
936933 RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_weights, exec, 0, 1 + i*2 + 0, 0,
937− weights_addr[i], ws_size[i],
934+ ws_vk, weights_addr[i], ws_size[i],
938935 VK_FORMAT_UNDEFINED));
939936 RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_weights, exec, 0, 1 + i*2 + 1, 0,
940− sums_addr[i], ws_size[i],
937+ ws_vk, sums_addr[i], ws_size[i],
941938 VK_FORMAT_UNDEFINED));
942939 }
943940
@@ -949,10 +946,10 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) · 5 unmodified lines
949946 VK_IMAGE_LAYOUT_GENERAL, s->sampler);
950947 for (int i = 0; i < desc->nb_components; i++) {
951948 RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_denoise, exec, 0, 2 + i*2 + 0, 0,
952− weights_addr[i], ws_size[i],
949+ ws_vk, weights_addr[i], ws_size[i],
953950 VK_FORMAT_UNDEFINED));
954951 RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_denoise, exec, 0, 2 + i*2 + 1, 0,
955− sums_addr[i], ws_size[i],
952+ ws_vk, sums_addr[i], ws_size[i],
956953 VK_FORMAT_UNDEFINED));
957954 }
958955
libavfilter/vulkan_filter.c+55−65
@@ -152,18 +152,6 @@ skip: · 151 unmodified lines
152152 s->extensions = ff_vk_extensions_to_mask(vk_dev->enabled_dev_extensions,
153153 vk_dev->nb_enabled_dev_extensions);
154154
155− /**
156− * libplacebo does not use descriptor buffers.
157− */
158− if (!(s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) &&
159− strcmp(avctx->filter->name, "libplacebo")) {
160− av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires that "
161− "the %s extension is supported!\n",
162− VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
163− av_buffer_unref(&frames_ref);
164− return AVERROR(EINVAL);
165− }
166−
167155 err = ff_vk_load_functions(device_ctx, &s->vkfn, s->extensions, 1, 1);
168156 if (err < 0) {
169157 av_buffer_unref(&frames_ref);
@@ -264,12 +252,13 @@ int ff_vk_filter_process_simple(FFVulkanContext *vkctx, FFVkExecPool *e, · 94 unmodified lines
264252 FFVkExecContext *exec = ff_vk_exec_get(e);
265253 ff_vk_exec_start(vkctx, exec);
266254
267− ff_vk_exec_bind_pipeline(vkctx, exec, pl);
268−
269− if (push_src)
270− ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
271− 0, push_size, push_src);
272−
255+ RET(ff_vk_exec_add_dep_frame(vkctx, exec, out_f,
256+ VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
257+ VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
258+ RET(ff_vk_create_imageviews(vkctx, exec, out_views, out_f));
259+ ff_vk_update_descriptor_img_array(vkctx, pl, exec, out_f, out_views, 0, !!in_f,
260+ VK_IMAGE_LAYOUT_GENERAL,
261+ VK_NULL_HANDLE);
273262 if (in_f) {
274263 RET(ff_vk_exec_add_dep_frame(vkctx, exec, in_f,
275264 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
@@ -278,27 +267,28 @@ int ff_vk_filter_process_simple(FFVulkanContext *vkctx, FFVkExecPool *e, · 2 unmodified lines
278267 ff_vk_update_descriptor_img_array(vkctx, pl, exec, in_f, in_views, 0, 0,
279268 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
280269 sampler);
281− ff_vk_frame_barrier(vkctx, exec, in_f, img_bar, &nb_img_bar,
282− VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
283− VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
284− VK_ACCESS_SHADER_READ_BIT,
285− VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
286− VK_QUEUE_FAMILY_IGNORED);
287270 }
288271
289− RET(ff_vk_exec_add_dep_frame(vkctx, exec, out_f,
290− VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
291− VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
292− RET(ff_vk_create_imageviews(vkctx, exec, out_views, out_f));
293− ff_vk_update_descriptor_img_array(vkctx, pl, exec, out_f, out_views, 0, !!in_f,
294− VK_IMAGE_LAYOUT_GENERAL,
295− VK_NULL_HANDLE);
272+ /* Bind pipeline, update push data */
273+ ff_vk_exec_bind_pipeline(vkctx, exec, pl);
274+ if (push_src)
275+ ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
276+ 0, push_size, push_src);
277+
278+ /* Add data sync barriers */
296279 ff_vk_frame_barrier(vkctx, exec, out_f, img_bar, &nb_img_bar,
297280 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
298281 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
299282 VK_ACCESS_SHADER_WRITE_BIT,
300283 VK_IMAGE_LAYOUT_GENERAL,
301284 VK_QUEUE_FAMILY_IGNORED);
285+ if (in_f)
286+ ff_vk_frame_barrier(vkctx, exec, in_f, img_bar, &nb_img_bar,
287+ VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
288+ VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
289+ VK_ACCESS_SHADER_READ_BIT,
290+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
291+ VK_QUEUE_FAMILY_IGNORED);
302292
303293 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
304294 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
@@ -380,12 +370,6 @@ int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e, · 75 unmodified lines
380370 VkImageView *src_views = !i ? in_views : tmp_views;
381371 VkImageView *dst_views = !i ? tmp_views : out_views;
382372
383− ff_vk_exec_bind_pipeline(vkctx, exec, pl);
384−
385− if (push_src)
386− ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
387− 0, push_size, push_src);
388−
389373 ff_vk_update_descriptor_img_array(vkctx, pl, exec, src_f, src_views, 0, 0,
390374 !i ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL :
391375 VK_IMAGE_LAYOUT_GENERAL,
@@ -394,6 +378,12 @@ int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e, · 2 unmodified lines
394378 VK_IMAGE_LAYOUT_GENERAL,
395379 VK_NULL_HANDLE);
396380
381+ /* Bind pipeline, update push data */
382+ ff_vk_exec_bind_pipeline(vkctx, exec, pl);
383+ if (push_src)
384+ ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
385+ 0, push_size, push_src);
386+
397387 vk->CmdDispatch(exec->buf,
398388 FFALIGN(vkctx->output_width, pl->wg_size[0])/pl->wg_size[0],
399389 FFALIGN(vkctx->output_height, pl->wg_size[1])/pl->wg_size[1],
@@ -422,32 +412,47 @@ int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e, · 22 unmodified lines
422412 FFVkExecContext *exec = ff_vk_exec_get(e);
423413 ff_vk_exec_start(vkctx, exec);
424414
425− /* Inputs */
415+ /* Add deps and create temporary imageviews */
416+ RET(ff_vk_exec_add_dep_frame(vkctx, exec, out,
417+ VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
418+ VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
419+ RET(ff_vk_create_imageviews(vkctx, exec, out_views, out));
426420 for (int i = 0; i < nb_in; i++) {
427421 RET(ff_vk_exec_add_dep_frame(vkctx, exec, in[i],
428422 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
429423 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
430424 RET(ff_vk_create_imageviews(vkctx, exec, in_views[i], in[i]));
431−
432− ff_vk_frame_barrier(vkctx, exec, in[i], img_bar, &nb_img_bar,
433− VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
434− VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
435− VK_ACCESS_SHADER_READ_BIT,
436− VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
437− VK_QUEUE_FAMILY_IGNORED);
438425 }
439426
440− /* Output */
441− RET(ff_vk_exec_add_dep_frame(vkctx, exec, out,
442− VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
443− VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
444− RET(ff_vk_create_imageviews(vkctx, exec, out_views, out));
427+ /* Update descriptor sets */
428+ ff_vk_update_descriptor_img_array(vkctx, pl, exec, out, out_views, 0, nb_in,
429+ VK_IMAGE_LAYOUT_GENERAL,
430+ VK_NULL_HANDLE);
431+ for (int i = 0; i < nb_in; i++)
432+ ff_vk_update_descriptor_img_array(vkctx, pl, exec, in[i], in_views[i], 0, i,
433+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
434+ sampler);
435+
436+ /* Bind pipeline, update push data */
437+ ff_vk_exec_bind_pipeline(vkctx, exec, pl);
438+ if (push_src)
439+ ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
440+ 0, push_size, push_src);
441+
442+ /* Add data sync barriers */
445443 ff_vk_frame_barrier(vkctx, exec, out, img_bar, &nb_img_bar,
446444 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
447445 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
448446 VK_ACCESS_SHADER_WRITE_BIT,
449447 VK_IMAGE_LAYOUT_GENERAL,
450448 VK_QUEUE_FAMILY_IGNORED);
449+ for (int i = 0; i < nb_in; i++)
450+ ff_vk_frame_barrier(vkctx, exec, in[i], img_bar, &nb_img_bar,
451+ VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
452+ VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
453+ VK_ACCESS_SHADER_READ_BIT,
454+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
455+ VK_QUEUE_FAMILY_IGNORED);
451456
452457 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
453458 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
@@ -455,21 +460,6 @@ int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e, · 1 unmodified line
455460 .imageMemoryBarrierCount = nb_img_bar,
456461 });
457462
458− ff_vk_exec_bind_pipeline(vkctx, exec, pl);
459−
460− if (push_src)
461− ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT,
462− 0, push_size, push_src);
463−
464− for (int i = 0; i < nb_in; i++)
465− ff_vk_update_descriptor_img_array(vkctx, pl, exec, in[i], in_views[i], 0, i,
466− VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
467− sampler);
468−
469− ff_vk_update_descriptor_img_array(vkctx, pl, exec, out, out_views, 0, nb_in,
470− VK_IMAGE_LAYOUT_GENERAL,
471− VK_NULL_HANDLE);
472−
473463 vk->CmdDispatch(exec->buf,
474464 FFALIGN(vkctx->output_width, pl->wg_size[0])/pl->wg_size[0],
475465 FFALIGN(vkctx->output_height, pl->wg_size[1])/pl->wg_size[1],
libavutil/hwcontext_vulkan.c+6−0
@@ -578,6 +578,12 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, · 577 unmodified lines
578578 for (int i = 0; i < optional_exts_num; i++) {
579579 tstr = optional_exts[i].name;
580580 found = 0;
581+
582+ if (dev && debug_mode &&
583+ !strcmp(tstr, VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME)) {
584+ continue;
585+ }
586+
581587 for (int j = 0; j < sup_ext_count; j++) {
582588 if (!strcmp(tstr, sup_ext[j].extensionName)) {
583589 found = 1;
libavutil/vulkan.c+271−114
@@ -1561,7 +1561,8 @@ int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl, · 1560 unmodified lines
15611561 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
15621562 .bindingCount = nb,
15631563 .pBindings = set->binding,
1564− .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,
1564+ .flags = (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) ?
1565+ VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT : 0x0,
15651566 };
15661567
15671568 for (int i = 0; i < nb; i++) {
@@ -1589,13 +1590,35 @@ int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl, · 21 unmodified lines
15891590 return AVERROR_EXTERNAL;
15901591 }
15911592
1592− vk->GetDescriptorSetLayoutSizeEXT(s->hwctx->act_dev, *layout, &set->layout_size);
1593+ if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
1594+ vk->GetDescriptorSetLayoutSizeEXT(s->hwctx->act_dev, *layout, &set->layout_size);
1595+ set->aligned_size = FFALIGN(set->layout_size, s->desc_buf_props.descriptorBufferOffsetAlignment);
15931596
1594− set->aligned_size = FFALIGN(set->layout_size, s->desc_buf_props.descriptorBufferOffsetAlignment);
1595−
1596− for (int i = 0; i < nb; i++)
1597− vk->GetDescriptorSetLayoutBindingOffsetEXT(s->hwctx->act_dev, *layout,
1598− i, &set->binding_offset[i]);
1597+ for (int i = 0; i < nb; i++)
1598+ vk->GetDescriptorSetLayoutBindingOffsetEXT(s->hwctx->act_dev, *layout,
1599+ i, &set->binding_offset[i]);
1600+ } else {
1601+ for (int i = 0; i < nb; i++) {
1602+ int j;
1603+ VkDescriptorPoolSize *desc_pool_size;
1604+ for (j = 0; j < pl->nb_desc_pool_size; j++)
1605+ if (pl->desc_pool_size[j].type == desc[i].type)
1606+ break;
1607+ if (j >= pl->nb_desc_pool_size) {
1608+ desc_pool_size = av_realloc_array(pl->desc_pool_size,
1609+ sizeof(*desc_pool_size),
1610+ pl->nb_desc_pool_size + 1);
1611+ if (!desc_pool_size)
1612+ return AVERROR(ENOMEM);
1613+
1614+ pl->desc_pool_size = desc_pool_size;
1615+ pl->nb_desc_pool_size++;
1616+ memset(&desc_pool_size[j], 0, sizeof(VkDescriptorPoolSize));
1617+ }
1618+ pl->desc_pool_size[j].type = desc[i].type;
1619+ pl->desc_pool_size[j].descriptorCount += FFMAX(desc[i].elems, 1);
1620+ }
1621+ }
15991622
16001623 set->singular = singular;
16011624 set->nb_bindings = nb;
@@ -1643,38 +1666,102 @@ int ff_vk_exec_pipeline_register(FFVulkanContext *s, FFVkExecPool *pool, · 41 unmodified lines
16431666 {
16441667 int err;
16451668
1646− pl->desc_bind = av_calloc(pl->nb_descriptor_sets, sizeof(*pl->desc_bind));
1647− if (!pl->desc_bind)
1648− return AVERROR(ENOMEM);
1669+ if (!pl->nb_descriptor_sets)
1670+ return 0;
16491671
1650− pl->bound_buffer_indices = av_calloc(pl->nb_descriptor_sets,
1651− sizeof(*pl->bound_buffer_indices));
1652− if (!pl->bound_buffer_indices)
1653− return AVERROR(ENOMEM);
1672+ if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
1673+ pl->desc_bind = av_calloc(pl->nb_descriptor_sets, sizeof(*pl->desc_bind));
1674+ if (!pl->desc_bind)
1675+ return AVERROR(ENOMEM);
16541676
1655− for (int i = 0; i < pl->nb_descriptor_sets; i++) {
1656− FFVulkanDescriptorSet *set = &pl->desc_set[i];
1657− int nb = set->singular ? 1 : pool->pool_size;
1658−
1659− err = ff_vk_create_buf(s, &set->buf, set->aligned_size*nb,
1660− NULL, NULL, set->usage,
1661− VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
1662− VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1663− VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
1664− if (err < 0)
1665− return err;
1677+ pl->bound_buffer_indices = av_calloc(pl->nb_descriptor_sets,
1678+ sizeof(*pl->bound_buffer_indices));
1679+ if (!pl->bound_buffer_indices)
1680+ return AVERROR(ENOMEM);
16661681
1667− err = ff_vk_map_buffer(s, &set->buf, &set->desc_mem, 0);
1668− if (err < 0)
1669− return err;
1682+ for (int i = 0; i < pl->nb_descriptor_sets; i++) {
1683+ FFVulkanDescriptorSet *set = &pl->desc_set[i];
1684+ int nb = set->singular ? 1 : pool->pool_size;
1685+
1686+ err = ff_vk_create_buf(s, &set->buf, set->aligned_size*nb,
1687+ NULL, NULL, set->usage,
1688+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
1689+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1690+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
1691+ if (err < 0)
1692+ return err;
1693+
1694+ err = ff_vk_map_buffer(s, &set->buf, &set->desc_mem, 0);
1695+ if (err < 0)
1696+ return err;
1697+
1698+ pl->desc_bind[i] = (VkDescriptorBufferBindingInfoEXT) {
1699+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT,
1700+ .usage = set->usage,
1701+ .address = set->buf.address,
1702+ };
16701703
1671− pl->desc_bind[i] = (VkDescriptorBufferBindingInfoEXT) {
1672− .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT,
1673− .usage = set->usage,
1674− .address = set->buf.address,
1704+ pl->bound_buffer_indices[i] = i;
1705+ }
1706+ } else {
1707+ VkResult ret;
1708+ FFVulkanFunctions *vk = &s->vkfn;
1709+ VkDescriptorSetLayout *tmp_layouts;
1710+ VkDescriptorSetAllocateInfo set_alloc_info;
1711+ VkDescriptorPoolCreateInfo pool_create_info;
1712+
1713+ for (int i = 0; i < pl->nb_desc_pool_size; i++)
1714+ pl->desc_pool_size[i].descriptorCount *= pool->pool_size;
1715+
1716+ pool_create_info = (VkDescriptorPoolCreateInfo) {
1717+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1718+ .flags = 0,
1719+ .pPoolSizes = pl->desc_pool_size,
1720+ .poolSizeCount = pl->nb_desc_pool_size,
1721+ .maxSets = pl->nb_descriptor_sets*pool->pool_size,
16751722 };
16761723
1677− pl->bound_buffer_indices[i] = i;
1724+ ret = vk->CreateDescriptorPool(s->hwctx->act_dev, &pool_create_info,
1725+ s->hwctx->alloc, &pl->desc_pool);
1726+ if (ret != VK_SUCCESS) {
1727+ av_log(s, AV_LOG_ERROR, "Unable to create descriptor pool: %s\n",
1728+ ff_vk_ret2str(ret));
1729+ return AVERROR_EXTERNAL;
1730+ }
1731+
1732+ tmp_layouts = av_malloc_array(pool_create_info.maxSets, sizeof(*tmp_layouts));
1733+ if (!tmp_layouts)
1734+ return AVERROR(ENOMEM);
1735+
1736+ /* Colate each execution context's descriptor set layouts */
1737+ for (int i = 0; i < pool->pool_size; i++)
1738+ for (int j = 0; j < pl->nb_descriptor_sets; j++)
1739+ tmp_layouts[i*pl->nb_descriptor_sets + j] = pl->desc_layout[j];
1740+
1741+ set_alloc_info = (VkDescriptorSetAllocateInfo) {
1742+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1743+ .descriptorPool = pl->desc_pool,
1744+ .pSetLayouts = tmp_layouts,
1745+ .descriptorSetCount = pool_create_info.maxSets,
1746+ };
1747+
1748+ pl->desc_sets = av_malloc_array(pool_create_info.maxSets,
1749+ sizeof(*tmp_layouts));
1750+ if (!pl->desc_sets) {
1751+ av_free(tmp_layouts);
1752+ return AVERROR(ENOMEM);
1753+ }
1754+ ret = vk->AllocateDescriptorSets(s->hwctx->act_dev, &set_alloc_info,
1755+ pl->desc_sets);
1756+ av_free(tmp_layouts);
1757+ if (ret != VK_SUCCESS) {
1758+ av_log(s, AV_LOG_ERROR, "Unable to allocate descriptor set: %s\n",
1759+ ff_vk_ret2str(ret));
1760+ av_freep(&pl->desc_sets);
1761+ return AVERROR_EXTERNAL;
1762+ }
1763+
1764+ pl->assoc_pool = pool;
16781765 }
16791766
16801767 return 0;
@@ -1696,94 +1783,150 @@ static inline void update_set_descriptor(FFVulkanContext *s, FFVkExecContext *e, · 15 unmodified lines
16961783 vk->GetDescriptorEXT(s->hwctx->act_dev, desc_get_info, desc_size, desc);
16971784 }
16981785
1786+static inline void update_set_pool_write(FFVulkanContext *s,
1787+ FFVulkanPipeline *pl,
1788+ FFVkExecContext *e,
1789+ FFVulkanDescriptorSet *desc_set, int set,
1790+ VkWriteDescriptorSet *write_info)
1791+{
1792+ FFVulkanFunctions *vk = &s->vkfn;
1793+ if (desc_set->singular) {
1794+ for (int i = 0; i < pl->assoc_pool->pool_size; i++) {
1795+ write_info->dstSet = pl->desc_sets[i*pl->nb_descriptor_sets + set];
1796+ vk->UpdateDescriptorSets(s->hwctx->act_dev, 1, write_info, 0, NULL);
1797+ }
1798+ } else {
1799+ write_info->dstSet = pl->desc_sets[e->idx*pl->nb_descriptor_sets + set];
1800+ vk->UpdateDescriptorSets(s->hwctx->act_dev, 1, write_info, 0, NULL);
1801+ }
1802+}
1803+
16991804 static int vk_set_descriptor_image(FFVulkanContext *s, FFVulkanPipeline *pl,
17001805 FFVkExecContext *e, int set, int bind, int offs,
17011806 VkImageView view, VkImageLayout layout,
17021807 VkSampler sampler)
17031808 {
17041809 FFVulkanDescriptorSet *desc_set = &pl->desc_set[set];
1705− VkDescriptorGetInfoEXT desc_get_info = {
1706− .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
1707− .type = desc_set->binding[bind].descriptorType,
1708− };
1709− VkDescriptorImageInfo desc_img_info = {
1710− .imageView = view,
1711− .sampler = sampler,
1712− .imageLayout = layout,
1713− };
1714− size_t desc_size;
17151810
1716− switch (desc_get_info.type) {
1717− case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
1718− desc_get_info.data.pSampledImage = &desc_img_info;
1719− desc_size = s->desc_buf_props.sampledImageDescriptorSize;
1720− break;
1721− case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
1722− desc_get_info.data.pStorageImage = &desc_img_info;
1723− desc_size = s->desc_buf_props.storageImageDescriptorSize;
1724− break;
1725− case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
1726− desc_get_info.data.pInputAttachmentImage = &desc_img_info;
1727− desc_size = s->desc_buf_props.inputAttachmentDescriptorSize;
1728− break;
1729− case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
1730− desc_get_info.data.pCombinedImageSampler = &desc_img_info;
1731− desc_size = s->desc_buf_props.combinedImageSamplerDescriptorSize;
1732− break;
1733− default:
1734− av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
1735− set, bind, desc_get_info.type);
1736− return AVERROR(EINVAL);
1737− break;
1738− };
1811+ if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
1812+ VkDescriptorGetInfoEXT desc_get_info = {
1813+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
1814+ .type = desc_set->binding[bind].descriptorType,
1815+ };
1816+ VkDescriptorImageInfo desc_img_info = {
1817+ .imageView = view,
1818+ .sampler = sampler,
1819+ .imageLayout = layout,
1820+ };
1821+ size_t desc_size;
1822+
1823+ switch (desc_get_info.type) {
1824+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
1825+ desc_get_info.data.pSampledImage = &desc_img_info;
1826+ desc_size = s->desc_buf_props.sampledImageDescriptorSize;
1827+ break;
1828+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
1829+ desc_get_info.data.pStorageImage = &desc_img_info;
1830+ desc_size = s->desc_buf_props.storageImageDescriptorSize;
1831+ break;
1832+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
1833+ desc_get_info.data.pInputAttachmentImage = &desc_img_info;
1834+ desc_size = s->desc_buf_props.inputAttachmentDescriptorSize;
1835+ break;
1836+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
1837+ desc_get_info.data.pCombinedImageSampler = &desc_img_info;
1838+ desc_size = s->desc_buf_props.combinedImageSamplerDescriptorSize;
1839+ break;
1840+ default:
1841+ av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
1842+ set, bind, desc_get_info.type);
1843+ return AVERROR(EINVAL);
1844+ break;
1845+ };
17391846
1740− update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size);
1847+ update_set_descriptor(s, e, desc_set, bind, offs,
1848+ &desc_get_info, desc_size);
1849+ } else {
1850+ VkDescriptorImageInfo desc_pool_write_info_img = {
1851+ .sampler = sampler,
1852+ .imageView = view,
1853+ .imageLayout = layout,
1854+ };
1855+ VkWriteDescriptorSet desc_pool_write_info = {
1856+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1857+ .dstBinding = bind,
1858+ .descriptorCount = 1,
1859+ .dstArrayElement = offs,
1860+ .descriptorType = desc_set->binding[bind].descriptorType,
1861+ .pImageInfo = &desc_pool_write_info_img,
1862+ };
1863+ update_set_pool_write(s, pl, e, desc_set, set, &desc_pool_write_info);
1864+ }
17411865
17421866 return 0;
17431867 }
17441868
17451869 int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl,
1746− FFVkExecContext *e, int set, int bind, int offs,
1747− VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt)
1870+ FFVkExecContext *e, int set, int bind, int elem,
1871+ FFVkBuffer *buf, VkDeviceSize offset, VkDeviceSize len,
1872+ VkFormat fmt)
17481873 {
17491874 FFVulkanDescriptorSet *desc_set = &pl->desc_set[set];
1750− VkDescriptorGetInfoEXT desc_get_info = {
1751− .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
1752− .type = desc_set->binding[bind].descriptorType,
1753− };
1754− VkDescriptorAddressInfoEXT desc_buf_info = {
1755− .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT,
1756− .address = addr,
1757− .range = len,
1758− .format = fmt,
1759− };
1760− size_t desc_size;
17611875
1762− switch (desc_get_info.type) {
1763− case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1764− desc_get_info.data.pUniformBuffer = &desc_buf_info;
1765− desc_size = s->desc_buf_props.uniformBufferDescriptorSize;
1766− break;
1767− case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1768− desc_get_info.data.pStorageBuffer = &desc_buf_info;
1769− desc_size = s->desc_buf_props.storageBufferDescriptorSize;
1770− break;
1771− case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1772− desc_get_info.data.pUniformTexelBuffer = &desc_buf_info;
1773− desc_size = s->desc_buf_props.uniformTexelBufferDescriptorSize;
1774− break;
1775− case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1776− desc_get_info.data.pStorageTexelBuffer = &desc_buf_info;
1777− desc_size = s->desc_buf_props.storageTexelBufferDescriptorSize;
1778− break;
1779− default:
1780− av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
1781− set, bind, desc_get_info.type);
1782− return AVERROR(EINVAL);
1783− break;
1784− };
1876+ if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
1877+ VkDescriptorGetInfoEXT desc_get_info = {
1878+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
1879+ .type = desc_set->binding[bind].descriptorType,
1880+ };
1881+ VkDescriptorAddressInfoEXT desc_buf_info = {
1882+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT,
1883+ .address = buf->address + offset,
1884+ .range = len,
1885+ .format = fmt,
1886+ };
1887+ size_t desc_size;
1888+
1889+ switch (desc_get_info.type) {
1890+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1891+ desc_get_info.data.pUniformBuffer = &desc_buf_info;
1892+ desc_size = s->desc_buf_props.uniformBufferDescriptorSize;
1893+ break;
1894+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1895+ desc_get_info.data.pStorageBuffer = &desc_buf_info;
1896+ desc_size = s->desc_buf_props.storageBufferDescriptorSize;
1897+ break;
1898+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1899+ desc_get_info.data.pUniformTexelBuffer = &desc_buf_info;
1900+ desc_size = s->desc_buf_props.uniformTexelBufferDescriptorSize;
1901+ break;
1902+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1903+ desc_get_info.data.pStorageTexelBuffer = &desc_buf_info;
1904+ desc_size = s->desc_buf_props.storageTexelBufferDescriptorSize;
1905+ break;
1906+ default:
1907+ av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
1908+ set, bind, desc_get_info.type);
1909+ return AVERROR(EINVAL);
1910+ break;
1911+ };
17851912
1786− update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size);
1913+ update_set_descriptor(s, e, desc_set, bind, elem, &desc_get_info, desc_size);
1914+ } else {
1915+ VkDescriptorBufferInfo desc_pool_write_info_buf = {
1916+ .buffer = buf->buf,
1917+ .offset = offset,
1918+ .range = len,
1919+ };
1920+ VkWriteDescriptorSet desc_pool_write_info = {
1921+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1922+ .dstBinding = bind,
1923+ .descriptorCount = 1,
1924+ .dstArrayElement = elem,
1925+ .descriptorType = desc_set->binding[bind].descriptorType,
1926+ .pBufferInfo = &desc_pool_write_info_buf,
1927+ };
1928+ update_set_pool_write(s, pl, e, desc_set, set, &desc_pool_write_info);
1929+ }
17871930
17881931 return 0;
17891932 }
@@ -1852,7 +1995,8 @@ int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl, · 62 unmodified lines
18521995
18531996 pipeline_create_info = (VkComputePipelineCreateInfo) {
18541997 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
1855− .flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,
1998+ .flags = (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) ?
1999+ VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT : 0x0,
18562000 .layout = pl->pipeline_layout,
18572001 .stage = shd->shader,
18582002 };
@@ -1884,15 +2028,22 @@ void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e, · 25 unmodified lines
18842028 vk->CmdBindPipeline(e->buf, pl->bind_point, pl->pipeline);
18852029
18862030 if (pl->nb_descriptor_sets) {
1887− for (int i = 0; i < pl->nb_descriptor_sets; i++)
1888− offsets[i] = pl->desc_set[i].singular ? 0 : pl->desc_set[i].aligned_size*e->idx;
1889−
1890− /* Bind descriptor buffers */
1891− vk->CmdBindDescriptorBuffersEXT(e->buf, pl->nb_descriptor_sets, pl->desc_bind);
1892− /* Binding offsets */
1893− vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, pl->bind_point, pl->pipeline_layout,
1894− 0, pl->nb_descriptor_sets,
1895− pl->bound_buffer_indices, offsets);
2031+ if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) {
2032+ for (int i = 0; i < pl->nb_descriptor_sets; i++)
2033+ offsets[i] = pl->desc_set[i].singular ? 0 : pl->desc_set[i].aligned_size*e->idx;
2034+
2035+ /* Bind descriptor buffers */
2036+ vk->CmdBindDescriptorBuffersEXT(e->buf, pl->nb_descriptor_sets, pl->desc_bind);
2037+ /* Binding offsets */
2038+ vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, pl->bind_point, pl->pipeline_layout,
2039+ 0, pl->nb_descriptor_sets,
2040+ pl->bound_buffer_indices, offsets);
2041+ } else {
2042+ vk->CmdBindDescriptorSets(e->buf, pl->bind_point, pl->pipeline_layout,
2043+ 0, pl->nb_descriptor_sets,
2044+ &pl->desc_sets[e->idx*pl->nb_descriptor_sets],
2045+ 0, NULL);
2046+ }
18962047 }
18972048 }
18982049
@@ -1920,7 +2071,13 @@ void ff_vk_pipeline_free(FFVulkanContext *s, FFVulkanPipeline *pl) · 21 unmodified lines
19202071 vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, pl->desc_layout[i],
19212072 s->hwctx->alloc);
19222073
2074+ if (pl->desc_pool)
2075+ vk->DestroyDescriptorPool(s->hwctx->act_dev, pl->desc_pool,
2076+ s->hwctx->alloc);
2077+
2078+ av_freep(&pl->desc_pool_size);
19232079 av_freep(&pl->desc_layout);
2080+ av_freep(&pl->desc_sets);
19242081 av_freep(&pl->desc_set);
19252082 av_freep(&pl->desc_bind);
19262083 av_freep(&pl->bound_buffer_indices);
libavutil/vulkan.h+49−40
@@ -112,44 +112,6 @@ typedef struct FFVkQueueFamilyCtx { · 111 unmodified lines
112112 int nb_queues;
113113 } FFVkQueueFamilyCtx;
114114
115−typedef struct FFVulkanDescriptorSet {
116− FFVkBuffer buf;
117− uint8_t *desc_mem;
118− VkDeviceSize layout_size;
119− VkDeviceSize aligned_size; /* descriptorBufferOffsetAlignment */
120− VkDeviceSize total_size; /* Once registered to an exec context */
121− VkBufferUsageFlags usage;
122−
123− VkDescriptorSetLayoutBinding *binding;
124− VkDeviceSize *binding_offset;
125− int nb_bindings;
126−
127− /* Descriptor set is shared between all submissions */
128− int singular;
129−} FFVulkanDescriptorSet;
130−
131−typedef struct FFVulkanPipeline {
132− VkPipelineBindPoint bind_point;
133−
134− /* Contexts */
135− VkPipelineLayout pipeline_layout;
136− VkPipeline pipeline;
137−
138− /* Push consts */
139− VkPushConstantRange *push_consts;
140− int push_consts_num;
141−
142− /* Workgroup */
143− int wg_size[3];
144−
145− /* Descriptor buffer */
146− VkDescriptorSetLayout *desc_layout;
147− FFVulkanDescriptorSet *desc_set;
148− VkDescriptorBufferBindingInfoEXT *desc_bind;
149− uint32_t *bound_buffer_indices;
150− int nb_descriptor_sets;
151−} FFVulkanPipeline;
152−
153115 typedef struct FFVkExecContext {
154116 uint32_t idx;
155117 const struct FFVkExecPool *parent;
@@ -226,6 +188,52 @@ typedef struct FFVkExecPool { · 70 unmodified lines
226188 size_t qd_size;
227189 } FFVkExecPool;
228190
191+typedef struct FFVulkanDescriptorSet {
192+ FFVkBuffer buf;
193+ uint8_t *desc_mem;
194+ VkDeviceSize layout_size;
195+ VkDeviceSize aligned_size; /* descriptorBufferOffsetAlignment */
196+ VkDeviceSize total_size; /* Once registered to an exec context */
197+ VkBufferUsageFlags usage;
198+
199+ VkDescriptorSetLayoutBinding *binding;
200+ VkDeviceSize *binding_offset;
201+ int nb_bindings;
202+
203+ /* Descriptor set is shared between all submissions */
204+ int singular;
205+} FFVulkanDescriptorSet;
206+
207+typedef struct FFVulkanPipeline {
208+ VkPipelineBindPoint bind_point;
209+
210+ /* Contexts */
211+ VkPipelineLayout pipeline_layout;
212+ VkPipeline pipeline;
213+
214+ /* Push consts */
215+ VkPushConstantRange *push_consts;
216+ int push_consts_num;
217+
218+ /* Workgroup */
219+ int wg_size[3];
220+
221+ /* Descriptor buffer */
222+ VkDescriptorSetLayout *desc_layout;
223+ FFVulkanDescriptorSet *desc_set;
224+ VkDescriptorBufferBindingInfoEXT *desc_bind;
225+ uint32_t *bound_buffer_indices;
226+ int nb_descriptor_sets;
227+
228+ /* Descriptor pool */
229+ VkDescriptorSet *desc_sets;
230+ VkDescriptorPool desc_pool;
231+ VkDescriptorPoolSize *desc_pool_size;
232+ int nb_desc_pool_size;
233+ int total_desc_sets;
234+ FFVkExecPool *assoc_pool;
235+} FFVulkanPipeline;
236+
229237 typedef struct FFVulkanContext {
230238 const AVClass *class;
231239 void *log_parent;
@@ -508,8 +516,9 @@ void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e, · 276 unmodified lines
508516 FFVulkanPipeline *pl);
509517
510518 int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl,
511− FFVkExecContext *e, int set, int bind, int offs,
512− VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt);
519+ FFVkExecContext *e, int set, int bind, int elem,
520+ FFVkBuffer *buf, VkDeviceSize offset, VkDeviceSize len,
521+ VkFormat fmt);
513522
514523 void ff_vk_update_descriptor_img_array(FFVulkanContext *s, FFVulkanPipeline *pl,
515524 FFVkExecContext *e, AVFrame *f,
libavutil/vulkan_functions.h+3−0
@@ -176,6 +176,9 @@ typedef enum FFVulkanExtensions { · 175 unmodified lines
176176 MACRO(1, 1, FF_VK_EXT_NO_FLAG, UpdateDescriptorSetWithTemplate) \
177177 MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateDescriptorUpdateTemplate) \
178178 MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroyDescriptorUpdateTemplate) \
179+ \
180+ /* Descriptors */ \
181+ MACRO(1, 1, FF_VK_EXT_NO_FLAG, UpdateDescriptorSets) \
179182 \
180183 /* Queries */ \
181184 MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateQueryPool) \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t