diff mbox series

[FFmpeg-devel,8/8] avutil/vulkan: Move functions only used by lavfi to it

Message ID AS8P250MB074472902C44239ACFB5C48E8F5C2@AS8P250MB0744.EURP250.PROD.OUTLOOK.COM
State New
Headers show
Series [FFmpeg-devel,1/8] avutil/vulkan: Don't autoinclude vulkan_loader.h | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Andreas Rheinhardt March 3, 2024, 6:42 p.m. UTC
lavu/vulkan.c is duplicated into lavfi, lavc and lavu,
yet lots of functions in it are only used by lavfi.
This commit moves them to lavfi, saving 6544B of .text
from both lavc and lavu as well as some .rodata and
.data.rel.ro (in total 7880B each for lavc and lavu).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
One could also move this stuff to new files; e.g. both the shader
and pipeline parts could be moved into files of their own
which would then only be compiled for lavfi.

 libavfilter/vulkan_filter.c  | 764 +++++++++++++++++++++++++++++++++++
 libavfilter/vulkan_filter.h  | 177 ++++++++
 libavfilter/vulkan_glslang.c |   1 +
 libavfilter/vulkan_shaderc.c |   1 +
 libavutil/vulkan.c           | 760 ----------------------------------
 libavutil/vulkan.h           | 176 --------
 6 files changed, 943 insertions(+), 936 deletions(-)

Comments

Lynne March 3, 2024, 9:49 p.m. UTC | #1
Mar 3, 2024, 19:42 by andreas.rheinhardt@outlook.com:

> lavu/vulkan.c is duplicated into lavfi, lavc and lavu,
> yet lots of functions in it are only used by lavfi.
> This commit moves them to lavfi, saving 6544B of .text
> from both lavc and lavu as well as some .rodata and
> .data.rel.ro (in total 7880B each for lavc and lavu).
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> One could also move this stuff to new files; e.g. both the shader
> and pipeline parts could be moved into files of their own
> which would then only be compiled for lavfi.
>
>  libavfilter/vulkan_filter.c  | 764 +++++++++++++++++++++++++++++++++++
>  libavfilter/vulkan_filter.h  | 177 ++++++++
>  libavfilter/vulkan_glslang.c |   1 +
>  libavfilter/vulkan_shaderc.c |   1 +
>  libavutil/vulkan.c           | 760 ----------------------------------
>  libavutil/vulkan.h           | 176 --------
>  6 files changed, 943 insertions(+), 936 deletions(-)
>

Patchset LGTM, except, sadly, the last commit.
We will need to implement shader-based film grain
application as Intel hardware does not support it,
so most of the functions will be used.
Also, a GSoC project I have to implement shader-based
encoders also depends on this code.

6k is a lot, but anyone serious about weight should
be using LTO, which would get rid of it.
diff mbox series

Patch

diff --git a/libavfilter/vulkan_filter.c b/libavfilter/vulkan_filter.c
index d3dc2fdacb..c354087dbc 100644
--- a/libavfilter/vulkan_filter.c
+++ b/libavfilter/vulkan_filter.c
@@ -19,6 +19,10 @@ 
  */
 
 #include "vulkan_filter.h"
+#include "libavutil/bprint.h"
+#include "libavutil/buffer.h"
+#include "libavutil/mem.h"
+#include "libavutil/pixdesc.h"
 #include "libavutil/vulkan_loader.h"
 
 int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s,
@@ -457,3 +461,763 @@  fail:
     ff_vk_exec_discard_deps(vkctx, exec);
     return err;
 }
+
+static void free_data_buf(void *opaque, uint8_t *data)
+{
+    FFVulkanContext *ctx = opaque;
+    FFVkBuffer *buf = (FFVkBuffer *)data;
+    ff_vk_free_buf(ctx, buf);
+    av_free(data);
+}
+
+static AVBufferRef *alloc_data_buf(void *opaque, size_t size)
+{
+    AVBufferRef *ref;
+    uint8_t *buf = av_mallocz(size);
+    if (!buf)
+        return NULL;
+
+    ref = av_buffer_create(buf, size, free_data_buf, opaque, 0);
+    if (!ref)
+        av_free(buf);
+    return ref;
+}
+
+int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVBufferPool **buf_pool,
+                            AVBufferRef **buf, VkBufferUsageFlags usage,
+                            void *create_pNext, size_t size,
+                            VkMemoryPropertyFlagBits mem_props)
+{
+    int err;
+    AVBufferRef *ref;
+    FFVkBuffer *data;
+
+    if (!(*buf_pool)) {
+        *buf_pool = av_buffer_pool_init2(sizeof(FFVkBuffer), ctx,
+                                         alloc_data_buf, NULL);
+        if (!(*buf_pool))
+            return AVERROR(ENOMEM);
+    }
+
+    *buf = ref = av_buffer_pool_get(*buf_pool);
+    if (!ref)
+        return AVERROR(ENOMEM);
+
+    data = (FFVkBuffer *)ref->data;
+    data->stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
+    data->access = VK_ACCESS_2_NONE;
+
+    if (data->size >= size)
+        return 0;
+
+    ff_vk_free_buf(ctx, data);
+    memset(data, 0, sizeof(*data));
+
+    av_log(ctx, AV_LOG_DEBUG, "Allocating buffer of %"SIZE_SPECIFIER" bytes for pool %p\n",
+           size, *buf_pool);
+
+    err = ff_vk_create_buf(ctx, data, size,
+                           create_pNext, NULL, usage,
+                           mem_props);
+    if (err < 0) {
+        av_buffer_unref(&ref);
+        return err;
+    }
+
+    if (mem_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+        err = ff_vk_map_buffer(ctx, data, &data->mapped_mem, 0);
+        if (err < 0) {
+            av_buffer_unref(&ref);
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+int ff_vk_add_push_constant(FFVulkanPipeline *pl, int offset, int size,
+                            VkShaderStageFlagBits stage)
+{
+    VkPushConstantRange *pc;
+
+    pl->push_consts = av_realloc_array(pl->push_consts, sizeof(*pl->push_consts),
+                                       pl->push_consts_num + 1);
+    if (!pl->push_consts)
+        return AVERROR(ENOMEM);
+
+    pc = &pl->push_consts[pl->push_consts_num++];
+    memset(pc, 0, sizeof(*pc));
+
+    pc->stageFlags = stage;
+    pc->offset = offset;
+    pc->size = size;
+
+    return 0;
+}
+
+int ff_vk_init_sampler(FFVulkanContext *s, VkSampler *sampler,
+                       int unnorm_coords, VkFilter filt)
+{
+    VkResult ret;
+    FFVulkanFunctions *vk = &s->vkfn;
+
+    VkSamplerCreateInfo sampler_info = {
+        .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+        .magFilter = filt,
+        .minFilter = sampler_info.magFilter,
+        .mipmapMode = unnorm_coords ? VK_SAMPLER_MIPMAP_MODE_NEAREST :
+                                      VK_SAMPLER_MIPMAP_MODE_LINEAR,
+        .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
+        .addressModeV = sampler_info.addressModeU,
+        .addressModeW = sampler_info.addressModeU,
+        .anisotropyEnable = VK_FALSE,
+        .compareOp = VK_COMPARE_OP_NEVER,
+        .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+        .unnormalizedCoordinates = unnorm_coords,
+    };
+
+    ret = vk->CreateSampler(s->hwctx->act_dev, &sampler_info,
+                            s->hwctx->alloc, sampler);
+    if (ret != VK_SUCCESS) {
+        av_log(s, AV_LOG_ERROR, "Unable to init sampler: %s\n",
+               ff_vk_ret2str(ret));
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
+int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt)
+{
+    if (pix_fmt == AV_PIX_FMT_ABGR   || pix_fmt == AV_PIX_FMT_BGRA   ||
+        pix_fmt == AV_PIX_FMT_RGBA   || pix_fmt == AV_PIX_FMT_RGB24  ||
+        pix_fmt == AV_PIX_FMT_BGR24  || pix_fmt == AV_PIX_FMT_RGB48  ||
+        pix_fmt == AV_PIX_FMT_RGBA64 || pix_fmt == AV_PIX_FMT_RGB565 ||
+        pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_BGR0   ||
+        pix_fmt == AV_PIX_FMT_0BGR   || pix_fmt == AV_PIX_FMT_RGB0)
+        return 1;
+    return 0;
+}
+
+typedef struct ImageViewCtx {
+    VkImageView views[AV_NUM_DATA_POINTERS];
+    int nb_views;
+} ImageViewCtx;
+
+static void destroy_imageviews(void *opaque, uint8_t *data)
+{
+    FFVulkanContext *s = opaque;
+    FFVulkanFunctions *vk = &s->vkfn;
+    ImageViewCtx *iv = (ImageViewCtx *)data;
+
+    for (int i = 0; i < iv->nb_views; i++)
+        vk->DestroyImageView(s->hwctx->act_dev, iv->views[i], s->hwctx->alloc);
+
+    av_free(iv);
+}
+
+int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e,
+                            VkImageView views[AV_NUM_DATA_POINTERS],
+                            AVFrame *f)
+{
+    int err;
+    VkResult ret;
+    AVBufferRef *buf;
+    FFVulkanFunctions *vk = &s->vkfn;
+    AVHWFramesContext *hwfc = (AVHWFramesContext *)f->hw_frames_ctx->data;
+    const VkFormat *rep_fmts = av_vkfmt_from_pixfmt(hwfc->sw_format);
+    AVVkFrame *vkf = (AVVkFrame *)f->data[0];
+    const int nb_images = ff_vk_count_images(vkf);
+    const int nb_planes = av_pix_fmt_count_planes(hwfc->sw_format);
+
+    ImageViewCtx *iv = av_mallocz(sizeof(*iv));
+    if (!iv)
+        return AVERROR(ENOMEM);
+
+    for (int i = 0; i < nb_planes; i++) {
+        VkImageAspectFlags plane_aspect[] = { VK_IMAGE_ASPECT_COLOR_BIT,
+                                              VK_IMAGE_ASPECT_PLANE_0_BIT,
+                                              VK_IMAGE_ASPECT_PLANE_1_BIT,
+                                              VK_IMAGE_ASPECT_PLANE_2_BIT, };
+
+        VkImageViewCreateInfo view_create_info = {
+            .sType      = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+            .pNext      = NULL,
+            .image      = vkf->img[FFMIN(i, nb_images - 1)],
+            .viewType   = VK_IMAGE_VIEW_TYPE_2D,
+            .format     = rep_fmts[i],
+            .components = ff_comp_identity_map,
+            .subresourceRange = {
+                .aspectMask = plane_aspect[(nb_planes != nb_images) +
+                                           i*(nb_planes != nb_images)],
+                .levelCount = 1,
+                .layerCount = 1,
+            },
+        };
+
+        ret = vk->CreateImageView(s->hwctx->act_dev, &view_create_info,
+                                  s->hwctx->alloc, &iv->views[i]);
+        if (ret != VK_SUCCESS) {
+            av_log(s, AV_LOG_ERROR, "Failed to create imageview: %s\n",
+                   ff_vk_ret2str(ret));
+            err = AVERROR_EXTERNAL;
+            goto fail;
+        }
+
+        iv->nb_views++;
+    }
+
+    buf = av_buffer_create((uint8_t *)iv, sizeof(*iv), destroy_imageviews, s, 0);
+    if (!buf) {
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    /* Add to queue dependencies */
+    err = ff_vk_exec_add_dep_buf(s, e, &buf, 1, 0);
+    if (err < 0)
+        av_buffer_unref(&buf);
+
+    memcpy(views, iv->views, nb_planes*sizeof(*views));
+
+    return err;
+
+fail:
+    for (int i = 0; i < iv->nb_views; i++)
+        vk->DestroyImageView(s->hwctx->act_dev, iv->views[i], s->hwctx->alloc);
+    av_free(iv);
+    return err;
+}
+
+const char *ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixfmt);
+    const int high = desc->comp[0].depth > 8;
+    return high ? "rgba16f" : "rgba8";
+}
+
+int ff_vk_shader_init(FFVulkanPipeline *pl, FFVkSPIRVShader *shd, const char *name,
+                      VkShaderStageFlags stage, uint32_t required_subgroup_size)
+{
+    av_bprint_init(&shd->src, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+    shd->shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    shd->shader.stage = stage;
+
+    if (required_subgroup_size) {
+        shd->shader.flags |= VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT;
+        shd->shader.pNext = &shd->subgroup_info;
+        shd->subgroup_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO;
+        shd->subgroup_info.requiredSubgroupSize = required_subgroup_size;
+    }
+
+    shd->name = name;
+
+    GLSLF(0, #version %i                                                  ,460);
+    GLSLC(0, #define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y))       );
+    GLSLC(0,                                                                  );
+    GLSLC(0, #extension GL_EXT_buffer_reference : require                     );
+    GLSLC(0, #extension GL_EXT_buffer_reference2 : require                    );
+
+    return 0;
+}
+
+void ff_vk_shader_set_compute_sizes(FFVkSPIRVShader *shd, int x, int y, int z)
+{
+    shd->local_size[0] = x;
+    shd->local_size[1] = y;
+    shd->local_size[2] = z;
+
+    av_bprintf(&shd->src, "layout (local_size_x = %i, "
+               "local_size_y = %i, local_size_z = %i) in;\n\n",
+               shd->local_size[0], shd->local_size[1], shd->local_size[2]);
+}
+
+void ff_vk_shader_print(void *ctx, FFVkSPIRVShader *shd, int prio)
+{
+    int line = 0;
+    const char *p = shd->src.str;
+    const char *start = p;
+    const size_t len = strlen(p);
+
+    AVBPrint buf;
+    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+    for (int i = 0; i < len; i++) {
+        if (p[i] == '\n') {
+            av_bprintf(&buf, "%i\t", ++line);
+            av_bprint_append_data(&buf, start, &p[i] - start + 1);
+            start = &p[i + 1];
+        }
+    }
+
+    av_log(ctx, prio, "Shader %s: \n%s", shd->name, buf.str);
+    av_bprint_finalize(&buf, NULL);
+}
+
+void ff_vk_shader_free(FFVulkanContext *s, FFVkSPIRVShader *shd)
+{
+    FFVulkanFunctions *vk = &s->vkfn;
+    av_bprint_finalize(&shd->src, NULL);
+
+    if (shd->shader.module)
+        vk->DestroyShaderModule(s->hwctx->act_dev, shd->shader.module, s->hwctx->alloc);
+}
+
+int ff_vk_shader_create(FFVulkanContext *s, FFVkSPIRVShader *shd,
+                        uint8_t *spirv, size_t spirv_size, const char *entrypoint)
+{
+    VkResult ret;
+    FFVulkanFunctions *vk = &s->vkfn;
+    VkShaderModuleCreateInfo shader_create;
+
+    shd->shader.pName = entrypoint;
+
+    av_log(s, AV_LOG_VERBOSE, "Shader %s compiled! Size: %zu bytes\n",
+           shd->name, spirv_size);
+
+    shader_create.sType    = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    shader_create.pNext    = NULL;
+    shader_create.codeSize = spirv_size;
+    shader_create.flags    = 0;
+    shader_create.pCode    = (void *)spirv;
+
+    ret = vk->CreateShaderModule(s->hwctx->act_dev, &shader_create, NULL,
+                                 &shd->shader.module);
+    if (ret != VK_SUCCESS) {
+        av_log(s, AV_LOG_VERBOSE, "Error creating shader module: %s\n",
+               ff_vk_ret2str(ret));
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
+static const struct descriptor_props {
+    size_t struct_size; /* Size of the opaque which updates the descriptor */
+    const char *type;
+    int is_uniform;
+    int mem_quali;      /* Can use a memory qualifier */
+    int dim_needed;     /* Must indicate dimension */
+    int buf_content;    /* Must indicate buffer contents */
+} descriptor_props[] = {
+    [VK_DESCRIPTOR_TYPE_SAMPLER]                = { sizeof(VkDescriptorImageInfo),  "sampler",       1, 0, 0, 0, },
+    [VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE]          = { sizeof(VkDescriptorImageInfo),  "texture",       1, 0, 1, 0, },
+    [VK_DESCRIPTOR_TYPE_STORAGE_IMAGE]          = { sizeof(VkDescriptorImageInfo),  "image",         1, 1, 1, 0, },
+    [VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT]       = { sizeof(VkDescriptorImageInfo),  "subpassInput",  1, 0, 0, 0, },
+    [VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] = { sizeof(VkDescriptorImageInfo),  "sampler",       1, 0, 1, 0, },
+    [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER]         = { sizeof(VkDescriptorBufferInfo),  NULL,           1, 0, 0, 1, },
+    [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER]         = { sizeof(VkDescriptorBufferInfo), "buffer",        0, 1, 0, 1, },
+    [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo),  NULL,           1, 0, 0, 1, },
+    [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), "buffer",        0, 1, 0, 1, },
+    [VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER]   = { sizeof(VkBufferView),           "samplerBuffer", 1, 0, 0, 0, },
+    [VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER]   = { sizeof(VkBufferView),           "imageBuffer",   1, 0, 0, 0, },
+};
+
+int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                      FFVkSPIRVShader *shd,
+                                      FFVulkanDescriptorSetBinding *desc, int nb,
+                                      int read_only, int print_to_shader_only)
+{
+    VkResult ret;
+    int has_sampler = 0;
+    FFVulkanFunctions *vk = &s->vkfn;
+    FFVulkanDescriptorSet *set;
+    VkDescriptorSetLayoutCreateInfo desc_create_layout;
+
+    if (print_to_shader_only)
+        goto print;
+
+    /* Actual layout allocated for the pipeline */
+    set = av_realloc_array(pl->desc_set, sizeof(*pl->desc_set),
+                           pl->nb_descriptor_sets + 1);
+    if (!set)
+        return AVERROR(ENOMEM);
+    pl->desc_set = set;
+    set = &set[pl->nb_descriptor_sets];
+    memset(set, 0, sizeof(*set));
+
+    set->binding = av_calloc(nb, sizeof(*set->binding));
+    if (!set->binding)
+        return AVERROR(ENOMEM);
+
+    set->binding_offset = av_calloc(nb, sizeof(*set->binding_offset));
+    if (!set->binding_offset) {
+        av_freep(&set->binding);
+        return AVERROR(ENOMEM);
+    }
+
+    desc_create_layout = (VkDescriptorSetLayoutCreateInfo) {
+        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+        .bindingCount = nb,
+        .pBindings = set->binding,
+        .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,
+    };
+
+    for (int i = 0; i < nb; i++) {
+        set->binding[i].binding            = i;
+        set->binding[i].descriptorType     = desc[i].type;
+        set->binding[i].descriptorCount    = FFMAX(desc[i].elems, 1);
+        set->binding[i].stageFlags         = desc[i].stages;
+        set->binding[i].pImmutableSamplers = desc[i].samplers;
+
+        if (desc[i].type == VK_DESCRIPTOR_TYPE_SAMPLER ||
+            desc[i].type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+            has_sampler |= 1;
+    }
+
+    set->usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT |
+                 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+    if (has_sampler)
+        set->usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT;
+
+    ret = vk->CreateDescriptorSetLayout(s->hwctx->act_dev, &desc_create_layout,
+                                        s->hwctx->alloc, &set->layout);
+    if (ret != VK_SUCCESS) {
+        av_log(s, AV_LOG_ERROR, "Unable to init descriptor set layout: %s",
+               ff_vk_ret2str(ret));
+        return AVERROR_EXTERNAL;
+    }
+
+    vk->GetDescriptorSetLayoutSizeEXT(s->hwctx->act_dev, set->layout, &set->layout_size);
+
+    set->aligned_size = FFALIGN(set->layout_size, s->desc_buf_props.descriptorBufferOffsetAlignment);
+
+    for (int i = 0; i < nb; i++)
+        vk->GetDescriptorSetLayoutBindingOffsetEXT(s->hwctx->act_dev, set->layout,
+                                                   i, &set->binding_offset[i]);
+
+    set->read_only = read_only;
+    set->nb_bindings = nb;
+    pl->nb_descriptor_sets++;
+
+print:
+    /* Write shader info */
+    for (int i = 0; i < nb; i++) {
+        const struct descriptor_props *prop = &descriptor_props[desc[i].type];
+        GLSLA("layout (set = %i, binding = %i", pl->nb_descriptor_sets - 1, i);
+
+        if (desc[i].mem_layout)
+            GLSLA(", %s", desc[i].mem_layout);
+        GLSLA(")");
+
+        if (prop->is_uniform)
+            GLSLA(" uniform");
+
+        if (prop->mem_quali && desc[i].mem_quali)
+            GLSLA(" %s", desc[i].mem_quali);
+
+        if (prop->type)
+            GLSLA(" %s", prop->type);
+
+        if (prop->dim_needed)
+            GLSLA("%iD", desc[i].dimensions);
+
+        GLSLA(" %s", desc[i].name);
+
+        if (prop->buf_content)
+            GLSLA(" {\n    %s\n}", desc[i].buf_content);
+        else if (desc[i].elems > 0)
+            GLSLA("[%i]", desc[i].elems);
+
+        GLSLA(";");
+        GLSLA("\n");
+    }
+    GLSLA("\n");
+
+    return 0;
+}
+
+int ff_vk_exec_pipeline_register(FFVulkanContext *s, FFVkExecPool *pool,
+                                 FFVulkanPipeline *pl)
+{
+    int err;
+
+    pl->desc_bind = av_calloc(pl->nb_descriptor_sets, sizeof(*pl->desc_bind));
+    if (!pl->desc_bind)
+        return AVERROR(ENOMEM);
+
+    pl->bound_buffer_indices = av_calloc(pl->nb_descriptor_sets,
+                                         sizeof(*pl->bound_buffer_indices));
+    if (!pl->bound_buffer_indices)
+        return AVERROR(ENOMEM);
+
+    for (int i = 0; i < pl->nb_descriptor_sets; i++) {
+        FFVulkanDescriptorSet *set = &pl->desc_set[i];
+        int nb = set->read_only ? 1 : pool->pool_size;
+
+        err = ff_vk_create_buf(s, &set->buf, set->aligned_size*nb,
+                               NULL, NULL, set->usage,
+                               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                               VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+        if (err < 0)
+            return err;
+
+        err = ff_vk_map_buffer(s, &set->buf, &set->desc_mem, 0);
+        if (err < 0)
+            return err;
+
+        pl->desc_bind[i] = (VkDescriptorBufferBindingInfoEXT) {
+            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT,
+            .usage = set->usage,
+            .address = set->buf.address,
+        };
+
+        pl->bound_buffer_indices[i] = i;
+    }
+
+    return 0;
+}
+
+static inline void update_set_descriptor(FFVulkanContext *s, FFVkExecContext *e,
+                                         FFVulkanDescriptorSet *set,
+                                         int bind_idx, int array_idx,
+                                         VkDescriptorGetInfoEXT *desc_get_info,
+                                         size_t desc_size)
+{
+    FFVulkanFunctions *vk = &s->vkfn;
+    const size_t exec_offset = set->read_only ? 0 : set->aligned_size*e->idx;
+    void *desc = set->desc_mem +                 /* Base */
+                 exec_offset +                   /* Execution context */
+                 set->binding_offset[bind_idx] + /* Descriptor binding */
+                 array_idx*desc_size;            /* Array position */
+
+    vk->GetDescriptorEXT(s->hwctx->act_dev, desc_get_info, desc_size, desc);
+}
+
+static int vk_set_descriptor_image(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                   FFVkExecContext *e, int set, int bind, int offs,
+                                   VkImageView view, VkImageLayout layout,
+                                   VkSampler sampler)
+{
+    FFVulkanDescriptorSet *desc_set = &pl->desc_set[set];
+    VkDescriptorGetInfoEXT desc_get_info = {
+        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
+        .type = desc_set->binding[bind].descriptorType,
+    };
+    VkDescriptorImageInfo desc_img_info = {
+        .imageView = view,
+        .sampler = sampler,
+        .imageLayout = layout,
+    };
+    size_t desc_size;
+
+    switch (desc_get_info.type) {
+    case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+        desc_get_info.data.pSampledImage = &desc_img_info;
+        desc_size = s->desc_buf_props.sampledImageDescriptorSize;
+        break;
+    case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+        desc_get_info.data.pStorageImage = &desc_img_info;
+        desc_size = s->desc_buf_props.storageImageDescriptorSize;
+        break;
+    case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+        desc_get_info.data.pInputAttachmentImage = &desc_img_info;
+        desc_size = s->desc_buf_props.inputAttachmentDescriptorSize;
+        break;
+    case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+        desc_get_info.data.pCombinedImageSampler = &desc_img_info;
+        desc_size = s->desc_buf_props.combinedImageSamplerDescriptorSize;
+        break;
+    default:
+        av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
+               set, bind, desc_get_info.type);
+        return AVERROR(EINVAL);
+        break;
+    };
+
+    update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size);
+
+    return 0;
+}
+
+int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                FFVkExecContext *e, int set, int bind, int offs,
+                                VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt)
+{
+    FFVulkanDescriptorSet *desc_set = &pl->desc_set[set];
+    VkDescriptorGetInfoEXT desc_get_info = {
+        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
+        .type = desc_set->binding[bind].descriptorType,
+    };
+    VkDescriptorAddressInfoEXT desc_buf_info = {
+        .address = addr,
+        .range = len,
+        .format = fmt,
+    };
+    size_t desc_size;
+
+    switch (desc_get_info.type) {
+    case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+        desc_get_info.data.pUniformBuffer = &desc_buf_info;
+        desc_size = s->desc_buf_props.uniformBufferDescriptorSize;
+        break;
+    case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+        desc_get_info.data.pStorageBuffer = &desc_buf_info;
+        desc_size = s->desc_buf_props.storageBufferDescriptorSize;
+        break;
+    case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+        desc_get_info.data.pUniformTexelBuffer = &desc_buf_info;
+        desc_size = s->desc_buf_props.uniformTexelBufferDescriptorSize;
+        break;
+    case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+        desc_get_info.data.pStorageTexelBuffer = &desc_buf_info;
+        desc_size = s->desc_buf_props.storageTexelBufferDescriptorSize;
+        break;
+    default:
+        av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
+               set, bind, desc_get_info.type);
+        return AVERROR(EINVAL);
+        break;
+    };
+
+    update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size);
+
+    return 0;
+}
+
+void ff_vk_update_descriptor_img_array(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                       FFVkExecContext *e, AVFrame *f,
+                                       VkImageView *views, int set, int binding,
+                                       VkImageLayout layout, VkSampler sampler)
+{
+    AVHWFramesContext *hwfc = (AVHWFramesContext *)f->hw_frames_ctx->data;
+    const int nb_planes = av_pix_fmt_count_planes(hwfc->sw_format);
+
+    for (int i = 0; i < nb_planes; i++)
+        vk_set_descriptor_image(s, pl, e, set, binding, i,
+                                views[i], layout, sampler);
+}
+
+void ff_vk_update_push_exec(FFVulkanContext *s, FFVkExecContext *e,
+                            FFVulkanPipeline *pl,
+                            VkShaderStageFlagBits stage,
+                            int offset, size_t size, void *src)
+{
+    FFVulkanFunctions *vk = &s->vkfn;
+    vk->CmdPushConstants(e->buf, pl->pipeline_layout,
+                         stage, offset, size, src);
+}
+
+static int init_pipeline_layout(FFVulkanContext *s, FFVulkanPipeline *pl)
+{
+    VkResult ret;
+    FFVulkanFunctions *vk = &s->vkfn;
+    VkPipelineLayoutCreateInfo pipeline_layout_info;
+
+    VkDescriptorSetLayout *desc_layouts = av_malloc(pl->nb_descriptor_sets*
+                                                    sizeof(desc_layouts));
+    if (!desc_layouts)
+        return AVERROR(ENOMEM);
+
+    for (int i = 0; i < pl->nb_descriptor_sets; i++)
+        desc_layouts[i] = pl->desc_set[i].layout;
+
+    /* Finally create the pipeline layout */
+    pipeline_layout_info = (VkPipelineLayoutCreateInfo) {
+        .sType                  = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+        .pSetLayouts            = desc_layouts,
+        .setLayoutCount         = pl->nb_descriptor_sets,
+        .pushConstantRangeCount = pl->push_consts_num,
+        .pPushConstantRanges    = pl->push_consts,
+    };
+
+    ret = vk->CreatePipelineLayout(s->hwctx->act_dev, &pipeline_layout_info,
+                                   s->hwctx->alloc, &pl->pipeline_layout);
+    av_free(desc_layouts);
+    if (ret != VK_SUCCESS) {
+        av_log(s, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n",
+               ff_vk_ret2str(ret));
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
+int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                FFVkSPIRVShader *shd)
+{
+    int err;
+    VkResult ret;
+    FFVulkanFunctions *vk = &s->vkfn;
+
+    VkComputePipelineCreateInfo pipeline_create_info;
+
+    err = init_pipeline_layout(s, pl);
+    if (err < 0)
+        return err;
+
+    pipeline_create_info = (VkComputePipelineCreateInfo) {
+        .sType  = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
+        .flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,
+        .layout = pl->pipeline_layout,
+        .stage = shd->shader,
+    };
+
+    ret = vk->CreateComputePipelines(s->hwctx->act_dev, VK_NULL_HANDLE, 1,
+                                     &pipeline_create_info,
+                                     s->hwctx->alloc, &pl->pipeline);
+    if (ret != VK_SUCCESS) {
+        av_log(s, AV_LOG_ERROR, "Unable to init compute pipeline: %s\n",
+               ff_vk_ret2str(ret));
+        return AVERROR_EXTERNAL;
+    }
+
+    pl->bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
+    pl->wg_size[0] = shd->local_size[0];
+    pl->wg_size[1] = shd->local_size[1];
+    pl->wg_size[2] = shd->local_size[2];
+
+    return 0;
+}
+
+void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e,
+                              FFVulkanPipeline *pl)
+{
+    FFVulkanFunctions *vk = &s->vkfn;
+    VkDeviceSize offsets[1024];
+
+    /* Bind pipeline */
+    vk->CmdBindPipeline(e->buf, pl->bind_point, pl->pipeline);
+
+    if (pl->nb_descriptor_sets) {
+        for (int i = 0; i < pl->nb_descriptor_sets; i++)
+            offsets[i] = pl->desc_set[i].read_only ? 0 : pl->desc_set[i].aligned_size*e->idx;
+
+        /* Bind descriptor buffers */
+        vk->CmdBindDescriptorBuffersEXT(e->buf, pl->nb_descriptor_sets, pl->desc_bind);
+        /* Binding offsets */
+        vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, pl->bind_point, pl->pipeline_layout,
+                                             0, pl->nb_descriptor_sets,
+                                             pl->bound_buffer_indices, offsets);
+    }
+}
+
+void ff_vk_pipeline_free(FFVulkanContext *s, FFVulkanPipeline *pl)
+{
+    FFVulkanFunctions *vk = &s->vkfn;
+
+    if (pl->pipeline)
+        vk->DestroyPipeline(s->hwctx->act_dev, pl->pipeline, s->hwctx->alloc);
+    if (pl->pipeline_layout)
+        vk->DestroyPipelineLayout(s->hwctx->act_dev, pl->pipeline_layout,
+                                  s->hwctx->alloc);
+
+    for (int i = 0; i < pl->nb_descriptor_sets; i++) {
+        FFVulkanDescriptorSet *set = &pl->desc_set[i];
+        if (set->buf.mem)
+            ff_vk_unmap_buffer(s, &set->buf, 0);
+        ff_vk_free_buf(s, &set->buf);
+        if (set->layout)
+            vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, set->layout,
+                                           s->hwctx->alloc);
+        av_free(set->binding);
+        av_free(set->binding_offset);
+    }
+
+    av_freep(&pl->desc_set);
+    av_freep(&pl->desc_bind);
+    av_freep(&pl->bound_buffer_indices);
+    av_freep(&pl->push_consts);
+    pl->push_consts_num = 0;
+}
diff --git a/libavfilter/vulkan_filter.h b/libavfilter/vulkan_filter.h
index d2c14601d9..9655f43caa 100644
--- a/libavfilter/vulkan_filter.h
+++ b/libavfilter/vulkan_filter.h
@@ -25,6 +25,98 @@ 
 
 #include "vulkan.h"
 
+#include "libavutil/bprint.h"
+
+/* GLSL management macros */
+#define INDENT(N) INDENT_##N
+#define INDENT_0
+#define INDENT_1 INDENT_0 "    "
+#define INDENT_2 INDENT_1 INDENT_1
+#define INDENT_3 INDENT_2 INDENT_1
+#define INDENT_4 INDENT_3 INDENT_1
+#define INDENT_5 INDENT_4 INDENT_1
+#define INDENT_6 INDENT_5 INDENT_1
+#define C(N, S)          INDENT(N) #S "\n"
+
+#define GLSLC(N, S)                     \
+    do {                                \
+        av_bprintf(&shd->src, C(N, S)); \
+    } while (0)
+
+#define GLSLA(...)                          \
+    do {                                    \
+        av_bprintf(&shd->src, __VA_ARGS__); \
+    } while (0)
+
+#define GLSLF(N, S, ...)                             \
+    do {                                             \
+        av_bprintf(&shd->src, C(N, S), __VA_ARGS__); \
+    } while (0)
+
+#define GLSLD(D)                                        \
+    do {                                                \
+        av_bprintf(&shd->src, "\n");                    \
+        av_bprint_append_data(&shd->src, D, strlen(D)); \
+        av_bprintf(&shd->src, "\n");                    \
+    } while (0)
+
+typedef struct FFVkSPIRVShader {
+    const char *name;                       /* Name for id/debugging purposes */
+    AVBPrint src;
+    int local_size[3];                      /* Compute shader workgroup sizes */
+    VkPipelineShaderStageCreateInfo shader;
+    VkPipelineShaderStageRequiredSubgroupSizeCreateInfo subgroup_info;
+} FFVkSPIRVShader;
+
+typedef struct FFVulkanDescriptorSetBinding {
+    const char         *name;
+    VkDescriptorType    type;
+    const char         *mem_layout;  /* Storage images (rgba8, etc.) and buffers (std430, etc.) */
+    const char         *mem_quali;   /* readonly, writeonly, etc. */
+    const char         *buf_content; /* For buffers */
+    uint32_t            dimensions;  /* Needed for e.g. sampler%iD */
+    uint32_t            elems;       /* 0 - scalar, 1 or more - vector */
+    VkShaderStageFlags  stages;
+    VkSampler           samplers[4]; /* Sampler to use for all elems */
+} FFVulkanDescriptorSetBinding;
+
+typedef struct FFVulkanDescriptorSet {
+    VkDescriptorSetLayout  layout;
+    FFVkBuffer             buf;
+    uint8_t               *desc_mem;
+    VkDeviceSize           layout_size;
+    VkDeviceSize           aligned_size; /* descriptorBufferOffsetAlignment */
+    VkDeviceSize           total_size; /* Once registered to an exec context */
+    VkBufferUsageFlags     usage;
+
+    VkDescriptorSetLayoutBinding *binding;
+    VkDeviceSize *binding_offset;
+    int nb_bindings;
+
+    int read_only;
+} FFVulkanDescriptorSet;
+
+typedef struct FFVulkanPipeline {
+    VkPipelineBindPoint bind_point;
+
+    /* Contexts */
+    VkPipelineLayout pipeline_layout;
+    VkPipeline       pipeline;
+
+    /* Push consts */
+    VkPushConstantRange *push_consts;
+    int push_consts_num;
+
+    /* Workgroup */
+    int wg_size[3];
+
+    /* Descriptors */
+    FFVulkanDescriptorSet *desc_set;
+    VkDescriptorBufferBindingInfoEXT *desc_bind;
+    uint32_t *bound_buffer_indices;
+    int nb_descriptor_sets;
+} FFVulkanPipeline;
+
 /**
  * General lavfi IO functions
  */
@@ -62,4 +154,89 @@  int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e,
                              AVFrame *out, AVFrame *in[], int nb_in,
                              VkSampler sampler, void *push_src, size_t push_size);
 
+/**
+ * Returns 1 if pixfmt is a usable RGB format.
+ */
+int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt);
+
+/**
+ * Create an imageview and add it as a dependency to an execution.
+ */
+int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e,
+                            VkImageView views[AV_NUM_DATA_POINTERS],
+                            AVFrame *f);
+
+/** Initialize a pool and create AVBufferRefs containing FFVkBuffer.
+ * Threadsafe to use. Buffers are automatically mapped on creation if
+ * VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT is set in mem_props. Users should
+ * synchronize access themselvesd. Mainly meant for device-local buffers. */
+int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVBufferPool **buf_pool,
+                            AVBufferRef **buf, VkBufferUsageFlags usage,
+                            void *create_pNext, size_t size,
+                            VkMemoryPropertyFlagBits mem_props);
+
+/**
+ * Create a sampler.
+ */
+int ff_vk_init_sampler(FFVulkanContext *s, VkSampler *sampler,
+                       int unnorm_coords, VkFilter filt);
+
+/**
+ * Returns the format to use for images in shaders.
+ */
+const char *ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt);
+/**
+ * Shader management.
+ */
+int ff_vk_shader_init(FFVulkanPipeline *pl, FFVkSPIRVShader *shd, const char *name,
+                      VkShaderStageFlags stage, uint32_t required_subgroup_size);
+void ff_vk_shader_set_compute_sizes(FFVkSPIRVShader *shd, int x, int y, int z);
+void ff_vk_shader_print(void *ctx, FFVkSPIRVShader *shd, int prio);
+int ff_vk_shader_create(FFVulkanContext *s, FFVkSPIRVShader *shd,
+                        uint8_t *spirv, size_t spirv_size, const char *entrypoint);
+void ff_vk_shader_free(FFVulkanContext *s, FFVkSPIRVShader *shd);
+
+/**
+ * Add/update push constants for execution.
+ */
+int ff_vk_add_push_constant(FFVulkanPipeline *pl, int offset, int size,
+                            VkShaderStageFlagBits stage);
+void ff_vk_update_push_exec(FFVulkanContext *s, FFVkExecContext *e,
+                            FFVulkanPipeline *pl,
+                            VkShaderStageFlagBits stage,
+                            int offset, size_t size, void *src);
+
+/**
+ * Add descriptor to a pipeline. Must be called before pipeline init.
+ */
+int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                      FFVkSPIRVShader *shd,
+                                      FFVulkanDescriptorSetBinding *desc, int nb,
+                                      int read_only, int print_to_shader_only);
+
+/* Initialize/free a pipeline. */
+int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                FFVkSPIRVShader *shd);
+void ff_vk_pipeline_free(FFVulkanContext *s, FFVulkanPipeline *pl);
+
+/**
+ * Register a pipeline with an exec pool.
+ * Pool may be NULL if all descriptor sets are read-only.
+ */
+int ff_vk_exec_pipeline_register(FFVulkanContext *s, FFVkExecPool *pool,
+                                 FFVulkanPipeline *pl);
+
+/* Bind pipeline */
+void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e,
+                              FFVulkanPipeline *pl);
+
+int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                FFVkExecContext *e, int set, int bind, int offs,
+                                VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt);
+
+void ff_vk_update_descriptor_img_array(FFVulkanContext *s, FFVulkanPipeline *pl,
+                                       FFVkExecContext *e, AVFrame *f,
+                                       VkImageView *views, int set, int binding,
+                                       VkImageLayout layout, VkSampler sampler);
+
 #endif /* AVFILTER_VULKAN_FILTER_H */
diff --git a/libavfilter/vulkan_glslang.c b/libavfilter/vulkan_glslang.c
index 845a530ee0..9ee6ad7c39 100644
--- a/libavfilter/vulkan_glslang.c
+++ b/libavfilter/vulkan_glslang.c
@@ -21,6 +21,7 @@ 
 #include <glslang/build_info.h>
 #include <glslang/Include/glslang_c_interface.h>
 
+#include "vulkan_filter.h"
 #include "vulkan_spirv.h"
 #include "libavutil/mem.h"
 #include "libavutil/avassert.h"
diff --git a/libavfilter/vulkan_shaderc.c b/libavfilter/vulkan_shaderc.c
index 38be1030ad..57c62b618b 100644
--- a/libavfilter/vulkan_shaderc.c
+++ b/libavfilter/vulkan_shaderc.c
@@ -19,6 +19,7 @@ 
 #include <shaderc/shaderc.h>
 
 #include "libavutil/mem.h"
+#include "vulkan_filter.h"
 #include "vulkan_spirv.h"
 
 static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx,
diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c
index 67b9526255..f609e8cd8d 100644
--- a/libavutil/vulkan.c
+++ b/libavutil/vulkan.c
@@ -1066,240 +1066,6 @@  void ff_vk_free_buf(FFVulkanContext *s, FFVkBuffer *buf)
         vk->FreeMemory(s->hwctx->act_dev, buf->mem, s->hwctx->alloc);
 }
 
-static void free_data_buf(void *opaque, uint8_t *data)
-{
-    FFVulkanContext *ctx = opaque;
-    FFVkBuffer *buf = (FFVkBuffer *)data;
-    ff_vk_free_buf(ctx, buf);
-    av_free(data);
-}
-
-static AVBufferRef *alloc_data_buf(void *opaque, size_t size)
-{
-    AVBufferRef *ref;
-    uint8_t *buf = av_mallocz(size);
-    if (!buf)
-        return NULL;
-
-    ref = av_buffer_create(buf, size, free_data_buf, opaque, 0);
-    if (!ref)
-        av_free(buf);
-    return ref;
-}
-
-int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVBufferPool **buf_pool,
-                            AVBufferRef **buf, VkBufferUsageFlags usage,
-                            void *create_pNext, size_t size,
-                            VkMemoryPropertyFlagBits mem_props)
-{
-    int err;
-    AVBufferRef *ref;
-    FFVkBuffer *data;
-
-    if (!(*buf_pool)) {
-        *buf_pool = av_buffer_pool_init2(sizeof(FFVkBuffer), ctx,
-                                         alloc_data_buf, NULL);
-        if (!(*buf_pool))
-            return AVERROR(ENOMEM);
-    }
-
-    *buf = ref = av_buffer_pool_get(*buf_pool);
-    if (!ref)
-        return AVERROR(ENOMEM);
-
-    data = (FFVkBuffer *)ref->data;
-    data->stage = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
-    data->access = VK_ACCESS_2_NONE;
-
-    if (data->size >= size)
-        return 0;
-
-    ff_vk_free_buf(ctx, data);
-    memset(data, 0, sizeof(*data));
-
-    av_log(ctx, AV_LOG_DEBUG, "Allocating buffer of %"SIZE_SPECIFIER" bytes for pool %p\n",
-           size, *buf_pool);
-
-    err = ff_vk_create_buf(ctx, data, size,
-                           create_pNext, NULL, usage,
-                           mem_props);
-    if (err < 0) {
-        av_buffer_unref(&ref);
-        return err;
-    }
-
-    if (mem_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
-        err = ff_vk_map_buffer(ctx, data, &data->mapped_mem, 0);
-        if (err < 0) {
-            av_buffer_unref(&ref);
-            return err;
-        }
-    }
-
-    return 0;
-}
-
-int ff_vk_add_push_constant(FFVulkanPipeline *pl, int offset, int size,
-                            VkShaderStageFlagBits stage)
-{
-    VkPushConstantRange *pc;
-
-    pl->push_consts = av_realloc_array(pl->push_consts, sizeof(*pl->push_consts),
-                                       pl->push_consts_num + 1);
-    if (!pl->push_consts)
-        return AVERROR(ENOMEM);
-
-    pc = &pl->push_consts[pl->push_consts_num++];
-    memset(pc, 0, sizeof(*pc));
-
-    pc->stageFlags = stage;
-    pc->offset = offset;
-    pc->size = size;
-
-    return 0;
-}
-
-int ff_vk_init_sampler(FFVulkanContext *s, VkSampler *sampler,
-                       int unnorm_coords, VkFilter filt)
-{
-    VkResult ret;
-    FFVulkanFunctions *vk = &s->vkfn;
-
-    VkSamplerCreateInfo sampler_info = {
-        .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
-        .magFilter = filt,
-        .minFilter = sampler_info.magFilter,
-        .mipmapMode = unnorm_coords ? VK_SAMPLER_MIPMAP_MODE_NEAREST :
-                                      VK_SAMPLER_MIPMAP_MODE_LINEAR,
-        .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
-        .addressModeV = sampler_info.addressModeU,
-        .addressModeW = sampler_info.addressModeU,
-        .anisotropyEnable = VK_FALSE,
-        .compareOp = VK_COMPARE_OP_NEVER,
-        .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
-        .unnormalizedCoordinates = unnorm_coords,
-    };
-
-    ret = vk->CreateSampler(s->hwctx->act_dev, &sampler_info,
-                            s->hwctx->alloc, sampler);
-    if (ret != VK_SUCCESS) {
-        av_log(s, AV_LOG_ERROR, "Unable to init sampler: %s\n",
-               ff_vk_ret2str(ret));
-        return AVERROR_EXTERNAL;
-    }
-
-    return 0;
-}
-
-int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt)
-{
-    if (pix_fmt == AV_PIX_FMT_ABGR   || pix_fmt == AV_PIX_FMT_BGRA   ||
-        pix_fmt == AV_PIX_FMT_RGBA   || pix_fmt == AV_PIX_FMT_RGB24  ||
-        pix_fmt == AV_PIX_FMT_BGR24  || pix_fmt == AV_PIX_FMT_RGB48  ||
-        pix_fmt == AV_PIX_FMT_RGBA64 || pix_fmt == AV_PIX_FMT_RGB565 ||
-        pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_BGR0   ||
-        pix_fmt == AV_PIX_FMT_0BGR   || pix_fmt == AV_PIX_FMT_RGB0)
-        return 1;
-    return 0;
-}
-
-const char *ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt)
-{
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixfmt);
-    const int high = desc->comp[0].depth > 8;
-    return high ? "rgba16f" : "rgba8";
-}
-
-typedef struct ImageViewCtx {
-    VkImageView views[AV_NUM_DATA_POINTERS];
-    int nb_views;
-} ImageViewCtx;
-
-static void destroy_imageviews(void *opaque, uint8_t *data)
-{
-    FFVulkanContext *s = opaque;
-    FFVulkanFunctions *vk = &s->vkfn;
-    ImageViewCtx *iv = (ImageViewCtx *)data;
-
-    for (int i = 0; i < iv->nb_views; i++)
-        vk->DestroyImageView(s->hwctx->act_dev, iv->views[i], s->hwctx->alloc);
-
-    av_free(iv);
-}
-
-int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e,
-                            VkImageView views[AV_NUM_DATA_POINTERS],
-                            AVFrame *f)
-{
-    int err;
-    VkResult ret;
-    AVBufferRef *buf;
-    FFVulkanFunctions *vk = &s->vkfn;
-    AVHWFramesContext *hwfc = (AVHWFramesContext *)f->hw_frames_ctx->data;
-    const VkFormat *rep_fmts = av_vkfmt_from_pixfmt(hwfc->sw_format);
-    AVVkFrame *vkf = (AVVkFrame *)f->data[0];
-    const int nb_images = ff_vk_count_images(vkf);
-    const int nb_planes = av_pix_fmt_count_planes(hwfc->sw_format);
-
-    ImageViewCtx *iv = av_mallocz(sizeof(*iv));
-    if (!iv)
-        return AVERROR(ENOMEM);
-
-    for (int i = 0; i < nb_planes; i++) {
-        VkImageAspectFlags plane_aspect[] = { VK_IMAGE_ASPECT_COLOR_BIT,
-                                              VK_IMAGE_ASPECT_PLANE_0_BIT,
-                                              VK_IMAGE_ASPECT_PLANE_1_BIT,
-                                              VK_IMAGE_ASPECT_PLANE_2_BIT, };
-
-        VkImageViewCreateInfo view_create_info = {
-            .sType      = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
-            .pNext      = NULL,
-            .image      = vkf->img[FFMIN(i, nb_images - 1)],
-            .viewType   = VK_IMAGE_VIEW_TYPE_2D,
-            .format     = rep_fmts[i],
-            .components = ff_comp_identity_map,
-            .subresourceRange = {
-                .aspectMask = plane_aspect[(nb_planes != nb_images) +
-                                           i*(nb_planes != nb_images)],
-                .levelCount = 1,
-                .layerCount = 1,
-            },
-        };
-
-        ret = vk->CreateImageView(s->hwctx->act_dev, &view_create_info,
-                                  s->hwctx->alloc, &iv->views[i]);
-        if (ret != VK_SUCCESS) {
-            av_log(s, AV_LOG_ERROR, "Failed to create imageview: %s\n",
-                   ff_vk_ret2str(ret));
-            err = AVERROR_EXTERNAL;
-            goto fail;
-        }
-
-        iv->nb_views++;
-    }
-
-    buf = av_buffer_create((uint8_t *)iv, sizeof(*iv), destroy_imageviews, s, 0);
-    if (!buf) {
-        err = AVERROR(ENOMEM);
-        goto fail;
-    }
-
-    /* Add to queue dependencies */
-    err = ff_vk_exec_add_dep_buf(s, e, &buf, 1, 0);
-    if (err < 0)
-        av_buffer_unref(&buf);
-
-    memcpy(views, iv->views, nb_planes*sizeof(*views));
-
-    return err;
-
-fail:
-    for (int i = 0; i < iv->nb_views; i++)
-        vk->DestroyImageView(s->hwctx->act_dev, iv->views[i], s->hwctx->alloc);
-    av_free(iv);
-    return err;
-}
-
 void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e,
                          AVFrame *pic, VkImageMemoryBarrier2 *bar, int *nb_bar,
                          VkPipelineStageFlags src_stage,
@@ -1343,532 +1109,6 @@  void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e,
     ff_vk_exec_update_frame(s, e, pic, &bar[*nb_bar - nb_images], NULL);
 }
 
-int ff_vk_shader_init(FFVulkanPipeline *pl, FFVkSPIRVShader *shd, const char *name,
-                      VkShaderStageFlags stage, uint32_t required_subgroup_size)
-{
-    av_bprint_init(&shd->src, 0, AV_BPRINT_SIZE_UNLIMITED);
-
-    shd->shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-    shd->shader.stage = stage;
-
-    if (required_subgroup_size) {
-        shd->shader.flags |= VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT;
-        shd->shader.pNext = &shd->subgroup_info;
-        shd->subgroup_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO;
-        shd->subgroup_info.requiredSubgroupSize = required_subgroup_size;
-    }
-
-    shd->name = name;
-
-    GLSLF(0, #version %i                                                  ,460);
-    GLSLC(0, #define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y))       );
-    GLSLC(0,                                                                  );
-    GLSLC(0, #extension GL_EXT_buffer_reference : require                     );
-    GLSLC(0, #extension GL_EXT_buffer_reference2 : require                    );
-
-    return 0;
-}
-
-void ff_vk_shader_set_compute_sizes(FFVkSPIRVShader *shd, int x, int y, int z)
-{
-    shd->local_size[0] = x;
-    shd->local_size[1] = y;
-    shd->local_size[2] = z;
-
-    av_bprintf(&shd->src, "layout (local_size_x = %i, "
-               "local_size_y = %i, local_size_z = %i) in;\n\n",
-               shd->local_size[0], shd->local_size[1], shd->local_size[2]);
-}
-
-void ff_vk_shader_print(void *ctx, FFVkSPIRVShader *shd, int prio)
-{
-    int line = 0;
-    const char *p = shd->src.str;
-    const char *start = p;
-    const size_t len = strlen(p);
-
-    AVBPrint buf;
-    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
-
-    for (int i = 0; i < len; i++) {
-        if (p[i] == '\n') {
-            av_bprintf(&buf, "%i\t", ++line);
-            av_bprint_append_data(&buf, start, &p[i] - start + 1);
-            start = &p[i + 1];
-        }
-    }
-
-    av_log(ctx, prio, "Shader %s: \n%s", shd->name, buf.str);
-    av_bprint_finalize(&buf, NULL);
-}
-
-void ff_vk_shader_free(FFVulkanContext *s, FFVkSPIRVShader *shd)
-{
-    FFVulkanFunctions *vk = &s->vkfn;
-    av_bprint_finalize(&shd->src, NULL);
-
-    if (shd->shader.module)
-        vk->DestroyShaderModule(s->hwctx->act_dev, shd->shader.module, s->hwctx->alloc);
-}
-
-int ff_vk_shader_create(FFVulkanContext *s, FFVkSPIRVShader *shd,
-                        uint8_t *spirv, size_t spirv_size, const char *entrypoint)
-{
-    VkResult ret;
-    FFVulkanFunctions *vk = &s->vkfn;
-    VkShaderModuleCreateInfo shader_create;
-
-    shd->shader.pName = entrypoint;
-
-    av_log(s, AV_LOG_VERBOSE, "Shader %s compiled! Size: %zu bytes\n",
-           shd->name, spirv_size);
-
-    shader_create.sType    = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
-    shader_create.pNext    = NULL;
-    shader_create.codeSize = spirv_size;
-    shader_create.flags    = 0;
-    shader_create.pCode    = (void *)spirv;
-
-    ret = vk->CreateShaderModule(s->hwctx->act_dev, &shader_create, NULL,
-                                 &shd->shader.module);
-    if (ret != VK_SUCCESS) {
-        av_log(s, AV_LOG_VERBOSE, "Error creating shader module: %s\n",
-               ff_vk_ret2str(ret));
-        return AVERROR_EXTERNAL;
-    }
-
-    return 0;
-}
-
-static const struct descriptor_props {
-    size_t struct_size; /* Size of the opaque which updates the descriptor */
-    const char *type;
-    int is_uniform;
-    int mem_quali;      /* Can use a memory qualifier */
-    int dim_needed;     /* Must indicate dimension */
-    int buf_content;    /* Must indicate buffer contents */
-} descriptor_props[] = {
-    [VK_DESCRIPTOR_TYPE_SAMPLER]                = { sizeof(VkDescriptorImageInfo),  "sampler",       1, 0, 0, 0, },
-    [VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE]          = { sizeof(VkDescriptorImageInfo),  "texture",       1, 0, 1, 0, },
-    [VK_DESCRIPTOR_TYPE_STORAGE_IMAGE]          = { sizeof(VkDescriptorImageInfo),  "image",         1, 1, 1, 0, },
-    [VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT]       = { sizeof(VkDescriptorImageInfo),  "subpassInput",  1, 0, 0, 0, },
-    [VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] = { sizeof(VkDescriptorImageInfo),  "sampler",       1, 0, 1, 0, },
-    [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER]         = { sizeof(VkDescriptorBufferInfo),  NULL,           1, 0, 0, 1, },
-    [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER]         = { sizeof(VkDescriptorBufferInfo), "buffer",        0, 1, 0, 1, },
-    [VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo),  NULL,           1, 0, 0, 1, },
-    [VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] = { sizeof(VkDescriptorBufferInfo), "buffer",        0, 1, 0, 1, },
-    [VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER]   = { sizeof(VkBufferView),           "samplerBuffer", 1, 0, 0, 0, },
-    [VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER]   = { sizeof(VkBufferView),           "imageBuffer",   1, 0, 0, 0, },
-};
-
-int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                      FFVkSPIRVShader *shd,
-                                      FFVulkanDescriptorSetBinding *desc, int nb,
-                                      int read_only, int print_to_shader_only)
-{
-    VkResult ret;
-    int has_sampler = 0;
-    FFVulkanFunctions *vk = &s->vkfn;
-    FFVulkanDescriptorSet *set;
-    VkDescriptorSetLayoutCreateInfo desc_create_layout;
-
-    if (print_to_shader_only)
-        goto print;
-
-    /* Actual layout allocated for the pipeline */
-    set = av_realloc_array(pl->desc_set, sizeof(*pl->desc_set),
-                           pl->nb_descriptor_sets + 1);
-    if (!set)
-        return AVERROR(ENOMEM);
-    pl->desc_set = set;
-    set = &set[pl->nb_descriptor_sets];
-    memset(set, 0, sizeof(*set));
-
-    set->binding = av_calloc(nb, sizeof(*set->binding));
-    if (!set->binding)
-        return AVERROR(ENOMEM);
-
-    set->binding_offset = av_calloc(nb, sizeof(*set->binding_offset));
-    if (!set->binding_offset) {
-        av_freep(&set->binding);
-        return AVERROR(ENOMEM);
-    }
-
-    desc_create_layout = (VkDescriptorSetLayoutCreateInfo) {
-        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
-        .bindingCount = nb,
-        .pBindings = set->binding,
-        .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,
-    };
-
-    for (int i = 0; i < nb; i++) {
-        set->binding[i].binding            = i;
-        set->binding[i].descriptorType     = desc[i].type;
-        set->binding[i].descriptorCount    = FFMAX(desc[i].elems, 1);
-        set->binding[i].stageFlags         = desc[i].stages;
-        set->binding[i].pImmutableSamplers = desc[i].samplers;
-
-        if (desc[i].type == VK_DESCRIPTOR_TYPE_SAMPLER ||
-            desc[i].type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
-            has_sampler |= 1;
-    }
-
-    set->usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT |
-                 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
-    if (has_sampler)
-        set->usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT;
-
-    ret = vk->CreateDescriptorSetLayout(s->hwctx->act_dev, &desc_create_layout,
-                                        s->hwctx->alloc, &set->layout);
-    if (ret != VK_SUCCESS) {
-        av_log(s, AV_LOG_ERROR, "Unable to init descriptor set layout: %s",
-               ff_vk_ret2str(ret));
-        return AVERROR_EXTERNAL;
-    }
-
-    vk->GetDescriptorSetLayoutSizeEXT(s->hwctx->act_dev, set->layout, &set->layout_size);
-
-    set->aligned_size = FFALIGN(set->layout_size, s->desc_buf_props.descriptorBufferOffsetAlignment);
-
-    for (int i = 0; i < nb; i++)
-        vk->GetDescriptorSetLayoutBindingOffsetEXT(s->hwctx->act_dev, set->layout,
-                                                   i, &set->binding_offset[i]);
-
-    set->read_only = read_only;
-    set->nb_bindings = nb;
-    pl->nb_descriptor_sets++;
-
-print:
-    /* Write shader info */
-    for (int i = 0; i < nb; i++) {
-        const struct descriptor_props *prop = &descriptor_props[desc[i].type];
-        GLSLA("layout (set = %i, binding = %i", pl->nb_descriptor_sets - 1, i);
-
-        if (desc[i].mem_layout)
-            GLSLA(", %s", desc[i].mem_layout);
-        GLSLA(")");
-
-        if (prop->is_uniform)
-            GLSLA(" uniform");
-
-        if (prop->mem_quali && desc[i].mem_quali)
-            GLSLA(" %s", desc[i].mem_quali);
-
-        if (prop->type)
-            GLSLA(" %s", prop->type);
-
-        if (prop->dim_needed)
-            GLSLA("%iD", desc[i].dimensions);
-
-        GLSLA(" %s", desc[i].name);
-
-        if (prop->buf_content)
-            GLSLA(" {\n    %s\n}", desc[i].buf_content);
-        else if (desc[i].elems > 0)
-            GLSLA("[%i]", desc[i].elems);
-
-        GLSLA(";");
-        GLSLA("\n");
-    }
-    GLSLA("\n");
-
-    return 0;
-}
-
-int ff_vk_exec_pipeline_register(FFVulkanContext *s, FFVkExecPool *pool,
-                                 FFVulkanPipeline *pl)
-{
-    int err;
-
-    pl->desc_bind = av_calloc(pl->nb_descriptor_sets, sizeof(*pl->desc_bind));
-    if (!pl->desc_bind)
-        return AVERROR(ENOMEM);
-
-    pl->bound_buffer_indices = av_calloc(pl->nb_descriptor_sets,
-                                         sizeof(*pl->bound_buffer_indices));
-    if (!pl->bound_buffer_indices)
-        return AVERROR(ENOMEM);
-
-    for (int i = 0; i < pl->nb_descriptor_sets; i++) {
-        FFVulkanDescriptorSet *set = &pl->desc_set[i];
-        int nb = set->read_only ? 1 : pool->pool_size;
-
-        err = ff_vk_create_buf(s, &set->buf, set->aligned_size*nb,
-                               NULL, NULL, set->usage,
-                               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
-                               VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
-        if (err < 0)
-            return err;
-
-        err = ff_vk_map_buffer(s, &set->buf, &set->desc_mem, 0);
-        if (err < 0)
-            return err;
-
-        pl->desc_bind[i] = (VkDescriptorBufferBindingInfoEXT) {
-            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT,
-            .usage = set->usage,
-            .address = set->buf.address,
-        };
-
-        pl->bound_buffer_indices[i] = i;
-    }
-
-    return 0;
-}
-
-static inline void update_set_descriptor(FFVulkanContext *s, FFVkExecContext *e,
-                                         FFVulkanDescriptorSet *set,
-                                         int bind_idx, int array_idx,
-                                         VkDescriptorGetInfoEXT *desc_get_info,
-                                         size_t desc_size)
-{
-    FFVulkanFunctions *vk = &s->vkfn;
-    const size_t exec_offset = set->read_only ? 0 : set->aligned_size*e->idx;
-    void *desc = set->desc_mem +                 /* Base */
-                 exec_offset +                   /* Execution context */
-                 set->binding_offset[bind_idx] + /* Descriptor binding */
-                 array_idx*desc_size;            /* Array position */
-
-    vk->GetDescriptorEXT(s->hwctx->act_dev, desc_get_info, desc_size, desc);
-}
-
-static int vk_set_descriptor_image(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                   FFVkExecContext *e, int set, int bind, int offs,
-                                   VkImageView view, VkImageLayout layout,
-                                   VkSampler sampler)
-{
-    FFVulkanDescriptorSet *desc_set = &pl->desc_set[set];
-    VkDescriptorGetInfoEXT desc_get_info = {
-        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
-        .type = desc_set->binding[bind].descriptorType,
-    };
-    VkDescriptorImageInfo desc_img_info = {
-        .imageView = view,
-        .sampler = sampler,
-        .imageLayout = layout,
-    };
-    size_t desc_size;
-
-    switch (desc_get_info.type) {
-    case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
-        desc_get_info.data.pSampledImage = &desc_img_info;
-        desc_size = s->desc_buf_props.sampledImageDescriptorSize;
-        break;
-    case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
-        desc_get_info.data.pStorageImage = &desc_img_info;
-        desc_size = s->desc_buf_props.storageImageDescriptorSize;
-        break;
-    case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
-        desc_get_info.data.pInputAttachmentImage = &desc_img_info;
-        desc_size = s->desc_buf_props.inputAttachmentDescriptorSize;
-        break;
-    case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
-        desc_get_info.data.pCombinedImageSampler = &desc_img_info;
-        desc_size = s->desc_buf_props.combinedImageSamplerDescriptorSize;
-        break;
-    default:
-        av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
-               set, bind, desc_get_info.type);
-        return AVERROR(EINVAL);
-        break;
-    };
-
-    update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size);
-
-    return 0;
-}
-
-int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                FFVkExecContext *e, int set, int bind, int offs,
-                                VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt)
-{
-    FFVulkanDescriptorSet *desc_set = &pl->desc_set[set];
-    VkDescriptorGetInfoEXT desc_get_info = {
-        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
-        .type = desc_set->binding[bind].descriptorType,
-    };
-    VkDescriptorAddressInfoEXT desc_buf_info = {
-        .address = addr,
-        .range = len,
-        .format = fmt,
-    };
-    size_t desc_size;
-
-    switch (desc_get_info.type) {
-    case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
-        desc_get_info.data.pUniformBuffer = &desc_buf_info;
-        desc_size = s->desc_buf_props.uniformBufferDescriptorSize;
-        break;
-    case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
-        desc_get_info.data.pStorageBuffer = &desc_buf_info;
-        desc_size = s->desc_buf_props.storageBufferDescriptorSize;
-        break;
-    case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
-        desc_get_info.data.pUniformTexelBuffer = &desc_buf_info;
-        desc_size = s->desc_buf_props.uniformTexelBufferDescriptorSize;
-        break;
-    case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
-        desc_get_info.data.pStorageTexelBuffer = &desc_buf_info;
-        desc_size = s->desc_buf_props.storageTexelBufferDescriptorSize;
-        break;
-    default:
-        av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n",
-               set, bind, desc_get_info.type);
-        return AVERROR(EINVAL);
-        break;
-    };
-
-    update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size);
-
-    return 0;
-}
-
-void ff_vk_update_descriptor_img_array(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                       FFVkExecContext *e, AVFrame *f,
-                                       VkImageView *views, int set, int binding,
-                                       VkImageLayout layout, VkSampler sampler)
-{
-    AVHWFramesContext *hwfc = (AVHWFramesContext *)f->hw_frames_ctx->data;
-    const int nb_planes = av_pix_fmt_count_planes(hwfc->sw_format);
-
-    for (int i = 0; i < nb_planes; i++)
-        vk_set_descriptor_image(s, pl, e, set, binding, i,
-                                views[i], layout, sampler);
-}
-
-void ff_vk_update_push_exec(FFVulkanContext *s, FFVkExecContext *e,
-                            FFVulkanPipeline *pl,
-                            VkShaderStageFlagBits stage,
-                            int offset, size_t size, void *src)
-{
-    FFVulkanFunctions *vk = &s->vkfn;
-    vk->CmdPushConstants(e->buf, pl->pipeline_layout,
-                         stage, offset, size, src);
-}
-
-static int init_pipeline_layout(FFVulkanContext *s, FFVulkanPipeline *pl)
-{
-    VkResult ret;
-    FFVulkanFunctions *vk = &s->vkfn;
-    VkPipelineLayoutCreateInfo pipeline_layout_info;
-
-    VkDescriptorSetLayout *desc_layouts = av_malloc(pl->nb_descriptor_sets*
-                                                    sizeof(desc_layouts));
-    if (!desc_layouts)
-        return AVERROR(ENOMEM);
-
-    for (int i = 0; i < pl->nb_descriptor_sets; i++)
-        desc_layouts[i] = pl->desc_set[i].layout;
-
-    /* Finally create the pipeline layout */
-    pipeline_layout_info = (VkPipelineLayoutCreateInfo) {
-        .sType                  = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
-        .pSetLayouts            = desc_layouts,
-        .setLayoutCount         = pl->nb_descriptor_sets,
-        .pushConstantRangeCount = pl->push_consts_num,
-        .pPushConstantRanges    = pl->push_consts,
-    };
-
-    ret = vk->CreatePipelineLayout(s->hwctx->act_dev, &pipeline_layout_info,
-                                   s->hwctx->alloc, &pl->pipeline_layout);
-    av_free(desc_layouts);
-    if (ret != VK_SUCCESS) {
-        av_log(s, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n",
-               ff_vk_ret2str(ret));
-        return AVERROR_EXTERNAL;
-    }
-
-    return 0;
-}
-
-int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                FFVkSPIRVShader *shd)
-{
-    int err;
-    VkResult ret;
-    FFVulkanFunctions *vk = &s->vkfn;
-
-    VkComputePipelineCreateInfo pipeline_create_info;
-
-    err = init_pipeline_layout(s, pl);
-    if (err < 0)
-        return err;
-
-    pipeline_create_info = (VkComputePipelineCreateInfo) {
-        .sType  = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
-        .flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,
-        .layout = pl->pipeline_layout,
-        .stage = shd->shader,
-    };
-
-    ret = vk->CreateComputePipelines(s->hwctx->act_dev, VK_NULL_HANDLE, 1,
-                                     &pipeline_create_info,
-                                     s->hwctx->alloc, &pl->pipeline);
-    if (ret != VK_SUCCESS) {
-        av_log(s, AV_LOG_ERROR, "Unable to init compute pipeline: %s\n",
-               ff_vk_ret2str(ret));
-        return AVERROR_EXTERNAL;
-    }
-
-    pl->bind_point = VK_PIPELINE_BIND_POINT_COMPUTE;
-    pl->wg_size[0] = shd->local_size[0];
-    pl->wg_size[1] = shd->local_size[1];
-    pl->wg_size[2] = shd->local_size[2];
-
-    return 0;
-}
-
-void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e,
-                              FFVulkanPipeline *pl)
-{
-    FFVulkanFunctions *vk = &s->vkfn;
-    VkDeviceSize offsets[1024];
-
-    /* Bind pipeline */
-    vk->CmdBindPipeline(e->buf, pl->bind_point, pl->pipeline);
-
-    if (pl->nb_descriptor_sets) {
-        for (int i = 0; i < pl->nb_descriptor_sets; i++)
-            offsets[i] = pl->desc_set[i].read_only ? 0 : pl->desc_set[i].aligned_size*e->idx;
-
-        /* Bind descriptor buffers */
-        vk->CmdBindDescriptorBuffersEXT(e->buf, pl->nb_descriptor_sets, pl->desc_bind);
-        /* Binding offsets */
-        vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, pl->bind_point, pl->pipeline_layout,
-                                             0, pl->nb_descriptor_sets,
-                                             pl->bound_buffer_indices, offsets);
-    }
-}
-
-void ff_vk_pipeline_free(FFVulkanContext *s, FFVulkanPipeline *pl)
-{
-    FFVulkanFunctions *vk = &s->vkfn;
-
-    if (pl->pipeline)
-        vk->DestroyPipeline(s->hwctx->act_dev, pl->pipeline, s->hwctx->alloc);
-    if (pl->pipeline_layout)
-        vk->DestroyPipelineLayout(s->hwctx->act_dev, pl->pipeline_layout,
-                                  s->hwctx->alloc);
-
-    for (int i = 0; i < pl->nb_descriptor_sets; i++) {
-        FFVulkanDescriptorSet *set = &pl->desc_set[i];
-        if (set->buf.mem)
-            ff_vk_unmap_buffer(s, &set->buf, 0);
-        ff_vk_free_buf(s, &set->buf);
-        if (set->layout)
-            vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, set->layout,
-                                           s->hwctx->alloc);
-        av_free(set->binding);
-        av_free(set->binding_offset);
-    }
-
-    av_freep(&pl->desc_set);
-    av_freep(&pl->desc_bind);
-    av_freep(&pl->bound_buffer_indices);
-    av_freep(&pl->push_consts);
-    pl->push_consts_num = 0;
-}
-
 void ff_vk_uninit(FFVulkanContext *s)
 {
     av_freep(&s->query_props);
diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h
index 15d954fcb8..e30f0361c3 100644
--- a/libavutil/vulkan.h
+++ b/libavutil/vulkan.h
@@ -25,43 +25,10 @@ 
 
 #include "thread.h"
 #include "pixdesc.h"
-#include "bprint.h"
 #include "hwcontext.h"
 #include "vulkan_functions.h"
 #include "hwcontext_vulkan.h"
 
-/* GLSL management macros */
-#define INDENT(N) INDENT_##N
-#define INDENT_0
-#define INDENT_1 INDENT_0 "    "
-#define INDENT_2 INDENT_1 INDENT_1
-#define INDENT_3 INDENT_2 INDENT_1
-#define INDENT_4 INDENT_3 INDENT_1
-#define INDENT_5 INDENT_4 INDENT_1
-#define INDENT_6 INDENT_5 INDENT_1
-#define C(N, S)          INDENT(N) #S "\n"
-
-#define GLSLC(N, S)                     \
-    do {                                \
-        av_bprintf(&shd->src, C(N, S)); \
-    } while (0)
-
-#define GLSLA(...)                          \
-    do {                                    \
-        av_bprintf(&shd->src, __VA_ARGS__); \
-    } while (0)
-
-#define GLSLF(N, S, ...)                             \
-    do {                                             \
-        av_bprintf(&shd->src, C(N, S), __VA_ARGS__); \
-    } while (0)
-
-#define GLSLD(D)                                        \
-    do {                                                \
-        av_bprintf(&shd->src, "\n");                    \
-        av_bprint_append_data(&shd->src, D, strlen(D)); \
-        av_bprintf(&shd->src, "\n");                    \
-    } while (0)
 
 /* Helper, pretty much every Vulkan return value needs to be checked */
 #define RET(x)                                                                 \
@@ -72,26 +39,6 @@ 
 
 #define DUP_SAMPLER(x) { x, x, x, x }
 
-typedef struct FFVkSPIRVShader {
-    const char *name;                       /* Name for id/debugging purposes */
-    AVBPrint src;
-    int local_size[3];                      /* Compute shader workgroup sizes */
-    VkPipelineShaderStageCreateInfo shader;
-    VkPipelineShaderStageRequiredSubgroupSizeCreateInfo subgroup_info;
-} FFVkSPIRVShader;
-
-typedef struct FFVulkanDescriptorSetBinding {
-    const char         *name;
-    VkDescriptorType    type;
-    const char         *mem_layout;  /* Storage images (rgba8, etc.) and buffers (std430, etc.) */
-    const char         *mem_quali;   /* readonly, writeonly, etc. */
-    const char         *buf_content; /* For buffers */
-    uint32_t            dimensions;  /* Needed for e.g. sampler%iD */
-    uint32_t            elems;       /* 0 - scalar, 1 or more - vector */
-    VkShaderStageFlags  stages;
-    VkSampler           samplers[4]; /* Sampler to use for all elems */
-} FFVulkanDescriptorSetBinding;
-
 typedef struct FFVkBuffer {
     VkBuffer buf;
     VkDeviceMemory mem;
@@ -112,43 +59,6 @@  typedef struct FFVkQueueFamilyCtx {
     int nb_queues;
 } FFVkQueueFamilyCtx;
 
-typedef struct FFVulkanDescriptorSet {
-    VkDescriptorSetLayout  layout;
-    FFVkBuffer             buf;
-    uint8_t               *desc_mem;
-    VkDeviceSize           layout_size;
-    VkDeviceSize           aligned_size; /* descriptorBufferOffsetAlignment */
-    VkDeviceSize           total_size; /* Once registered to an exec context */
-    VkBufferUsageFlags     usage;
-
-    VkDescriptorSetLayoutBinding *binding;
-    VkDeviceSize *binding_offset;
-    int nb_bindings;
-
-    int read_only;
-} FFVulkanDescriptorSet;
-
-typedef struct FFVulkanPipeline {
-    VkPipelineBindPoint bind_point;
-
-    /* Contexts */
-    VkPipelineLayout pipeline_layout;
-    VkPipeline       pipeline;
-
-    /* Push consts */
-    VkPushConstantRange *push_consts;
-    int push_consts_num;
-
-    /* Workgroup */
-    int wg_size[3];
-
-    /* Descriptors */
-    FFVulkanDescriptorSet *desc_set;
-    VkDescriptorBufferBindingInfoEXT *desc_bind;
-    uint32_t *bound_buffer_indices;
-    int nb_descriptor_sets;
-} FFVulkanPipeline;
-
 typedef struct FFVkExecContext {
     uint32_t idx;
     const struct FFVkExecPool *parent;
@@ -297,16 +207,6 @@  extern const VkComponentMapping ff_comp_identity_map;
  */
 const char *ff_vk_ret2str(VkResult res);
 
-/**
- * Returns 1 if pixfmt is a usable RGB format.
- */
-int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt);
-
-/**
- * Returns the format to use for images in shaders.
- */
-const char *ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt);
-
 /**
  * Loads props/mprops/driver_props
  */
@@ -371,13 +271,6 @@  int ff_vk_exec_mirror_sem_value(FFVulkanContext *s, FFVkExecContext *e,
                                 AVFrame *f);
 void ff_vk_exec_discard_deps(FFVulkanContext *s, FFVkExecContext *e);
 
-/**
- * Create an imageview and add it as a dependency to an execution.
- */
-int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e,
-                            VkImageView views[AV_NUM_DATA_POINTERS],
-                            AVFrame *f);
-
 void ff_vk_frame_barrier(FFVulkanContext *s, FFVkExecContext *e,
                          AVFrame *pic, VkImageMemoryBarrier2 *bar, int *nb_bar,
                          VkPipelineStageFlags src_stage,
@@ -421,75 +314,6 @@  static inline int ff_vk_unmap_buffer(FFVulkanContext *s, FFVkBuffer *buf, int fl
 
 void ff_vk_free_buf(FFVulkanContext *s, FFVkBuffer *buf);
 
-/** Initialize a pool and create AVBufferRefs containing FFVkBuffer.
- * Threadsafe to use. Buffers are automatically mapped on creation if
- * VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT is set in mem_props. Users should
- * synchronize access themselvesd. Mainly meant for device-local buffers. */
-int ff_vk_get_pooled_buffer(FFVulkanContext *ctx, AVBufferPool **buf_pool,
-                            AVBufferRef **buf, VkBufferUsageFlags usage,
-                            void *create_pNext, size_t size,
-                            VkMemoryPropertyFlagBits mem_props);
-
-/**
- * Create a sampler.
- */
-int ff_vk_init_sampler(FFVulkanContext *s, VkSampler *sampler,
-                       int unnorm_coords, VkFilter filt);
-
-/**
- * Shader management.
- */
-int ff_vk_shader_init(FFVulkanPipeline *pl, FFVkSPIRVShader *shd, const char *name,
-                      VkShaderStageFlags stage, uint32_t required_subgroup_size);
-void ff_vk_shader_set_compute_sizes(FFVkSPIRVShader *shd, int x, int y, int z);
-void ff_vk_shader_print(void *ctx, FFVkSPIRVShader *shd, int prio);
-int ff_vk_shader_create(FFVulkanContext *s, FFVkSPIRVShader *shd,
-                        uint8_t *spirv, size_t spirv_size, const char *entrypoint);
-void ff_vk_shader_free(FFVulkanContext *s, FFVkSPIRVShader *shd);
-
-/**
- * Add/update push constants for execution.
- */
-int ff_vk_add_push_constant(FFVulkanPipeline *pl, int offset, int size,
-                            VkShaderStageFlagBits stage);
-void ff_vk_update_push_exec(FFVulkanContext *s, FFVkExecContext *e,
-                            FFVulkanPipeline *pl,
-                            VkShaderStageFlagBits stage,
-                            int offset, size_t size, void *src);
-
-/**
- * Add descriptor to a pipeline. Must be called before pipeline init.
- */
-int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                      FFVkSPIRVShader *shd,
-                                      FFVulkanDescriptorSetBinding *desc, int nb,
-                                      int read_only, int print_to_shader_only);
-
-/* Initialize/free a pipeline. */
-int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                FFVkSPIRVShader *shd);
-void ff_vk_pipeline_free(FFVulkanContext *s, FFVulkanPipeline *pl);
-
-/**
- * Register a pipeline with an exec pool.
- * Pool may be NULL if all descriptor sets are read-only.
- */
-int ff_vk_exec_pipeline_register(FFVulkanContext *s, FFVkExecPool *pool,
-                                 FFVulkanPipeline *pl);
-
-/* Bind pipeline */
-void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e,
-                              FFVulkanPipeline *pl);
-
-int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                FFVkExecContext *e, int set, int bind, int offs,
-                                VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt);
-
-void ff_vk_update_descriptor_img_array(FFVulkanContext *s, FFVulkanPipeline *pl,
-                                       FFVkExecContext *e, AVFrame *f,
-                                       VkImageView *views, int set, int binding,
-                                       VkImageLayout layout, VkSampler sampler);
-
 /**
  * Frees main context.
  */