History

overlay_vulkan: port for the rewrite

Lynne committed 3 years ago

Commit 8e9ceb11 parent 59f21c01 file · +123 −275Browse files

Showing the changes to libavfilter (1 of 1 file). Show all

Unified · Split

libavfilter/vf_overlay_vulkan.c+123−275
@@ -1,4 +1,6 @@
1/*1/*
2 * Copyright (c) Lynne
3 *
2 * This file is part of FFmpeg.4 * This file is part of FFmpeg.
3 *5 *
4 * FFmpeg is free software; you can redistribute it and/or6 * FFmpeg is free software; you can redistribute it and/or
@@ -19,26 +21,26 @@ · 14 unmodified lines
19#include "libavutil/random_seed.h"21#include "libavutil/random_seed.h"
20#include "libavutil/opt.h"22#include "libavutil/opt.h"
21#include "vulkan_filter.h"23#include "vulkan_filter.h"
24#include "vulkan_spirv.h"
22#include "internal.h"25#include "internal.h"
23#include "framesync.h"26#include "framesync.h"
24 27
25#define CGROUPS (int [3]){ 32, 32, 1 }
26
27typedef struct OverlayVulkanContext {28typedef struct OverlayVulkanContext {
28 FFVulkanContext vkctx;29 FFVulkanContext vkctx;
30 FFFrameSync fs;
29 31
30 int initialized;32 int initialized;
33 FFVulkanPipeline pl;
34 FFVkExecPool e;
31 FFVkQueueFamilyCtx qf;35 FFVkQueueFamilyCtx qf;
32 FFVkExecContext *exec;36 FFVkSPIRVShader shd;
33 FFVulkanPipeline *pl;37 VkSampler sampler;
34 FFFrameSync fs;
35 FFVkBuffer params_buf;
36 38
37 /* Shader updators, must be in the main filter struct */39 /* Push constants / options */
38 VkDescriptorImageInfo main_images[3];40 struct {
39 VkDescriptorImageInfo overlay_images[3];41 int32_t o_offset[2*3];
40 VkDescriptorImageInfo output_images[3];42 int32_t o_size[2*3];
41 VkDescriptorBufferInfo params_desc;43 } opts;
42 44
43 int overlay_x;45 int overlay_x;
44 int overlay_y;46 int overlay_y;
@@ -80,279 +82,114 @@ static const char overlay_alpha[] = { · 35 unmodified lines
80static av_cold int init_filter(AVFilterContext *ctx)82static av_cold int init_filter(AVFilterContext *ctx)
81{83{
82 int err;84 int err;
83 FFVkSampler *sampler;85 uint8_t *spv_data;
86 size_t spv_len;
87 void *spv_opaque = NULL;
84 OverlayVulkanContext *s = ctx->priv;88 OverlayVulkanContext *s = ctx->priv;
85 FFVulkanContext *vkctx = &s->vkctx;89 FFVulkanContext *vkctx = &s->vkctx;
86 const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);90 const int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
87 91 const int ialpha = av_pix_fmt_desc_get(s->vkctx.input_format)->flags & AV_PIX_FMT_FLAG_ALPHA;
88 ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT, 0);92 const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(s->vkctx.output_format);
89 93 FFVkSPIRVShader *shd = &s->shd;
90 sampler = ff_vk_init_sampler(vkctx, 1, VK_FILTER_NEAREST);94 FFVkSPIRVCompiler *spv;
91 if (!sampler)95 FFVulkanDescriptorSetBinding *desc;
96
97 spv = ff_vk_spirv_init();
98 if (!spv) {
99 av_log(ctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
92 return AVERROR_EXTERNAL;100 return AVERROR_EXTERNAL;
93
94 s->pl = ff_vk_create_pipeline(vkctx, &s->qf);
95 if (!s->pl)
96 return AVERROR(ENOMEM);
97
98 { /* Create the shader */
99 const int ialpha = av_pix_fmt_desc_get(s->vkctx.input_format)->flags & AV_PIX_FMT_FLAG_ALPHA;
100
101 FFVulkanDescriptorSetBinding desc_i[3] = {
102 {
103 .name = "main_img",
104 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
105 .dimensions = 2,
106 .elems = planes,
107 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
108 .updater = s->main_images,
109 .sampler = sampler,
110 },
111 {
112 .name = "overlay_img",
113 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
114 .dimensions = 2,
115 .elems = planes,
116 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
117 .updater = s->overlay_images,
118 .sampler = sampler,
119 },
120 {
121 .name = "output_img",
122 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
123 .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),
124 .mem_quali = "writeonly",
125 .dimensions = 2,
126 .elems = planes,
127 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
128 .updater = s->output_images,
129 },
130 };
131
132 FFVulkanDescriptorSetBinding desc_b = {
133 .name = "params",
134 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
135 .mem_quali = "readonly",
136 .mem_layout = "std430",
137 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
138 .updater = &s->params_desc,
139 .buf_content = "ivec2 o_offset[3], o_size[3];",
140 };
141
142 FFVkSPIRVShader *shd = ff_vk_init_shader(s->pl, "overlay_compute",
143 VK_SHADER_STAGE_COMPUTE_BIT);
144 if (!shd)
145 return AVERROR(ENOMEM);
146
147 ff_vk_set_compute_shader_sizes(shd, CGROUPS);
148
149 RET(ff_vk_add_descriptor_set(vkctx, s->pl, shd, desc_i, FF_ARRAY_ELEMS(desc_i), 0)); /* set 0 */
150 RET(ff_vk_add_descriptor_set(vkctx, s->pl, shd, &desc_b, 1, 0)); /* set 1 */
151
152 GLSLD( overlay_noalpha );
153 GLSLD( overlay_alpha );
154 GLSLC(0, void main() );
155 GLSLC(0, { );
156 GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
157 GLSLF(1, int planes = %i; ,planes);
158 GLSLC(1, for (int i = 0; i < planes; i++) { );
159 if (ialpha)
160 GLSLC(2, overlay_alpha_opaque(i, pos); );
161 else
162 GLSLC(2, overlay_noalpha(i, pos); );
163 GLSLC(1, } );
164 GLSLC(0, } );
165
166 RET(ff_vk_compile_shader(vkctx, shd, "main"));
167 }
168
169 RET(ff_vk_init_pipeline_layout(vkctx, s->pl));
170 RET(ff_vk_init_compute_pipeline(vkctx, s->pl));
171
172 { /* Create and update buffer */
173 const AVPixFmtDescriptor *desc;
174
175 /* NOTE: std430 requires the same identical struct layout, padding and
176 * alignment as C, so we're allowed to do this, as this will map
177 * exactly to what the shader recieves */
178 struct {
179 int32_t o_offset[2*3];
180 int32_t o_size[2*3];
181 } *par;
182
183 err = ff_vk_create_buf(vkctx, &s->params_buf,
184 sizeof(*par), NULL,
185 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
186 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
187 if (err)
188 return err;
189
190 err = ff_vk_map_buffers(vkctx, &s->params_buf, (uint8_t **)&par, 1, 0);
191 if (err)
192 return err;
193
194 desc = av_pix_fmt_desc_get(s->vkctx.output_format);
195
196 par->o_offset[0] = s->overlay_x;
197 par->o_offset[1] = s->overlay_y;
198 par->o_offset[2] = par->o_offset[0] >> desc->log2_chroma_w;
199 par->o_offset[3] = par->o_offset[1] >> desc->log2_chroma_h;
200 par->o_offset[4] = par->o_offset[0] >> desc->log2_chroma_w;
201 par->o_offset[5] = par->o_offset[1] >> desc->log2_chroma_h;
202
203 par->o_size[0] = s->overlay_w;
204 par->o_size[1] = s->overlay_h;
205 par->o_size[2] = par->o_size[0] >> desc->log2_chroma_w;
206 par->o_size[3] = par->o_size[1] >> desc->log2_chroma_h;
207 par->o_size[4] = par->o_size[0] >> desc->log2_chroma_w;
208 par->o_size[5] = par->o_size[1] >> desc->log2_chroma_h;
209
210 err = ff_vk_unmap_buffers(vkctx, &s->params_buf, 1, 1);
211 if (err)
212 return err;
213
214 s->params_desc.buffer = s->params_buf.buf;
215 s->params_desc.range = VK_WHOLE_SIZE;
216
217 ff_vk_update_descriptor_set(vkctx, s->pl, 1);
218 }101 }
219 102
220 /* Execution context */103 ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT);
221 RET(ff_vk_create_exec_ctx(vkctx, &s->exec, &s->qf));104 RET(ff_vk_exec_pool_init(vkctx, &s->qf, &s->e, s->qf.nb_queues*4, 0, 0, 0, NULL));
105 RET(ff_vk_init_sampler(vkctx, &s->sampler, 1, VK_FILTER_NEAREST));
106 RET(ff_vk_shader_init(&s->pl, &s->shd, "overlay_compute",
107 VK_SHADER_STAGE_COMPUTE_BIT, 0));
108
109 ff_vk_shader_set_compute_sizes(&s->shd, 32, 32, 1);
110
111 GLSLC(0, layout(push_constant, std430) uniform pushConstants { );
112 GLSLC(1, ivec2 o_offset[3]; );
113 GLSLC(1, ivec2 o_size[3]; );
114 GLSLC(0, }; );
115 GLSLC(0, );
116
117 ff_vk_add_push_constant(&s->pl, 0, sizeof(s->opts),
118 VK_SHADER_STAGE_COMPUTE_BIT);
119
120 desc = (FFVulkanDescriptorSetBinding []) {
121 {
122 .name = "main_img",
123 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
124 .dimensions = 2,
125 .elems = planes,
126 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
127 .samplers = DUP_SAMPLER(s->sampler),
128 },
129 {
130 .name = "overlay_img",
131 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
132 .dimensions = 2,
133 .elems = planes,
134 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
135 .samplers = DUP_SAMPLER(s->sampler),
136 },
137 {
138 .name = "output_img",
139 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
140 .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),
141 .mem_quali = "writeonly",
142 .dimensions = 2,
143 .elems = planes,
144 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
145 },
146 };
147
148 RET(ff_vk_pipeline_descriptor_set_add(vkctx, &s->pl, shd, desc, 3, 0, 0));
149
150 GLSLD( overlay_noalpha );
151 GLSLD( overlay_alpha );
152 GLSLC(0, void main() );
153 GLSLC(0, { );
154 GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
155 GLSLF(1, int planes = %i; ,planes);
156 GLSLC(1, for (int i = 0; i < planes; i++) { );
157 if (ialpha)
158 GLSLC(2, overlay_alpha_opaque(i, pos); );
159 else
160 GLSLC(2, overlay_noalpha(i, pos); );
161 GLSLC(1, } );
162 GLSLC(0, } );
163
164 RET(spv->compile_shader(spv, ctx, shd, &spv_data, &spv_len, "main",
165 &spv_opaque));
166 RET(ff_vk_shader_create(vkctx, shd, spv_data, spv_len, "main"));
167
168 RET(ff_vk_init_compute_pipeline(vkctx, &s->pl, shd));
169 RET(ff_vk_exec_pipeline_register(vkctx, &s->e, &s->pl));
170
171 s->opts.o_offset[0] = s->overlay_x;
172 s->opts.o_offset[1] = s->overlay_y;
173 s->opts.o_offset[2] = s->opts.o_offset[0] >> pix_desc->log2_chroma_w;
174 s->opts.o_offset[3] = s->opts.o_offset[1] >> pix_desc->log2_chroma_h;
175 s->opts.o_offset[4] = s->opts.o_offset[0] >> pix_desc->log2_chroma_w;
176 s->opts.o_offset[5] = s->opts.o_offset[1] >> pix_desc->log2_chroma_h;
177
178 s->opts.o_size[0] = s->overlay_w;
179 s->opts.o_size[1] = s->overlay_h;
180 s->opts.o_size[2] = s->opts.o_size[0] >> pix_desc->log2_chroma_w;
181 s->opts.o_size[3] = s->opts.o_size[1] >> pix_desc->log2_chroma_h;
182 s->opts.o_size[4] = s->opts.o_size[0] >> pix_desc->log2_chroma_w;
183 s->opts.o_size[5] = s->opts.o_size[1] >> pix_desc->log2_chroma_h;
222 184
223 s->initialized = 1;185 s->initialized = 1;
224 186
225 return 0;
226
227fail:187fail:
228 return err;188 if (spv_opaque)
229}189 spv->free_shader(spv, &spv_opaque);
230 190 if (spv)
231static int process_frames(AVFilterContext *avctx, AVFrame *out_f,191 spv->uninit(&spv);
232 AVFrame *main_f, AVFrame *overlay_f)
233{
234 int err;
235 VkCommandBuffer cmd_buf;
236 OverlayVulkanContext *s = avctx->priv;
237 FFVulkanContext *vkctx = &s->vkctx;
238 FFVulkanFunctions *vk = &vkctx->vkfn;
239 int planes = av_pix_fmt_count_planes(s->vkctx.output_format);
240
241 AVVkFrame *out = (AVVkFrame *)out_f->data[0];
242 AVVkFrame *main = (AVVkFrame *)main_f->data[0];
243 AVVkFrame *overlay = (AVVkFrame *)overlay_f->data[0];
244
245 AVHWFramesContext *main_fc = (AVHWFramesContext*)main_f->hw_frames_ctx->data;
246 AVHWFramesContext *overlay_fc = (AVHWFramesContext*)overlay_f->hw_frames_ctx->data;
247
248 const VkFormat *output_formats = av_vkfmt_from_pixfmt(s->vkctx.output_format);
249 const VkFormat *main_sw_formats = av_vkfmt_from_pixfmt(main_fc->sw_format);
250 const VkFormat *overlay_sw_formats = av_vkfmt_from_pixfmt(overlay_fc->sw_format);
251
252 /* Update descriptors and init the exec context */
253 ff_vk_start_exec_recording(vkctx, s->exec);
254 cmd_buf = ff_vk_get_exec_buf(s->exec);
255
256 for (int i = 0; i < planes; i++) {
257 RET(ff_vk_create_imageview(vkctx, s->exec,
258 &s->main_images[i].imageView, main->img[i],
259 main_sw_formats[i],
260 ff_comp_identity_map));
261
262 RET(ff_vk_create_imageview(vkctx, s->exec,
263 &s->overlay_images[i].imageView, overlay->img[i],
264 overlay_sw_formats[i],
265 ff_comp_identity_map));
266
267 RET(ff_vk_create_imageview(vkctx, s->exec,
268 &s->output_images[i].imageView, out->img[i],
269 output_formats[i],
270 ff_comp_identity_map));
271
272 s->main_images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
273 s->overlay_images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
274 s->output_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
275 }
276
277 ff_vk_update_descriptor_set(vkctx, s->pl, 0);
278
279 for (int i = 0; i < planes; i++) {
280 VkImageMemoryBarrier bar[3] = {
281 {
282 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
283 .srcAccessMask = 0,
284 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
285 .oldLayout = main->layout[i],
286 .newLayout = s->main_images[i].imageLayout,
287 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
288 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
289 .image = main->img[i],
290 .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
291 .subresourceRange.levelCount = 1,
292 .subresourceRange.layerCount = 1,
293 },
294 {
295 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
296 .srcAccessMask = 0,
297 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
298 .oldLayout = overlay->layout[i],
299 .newLayout = s->overlay_images[i].imageLayout,
300 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
301 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
302 .image = overlay->img[i],
303 .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
304 .subresourceRange.levelCount = 1,
305 .subresourceRange.layerCount = 1,
306 },
307 {
308 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
309 .srcAccessMask = 0,
310 .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
311 .oldLayout = out->layout[i],
312 .newLayout = s->output_images[i].imageLayout,
313 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
314 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
315 .image = out->img[i],
316 .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
317 .subresourceRange.levelCount = 1,
318 .subresourceRange.layerCount = 1,
319 },
320 };
321
322 vk->CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
323 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
324 0, NULL, 0, NULL, FF_ARRAY_ELEMS(bar), bar);
325
326 main->layout[i] = bar[0].newLayout;
327 main->access[i] = bar[0].dstAccessMask;
328
329 overlay->layout[i] = bar[1].newLayout;
330 overlay->access[i] = bar[1].dstAccessMask;
331
332 out->layout[i] = bar[2].newLayout;
333 out->access[i] = bar[2].dstAccessMask;
334 }
335
336 ff_vk_bind_pipeline_exec(vkctx, s->exec, s->pl);
337
338 vk->CmdDispatch(cmd_buf,
339 FFALIGN(s->vkctx.output_width, CGROUPS[0])/CGROUPS[0],
340 FFALIGN(s->vkctx.output_height, CGROUPS[1])/CGROUPS[1], 1);
341
342 ff_vk_add_exec_dep(vkctx, s->exec, main_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
343 ff_vk_add_exec_dep(vkctx, s->exec, overlay_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
344 ff_vk_add_exec_dep(vkctx, s->exec, out_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
345
346 err = ff_vk_submit_exec_queue(vkctx, s->exec);
347 if (err)
348 return err;
349 192
350 ff_vk_qf_rotate(&s->qf);
351
352 return err;
353
354fail:
355 ff_vk_discard_exec_deps(s->exec);
356 return err;193 return err;
357}194}
358 195
@@ -394,7 +231,9 @@ static int overlay_vulkan_blend(FFFrameSync *fs) · 35 unmodified lines
394 goto fail;231 goto fail;
395 }232 }
396 233
397 RET(process_frames(ctx, out, input_main, input_overlay));234 RET(ff_vk_filter_process_Nin(&s->vkctx, &s->e, &s->pl,
235 out, (AVFrame *[]){ input_main, input_overlay }, 2,
236 s->sampler, &s->opts, sizeof(s->opts)));
398 237
399 err = av_frame_copy_props(out, input_main);238 err = av_frame_copy_props(out, input_main);
400 if (err < 0)239 if (err < 0)
@@ -443,8 +282,17 @@ static av_cold int overlay_vulkan_init(AVFilterContext *avctx) · 42 unmodified lines
443static void overlay_vulkan_uninit(AVFilterContext *avctx)282static void overlay_vulkan_uninit(AVFilterContext *avctx)
444{283{
445 OverlayVulkanContext *s = avctx->priv;284 OverlayVulkanContext *s = avctx->priv;
285 FFVulkanContext *vkctx = &s->vkctx;
286 FFVulkanFunctions *vk = &vkctx->vkfn;
287
288 ff_vk_exec_pool_free(vkctx, &s->e);
289 ff_vk_pipeline_free(vkctx, &s->pl);
290 ff_vk_shader_free(vkctx, &s->shd);
291
292 if (s->sampler)
293 vk->DestroySampler(vkctx->hwctx->act_dev, s->sampler,
294 vkctx->hwctx->alloc);
446 295
447 ff_vk_free_buf(&s->vkctx, &s->params_buf);
448 ff_vk_uninit(&s->vkctx);296 ff_vk_uninit(&s->vkctx);
449 ff_framesync_uninit(&s->fs);297 ff_framesync_uninit(&s->fs);
450 298

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