1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
24
25 #define CGROUPS (int [3]){ 32, 32, 1 }
26
29
36
37 /* Shader updators, must be in the main filter struct */
42
48
52 C(1,
if ((o_offset[
i].x <=
pos.x) && (o_offset[
i].y <=
pos.y) &&
53 (
pos.x < (o_offset[
i].x + o_size[
i].x)) &&
54 (
pos.y < (o_offset[
i].y + o_size[
i].y))) { )
55 C(2, vec4 res = texture(overlay_img[i], pos - o_offset[i]); )
56 C(2, imageStore(output_img[i], pos, res); )
57 C(1, } else { )
58 C(2, vec4 res = texture(main_img[i], pos); )
59 C(2, imageStore(output_img[i], pos, res); )
60 C(1, } )
62 };
63
65 C(0,
void overlay_alpha_opaque(
int i, ivec2
pos) )
67 C(1, vec4 res = texture(main_img[
i],
pos); )
68 C(1,
if ((o_offset[
i].x <=
pos.x) && (o_offset[
i].y <=
pos.y) &&
69 (
pos.x < (o_offset[
i].x + o_size[
i].x)) &&
70 (
pos.y < (o_offset[
i].y + o_size[
i].y))) { )
71 C(2, vec4 ovr = texture(overlay_img[i], pos - o_offset[i]); )
72 C(2, res = ovr * ovr.a + res * (1.0f - ovr.a); )
73 C(2, res.a = 1.0f; )
74 C(2, imageStore(output_img[i], pos, res); )
75 C(1, } )
76 C(1, imageStore(output_img[
i],
pos, res); )
78 };
79
81 {
82 int err;
87
89
91 if (!sampler)
93
97
98 { /* Create the shader */
100
102 {
104 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
105 .dimensions = 2,
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,
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,
124 .mem_quali = "writeonly",
125 .dimensions = 2,
127 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
128 .updater =
s->output_images,
129 },
130 };
131
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
143 VK_SHADER_STAGE_COMPUTE_BIT);
144 if (!shd)
146
148
151
156 GLSLC(1, ivec2
pos = ivec2(gl_GlobalInvocationID.xy); );
159 if (ialpha)
160 GLSLC(2, overlay_alpha_opaque(
i,
pos); );
161 else
165
167 }
168
171
172 { /* Create and update buffer */
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 {
181 } *par;
182
184 sizeof(*par),
185 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
186 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
187 if (err)
188 return err;
189
191 if (err)
192 return err;
193
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
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
218 }
219
220 /* Execution context */
222
224
225 return 0;
226
228 return err;
229 }
230
233 {
234 int err;
235 VkCommandBuffer cmd_buf;
240
244
247
251
252 /* Update descriptors and init the exec context */
255
258 &
s->main_images[
i].imageView,
main->img[
i],
261
263 &
s->overlay_images[
i].imageView, overlay->
img[
i],
264 overlay_sw_formats[
i],
266
268 &
s->output_images[
i].imageView,
out->img[
i],
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
278
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,
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
337
338 vk->CmdDispatch(cmd_buf,
341
345
347 if (err)
348 return err;
349
351
352 return err;
353
356 return err;
357 }
358
360 {
361 int err;
366
368 if (err < 0)
371 if (err < 0)
373
374 if (!input_main || !input_overlay)
375 return 0;
376
377 if (!
s->initialized) {
380 if (main_fc->
sw_format != overlay_fc->sw_format) {
383 }
384
385 s->overlay_w = input_overlay->
width;
386 s->overlay_h = input_overlay->
height;
387
389 }
390
395 }
396
398
400 if (err < 0)
402
404
407 return err;
408 }
409
411 {
412 int err;
415
417 if (err < 0)
418 return err;
419
421 if (err < 0)
422 return err;
423
425 }
426
428 {
430
432 }
433
435 {
437
439
441 }
442
444 {
446
450
452 }
453
454 #define OFFSET(x) offsetof(OverlayVulkanContext, x)
455 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
460 };
461
463
465 {
469 },
470 {
471 .name = "overlay",
474 },
475 };
476
478 {
482 },
483 };
484
486 .
name =
"overlay_vulkan",
495 .priv_class = &overlay_vulkan_class,
497 };