History

scale_vulkan: port for the rewrite

Lynne committed 3 years ago

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

Unified · Split

libavfilter/vf_scale_vulkan.c+125−241
@@ -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,12 +21,11 @@ · 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 "scale_eval.h"25#include "scale_eval.h"
23#include "internal.h"26#include "internal.h"
24#include "colorspace.h"27#include "colorspace.h"
25 28
26#define CGROUPS (int [3]){ 32, 32, 1 }
27
28enum ScalerFunc {29enum ScalerFunc {
29 F_BILINEAR = 0,30 F_BILINEAR = 0,
30 F_NEAREST,31 F_NEAREST,
@@ -35,15 +36,17 @@ enum ScalerFunc { · 4 unmodified lines
35typedef struct ScaleVulkanContext {36typedef struct ScaleVulkanContext {
36 FFVulkanContext vkctx;37 FFVulkanContext vkctx;
37 38
39 int initialized;
40 FFVulkanPipeline pl;
41 FFVkExecPool e;
38 FFVkQueueFamilyCtx qf;42 FFVkQueueFamilyCtx qf;
39 FFVkExecContext *exec;43 FFVkSPIRVShader shd;
40 FFVulkanPipeline *pl;44 VkSampler sampler;
41 FFVkBuffer params_buf;
42 45
43 /* Shader updators, must be in the main filter struct */46 /* Push constants / options */
44 VkDescriptorImageInfo input_images[3];47 struct {
45 VkDescriptorImageInfo output_images[3];48 float yuv_matrix[4][4];
46 VkDescriptorBufferInfo params_desc;49 } opts;
47 50
48 char *out_format_string;51 char *out_format_string;
49 char *w_expr;52 char *w_expr;
@@ -51,8 +54,6 @@ typedef struct ScaleVulkanContext { · 1 unmodified line
51 54
52 enum ScalerFunc scaler;55 enum ScalerFunc scaler;
53 enum AVColorRange out_range;56 enum AVColorRange out_range;
54
55 int initialized;
56} ScaleVulkanContext;57} ScaleVulkanContext;
57 58
58static const char scale_bilinear[] = {59static const char scale_bilinear[] = {
@@ -110,10 +111,15 @@ static const char write_444[] = { · 51 unmodified lines
110static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)111static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
111{112{
112 int err;113 int err;
113 FFVkSampler *sampler;114 uint8_t *spv_data;
115 size_t spv_len;
116 void *spv_opaque = NULL;
114 VkFilter sampler_mode;117 VkFilter sampler_mode;
115 ScaleVulkanContext *s = ctx->priv;118 ScaleVulkanContext *s = ctx->priv;
116 FFVulkanContext *vkctx = &s->vkctx;119 FFVulkanContext *vkctx = &s->vkctx;
120 FFVkSPIRVShader *shd = &s->shd;
121 FFVkSPIRVCompiler *spv;
122 FFVulkanDescriptorSetBinding *desc;
117 123
118 int crop_x = in->crop_left;124 int crop_x = in->crop_left;
119 int crop_y = in->crop_top;125 int crop_y = in->crop_top;
@@ -121,8 +127,6 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) · 1 unmodified line
121 int crop_h = in->height - (in->crop_top + in->crop_bottom);127 int crop_h = in->height - (in->crop_top + in->crop_bottom);
122 int in_planes = av_pix_fmt_count_planes(s->vkctx.input_format);128 int in_planes = av_pix_fmt_count_planes(s->vkctx.input_format);
123 129
124 ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT, 0);
125
126 switch (s->scaler) {130 switch (s->scaler) {
127 case F_NEAREST:131 case F_NEAREST:
128 sampler_mode = VK_FILTER_NEAREST;132 sampler_mode = VK_FILTER_NEAREST;
@@ -132,264 +136,134 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) · 3 unmodified lines
132 break;136 break;
133 };137 };
134 138
135 /* Create a sampler */139 spv = ff_vk_spirv_init();
136 sampler = ff_vk_init_sampler(vkctx, 0, sampler_mode);140 if (!spv) {
137 if (!sampler)141 av_log(ctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
138 return AVERROR_EXTERNAL;142 return AVERROR_EXTERNAL;
143 }
139 144
140 s->pl = ff_vk_create_pipeline(vkctx, &s->qf);145 ff_vk_qf_init(vkctx, &s->qf, VK_QUEUE_COMPUTE_BIT);
141 if (!s->pl)146 RET(ff_vk_exec_pool_init(vkctx, &s->qf, &s->e, s->qf.nb_queues*4, 0, 0, 0, NULL));
142 return AVERROR(ENOMEM);147 RET(ff_vk_init_sampler(vkctx, &s->sampler, 0, sampler_mode));
143 148 RET(ff_vk_shader_init(&s->pl, &s->shd, "scale_compute",
144 { /* Create the shader */149 VK_SHADER_STAGE_COMPUTE_BIT, 0));
145 FFVulkanDescriptorSetBinding desc_i[2] = {150
146 {151 ff_vk_shader_set_compute_sizes(&s->shd, 32, 32, 1);
147 .name = "input_img",152
148 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,153 GLSLC(0, layout(push_constant, std430) uniform pushConstants { );
149 .dimensions = 2,154 GLSLC(1, mat4 yuv_matrix; );
150 .elems = in_planes,155 GLSLC(0, }; );
151 .stages = VK_SHADER_STAGE_COMPUTE_BIT,156 GLSLC(0, );
152 .updater = s->input_images,157
153 .sampler = sampler,158 ff_vk_add_push_constant(&s->pl, 0, sizeof(s->opts),
154 },159 VK_SHADER_STAGE_COMPUTE_BIT);
155 {160
156 .name = "output_img",161 desc = (FFVulkanDescriptorSetBinding []) {
157 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,162 {
158 .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),163 .name = "input_img",
159 .mem_quali = "writeonly",164 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
160 .dimensions = 2,165 .dimensions = 2,
161 .elems = av_pix_fmt_count_planes(s->vkctx.output_format),166 .elems = in_planes,
162 .stages = VK_SHADER_STAGE_COMPUTE_BIT,167 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
163 .updater = s->output_images,168 .samplers = DUP_SAMPLER(s->sampler),
164 },169 },
165 };170 {
166 171 .name = "output_img",
167 FFVulkanDescriptorSetBinding desc_b = {172 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
168 .name = "params",173 .mem_layout = ff_vk_shader_rep_fmt(s->vkctx.output_format),
169 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,174 .mem_quali = "writeonly",
170 .mem_quali = "readonly",175 .dimensions = 2,
171 .mem_layout = "std430",176 .elems = av_pix_fmt_count_planes(s->vkctx.output_format),
172 .stages = VK_SHADER_STAGE_COMPUTE_BIT,177 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
173 .updater = &s->params_desc,178 },
174 .buf_content = "mat4 yuv_matrix;",179 };
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 }
192 180
193 switch (s->vkctx.output_format) {181 RET(ff_vk_pipeline_descriptor_set_add(vkctx, &s->pl, shd, desc, 2, 0, 0));
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 }
199 182
200 GLSLC(0, void main() );183 GLSLD( scale_bilinear );
201 GLSLC(0, { );184
202 GLSLC(1, ivec2 size; );185 if (s->vkctx.output_format != s->vkctx.input_format) {
203 GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); );186 GLSLD( rgb2yuv );
204 GLSLF(1, vec2 in_d = vec2(%i, %i); ,in->width, in->height);187 }
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 }
232 188
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 }
234 195
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 }
236 }227 }
237 228
238 RET(ff_vk_init_pipeline_layout(vkctx, s->pl));229 GLSLC(0, } );
239 RET(ff_vk_init_compute_pipeline(vkctx, s->pl));
240 230
241 if (s->vkctx.output_format != s->vkctx.input_format) {231 if (s->vkctx.output_format != s->vkctx.input_format) {
242 const AVLumaCoefficients *lcoeffs;232 const AVLumaCoefficients *lcoeffs;
243 double tmp_mat[3][3];233 double tmp_mat[3][3];
244 234
245 struct {
246 float yuv_matrix[4][4];
247 } *par;
248
249 lcoeffs = av_csp_luma_coeffs_from_avcsp(in->colorspace);235 lcoeffs = av_csp_luma_coeffs_from_avcsp(in->colorspace);
250 if (!lcoeffs) {236 if (!lcoeffs) {
251 av_log(ctx, AV_LOG_ERROR, "Unsupported colorspace\n");237 av_log(ctx, AV_LOG_ERROR, "Unsupported colorspace\n");
252 return AVERROR(EINVAL);238 return AVERROR(EINVAL);
253 }239 }
254 240
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
262 ff_fill_rgb2yuv_table(lcoeffs, tmp_mat);241 ff_fill_rgb2yuv_table(lcoeffs, tmp_mat);
263 242
264 memset(par, 0, sizeof(*par));
265
266 for (int y = 0; y < 3; y++)243 for (int y = 0; y < 3; y++)
267 for (int x = 0; x < 3; x++)244 for (int x = 0; x < 3; x++)
268 par->yuv_matrix[x][y] = tmp_mat[x][y];245 s->opts.yuv_matrix[x][y] = tmp_mat[x][y];
269 246 s->opts.yuv_matrix[3][3] = 1.0;
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);
278 }247 }
279 248
280 /* Execution context */249 RET(spv->compile_shader(spv, ctx, shd, &spv_data, &spv_len, "main",
281 RET(ff_vk_create_exec_ctx(vkctx, &s->exec, &s->qf));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));
282 255
283 s->initialized = 1;256 s->initialized = 1;
284 257
285 return 0;258 return 0;
286 259
287fail:260fail:
288 return err;261 if (spv_opaque)
289}262 spv->free_shader(spv, &spv_opaque);
290 263 if (spv)
291static int process_frames(AVFilterContext *avctx, AVFrame *out_f, AVFrame *in_f)264 spv->uninit(&spv);
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);
387 265
388 return err;266 return err;
389
390fail:
391 ff_vk_discard_exec_deps(s->exec);
392 return err;
393}267}
394 268
395static int scale_vulkan_filter_frame(AVFilterLink *link, AVFrame *in)269static 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
408 if (!s->initialized)282 if (!s->initialized)
409 RET(init_filter(ctx, in));283 RET(init_filter(ctx, in));
410 284
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)));
412 287
413 err = av_frame_copy_props(out, in);288 err = av_frame_copy_props(out, in);
414 if (err < 0)289 if (err < 0)
@@ -475,8 +350,17 @@ static int scale_vulkan_config_output(AVFilterLink *outlink) · 60 unmodified lines
475static void scale_vulkan_uninit(AVFilterContext *avctx)350static void scale_vulkan_uninit(AVFilterContext *avctx)
476{351{
477 ScaleVulkanContext *s = avctx->priv;352 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);
478 363
479 ff_vk_free_buf(&s->vkctx, &s->params_buf);
480 ff_vk_uninit(&s->vkctx);364 ff_vk_uninit(&s->vkctx);
481 365
482 s->initialized = 0;366 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