3 * Copyright (C) 2019 Matthew Waters <matthew@centricular.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:element-vulkancolorconvert
23 * @title: vulkancolorconvert
25 * vulkancolorconvert converts between different video colorspaces.
34 #include "vkcolorconvert.h"
36 #include "shaders/identity.vert.h"
37 #include "shaders/swizzle.frag.h"
38 #include "shaders/swizzle_and_clobber_alpha.frag.h"
39 #include "shaders/yuy2_to_rgb.frag.h"
40 #include "shaders/ayuv_to_rgb.frag.h"
41 #include "shaders/nv12_to_rgb.frag.h"
42 #include "shaders/rgb_to_ayuv.frag.h"
43 #include "shaders/rgb_to_yuy2.frag.h"
44 #include "shaders/rgb_to_nv12.frag.h"
46 GST_DEBUG_CATEGORY (gst_debug_vulkan_color_convert);
47 #define GST_CAT_DEFAULT gst_debug_vulkan_color_convert
49 #define N_SHADER_INFO (8*8 + 8*3*2)
50 static shader_info shader_infos[N_SHADER_INFO];
53 get_rgb_format_swizzle_order (GstVideoFormat format,
54 gint swizzle[GST_VIDEO_MAX_COMPONENTS])
56 const GstVideoFormatInfo *finfo = gst_video_format_get_info (format);
59 g_return_if_fail (finfo->flags & GST_VIDEO_FORMAT_FLAG_RGB
60 || format == GST_VIDEO_FORMAT_AYUV);
62 for (i = 0; i < finfo->n_components; i++) {
63 swizzle[c_i++] = finfo->poffset[i];
66 /* special case spaced RGB formats as the space does not contain a poffset
67 * value and we need all four components to be valid in order to swizzle
69 if (format == GST_VIDEO_FORMAT_xRGB || format == GST_VIDEO_FORMAT_xBGR) {
71 } else if (format == GST_VIDEO_FORMAT_RGBx || format == GST_VIDEO_FORMAT_BGRx) {
74 for (i = finfo->n_components; i < GST_VIDEO_MAX_COMPONENTS; i++) {
81 get_vulkan_rgb_format_swizzle_order (VkFormat format, gint * swizzle,
82 guint swizzle_count, guint offset)
84 const GstVulkanFormatInfo *finfo = gst_vulkan_format_get_info (format);
87 g_return_if_fail (finfo->flags & GST_VULKAN_FORMAT_FLAG_RGB);
88 g_return_if_fail (finfo->n_components <= swizzle_count);
90 for (i = 0; i < finfo->n_components; i++) {
91 swizzle[i] = offset + finfo->poffset[i];
93 for (i = finfo->n_components; i < swizzle_count; i++) {
98 /* given a swizzle index, produce an index such that:
100 * swizzle[idx[i]] == identity[i] where:
101 * - swizzle is the original swizzle
102 * - idx is the result
103 * - identity = {0, 1, 2,...}
104 * - unset fields are marked by -1
107 swizzle_identity_order (gint * swizzle, gint * idx)
111 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
115 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
116 if (swizzle[i] >= 0 && swizzle[i] < 4 && idx[swizzle[i]] == -1) {
128 matrix_debug (const Matrix4 * s)
130 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
132 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
134 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
136 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
141 matrix_to_float (const Matrix4 * m, float *ret)
145 for (i = 0; i < 4; i++) {
146 for (j = 0; j < 4; j++) {
147 ret[j * 4 + i] = m->dm[i][j];
153 matrix_set_identity (Matrix4 * m)
157 for (i = 0; i < 4; i++) {
158 for (j = 0; j < 4; j++) {
159 m->dm[i][j] = (i == j);
165 matrix_copy (Matrix4 * d, const Matrix4 * s)
169 for (i = 0; i < 4; i++)
170 for (j = 0; j < 4; j++)
171 d->dm[i][j] = s->dm[i][j];
174 /* Perform 4x4 matrix multiplication:
175 * - @dst@ = @a@ * @b@
176 * - @dst@ may be a pointer to @a@ andor @b@
179 matrix_multiply (Matrix4 * dst, Matrix4 * a, Matrix4 * b)
184 for (i = 0; i < 4; i++) {
185 for (j = 0; j < 4; j++) {
187 for (k = 0; k < 4; k++) {
188 x += a->dm[i][k] * b->dm[k][j];
193 matrix_copy (dst, &tmp);
198 matrix_invert (Matrix4 * d, Matrix4 * s)
204 matrix_set_identity (&tmp);
205 for (j = 0; j < 3; j++) {
206 for (i = 0; i < 3; i++) {
208 s->dm[(i + 1) % 3][(j + 1) % 3] * s->dm[(i + 2) % 3][(j + 2) % 3] -
209 s->dm[(i + 1) % 3][(j + 2) % 3] * s->dm[(i + 2) % 3][(j + 1) % 3];
213 tmp.dm[0][0] * s->dm[0][0] + tmp.dm[0][1] * s->dm[1][0] +
214 tmp.dm[0][2] * s->dm[2][0];
215 for (j = 0; j < 3; j++) {
216 for (i = 0; i < 3; i++) {
220 matrix_copy (d, &tmp);
224 matrix_offset_components (Matrix4 * m, double a1, double a2, double a3)
228 matrix_set_identity (&a);
233 matrix_multiply (m, &a, m);
237 matrix_scale_components (Matrix4 * m, double a1, double a2, double a3)
241 matrix_set_identity (&a);
245 matrix_multiply (m, &a, m);
249 matrix_YCbCr_to_RGB (Matrix4 * m, double Kr, double Kb)
251 double Kg = 1.0 - Kr - Kb;
254 {1., 0., 2 * (1 - Kr), 0.},
255 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
256 {1., 2 * (1 - Kb), 0., 0.},
261 matrix_multiply (m, &k, m);
266 GstVideoInfo in_info;
267 GstVideoInfo out_info;
269 Matrix4 to_RGB_matrix;
270 Matrix4 to_YUV_matrix;
271 Matrix4 convert_matrix;
275 convert_to_RGB (ConvertInfo * conv, Matrix4 * m)
277 GstVideoInfo *info = &conv->in_info;
280 const GstVideoFormatInfo *uinfo;
281 gint offset[4], scale[4], depth[4];
284 uinfo = gst_video_format_get_info (GST_VIDEO_INFO_FORMAT (info));
286 /* bring color components to [0..1.0] range */
287 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
290 for (i = 0; i < uinfo->n_components; i++)
291 depth[i] = (1 << uinfo->depth[i]) - 1;
293 matrix_offset_components (m, -offset[0] / (float) depth[0],
294 -offset[1] / (float) depth[1], -offset[2] / (float) depth[2]);
295 matrix_scale_components (m, depth[0] / ((float) scale[0]),
296 depth[1] / ((float) scale[1]), depth[2] / ((float) scale[2]));
297 GST_DEBUG ("to RGB scale/offset matrix");
301 if (GST_VIDEO_INFO_IS_YUV (info)) {
304 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
305 matrix_YCbCr_to_RGB (m, Kr, Kb);
306 GST_DEBUG ("to RGB matrix");
312 matrix_RGB_to_YCbCr (Matrix4 * m, double Kr, double Kb)
314 double Kg = 1.0 - Kr - Kb;
323 x = 1 / (2 * (1 - Kb));
324 k.dm[1][0] = -x * Kr;
325 k.dm[1][1] = -x * Kg;
326 k.dm[1][2] = x * (1 - Kb);
329 x = 1 / (2 * (1 - Kr));
330 k.dm[2][0] = x * (1 - Kr);
331 k.dm[2][1] = -x * Kg;
332 k.dm[2][2] = -x * Kb;
340 matrix_multiply (m, &k, m);
344 convert_to_YUV (ConvertInfo * conv, Matrix4 * m)
346 GstVideoInfo *info = &conv->out_info;
348 if (GST_VIDEO_INFO_IS_YUV (info)) {
351 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
352 matrix_RGB_to_YCbCr (m, Kr, Kb);
353 GST_DEBUG ("to YUV matrix");
358 const GstVideoFormatInfo *uinfo;
359 gint offset[4], scale[4], depth[4];
362 uinfo = gst_video_format_get_info (GST_VIDEO_INFO_FORMAT (info));
364 /* bring color components to nominal range */
365 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
368 for (i = 0; i < uinfo->n_components; i++)
369 depth[i] = (1 << uinfo->depth[i]) - 1;
371 matrix_scale_components (m, scale[0] / (float) depth[0],
372 scale[1] / (float) depth[1], scale[2] / (float) depth[2]);
373 matrix_offset_components (m, offset[0] / (float) depth[0],
374 offset[1] / (float) depth[1], offset[2] / (float) depth[2]);
375 GST_DEBUG ("to YUV scale/offset matrix");
382 matrix_RGB_to_XYZ (Matrix4 * dst, double Rx, double Ry, double Gx,
383 double Gy, double Bx, double By, double Wx, double Wy)
389 matrix_set_identity (&m);
393 m.dm[2][0] = (1.0 - Rx - Ry);
396 m.dm[2][1] = (1.0 - Gx - Gy);
399 m.dm[2][2] = (1.0 - Bx - By);
401 matrix_invert (&im, &m);
405 wz = (1.0 - Wx - Wy) / Wy;
407 sx = im.dm[0][0] * wx + im.dm[0][1] * wy + im.dm[0][2] * wz;
408 sy = im.dm[1][0] * wx + im.dm[1][1] * wy + im.dm[1][2] * wz;
409 sz = im.dm[2][0] * wx + im.dm[2][1] * wy + im.dm[2][2] * wz;
421 matrix_copy (dst, &m);
425 convert_primaries (ConvertInfo * conv)
427 gboolean same_matrix, same_primaries;
431 conv->in_info.colorimetry.matrix == conv->out_info.colorimetry.matrix;
433 conv->in_info.colorimetry.primaries ==
434 conv->out_info.colorimetry.primaries;
436 GST_DEBUG ("matrix %d -> %d (%d)", conv->in_info.colorimetry.matrix,
437 conv->out_info.colorimetry.matrix, same_matrix);
438 GST_DEBUG ("primaries %d -> %d (%d)", conv->in_info.colorimetry.primaries,
439 conv->out_info.colorimetry.primaries, same_primaries);
441 matrix_set_identity (&conv->convert_matrix);
443 if (!same_primaries) {
444 const GstVideoColorPrimariesInfo *pi;
446 pi = gst_video_color_primaries_get_info (conv->in_info.colorimetry.
448 matrix_RGB_to_XYZ (&p1, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx, pi->By,
450 GST_DEBUG ("to XYZ matrix");
452 GST_DEBUG ("current matrix");
453 matrix_multiply (&conv->convert_matrix, &conv->convert_matrix, &p1);
454 matrix_debug (&conv->convert_matrix);
456 pi = gst_video_color_primaries_get_info (conv->out_info.colorimetry.
458 matrix_RGB_to_XYZ (&p2, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx, pi->By,
460 matrix_invert (&p2, &p2);
461 GST_DEBUG ("to RGB matrix");
463 matrix_multiply (&conv->convert_matrix, &conv->convert_matrix, &p2);
464 GST_DEBUG ("current matrix");
465 matrix_debug (&conv->convert_matrix);
470 convert_info_new (GstVideoInfo * in_info, GstVideoInfo * out_info)
472 ConvertInfo *conv = g_new0 (ConvertInfo, 1);
474 matrix_set_identity (&conv->to_RGB_matrix);
475 matrix_set_identity (&conv->convert_matrix);
476 matrix_set_identity (&conv->to_YUV_matrix);
478 memcpy (&conv->in_info, in_info, sizeof (*in_info));
479 memcpy (&conv->out_info, out_info, sizeof (*out_info));
481 convert_to_RGB (conv, &conv->to_RGB_matrix);
482 /* by default videoconvert does not convert primaries
483 convert_primaries (conv); */
484 convert_to_YUV (conv, &conv->to_YUV_matrix);
490 video_format_to_reorder (GstVideoFormat v_format, gint * reorder,
494 case GST_VIDEO_FORMAT_RGBA:
495 case GST_VIDEO_FORMAT_RGBx:
496 case GST_VIDEO_FORMAT_BGRA:
497 case GST_VIDEO_FORMAT_BGRx:
498 case GST_VIDEO_FORMAT_ARGB:
499 case GST_VIDEO_FORMAT_xRGB:
500 case GST_VIDEO_FORMAT_ABGR:
501 case GST_VIDEO_FORMAT_xBGR:
502 case GST_VIDEO_FORMAT_AYUV:
503 get_rgb_format_swizzle_order (v_format, reorder);
505 case GST_VIDEO_FORMAT_UYVY:
508 reorder[2] = input ? 3 : 2;
511 case GST_VIDEO_FORMAT_YUY2:
515 reorder[3] = input ? 3 : 2;
517 case GST_VIDEO_FORMAT_NV12:
524 g_assert_not_reached ();
528 GST_TRACE ("swizzle: %u, %u, %u, %u", reorder[0], reorder[1], reorder[2],
533 finfo_get_plane_n_components (const GstVideoFormatInfo * finfo, guint plane)
535 guint n_components = 0, i;
537 switch (finfo->format) {
538 case GST_VIDEO_FORMAT_RGBx:
539 case GST_VIDEO_FORMAT_xRGB:
540 case GST_VIDEO_FORMAT_BGRx:
541 case GST_VIDEO_FORMAT_xBGR:
542 /* fixup spaced RGB formats as we treat the space as a normal alpha
544 return plane == 0 ? 4 : 0;
549 for (i = 0; i < finfo->n_components; i++) {
550 if (finfo->plane[i] == plane)
558 get_vulkan_format_swizzle_order (GstVideoFormat v_format,
559 VkFormat vk_format[GST_VIDEO_MAX_PLANES],
560 gint swizzle[GST_VIDEO_MAX_COMPONENTS])
562 const GstVideoFormatInfo *finfo;
563 int i, prev_in_i = 0;
565 finfo = gst_video_format_get_info (v_format);
566 for (i = 0; i < finfo->n_planes; i++) {
567 guint plane_components = finfo_get_plane_n_components (finfo, i);
568 get_vulkan_rgb_format_swizzle_order (vk_format[i],
569 &swizzle[prev_in_i], plane_components, prev_in_i);
570 prev_in_i += plane_components;
573 if (v_format == GST_VIDEO_FORMAT_YUY2 || v_format == GST_VIDEO_FORMAT_UYVY) {
574 /* Fixup these packed YUV formats as we use a two component format for
575 * a 4-component pixel and access two samples in the shader */
576 g_assert (swizzle[0] == 0);
577 g_assert (swizzle[1] == 1);
582 GST_TRACE ("%s: %i, %i, %i, %i", finfo->name, swizzle[0], swizzle[1],
583 swizzle[2], swizzle[3]);
587 calculate_reorder_indexes (GstVideoFormat in_format,
588 GstVulkanImageView * in_views[GST_VIDEO_MAX_COMPONENTS],
589 GstVideoFormat out_format,
590 GstVulkanImageView * out_views[GST_VIDEO_MAX_COMPONENTS],
591 int ret_in[GST_VIDEO_MAX_COMPONENTS], int ret_out[GST_VIDEO_MAX_COMPONENTS])
593 const GstVideoFormatInfo *in_finfo, *out_finfo;
594 VkFormat in_vk_formats[GST_VIDEO_MAX_COMPONENTS];
595 VkFormat out_vk_formats[GST_VIDEO_MAX_COMPONENTS];
596 int in_vk_order[GST_VIDEO_MAX_COMPONENTS] = { 0, };
597 int in_reorder[GST_VIDEO_MAX_COMPONENTS] = { 0, };
598 int out_vk_order[GST_VIDEO_MAX_COMPONENTS] = { 0, };
599 int out_reorder[GST_VIDEO_MAX_COMPONENTS] = { 0, };
600 int tmp[GST_VIDEO_MAX_PLANES] = { 0, };
603 in_finfo = gst_video_format_get_info (in_format);
604 out_finfo = gst_video_format_get_info (out_format);
606 for (i = 0; i < in_finfo->n_planes; i++)
607 in_vk_formats[i] = in_views[i]->image->create_info.format;
608 for (i = 0; i < out_finfo->n_planes; i++)
609 out_vk_formats[i] = out_views[i]->image->create_info.format;
611 get_vulkan_format_swizzle_order (in_format, in_vk_formats, in_vk_order);
612 video_format_to_reorder (in_format, in_reorder, TRUE);
614 video_format_to_reorder (out_format, out_reorder, FALSE);
615 get_vulkan_format_swizzle_order (out_format, out_vk_formats, out_vk_order);
617 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++)
618 tmp[i] = out_vk_order[out_reorder[i]];
619 /* find the identity order for RGBA->$format */
620 GST_TRACE ("pre-invert: %u, %u, %u, %u", tmp[0], tmp[1], tmp[2], tmp[3]);
621 if (out_format == GST_VIDEO_FORMAT_YUY2
622 || out_format == GST_VIDEO_FORMAT_UYVY) {
623 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++)
626 swizzle_identity_order (tmp, ret_out);
629 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++)
630 ret_in[i] = in_reorder[in_vk_order[i]];
631 GST_TRACE ("in reorder: %u, %u, %u, %u", ret_in[0], ret_in[1], ret_in[2],
633 GST_TRACE ("out reorder: %u, %u, %u, %u", ret_out[0], ret_out[1], ret_out[2],
644 swizzle_rgb_create_uniform_memory (GstVulkanColorConvert * conv,
645 shader_info * sinfo, GstVulkanImageView ** in_views,
646 GstVulkanImageView ** out_views)
648 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (conv);
650 if (sinfo->user_data) {
651 return gst_memory_ref (sinfo->user_data);
653 struct RGBUpdateData data = { 0, };
658 gst_vulkan_buffer_memory_alloc (vfilter->device,
659 sizeof (struct RGBUpdateData),
660 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
661 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
662 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
664 calculate_reorder_indexes (GST_VIDEO_INFO_FORMAT (&conv->quad->in_info),
665 in_views, GST_VIDEO_INFO_FORMAT (&conv->quad->out_info),
666 out_views, data.in_reorder, data.out_reorder);
668 if (!gst_memory_map (uniforms, &map_info, GST_MAP_WRITE)) {
669 gst_memory_unref (uniforms);
672 memcpy (map_info.data, &data, sizeof (data));
673 gst_memory_unmap (uniforms, &map_info);
675 sinfo->user_data = gst_memory_ref (uniforms);
692 /* each member is aligned on 4x previous component size boundaries */
694 struct ColorMatrices matrices;
698 yuv_to_rgb_create_uniform_memory (GstVulkanColorConvert * conv,
699 shader_info * sinfo, GstVulkanImageView ** in_views,
700 GstVulkanImageView ** out_views)
702 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (conv);
704 if (sinfo->user_data) {
705 return gst_memory_ref (sinfo->user_data);
707 struct YUVUpdateData data;
708 ConvertInfo *conv_info;
713 gst_vulkan_buffer_memory_alloc (vfilter->device,
714 sizeof (struct YUVUpdateData),
715 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
716 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
717 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
719 calculate_reorder_indexes (GST_VIDEO_INFO_FORMAT (&conv->quad->in_info),
720 in_views, GST_VIDEO_INFO_FORMAT (&conv->quad->out_info),
721 out_views, data.in_reorder, data.out_reorder);
723 conv_info = convert_info_new (&conv->quad->in_info, &conv->quad->out_info);
724 matrix_to_float (&conv_info->to_RGB_matrix, data.matrices.to_RGB);
725 matrix_to_float (&conv_info->convert_matrix, data.matrices.primaries);
726 matrix_to_float (&conv_info->to_YUV_matrix, data.matrices.to_YUV);
727 /* FIXME: keep this around */
730 data.tex_size[0] = GST_VIDEO_INFO_WIDTH (&conv->quad->in_info);
731 data.tex_size[1] = GST_VIDEO_INFO_HEIGHT (&conv->quad->in_info);
733 if (!gst_memory_map (uniforms, &map_info, GST_MAP_WRITE)) {
734 gst_memory_unref (uniforms);
737 memcpy (map_info.data, &data, sizeof (data));
738 gst_memory_unmap (uniforms, &map_info);
740 sinfo->user_data = gst_memory_ref (uniforms);
747 unref_memory_if_set (shader_info * sinfo)
749 if (sinfo->user_data)
750 gst_memory_unref (sinfo->user_data);
751 sinfo->user_data = NULL;
754 static gboolean gst_vulkan_color_convert_start (GstBaseTransform * bt);
755 static gboolean gst_vulkan_color_convert_stop (GstBaseTransform * bt);
757 static GstCaps *gst_vulkan_color_convert_transform_caps (GstBaseTransform * bt,
758 GstPadDirection direction, GstCaps * caps, GstCaps * filter);
759 static GstFlowReturn gst_vulkan_color_convert_transform (GstBaseTransform * bt,
760 GstBuffer * inbuf, GstBuffer * outbuf);
761 static gboolean gst_vulkan_color_convert_set_caps (GstBaseTransform * bt,
762 GstCaps * in_caps, GstCaps * out_caps);
764 static GstStaticPadTemplate gst_vulkan_sink_template =
765 GST_STATIC_PAD_TEMPLATE ("sink",
768 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
769 (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE,
770 "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, NV12 }")));
772 static GstStaticPadTemplate gst_vulkan_src_template =
773 GST_STATIC_PAD_TEMPLATE ("src",
776 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
777 (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE,
778 "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, NV12 }")));
791 /* static guint gst_vulkan_color_convert_signals[LAST_SIGNAL] = { 0 }; */
793 #define gst_vulkan_color_convert_parent_class parent_class
794 G_DEFINE_TYPE_WITH_CODE (GstVulkanColorConvert, gst_vulkan_color_convert,
795 GST_TYPE_VULKAN_VIDEO_FILTER,
796 GST_DEBUG_CATEGORY_INIT (gst_debug_vulkan_color_convert,
797 "vulkancolorconvert", 0, "Vulkan Color Convert"));
801 GstVideoFormat format;
803 gsize from_frag_size;
809 fill_shader_info (void)
811 GstVideoFormat rgbs[] = { GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_ARGB,
812 GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_RGBx,
813 GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_xBGR
815 struct yuv_info yuvs[] = {
816 {GST_VIDEO_FORMAT_AYUV, ayuv_to_rgb_frag, ayuv_to_rgb_frag_size,
817 rgb_to_ayuv_frag, rgb_to_ayuv_frag_size},
818 {GST_VIDEO_FORMAT_YUY2, yuy2_to_rgb_frag, yuy2_to_rgb_frag_size,
819 rgb_to_yuy2_frag, rgb_to_yuy2_frag_size},
820 /* {GST_VIDEO_FORMAT_UYVY, yuy2_to_rgb_frag, yuy2_to_rgb_frag_size,
821 rgb_to_yuy2_frag, rgb_to_yuy2_frag_size},*/
822 {GST_VIDEO_FORMAT_NV12, nv12_to_rgb_frag, nv12_to_rgb_frag_size,
823 rgb_to_nv12_frag, rgb_to_nv12_frag_size},
828 /* standard RGB with alpha conversion all components are copied */
830 for (i = 0; i < G_N_ELEMENTS (rgbs); i++) {
831 const GstVideoFormatInfo *from_finfo = gst_video_format_get_info (rgbs[i]);
833 for (j = 0; j < G_N_ELEMENTS (rgbs); j++) {
834 const GstVideoFormatInfo *to_finfo = gst_video_format_get_info (rgbs[j]);
835 gboolean clobber_alpha = FALSE;
837 GST_TRACE ("Initializing info for %s -> %s", from_finfo->name, to_finfo->name);
839 /* copying to an RGBx variant means we can store whatever we like in the 'x'
840 * component we choose to copy the alpha component like a standard RGBA->RGBA
842 * Copying from an rgbx to a rgba format means we need to reset the
844 clobber_alpha = !GST_VIDEO_FORMAT_INFO_HAS_ALPHA (from_finfo) && GST_VIDEO_FORMAT_INFO_HAS_ALPHA (to_finfo);
845 shader_infos[info_i++] = (shader_info) {
848 .cmd_create_uniform = swizzle_rgb_create_uniform_memory,
849 .frag_code = clobber_alpha ? swizzle_and_clobber_alpha_frag : swizzle_frag,
850 .frag_size = clobber_alpha ? swizzle_and_clobber_alpha_frag_size : swizzle_frag_size,
851 .uniform_size = sizeof (struct RGBUpdateData),
852 .notify = (GDestroyNotify) unref_memory_if_set,
857 for (j = 0; j < G_N_ELEMENTS (yuvs); j++) {
858 const GstVideoFormatInfo *to_finfo = gst_video_format_get_info (yuvs[j].format);
859 GST_TRACE ("Initializing info for %s -> %s", from_finfo->name, to_finfo->name);
860 shader_infos[info_i++] = (shader_info) {
862 .to = yuvs[j].format,
863 .cmd_create_uniform = yuv_to_rgb_create_uniform_memory,
864 .frag_code = yuvs[j].to_frag,
865 .frag_size = yuvs[j].to_frag_size,
866 .uniform_size = sizeof(struct YUVUpdateData),
867 .notify = (GDestroyNotify) unref_memory_if_set,
870 GST_TRACE ("Initializing info for %s -> %s", to_finfo->name, from_finfo->name);
871 shader_infos[info_i++] = (shader_info) {
872 .from = yuvs[j].format,
874 .cmd_create_uniform = yuv_to_rgb_create_uniform_memory,
875 .frag_code = yuvs[j].from_frag,
876 .frag_size = yuvs[j].from_frag_size,
877 .uniform_size = sizeof(struct YUVUpdateData),
878 .notify = (GDestroyNotify) unref_memory_if_set,
884 GST_TRACE ("initialized %u formats", info_i);
886 g_assert (info_i == N_SHADER_INFO);
890 gst_vulkan_color_convert_class_init (GstVulkanColorConvertClass * klass)
892 GstElementClass *gstelement_class;
893 GstBaseTransformClass *gstbasetransform_class;
895 gstelement_class = (GstElementClass *) klass;
896 gstbasetransform_class = (GstBaseTransformClass *) klass;
898 gst_element_class_set_metadata (gstelement_class, "Vulkan Uploader",
899 "Filter/Video/Convert", "A Vulkan Color Convert",
900 "Matthew Waters <matthew@centricular.com>");
902 gst_element_class_add_static_pad_template (gstelement_class,
903 &gst_vulkan_sink_template);
904 gst_element_class_add_static_pad_template (gstelement_class,
905 &gst_vulkan_src_template);
907 gstbasetransform_class->start =
908 GST_DEBUG_FUNCPTR (gst_vulkan_color_convert_start);
909 gstbasetransform_class->stop =
910 GST_DEBUG_FUNCPTR (gst_vulkan_color_convert_stop);
911 gstbasetransform_class->transform_caps =
912 gst_vulkan_color_convert_transform_caps;
913 gstbasetransform_class->set_caps = gst_vulkan_color_convert_set_caps;
914 gstbasetransform_class->transform = gst_vulkan_color_convert_transform;
920 gst_vulkan_color_convert_init (GstVulkanColorConvert * conv)
925 _init_value_string_list (GValue * list, ...)
927 GValue item = G_VALUE_INIT;
931 g_value_init (list, GST_TYPE_LIST);
933 va_start (args, list);
934 while ((str = va_arg (args, gchar *))) {
935 g_value_init (&item, G_TYPE_STRING);
936 g_value_set_string (&item, str);
938 gst_value_list_append_value (list, &item);
939 g_value_unset (&item);
945 _append_value_string_list (GValue * list, ...)
947 GValue item = G_VALUE_INIT;
951 va_start (args, list);
952 while ((str = va_arg (args, gchar *))) {
953 g_value_init (&item, G_TYPE_STRING);
954 g_value_set_string (&item, str);
956 gst_value_list_append_value (list, &item);
957 g_value_unset (&item);
963 _init_supported_formats (GstVulkanDevice * device, gboolean output,
964 GValue * supported_formats)
966 /* Assume if device == NULL that we don't have a Vulkan device and can
967 * do the conversion */
969 /* Always supported input and output formats */
970 _init_value_string_list (supported_formats, "RGBA", "RGB", "RGBx", "BGR",
971 "BGRx", "BGRA", "xRGB", "xBGR", "ARGB", "ABGR", NULL);
973 _append_value_string_list (supported_formats, "AYUV", "YUY2", /*"UYVY", */
977 /* copies the given caps */
979 gst_vulkan_color_convert_transform_format_info (GstVulkanDevice * device,
980 gboolean output, GstCaps * caps)
986 GValue supported_formats = G_VALUE_INIT;
987 GValue rgb_formats = G_VALUE_INIT;
988 GValue supported_rgb_formats = G_VALUE_INIT;
990 /* There are effectively two modes here with the RGB/YUV transition:
991 * 1. There is a RGB-like format as input and we can transform to YUV or,
992 * 2. No RGB-like format as input so we can only transform to RGB-like formats
994 * We also filter down the list of formats depending on what the OpenGL
995 * device supports (when provided).
998 _init_value_string_list (&rgb_formats, "RGBA", "ARGB", "BGRA", "ABGR", "RGBx",
999 "xRGB", "BGRx", "xBGR", "RGB", "BGR", "ARGB64", NULL);
1000 _init_supported_formats (device, output, &supported_formats);
1001 gst_value_intersect (&supported_rgb_formats, &rgb_formats,
1002 &supported_formats);
1004 res = gst_caps_new_empty ();
1006 n = gst_caps_get_size (caps);
1007 for (i = 0; i < n; i++) {
1008 const GValue *format;
1010 st = gst_caps_get_structure (caps, i);
1011 f = gst_caps_get_features (caps, i);
1013 format = gst_structure_get_value (st, "format");
1014 st = gst_structure_copy (st);
1015 if (GST_VALUE_HOLDS_LIST (format)) {
1016 gboolean have_rgb_formats = FALSE;
1017 GValue passthrough_formats = G_VALUE_INIT;
1020 g_value_init (&passthrough_formats, GST_TYPE_LIST);
1021 len = gst_value_list_get_size (format);
1022 for (j = 0; j < len; j++) {
1025 val = gst_value_list_get_value (format, j);
1026 if (G_VALUE_HOLDS_STRING (val)) {
1027 const gchar *format_str = g_value_get_string (val);
1028 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1029 const GstVideoFormatInfo *t_info =
1030 gst_video_format_get_info (v_format);
1031 if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) & (GST_VIDEO_FORMAT_FLAG_YUV
1032 | GST_VIDEO_FORMAT_FLAG_GRAY)) {
1033 gst_value_list_append_value (&passthrough_formats, val);
1034 } else if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) &
1035 GST_VIDEO_FORMAT_FLAG_RGB) {
1036 have_rgb_formats = TRUE;
1041 if (have_rgb_formats) {
1042 gst_structure_set_value (st, "format", &supported_formats);
1044 /* add passthrough structure, then the rgb conversion structure */
1045 gst_structure_set_value (st, "format", &passthrough_formats);
1046 gst_caps_append_structure_full (res, gst_structure_copy (st),
1047 gst_caps_features_copy (f));
1048 gst_structure_set_value (st, "format", &supported_rgb_formats);
1050 g_value_unset (&passthrough_formats);
1051 } else if (G_VALUE_HOLDS_STRING (format)) {
1052 const gchar *format_str = g_value_get_string (format);
1053 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1054 const GstVideoFormatInfo *t_info = gst_video_format_get_info (v_format);
1055 if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) & (GST_VIDEO_FORMAT_FLAG_YUV |
1056 GST_VIDEO_FORMAT_FLAG_GRAY)) {
1057 /* add passthrough structure, then the rgb conversion structure */
1058 gst_structure_set_value (st, "format", format);
1059 gst_caps_append_structure_full (res, gst_structure_copy (st),
1060 gst_caps_features_copy (f));
1061 gst_structure_set_value (st, "format", &supported_rgb_formats);
1063 gst_structure_set_value (st, "format", &supported_formats);
1066 gst_structure_remove_fields (st, "colorimetry", "chroma-site", NULL);
1068 gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
1071 g_value_unset (&supported_formats);
1072 g_value_unset (&rgb_formats);
1073 g_value_unset (&supported_rgb_formats);
1079 gst_vulkan_color_convert_transform_caps (GstBaseTransform * bt,
1080 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1082 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (bt);
1084 caps = gst_vulkan_color_convert_transform_format_info (vfilter->device,
1085 direction == GST_PAD_SRC, caps);
1090 tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1091 gst_caps_unref (caps);
1099 gst_vulkan_color_convert_start (GstBaseTransform * bt)
1101 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1102 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (conv);
1104 if (!GST_BASE_TRANSFORM_CLASS (parent_class)->start (bt))
1107 conv->quad = gst_vulkan_full_screen_quad_new (vfilter->queue);
1113 gst_vulkan_color_convert_set_caps (GstBaseTransform * bt, GstCaps * in_caps,
1116 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (bt);
1117 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1118 GstVulkanHandle *vert, *frag;
1121 if (!GST_BASE_TRANSFORM_CLASS (parent_class)->set_caps (bt, in_caps,
1125 if (!gst_vulkan_full_screen_quad_set_info (conv->quad, &vfilter->in_info,
1126 &vfilter->out_info))
1129 if (conv->current_shader) {
1130 conv->current_shader->notify (conv->current_shader);
1131 conv->current_shader = NULL;
1134 for (i = 0; i < G_N_ELEMENTS (shader_infos); i++) {
1135 if (shader_infos[i].from != GST_VIDEO_INFO_FORMAT (&vfilter->in_info))
1137 if (shader_infos[i].to != GST_VIDEO_INFO_FORMAT (&vfilter->out_info))
1140 GST_INFO_OBJECT (conv,
1141 "Found compatible conversion information from %s to %s",
1142 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&vfilter->in_info)),
1143 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
1144 (&vfilter->out_info)));
1145 conv->current_shader = &shader_infos[i];
1148 if (!conv->current_shader) {
1149 GST_ERROR_OBJECT (conv, "Could not find a conversion info for the "
1150 "requested formats");
1155 gst_vulkan_create_shader (vfilter->device, identity_vert,
1156 identity_vert_size, NULL))) {
1160 gst_vulkan_create_shader (vfilter->device,
1161 conv->current_shader->frag_code, conv->current_shader->frag_size,
1163 gst_vulkan_handle_unref (vert);
1167 if (!gst_vulkan_full_screen_quad_set_shaders (conv->quad, vert, frag)) {
1168 gst_vulkan_handle_unref (vert);
1169 gst_vulkan_handle_unref (frag);
1173 gst_vulkan_handle_unref (vert);
1174 gst_vulkan_handle_unref (frag);
1180 gst_vulkan_color_convert_stop (GstBaseTransform * bt)
1182 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1184 if (conv->current_shader) {
1185 conv->current_shader->notify (conv->current_shader);
1186 conv->current_shader = NULL;
1189 gst_clear_object (&conv->quad);
1191 return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (bt);
1194 static GstFlowReturn
1195 gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
1198 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1199 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (bt);
1200 GstVulkanImageView *in_img_views[GST_VIDEO_MAX_PLANES] = { NULL, };
1201 GstVulkanImageMemory *render_img_mems[GST_VIDEO_MAX_PLANES] = { NULL, };
1202 GstVulkanImageView *render_img_views[GST_VIDEO_MAX_PLANES] = { NULL, };
1203 GstVulkanImageMemory *out_img_mems[GST_VIDEO_MAX_PLANES] = { NULL, };
1204 GstBuffer *render_buf = NULL;
1205 GstVulkanFence *fence = NULL;
1206 GstVulkanCommandBuffer *cmd_buf;
1207 GError *error = NULL;
1211 fence = gst_vulkan_device_create_fence (vfilter->device, &error);
1215 if (!gst_vulkan_full_screen_quad_set_input_buffer (conv->quad, inbuf, &error))
1218 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->in_info); i++) {
1219 GstMemory *img_mem = gst_buffer_peek_memory (inbuf, i);
1220 if (!gst_is_vulkan_image_memory (img_mem)) {
1221 g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
1222 "Input memory must be a GstVulkanImageMemory");
1226 gst_vulkan_get_or_create_image_view ((GstVulkanImageMemory *) img_mem);
1227 gst_vulkan_trash_list_add (conv->quad->trash_list,
1228 gst_vulkan_trash_list_acquire (conv->quad->trash_list, fence,
1229 gst_vulkan_trash_mini_object_unref,
1230 (GstMiniObject *) in_img_views[i]));
1234 gboolean need_render_buf = FALSE;
1236 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->out_info); i++) {
1237 GstMemory *mem = gst_buffer_peek_memory (outbuf, i);
1238 if (!gst_is_vulkan_image_memory (mem)) {
1239 g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
1240 "Output memory must be a GstVulkanImageMemory");
1243 out_img_mems[i] = (GstVulkanImageMemory *) mem;
1245 if (GST_VIDEO_INFO_WIDTH (&conv->quad->out_info) ==
1246 GST_VIDEO_INFO_COMP_WIDTH (&conv->quad->out_info, i)
1247 && GST_VIDEO_INFO_HEIGHT (&conv->quad->out_info) ==
1248 GST_VIDEO_INFO_COMP_HEIGHT (&conv->quad->out_info, i)) {
1249 render_img_mems[i] = out_img_mems[i];
1250 GST_LOG_OBJECT (conv, "using original output memory %p for plane %u",
1251 out_img_mems[i], i);
1253 /* we need a scratch buffer because framebuffers can only output to
1254 * attachments of at least the same size which means no sub-sampled
1256 VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
1261 gst_vulkan_format_from_video_info (&conv->quad->out_info, i);
1263 mem = gst_vulkan_image_memory_alloc (vfilter->device,
1264 vk_format, GST_VIDEO_INFO_WIDTH (&conv->quad->out_info),
1265 GST_VIDEO_INFO_HEIGHT (&conv->quad->out_info), tiling,
1266 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1267 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1268 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
1269 render_img_mems[i] = (GstVulkanImageMemory *) mem;
1270 need_render_buf = TRUE;
1271 GST_LOG_OBJECT (conv, "using replacement output memory %p for plane %u",
1276 if (need_render_buf) {
1277 render_buf = gst_buffer_new ();
1278 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->out_info); i++) {
1279 gst_buffer_append_memory (render_buf,
1280 gst_memory_ref ((GstMemory *) render_img_mems[i]));
1282 gst_vulkan_trash_list_add (conv->quad->trash_list,
1283 gst_vulkan_trash_list_acquire (conv->quad->trash_list, fence,
1284 gst_vulkan_trash_mini_object_unref,
1285 (GstMiniObject *) render_buf));
1287 render_buf = outbuf;
1290 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->out_info); i++) {
1291 GstMemory *img_mem = gst_buffer_peek_memory (render_buf, i);
1292 if (!gst_is_vulkan_image_memory (img_mem)) {
1293 g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
1294 "Input memory must be a GstVulkanImageMemory");
1297 render_img_views[i] =
1298 gst_vulkan_get_or_create_image_view ((GstVulkanImageMemory *)
1300 gst_vulkan_trash_list_add (conv->quad->trash_list,
1301 gst_vulkan_trash_list_acquire (conv->quad->trash_list, fence,
1302 gst_vulkan_trash_mini_object_unref,
1303 (GstMiniObject *) render_img_views[i]));
1307 if (!gst_vulkan_full_screen_quad_set_output_buffer (conv->quad, render_buf,
1312 GstMemory *uniforms = conv->current_shader->cmd_create_uniform (conv,
1313 conv->current_shader, in_img_views, render_img_views);
1314 if (!gst_vulkan_full_screen_quad_set_uniform_buffer (conv->quad, uniforms,
1316 gst_memory_unref (uniforms);
1319 gst_memory_unref (uniforms);
1322 if (!gst_vulkan_full_screen_quad_prepare_draw (conv->quad, fence, &error))
1326 gst_vulkan_command_pool_create (conv->quad->cmd_pool, &error)))
1330 VkCommandBufferBeginInfo cmd_buf_info = { 0, };
1333 cmd_buf_info = (VkCommandBufferBeginInfo) {
1334 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1336 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1337 .pInheritanceInfo = NULL
1341 gst_vulkan_command_buffer_lock (cmd_buf);
1342 err = vkBeginCommandBuffer (cmd_buf->cmd, &cmd_buf_info);
1343 if (gst_vulkan_error_to_g_error (err, &error, "vkBeginCommandBuffer") < 0)
1347 if (!gst_vulkan_full_screen_quad_fill_command_buffer (conv->quad, cmd_buf,
1351 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->out_info); i++) {
1352 if (render_img_mems[i] != out_img_mems[i]) {
1353 VkImageMemoryBarrier out_image_memory_barrier;
1354 VkImageMemoryBarrier render_image_memory_barrier;
1358 render_image_memory_barrier = (VkImageMemoryBarrier) {
1359 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1361 .srcAccessMask = render_img_mems[i]->barrier.parent.access_flags,
1362 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
1363 .oldLayout = render_img_mems[i]->barrier.image_layout,
1364 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1365 /* FIXME: implement exclusive transfers */
1366 .srcQueueFamilyIndex = 0,
1367 .dstQueueFamilyIndex = 0,
1368 .image = render_img_mems[i]->image,
1369 .subresourceRange = render_img_mems[i]->barrier.subresource_range
1371 out_image_memory_barrier = (VkImageMemoryBarrier) {
1372 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1374 .srcAccessMask = out_img_mems[i]->barrier.parent.access_flags,
1375 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
1376 .oldLayout = out_img_mems[i]->barrier.image_layout,
1377 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1378 /* FIXME: implement exclusive transfers */
1379 .srcQueueFamilyIndex = 0,
1380 .dstQueueFamilyIndex = 0,
1381 .image = out_img_mems[i]->image,
1382 .subresourceRange = out_img_mems[i]->barrier.subresource_range
1384 blit = (VkImageBlit) {
1386 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1388 .baseArrayLayer = 0,
1394 GST_VIDEO_INFO_COMP_WIDTH (&conv->quad->out_info, i),
1395 GST_VIDEO_INFO_COMP_HEIGHT (&conv->quad->out_info, i),
1400 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1402 .baseArrayLayer = 0,
1408 GST_VIDEO_INFO_COMP_WIDTH (&conv->quad->out_info, i),
1409 GST_VIDEO_INFO_COMP_HEIGHT (&conv->quad->out_info, i),
1416 GST_LOG_OBJECT (conv, "blitting plane %u from %p to %p", i,
1417 render_img_mems[i], out_img_mems[i]);
1419 vkCmdPipelineBarrier (cmd_buf->cmd,
1420 render_img_mems[i]->barrier.parent.pipeline_stages,
1421 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
1422 &render_image_memory_barrier);
1424 render_img_mems[i]->barrier.parent.pipeline_stages =
1425 VK_PIPELINE_STAGE_TRANSFER_BIT;
1426 render_img_mems[i]->barrier.parent.access_flags =
1427 render_image_memory_barrier.dstAccessMask;
1428 render_img_mems[i]->barrier.image_layout =
1429 render_image_memory_barrier.newLayout;
1431 vkCmdPipelineBarrier (cmd_buf->cmd,
1432 out_img_mems[i]->barrier.parent.pipeline_stages,
1433 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
1434 &out_image_memory_barrier);
1436 out_img_mems[i]->barrier.parent.pipeline_stages =
1437 VK_PIPELINE_STAGE_TRANSFER_BIT;
1438 out_img_mems[i]->barrier.parent.access_flags =
1439 out_image_memory_barrier.dstAccessMask;
1440 out_img_mems[i]->barrier.image_layout =
1441 out_image_memory_barrier.newLayout;
1443 /* XXX: This is mostly right for a downsampling pass however if
1444 * anything is more complicated, then we will need a new render pass */
1445 vkCmdBlitImage (cmd_buf->cmd, render_img_mems[i]->image,
1446 render_img_mems[i]->barrier.image_layout, out_img_mems[i]->image,
1447 out_img_mems[i]->barrier.image_layout, 1, &blit, VK_FILTER_LINEAR);
1449 /* XXX: try to reuse this image later */
1450 gst_vulkan_trash_list_add (conv->quad->trash_list,
1451 gst_vulkan_trash_list_acquire (conv->quad->trash_list, fence,
1452 gst_vulkan_trash_mini_object_unref,
1453 (GstMiniObject *) render_img_mems[i]));
1457 err = vkEndCommandBuffer (cmd_buf->cmd);
1458 gst_vulkan_command_buffer_unlock (cmd_buf);
1459 if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0)
1462 if (!gst_vulkan_full_screen_quad_submit (conv->quad, cmd_buf, fence, &error))
1465 gst_vulkan_fence_unref (fence);
1471 gst_vulkan_command_buffer_unlock (cmd_buf);
1472 gst_vulkan_command_buffer_unref (cmd_buf);
1475 gst_clear_mini_object ((GstMiniObject **) & fence);
1477 GST_ELEMENT_ERROR (bt, LIBRARY, FAILED, ("%s", error->message), (NULL));
1478 g_clear_error (&error);
1479 return GST_FLOW_ERROR;