History

scale_vulkan: port for the rewrite

Lynne committed 3 years ago

Commit d4b51b51 parent 8e9ceb11 file · +125 −241Browse files

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

Unified · Split

libavfilter/vf_scale_vulkan.c+125−241
@@ -1,4 +1,6 @@
11 /*
2+ * Copyright (c) Lynne
3+ *
24 * This file is part of FFmpeg.
35 *
46 * FFmpeg is free software; you can redistribute it and/or
@@ -19,12 +21,11 @@ · 14 unmodified lines
1921 #include "libavutil/random_seed.h"
2022 #include "libavutil/opt.h"
2123 #include "vulkan_filter.h"
24+#include "vulkan_spirv.h"
2225 #include "scale_eval.h"
2326 #include "internal.h"
2427 #include "colorspace.h"
2528
26−#define CGROUPS (int [3]){ 32, 32, 1 }
27−
2829 enum ScalerFunc {
2930 F_BILINEAR = 0,
3031 F_NEAREST,
@@ -35,15 +36,17 @@ enum ScalerFunc { · 4 unmodified lines
3536 typedef struct ScaleVulkanContext {
3637 FFVulkanContext vkctx;
3738
39+ int initialized;
40+ FFVulkanPipeline pl;
41+ FFVkExecPool e;
3842 FFVkQueueFamilyCtx qf;
39− FFVkExecContext *exec;
40− FFVulkanPipeline *pl;
41− FFVkBuffer params_buf;
43+ FFVkSPIRVShader shd;
44+ VkSampler sampler;
4245
43− /* Shader updators, must be in the main filter struct */
44− VkDescriptorImageInfo input_images[3];
45− VkDescriptorImageInfo output_images[3];
46− VkDescriptorBufferInfo params_desc;
46+ /* Push constants / options */
47+ struct {
48+ float yuv_matrix[4][4];
49+ } opts;
4750
4851 char *out_format_string;
4952 char *w_expr;
@@ -51,8 +54,6 @@ typedef struct ScaleVulkanContext { · 1 unmodified line
5154
5255 enum ScalerFunc scaler;
5356 enum AVColorRange out_range;
54−
55− int initialized;
5657 } ScaleVulkanContext;
5758
5859 static const char scale_bilinear[] = {
@@ -110,10 +111,15 @@ static const char write_444[] = { · 51 unmodified lines
110111 static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
111112 {
112113 int err;
113− FFVkSampler *sampler;
114+ uint8_t *spv_data;
115+ size_t spv_len;
116+ void *spv_opaque = NULL;
114117 VkFilter sampler_mode;
115118 ScaleVulkanContext *s = ctx->priv;
116119 FFVulkanContext *vkctx = &s->vkctx;
120+ FFVkSPIRVShader *shd = &s->shd;
121+ FFVkSPIRVCompiler *spv;
122+ FFVulkanDescriptorSetBinding *desc;
117123
118124 int crop_x = in->crop_left;
119125 int crop_y = in->crop_top;
@@ -121,8 +127,6 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) · 1 unmodified line
121127 int crop_h = in->height - (in->crop_top + in->crop_bottom);
122128 int in_planes = av_pix_fmt_count_planes(s->vkctx.input_format);
123129
124− ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT, 0);
125−
126130 switch (s->scaler) {
127131 case F_NEAREST:
128132 sampler_mode = VK_FILTER_NEAREST;
@@ -132,264 +136,134 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) · 3 unmodified lines
132136 break;
133137 };
134138
135− /* Create a sampler */
136− sampler = ff_vk_init_sampler(vkctx, 0, sampler_mode);
137− if (!sampler)
139+ spv = ff_vk_spirv_init();
140+ if (!spv) {
141+ av_log(ctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
138142 return AVERROR_EXTERNAL;
143+ }
139144
140− s->pl = ff_vk_create_pipeline(vkctx, &s->qf);
141− if (!s->pl)
142− return AVERROR(ENOMEM);
143−
144− { /* Create the shader */
145− FFVulkanDescriptorSetBinding desc_i[2] = {
146− {
147− .name = "input_img",
148− .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
149− .dimensions = 2,
150− .elems = in_planes,
151− .stages = VK_SHADER_STAGE_COMPUTE_BIT,
152− .updater = s->input_images,
153− .sampler = sampler,
154− },
155− {
156− .name = "output_img",
157− .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
158− .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),
159− .mem_quali = "writeonly",
160− .dimensions = 2,
161− .elems = av_pix_fmt_count_planes(s->vkctx.output_format),
162− .stages = VK_SHADER_STAGE_COMPUTE_BIT,
163− .updater = s->output_images,
164− },
165− };
166−
167− FFVulkanDescriptorSetBinding desc_b = {
168− .name = "params",
169− .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
170− .mem_quali = "readonly",
171− .mem_layout = "std430",
172− .stages = VK_SHADER_STAGE_COMPUTE_BIT,
173− .updater = &s->params_desc,
174− .buf_content = "mat4 yuv_matrix;",
175− };
176−
177− FFVkSPIRVShader *shd = ff_vk_init_shader(s->pl, "scale_compute",
178− VK_SHADER_STAGE_COMPUTE_BIT);
179− if (!shd)
180− return AVERROR(ENOMEM);
181−
182− ff_vk_set_compute_shader_sizes(shd, CGROUPS);
183−
184− RET(ff_vk_add_descriptor_set(vkctx, s->pl, shd, desc_i, FF_ARRAY_ELEMS(desc_i), 0)); /* set 0 */
185− RET(ff_vk_add_descriptor_set(vkctx, s->pl, shd, &desc_b, 1, 0)); /* set 1 */
186−
187− GLSLD( scale_bilinear );
188−
189− if (s->vkctx.output_format != s->vkctx.input_format) {
190− GLSLD( rgb2yuv );
191− }
145+ ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT);
146+ RET(ff_vk_exec_pool_init(vkctx, &s->qf, &s->e, s->qf.nb_queues*4, 0, 0, 0, NULL));
147+ RET(ff_vk_init_sampler(vkctx, &s->sampler, 0, sampler_mode));
148+ RET(ff_vk_shader_init(&s->pl, &s->shd, "scale_compute",
149+ VK_SHADER_STAGE_COMPUTE_BIT, 0));
150+
151+ ff_vk_shader_set_compute_sizes(&s->shd, 32, 32, 1);
152+
153+ GLSLC(0, layout(push_constant, std430) uniform pushConstants { );
154+ GLSLC(1, mat4 yuv_matrix; );
155+ GLSLC(0, }; );
156+ GLSLC(0, );
157+
158+ ff_vk_add_push_constant(&s->pl, 0, sizeof(s->opts),
159+ VK_SHADER_STAGE_COMPUTE_BIT);
160+
161+ desc = (FFVulkanDescriptorSetBinding []) {
162+ {
163+ .name = "input_img",
164+ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
165+ .dimensions = 2,
166+ .elems = in_planes,
167+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
168+ .samplers = DUP_SAMPLER(s->sampler),
169+ },
170+ {
171+ .name = "output_img",
172+ .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
173+ .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),
174+ .mem_quali = "writeonly",
175+ .dimensions = 2,
176+ .elems = av_pix_fmt_count_planes(s->vkctx.output_format),
177+ .stages = VK_SHADER_STAGE_COMPUTE_BIT,
178+ },
179+ };
192180
193− switch (s->vkctx.output_format) {
194− case AV_PIX_FMT_NV12: GLSLD(write_nv12); break;
195− case AV_PIX_FMT_YUV420P: GLSLD( write_420); break;
196− case AV_PIX_FMT_YUV444P: GLSLD( write_444); break;
197− default: break;
198− }
181+ RET(ff_vk_pipeline_descriptor_set_add(vkctx, &s->pl, shd, desc, 2, 0, 0));
199182
200− GLSLC(0, void main() );
201− GLSLC(0, { );
202− GLSLC(1, ivec2 size; );
203− GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
204− GLSLF(1, vec2 in_d = vec2(%i, %i); ,in->width, in->height);
205− GLSLF(1, vec2 c_r = vec2(%i, %i) / in_d; ,crop_w, crop_h);
206− GLSLF(1, vec2 c_o = vec2(%i, %i) / in_d; ,crop_x,crop_y);
207− GLSLC(0, );
208−
209− if (s->vkctx.output_format == s->vkctx.input_format) {
210− for (int i = 0; i < desc_i[1].elems; i++) {
211− GLSLF(1, size = imageSize(output_img[%i]); ,i);
212− GLSLC(1, if (IS_WITHIN(pos, size)) { );
213− switch (s->scaler) {
214− case F_NEAREST:
215− case F_BILINEAR:
216− GLSLF(2, vec4 res = scale_bilinear(%i, pos, c_r, c_o); ,i);
217− GLSLF(2, imageStore(output_img[%i], pos, res); ,i);
218− break;
219− };
220− GLSLC(1, } );
221− }
222− } else {
223− GLSLC(1, vec4 res = scale_bilinear(0, pos, c_r, c_o); );
224− GLSLF(1, res = rgb2yuv(res, %i); ,s->out_range == AVCOL_RANGE_JPEG);
225− switch (s->vkctx.output_format) {
226− case AV_PIX_FMT_NV12: GLSLC(1, write_nv12(res, pos); ); break;
227− case AV_PIX_FMT_YUV420P: GLSLC(1, write_420(res, pos); ); break;
228− case AV_PIX_FMT_YUV444P: GLSLC(1, write_444(res, pos); ); break;
229− default: return AVERROR(EINVAL);
230− }
231− }
183+ GLSLD( scale_bilinear );
184+
185+ if (s->vkctx.output_format != s->vkctx.input_format) {
186+ GLSLD( rgb2yuv );
187+ }
232188
233− GLSLC(0, } );
189+ switch (s->vkctx.output_format) {
190+ case AV_PIX_FMT_NV12: GLSLD(write_nv12); break;
191+ case AV_PIX_FMT_YUV420P: GLSLD( write_420); break;
192+ case AV_PIX_FMT_YUV444P: GLSLD( write_444); break;
193+ default: break;
194+ }
234195
235− RET(ff_vk_compile_shader(vkctx, shd, "main"));
196+ GLSLC(0, void main() );
197+ GLSLC(0, { );
198+ GLSLC(1, ivec2 size; );
199+ GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );
200+ GLSLF(1, vec2 in_d = vec2(%i, %i); ,in->width, in->height);
201+ GLSLF(1, vec2 c_r = vec2(%i, %i) / in_d; ,crop_w, crop_h);
202+ GLSLF(1, vec2 c_o = vec2(%i, %i) / in_d; ,crop_x,crop_y);
203+ GLSLC(0, );
204+
205+ if (s->vkctx.output_format == s->vkctx.input_format) {
206+ for (int i = 0; i < desc[i].elems; i++) {
207+ GLSLF(1, size = imageSize(output_img[%i]); ,i);
208+ GLSLC(1, if (IS_WITHIN(pos, size)) { );
209+ switch (s->scaler) {
210+ case F_NEAREST:
211+ case F_BILINEAR:
212+ GLSLF(2, vec4 res = scale_bilinear(%i, pos, c_r, c_o); ,i);
213+ GLSLF(2, imageStore(output_img[%i], pos, res); ,i);
214+ break;
215+ };
216+ GLSLC(1, } );
217+ }
218+ } else {
219+ GLSLC(1, vec4 res = scale_bilinear(0, pos, c_r, c_o); );
220+ GLSLF(1, res = rgb2yuv(res, %i); ,s->out_range == AVCOL_RANGE_JPEG);
221+ switch (s->vkctx.output_format) {
222+ case AV_PIX_FMT_NV12: GLSLC(1, write_nv12(res, pos); ); break;
223+ case AV_PIX_FMT_YUV420P: GLSLC(1, write_420(res, pos); ); break;
224+ case AV_PIX_FMT_YUV444P: GLSLC(1, write_444(res, pos); ); break;
225+ default: return AVERROR(EINVAL);
226+ }
236227 }
237228
238− RET(ff_vk_init_pipeline_layout(vkctx, s->pl));
239− RET(ff_vk_init_compute_pipeline(vkctx, s->pl));
229+ GLSLC(0, } );
240230
241231 if (s->vkctx.output_format != s->vkctx.input_format) {
242232 const AVLumaCoefficients *lcoeffs;
243233 double tmp_mat[3][3];
244234
245− struct {
246− float yuv_matrix[4][4];
247− } *par;
248−
249235 lcoeffs = av_csp_luma_coeffs_from_avcsp(in->colorspace);
250236 if (!lcoeffs) {
251237 av_log(ctx, AV_LOG_ERROR, "Unsupported colorspace\n");
252238 return AVERROR(EINVAL);
253239 }
254240
255− RET(ff_vk_create_buf(vkctx, &s->params_buf,
256− sizeof(*par), NULL, NULL,
257− VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
258− VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
259−
260− RET(ff_vk_map_buffers(vkctx, &s->params_buf, (uint8_t **)&par, 1, 0));
261−
262241 ff_fill_rgb2yuv_table(lcoeffs, tmp_mat);
263242
264− memset(par, 0, sizeof(*par));
265−
266243 for (int y = 0; y < 3; y++)
267244 for (int x = 0; x < 3; x++)
268− par->yuv_matrix[x][y] = tmp_mat[x][y];
269−
270− par->yuv_matrix[3][3] = 1.0;
271−
272− RET(ff_vk_unmap_buffers(vkctx, &s->params_buf, 1, 1));
273−
274− s->params_desc.buffer = s->params_buf.buf;
275− s->params_desc.range = VK_WHOLE_SIZE;
276−
277− ff_vk_update_descriptor_set(vkctx, s->pl, 1);
245+ s->opts.yuv_matrix[x][y] = tmp_mat[x][y];
246+ s->opts.yuv_matrix[3][3] = 1.0;
278247 }
279248
280− /* Execution context */
281− RET(ff_vk_create_exec_ctx(vkctx, &s->exec, &s->qf));
249+ RET(spv->compile_shader(spv, ctx, shd, &spv_data, &spv_len, "main",
250+ &spv_opaque));
251+ RET(ff_vk_shader_create(vkctx, shd, spv_data, spv_len, "main"));
252+
253+ RET(ff_vk_init_compute_pipeline(vkctx, &s->pl, shd));
254+ RET(ff_vk_exec_pipeline_register(vkctx, &s->e, &s->pl));
282255
283256 s->initialized = 1;
284257
285258 return 0;
286259
287260 fail:
288− return err;
289−}
290−
291−static int process_frames(AVFilterContext *avctx, AVFrame *out_f, AVFrame *in_f)
292−{
293− int err = 0;
294− VkCommandBuffer cmd_buf;
295− ScaleVulkanContext *s = avctx->priv;
296− FFVulkanContext *vkctx = &s->vkctx;
297− FFVulkanFunctions *vk = &vkctx->vkfn;
298− AVVkFrame *in = (AVVkFrame *)in_f->data[0];
299− AVVkFrame *out = (AVVkFrame *)out_f->data[0];
300− VkImageMemoryBarrier barriers[AV_NUM_DATA_POINTERS*2];
301− int barrier_count = 0;
302− const int planes = av_pix_fmt_count_planes(s->vkctx.input_format);
303− const VkFormat *input_formats = av_vkfmt_from_pixfmt(s->vkctx.input_format);
304− const VkFormat *output_formats = av_vkfmt_from_pixfmt(s->vkctx.output_format);
305−
306− /* Update descriptors and init the exec context */
307− ff_vk_start_exec_recording(vkctx, s->exec);
308− cmd_buf = ff_vk_get_exec_buf(s->exec);
309−
310− for (int i = 0; i < planes; i++) {
311− RET(ff_vk_create_imageview(vkctx, s->exec,
312− &s->input_images[i].imageView, in->img[i],
313− input_formats[i],
314− ff_comp_identity_map));
315−
316− RET(ff_vk_create_imageview(vkctx, s->exec,
317− &s->output_images[i].imageView, out->img[i],
318− output_formats[i],
319− ff_comp_identity_map));
320−
321− s->input_images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
322− s->output_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
323− }
324−
325− ff_vk_update_descriptor_set(vkctx, s->pl, 0);
326−
327− for (int i = 0; i < planes; i++) {
328− VkImageMemoryBarrier bar = {
329− .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
330− .srcAccessMask = 0,
331− .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
332− .oldLayout = in->layout[i],
333− .newLayout = s->input_images[i].imageLayout,
334− .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
335− .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
336− .image = in->img[i],
337− .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
338− .subresourceRange.levelCount = 1,
339− .subresourceRange.layerCount = 1,
340− };
341−
342− memcpy(&barriers[barrier_count++], &bar, sizeof(VkImageMemoryBarrier));
343−
344− in->layout[i] = bar.newLayout;
345− in->access[i] = bar.dstAccessMask;
346− }
347−
348− for (int i = 0; i < av_pix_fmt_count_planes(s->vkctx.output_format); i++) {
349− VkImageMemoryBarrier bar = {
350− .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
351− .srcAccessMask = 0,
352− .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
353− .oldLayout = out->layout[i],
354− .newLayout = s->output_images[i].imageLayout,
355− .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
356− .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
357− .image = out->img[i],
358− .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
359− .subresourceRange.levelCount = 1,
360− .subresourceRange.layerCount = 1,
361− };
362−
363− memcpy(&barriers[barrier_count++], &bar, sizeof(VkImageMemoryBarrier));
364−
365− out->layout[i] = bar.newLayout;
366− out->access[i] = bar.dstAccessMask;
367− }
368−
369− vk->CmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
370− VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
371− 0, NULL, 0, NULL, barrier_count, barriers);
372−
373− ff_vk_bind_pipeline_exec(vkctx, s->exec, s->pl);
374−
375− vk->CmdDispatch(cmd_buf,
376− FFALIGN(vkctx->output_width, CGROUPS[0])/CGROUPS[0],
377− FFALIGN(vkctx->output_height, CGROUPS[1])/CGROUPS[1], 1);
378−
379− ff_vk_add_exec_dep(vkctx, s->exec, in_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
380− ff_vk_add_exec_dep(vkctx, s->exec, out_f, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
381−
382− err = ff_vk_submit_exec_queue(vkctx, s->exec);
383− if (err)
384− return err;
385−
386− ff_vk_qf_rotate(&s->qf);
261+ if (spv_opaque)
262+ spv->free_shader(spv, &spv_opaque);
263+ if (spv)
264+ spv->uninit(&spv);
387265
388266 return err;
389−
390−fail:
391− ff_vk_discard_exec_deps(s->exec);
392− return err;
393267 }
394268
395269 static int scale_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)
@@ -408,7 +282,8 @@ static int scale_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) · 12 unmodified lines
408282 if (!s->initialized)
409283 RET(init_filter(ctx, in));
410284
411− RET(process_frames(ctx, out, in));
285+ RET(ff_vk_filter_process_simple(&s->vkctx, &s->e, &s->pl, out, in,
286+ s->sampler, &s->opts, sizeof(s->opts)));
412287
413288 err = av_frame_copy_props(out, in);
414289 if (err < 0)
@@ -475,8 +350,17 @@ static int scale_vulkan_config_output(AVFilterLink *outlink) · 60 unmodified lines
475350 static void scale_vulkan_uninit(AVFilterContext *avctx)
476351 {
477352 ScaleVulkanContext *s = avctx->priv;
353+ FFVulkanContext *vkctx = &s->vkctx;
354+ FFVulkanFunctions *vk = &vkctx->vkfn;
355+
356+ ff_vk_exec_pool_free(vkctx, &s->e);
357+ ff_vk_pipeline_free(vkctx, &s->pl);
358+ ff_vk_shader_free(vkctx, &s->shd);
359+
360+ if (s->sampler)
361+ vk->DestroySampler(vkctx->hwctx->act_dev, s->sampler,
362+ vkctx->hwctx->alloc);
478363
479− ff_vk_free_buf(&s->vkctx, &s->params_buf);
480364 ff_vk_uninit(&s->vkctx);
481365
482366 s->initialized = 0;

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