Unified · Split
| @@ -1,5 +1,7 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * copyright (c) 2021 Wu Jianhua <jianhua.wu@intel.com> |
| 3 | + * Copyright (c) Lynne | |
| 4 | + * | |
| 3 | 5 | * This file is part of FFmpeg. |
| 4 | 6 | * |
| 5 | 7 | * FFmpeg is free software; you can redistribute it and/or |
| @@ -20,41 +22,60 @@ · 14 unmodified lines | ||
| 20 | 22 | #include "libavutil/random_seed.h" |
| 21 | 23 | #include "libavutil/opt.h" |
| 22 | 24 | #include "vulkan_filter.h" |
| 25 | +#include "vulkan_spirv.h" | |
| 23 | 26 | #include "internal.h" |
| 24 | 27 | #include "transpose.h" |
| 25 | 28 | |
| 26 | −#define CGS 32 | |
| 27 | − | |
| 28 | 29 | typedef struct TransposeVulkanContext { |
| 29 | 30 | FFVulkanContext vkctx; |
| 30 | − FFVkQueueFamilyCtx qf; | |
| 31 | − FFVkExecContext *exec; | |
| 32 | − FFVulkanPipeline *pl; | |
| 33 | 31 | |
| 34 | − VkDescriptorImageInfo input_images[3]; | |
| 35 | − VkDescriptorImageInfo output_images[3]; | |
| 32 | + int initialized; | |
| 33 | + FFVulkanPipeline pl; | |
| 34 | + FFVkExecPool e; | |
| 35 | + FFVkQueueFamilyCtx qf; | |
| 36 | + FFVkSPIRVShader shd; | |
| 37 | + VkSampler sampler; | |
| 36 | 38 | |
| 37 | 39 | int dir; |
| 38 | 40 | int passthrough; |
| 39 | − int initialized; | |
| 40 | 41 | } TransposeVulkanContext; |
| 41 | 42 | |
| 42 | 43 | static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) |
| 43 | 44 | { |
| 44 | − int err = 0; | |
| 45 | − FFVkSPIRVShader *shd; | |
| 45 | + int err; | |
| 46 | + uint8_t *spv_data; | |
| 47 | + size_t spv_len; | |
| 48 | + void *spv_opaque = NULL; | |
| 46 | 49 | TransposeVulkanContext *s = ctx->priv; |
| 47 | 50 | FFVulkanContext *vkctx = &s->vkctx; |
| 51 | + | |
| 48 | 52 | const int planes = av_pix_fmt_count_planes(s->vkctx.output_format); |
| 53 | + FFVkSPIRVShader *shd = &s->shd; | |
| 54 | + FFVkSPIRVCompiler *spv; | |
| 55 | + FFVulkanDescriptorSetBinding *desc; | |
| 56 | + | |
| 57 | + spv = ff_vk_spirv_init(); | |
| 58 | + if (!spv) { | |
| 59 | + av_log(ctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n"); | |
| 60 | + return AVERROR_EXTERNAL; | |
| 61 | + } | |
| 62 | + | |
| 63 | + ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT); | |
| 64 | + RET(ff_vk_exec_pool_init(vkctx, &s->qf, &s->e, s->qf.nb_queues*4, 0, 0, 0, NULL)); | |
| 65 | + RET(ff_vk_init_sampler(vkctx, &s->sampler, 1, VK_FILTER_LINEAR)); | |
| 66 | + RET(ff_vk_shader_init(&s->pl, &s->shd, "transpose_compute", | |
| 67 | + VK_SHADER_STAGE_COMPUTE_BIT, 0)); | |
| 49 | 68 | |
| 50 | − FFVulkanDescriptorSetBinding image_descs[] = { | |
| 69 | + ff_vk_shader_set_compute_sizes(&s->shd, 32, 1, 1); | |
| 70 | + | |
| 71 | + desc = (FFVulkanDescriptorSetBinding []) { | |
| 51 | 72 | { |
| 52 | 73 | .name = "input_images", |
| 53 | 74 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| 54 | 75 | .dimensions = 2, |
| 55 | 76 | .elems = planes, |
| 56 | 77 | .stages = VK_SHADER_STAGE_COMPUTE_BIT, |
| 57 | − .updater = s->input_images, | |
| 78 | + .samplers = DUP_SAMPLER(s->sampler), | |
| 58 | 79 | }, |
| 59 | 80 | { |
| 60 | 81 | .name = "output_images", |
| @@ -64,154 +85,49 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) · 3 unmodified lines | ||
| 64 | 85 | .dimensions = 2, |
| 65 | 86 | .elems = planes, |
| 66 | 87 | .stages = VK_SHADER_STAGE_COMPUTE_BIT, |
| 67 | − .updater = s->output_images, | |
| 68 | 88 | }, |
| 69 | 89 | }; |
| 70 | 90 | |
| 71 | − image_descs[0].sampler = ff_vk_init_sampler(vkctx, 1, VK_FILTER_LINEAR); | |
| 72 | − if (!image_descs[0].sampler) | |
| 73 | − return AVERROR_EXTERNAL; | |
| 74 | − | |
| 75 | − ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT, 0); | |
| 76 | − | |
| 77 | − { | |
| 78 | − s->pl = ff_vk_create_pipeline(vkctx, &s->qf); | |
| 79 | − if (!s->pl) | |
| 80 | − return AVERROR(ENOMEM); | |
| 81 | − | |
| 82 | − shd = ff_vk_init_shader(s->pl, "transpose_compute", image_descs[0].stages); | |
| 83 | − if (!shd) | |
| 84 | − return AVERROR(ENOMEM); | |
| 85 | − | |
| 86 | − ff_vk_set_compute_shader_sizes(shd, (int [3]){ CGS, 1, 1 }); | |
| 87 | − RET(ff_vk_add_descriptor_set(vkctx, s->pl, shd, image_descs, FF_ARRAY_ELEMS(image_descs), 0)); | |
| 88 | − | |
| 89 | − GLSLC(0, void main() ); | |
| 90 | − GLSLC(0, { ); | |
| 91 | − GLSLC(1, ivec2 size; ); | |
| 92 | − GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); ); | |
| 93 | − for (int i = 0; i < planes; i++) { | |
| 94 | − GLSLC(0, ); | |
| 95 | − GLSLF(1, size = imageSize(output_images[%i]); ,i); | |
| 96 | − GLSLC(1, if (IS_WITHIN(pos, size)) { ); | |
| 97 | − if (s->dir == TRANSPOSE_CCLOCK) | |
| 98 | − GLSLF(2, vec4 res = texture(input_images[%i], ivec2(size.y - pos.y, pos.x)); ,i); | |
| 99 | − else if (s->dir == TRANSPOSE_CLOCK_FLIP || s->dir == TRANSPOSE_CLOCK) { | |
| 100 | − GLSLF(2, vec4 res = texture(input_images[%i], ivec2(size.yx - pos.yx)); ,i); | |
| 101 | − if (s->dir == TRANSPOSE_CLOCK) | |
| 102 | − GLSLC(2, pos = ivec2(pos.x, size.y - pos.y); ); | |
| 103 | − } else | |
| 104 | − GLSLF(2, vec4 res = texture(input_images[%i], pos.yx); ,i); | |
| 105 | − GLSLF(2, imageStore(output_images[%i], pos, res); ,i); | |
| 106 | − GLSLC(1, } ); | |
| 107 | − } | |
| 108 | − GLSLC(0, } ); | |
| 109 | − | |
| 110 | − RET(ff_vk_compile_shader(vkctx, shd, "main")); | |
| 111 | − RET(ff_vk_init_pipeline_layout(vkctx, s->pl)); | |
| 112 | − RET(ff_vk_init_compute_pipeline(vkctx, s->pl)); | |
| 113 | − } | |
| 114 | − | |
| 115 | − RET(ff_vk_create_exec_ctx(vkctx, &s->exec, &s->qf)); | |
| 116 | − s->initialized = 1; | |
| 117 | − | |
| 118 | −fail: | |
| 119 | − return err; | |
| 120 | −} | |
| 121 | − | |
| 122 | −static int process_frames(AVFilterContext *avctx, AVFrame *outframe, AVFrame *inframe) | |
| 123 | −{ | |
| 124 | − int err = 0; | |
| 125 | − VkCommandBuffer cmd_buf; | |
| 126 | − TransposeVulkanContext *s = avctx->priv; | |
| 127 | − FFVulkanContext *vkctx = &s->vkctx; | |
| 128 | − FFVulkanFunctions *vk = &s->vkctx.vkfn; | |
| 129 | − const int planes = av_pix_fmt_count_planes(s->vkctx.output_format); | |
| 130 | − | |
| 131 | − AVVkFrame *in = (AVVkFrame *)inframe->data[0]; | |
| 132 | − AVVkFrame *out = (AVVkFrame *)outframe->data[0]; | |
| 133 | − | |
| 134 | − const VkFormat *input_formats = av_vkfmt_from_pixfmt(s->vkctx.input_format); | |
| 135 | − const VkFormat *output_formats = av_vkfmt_from_pixfmt(s->vkctx.output_format); | |
| 136 | − | |
| 137 | − ff_vk_start_exec_recording(vkctx, s->exec); | |
| 138 | − cmd_buf = ff_vk_get_exec_buf(s->exec); | |
| 139 | − | |
| 140 | − for (int i = 0; i < planes; i++) { | |
| 141 | − RET(ff_vk_create_imageview(vkctx, s->exec, | |
| 142 | − &s->input_images[i].imageView, in->img[i], | |
| 143 | − input_formats[i], | |
| 144 | − ff_comp_identity_map)); | |
| 145 | − | |
| 146 | − RET(ff_vk_create_imageview(vkctx, s->exec, | |
| 147 | − &s->output_images[i].imageView, out->img[i], | |
| 148 | − output_formats[i], | |
| 149 | − ff_comp_identity_map)); | |
| 150 | − | |
| 151 | − s->input_images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; | |
| 152 | − s->output_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; | |
| 153 | − } | |
| 154 | − | |
| 155 | − ff_vk_update_descriptor_set(vkctx, s->pl, 0); | |
| 91 | + RET(ff_vk_pipeline_descriptor_set_add(vkctx, &s->pl, shd, desc, 2, 0, 0)); | |
| 156 | 92 | |
| 93 | + GLSLC(0, void main() ); | |
| 94 | + GLSLC(0, { ); | |
| 95 | + GLSLC(1, ivec2 size; ); | |
| 96 | + GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); ); | |
| 157 | 97 | for (int i = 0; i < planes; i++) { |
| 158 | − VkImageMemoryBarrier barriers[] = { | |
| 159 | − { | |
| 160 | − .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | |
| 161 | − .srcAccessMask = 0, | |
| 162 | − .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, | |
| 163 | − .oldLayout = in->layout[i], | |
| 164 | − .newLayout = s->input_images[i].imageLayout, | |
| 165 | − .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
| 166 | − .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
| 167 | − .image = in->img[i], | |
| 168 | − .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | |
| 169 | − .subresourceRange.levelCount = 1, | |
| 170 | − .subresourceRange.layerCount = 1, | |
| 171 | − }, | |
| 172 | − { | |
| 173 | − .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | |
| 174 | − .srcAccessMask = 0, | |
| 175 | − .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT, | |
| 176 | − .oldLayout = out->layout[i], | |
| 177 | − .newLayout = s->output_images[i].imageLayout, | |
| 178 | − .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
| 179 | − .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
| 180 | − .image = out->img[i], | |
| 181 | − .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | |
| 182 | − .subresourceRange.levelCount = 1, | |
| 183 | − .subresourceRange.layerCount = 1, | |
| 184 | − }, | |
| 185 | − }; | |
| 186 | − | |
| 187 | − vk->CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, | |
| 188 | − VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, | |
| 189 | − 0, NULL, 0, NULL, FF_ARRAY_ELEMS(barriers), barriers); | |
| 190 | − | |
| 191 | − in->layout[i] = barriers[0].newLayout; | |
| 192 | − in->access[i] = barriers[0].dstAccessMask; | |
| 193 | − | |
| 194 | − out->layout[i] = barriers[1].newLayout; | |
| 195 | − out->access[i] = barriers[1].dstAccessMask; | |
| 98 | + GLSLC(0, ); | |
| 99 | + GLSLF(1, size = imageSize(output_images[%i]); ,i); | |
| 100 | + GLSLC(1, if (IS_WITHIN(pos, size)) { ); | |
| 101 | + if (s->dir == TRANSPOSE_CCLOCK) | |
| 102 | + GLSLF(2, vec4 res = texture(input_images[%i], ivec2(size.y - pos.y, pos.x)); ,i); | |
| 103 | + else if (s->dir == TRANSPOSE_CLOCK_FLIP || s->dir == TRANSPOSE_CLOCK) { | |
| 104 | + GLSLF(2, vec4 res = texture(input_images[%i], ivec2(size.yx - pos.yx)); ,i); | |
| 105 | + if (s->dir == TRANSPOSE_CLOCK) | |
| 106 | + GLSLC(2, pos = ivec2(pos.x, size.y - pos.y); ); | |
| 107 | + } else | |
| 108 | + GLSLF(2, vec4 res = texture(input_images[%i], pos.yx); ,i); | |
| 109 | + GLSLF(2, imageStore(output_images[%i], pos, res); ,i); | |
| 110 | + GLSLC(1, } ); | |
| 196 | 111 | } |
| 112 | + GLSLC(0, } ); | |
| 197 | 113 | |
| 198 | − ff_vk_bind_pipeline_exec(vkctx, s->exec, s->pl); | |
| 199 | − vk->CmdDispatch(cmd_buf, FFALIGN(s->vkctx.output_width, CGS)/CGS, | |
| 200 | − s->vkctx.output_height, 1); | |
| 114 | + RET(spv->compile_shader(spv, ctx, shd, &spv_data, &spv_len, "main", | |
| 115 | + &spv_opaque)); | |
| 116 | + RET(ff_vk_shader_create(vkctx, shd, spv_data, spv_len, "main")); | |
| 201 | 117 | |
| 202 | − ff_vk_add_exec_dep(vkctx, s->exec, inframe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); | |
| 203 | − ff_vk_add_exec_dep(vkctx, s->exec, outframe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); | |
| 118 | + RET(ff_vk_init_compute_pipeline(vkctx, &s->pl, shd)); | |
| 119 | + RET(ff_vk_exec_pipeline_register(vkctx, &s->e, &s->pl)); | |
| 204 | 120 | |
| 205 | − err = ff_vk_submit_exec_queue(vkctx, s->exec); | |
| 206 | − if (err) | |
| 207 | − return err; | |
| 208 | − | |
| 209 | − ff_vk_qf_rotate(&s->qf); | |
| 121 | + s->initialized = 1; | |
| 210 | 122 | |
| 211 | 123 | return 0; |
| 212 | 124 | |
| 213 | 125 | fail: |
| 214 | − ff_vk_discard_exec_deps(s->exec); | |
| 126 | + if (spv_opaque) | |
| 127 | + spv->free_shader(spv, &spv_opaque); | |
| 128 | + if (spv) | |
| 129 | + spv->uninit(&spv); | |
| 130 | + | |
| 215 | 131 | return err; |
| 216 | 132 | } |
| 217 | 133 | |
| @@ -235,7 +151,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) · 17 unmodified lines | ||
| 235 | 151 | if (!s->initialized) |
| 236 | 152 | RET(init_filter(ctx, in)); |
| 237 | 153 | |
| 238 | − RET(process_frames(ctx, out, in)); | |
| 154 | + RET(ff_vk_filter_process_simple(&s->vkctx, &s->e, &s->pl, out, in, | |
| 155 | + s->sampler, NULL, 0)); | |
| 239 | 156 | |
| 240 | 157 | RET(av_frame_copy_props(out, in)); |
| 241 | 158 | |
| @@ -259,6 +176,17 @@ fail: · 17 unmodified lines | ||
| 259 | 176 | static av_cold void transpose_vulkan_uninit(AVFilterContext *avctx) |
| 260 | 177 | { |
| 261 | 178 | TransposeVulkanContext *s = avctx->priv; |
| 179 | + FFVulkanContext *vkctx = &s->vkctx; | |
| 180 | + FFVulkanFunctions *vk = &vkctx->vkfn; | |
| 181 | + | |
| 182 | + ff_vk_exec_pool_free(vkctx, &s->e); | |
| 183 | + ff_vk_pipeline_free(vkctx, &s->pl); | |
| 184 | + ff_vk_shader_free(vkctx, &s->shd); | |
| 185 | + | |
| 186 | + if (s->sampler) | |
| 187 | + vk->DestroySampler(vkctx->hwctx->act_dev, s->sampler, | |
| 188 | + vkctx->hwctx->alloc); | |
| 189 | + | |
| 262 | 190 | ff_vk_uninit(&s->vkctx); |
| 263 | 191 | |
| 264 | 192 | s->initialized = 0; |