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 "vkelementutils.h"
38 #include "shaders/identity.vert.h"
39 #include "shaders/swizzle.frag.h"
40 #include "shaders/swizzle_and_clobber_alpha.frag.h"
41 #include "shaders/yuy2_to_rgb.frag.h"
42 #include "shaders/ayuv_to_rgb.frag.h"
43 #include "shaders/nv12_to_rgb.frag.h"
44 #include "shaders/rgb_to_ayuv.frag.h"
45 #include "shaders/rgb_to_yuy2.frag.h"
46 #include "shaders/rgb_to_nv12.frag.h"
48 GST_DEBUG_CATEGORY (gst_debug_vulkan_color_convert);
49 #define GST_CAT_DEFAULT gst_debug_vulkan_color_convert
51 #define N_SHADER_INFO (8*8 + 8*3*2)
52 static shader_info shader_infos[N_SHADER_INFO];
55 get_rgb_format_swizzle_order (GstVideoFormat format,
56 gint swizzle[GST_VIDEO_MAX_COMPONENTS])
58 const GstVideoFormatInfo *finfo = gst_video_format_get_info (format);
61 g_return_if_fail (finfo->flags & GST_VIDEO_FORMAT_FLAG_RGB
62 || format == GST_VIDEO_FORMAT_AYUV);
64 for (i = 0; i < finfo->n_components; i++) {
65 swizzle[c_i++] = finfo->poffset[i];
68 /* special case spaced RGB formats as the space does not contain a poffset
69 * value and we need all four components to be valid in order to swizzle
71 if (format == GST_VIDEO_FORMAT_xRGB || format == GST_VIDEO_FORMAT_xBGR) {
73 } else if (format == GST_VIDEO_FORMAT_RGBx || format == GST_VIDEO_FORMAT_BGRx) {
76 for (i = finfo->n_components; i < GST_VIDEO_MAX_COMPONENTS; i++) {
83 get_vulkan_rgb_format_swizzle_order (VkFormat format, gint * swizzle,
84 guint swizzle_count, guint offset)
86 const GstVulkanFormatInfo *finfo = gst_vulkan_format_get_info (format);
89 g_return_if_fail (finfo->flags & GST_VULKAN_FORMAT_FLAG_RGB);
90 g_return_if_fail (finfo->n_components <= swizzle_count);
92 for (i = 0; i < finfo->n_components; i++) {
93 swizzle[i] = offset + finfo->poffset[i];
95 for (i = finfo->n_components; i < swizzle_count; i++) {
100 /* given a swizzle index, produce an index such that:
102 * swizzle[idx[i]] == identity[i] where:
103 * - swizzle is the original swizzle
104 * - idx is the result
105 * - identity = {0, 1, 2,...}
106 * - unset fields are marked by -1
109 swizzle_identity_order (gint * swizzle, gint * idx)
113 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
117 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
118 if (swizzle[i] >= 0 && swizzle[i] < 4 && idx[swizzle[i]] == -1) {
130 matrix_debug (const Matrix4 * s)
132 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
134 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
136 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
138 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
143 matrix_to_float (const Matrix4 * m, float *ret)
147 for (i = 0; i < 4; i++) {
148 for (j = 0; j < 4; j++) {
149 ret[j * 4 + i] = m->dm[i][j];
155 matrix_set_identity (Matrix4 * m)
159 for (i = 0; i < 4; i++) {
160 for (j = 0; j < 4; j++) {
161 m->dm[i][j] = (i == j);
167 matrix_copy (Matrix4 * d, const Matrix4 * s)
171 for (i = 0; i < 4; i++)
172 for (j = 0; j < 4; j++)
173 d->dm[i][j] = s->dm[i][j];
176 /* Perform 4x4 matrix multiplication:
177 * - @dst@ = @a@ * @b@
178 * - @dst@ may be a pointer to @a@ andor @b@
181 matrix_multiply (Matrix4 * dst, Matrix4 * a, Matrix4 * b)
186 for (i = 0; i < 4; i++) {
187 for (j = 0; j < 4; j++) {
189 for (k = 0; k < 4; k++) {
190 x += a->dm[i][k] * b->dm[k][j];
195 matrix_copy (dst, &tmp);
200 matrix_invert (Matrix4 * d, Matrix4 * s)
206 matrix_set_identity (&tmp);
207 for (j = 0; j < 3; j++) {
208 for (i = 0; i < 3; i++) {
210 s->dm[(i + 1) % 3][(j + 1) % 3] * s->dm[(i + 2) % 3][(j + 2) % 3] -
211 s->dm[(i + 1) % 3][(j + 2) % 3] * s->dm[(i + 2) % 3][(j + 1) % 3];
215 tmp.dm[0][0] * s->dm[0][0] + tmp.dm[0][1] * s->dm[1][0] +
216 tmp.dm[0][2] * s->dm[2][0];
217 for (j = 0; j < 3; j++) {
218 for (i = 0; i < 3; i++) {
222 matrix_copy (d, &tmp);
226 matrix_offset_components (Matrix4 * m, double a1, double a2, double a3)
230 matrix_set_identity (&a);
235 matrix_multiply (m, &a, m);
239 matrix_scale_components (Matrix4 * m, double a1, double a2, double a3)
243 matrix_set_identity (&a);
247 matrix_multiply (m, &a, m);
251 matrix_YCbCr_to_RGB (Matrix4 * m, double Kr, double Kb)
253 double Kg = 1.0 - Kr - Kb;
256 {1., 0., 2 * (1 - Kr), 0.},
257 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
258 {1., 2 * (1 - Kb), 0., 0.},
263 matrix_multiply (m, &k, m);
268 GstVideoInfo in_info;
269 GstVideoInfo out_info;
271 Matrix4 to_RGB_matrix;
272 Matrix4 to_YUV_matrix;
273 Matrix4 convert_matrix;
277 convert_to_RGB (ConvertInfo * conv, Matrix4 * m)
279 GstVideoInfo *info = &conv->in_info;
282 const GstVideoFormatInfo *uinfo;
283 gint offset[4], scale[4], depth[4];
286 uinfo = gst_video_format_get_info (GST_VIDEO_INFO_FORMAT (info));
288 /* bring color components to [0..1.0] range */
289 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
292 for (i = 0; i < uinfo->n_components; i++)
293 depth[i] = (1 << uinfo->depth[i]) - 1;
295 matrix_offset_components (m, -offset[0] / (float) depth[0],
296 -offset[1] / (float) depth[1], -offset[2] / (float) depth[2]);
297 matrix_scale_components (m, depth[0] / ((float) scale[0]),
298 depth[1] / ((float) scale[1]), depth[2] / ((float) scale[2]));
299 GST_DEBUG ("to RGB scale/offset matrix");
303 if (GST_VIDEO_INFO_IS_YUV (info)) {
306 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
307 matrix_YCbCr_to_RGB (m, Kr, Kb);
308 GST_DEBUG ("to RGB matrix");
314 matrix_RGB_to_YCbCr (Matrix4 * m, double Kr, double Kb)
316 double Kg = 1.0 - Kr - Kb;
325 x = 1 / (2 * (1 - Kb));
326 k.dm[1][0] = -x * Kr;
327 k.dm[1][1] = -x * Kg;
328 k.dm[1][2] = x * (1 - Kb);
331 x = 1 / (2 * (1 - Kr));
332 k.dm[2][0] = x * (1 - Kr);
333 k.dm[2][1] = -x * Kg;
334 k.dm[2][2] = -x * Kb;
342 matrix_multiply (m, &k, m);
346 convert_to_YUV (ConvertInfo * conv, Matrix4 * m)
348 GstVideoInfo *info = &conv->out_info;
350 if (GST_VIDEO_INFO_IS_YUV (info)) {
353 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
354 matrix_RGB_to_YCbCr (m, Kr, Kb);
355 GST_DEBUG ("to YUV matrix");
360 const GstVideoFormatInfo *uinfo;
361 gint offset[4], scale[4], depth[4];
364 uinfo = gst_video_format_get_info (GST_VIDEO_INFO_FORMAT (info));
366 /* bring color components to nominal range */
367 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
370 for (i = 0; i < uinfo->n_components; i++)
371 depth[i] = (1 << uinfo->depth[i]) - 1;
373 matrix_scale_components (m, scale[0] / (float) depth[0],
374 scale[1] / (float) depth[1], scale[2] / (float) depth[2]);
375 matrix_offset_components (m, offset[0] / (float) depth[0],
376 offset[1] / (float) depth[1], offset[2] / (float) depth[2]);
377 GST_DEBUG ("to YUV scale/offset matrix");
384 matrix_RGB_to_XYZ (Matrix4 * dst, double Rx, double Ry, double Gx,
385 double Gy, double Bx, double By, double Wx, double Wy)
391 matrix_set_identity (&m);
395 m.dm[2][0] = (1.0 - Rx - Ry);
398 m.dm[2][1] = (1.0 - Gx - Gy);
401 m.dm[2][2] = (1.0 - Bx - By);
403 matrix_invert (&im, &m);
407 wz = (1.0 - Wx - Wy) / Wy;
409 sx = im.dm[0][0] * wx + im.dm[0][1] * wy + im.dm[0][2] * wz;
410 sy = im.dm[1][0] * wx + im.dm[1][1] * wy + im.dm[1][2] * wz;
411 sz = im.dm[2][0] * wx + im.dm[2][1] * wy + im.dm[2][2] * wz;
423 matrix_copy (dst, &m);
427 convert_primaries (ConvertInfo * conv)
429 gboolean same_matrix, same_primaries;
433 conv->in_info.colorimetry.matrix == conv->out_info.colorimetry.matrix;
435 conv->in_info.colorimetry.primaries ==
436 conv->out_info.colorimetry.primaries;
438 GST_DEBUG ("matrix %d -> %d (%d)", conv->in_info.colorimetry.matrix,
439 conv->out_info.colorimetry.matrix, same_matrix);
440 GST_DEBUG ("primaries %d -> %d (%d)", conv->in_info.colorimetry.primaries,
441 conv->out_info.colorimetry.primaries, same_primaries);
443 matrix_set_identity (&conv->convert_matrix);
445 if (!same_primaries) {
446 const GstVideoColorPrimariesInfo *pi;
448 pi = gst_video_color_primaries_get_info (conv->in_info.colorimetry.
450 matrix_RGB_to_XYZ (&p1, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx, pi->By,
452 GST_DEBUG ("to XYZ matrix");
454 GST_DEBUG ("current matrix");
455 matrix_multiply (&conv->convert_matrix, &conv->convert_matrix, &p1);
456 matrix_debug (&conv->convert_matrix);
458 pi = gst_video_color_primaries_get_info (conv->out_info.colorimetry.
460 matrix_RGB_to_XYZ (&p2, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx, pi->By,
462 matrix_invert (&p2, &p2);
463 GST_DEBUG ("to RGB matrix");
465 matrix_multiply (&conv->convert_matrix, &conv->convert_matrix, &p2);
466 GST_DEBUG ("current matrix");
467 matrix_debug (&conv->convert_matrix);
472 convert_info_new (GstVideoInfo * in_info, GstVideoInfo * out_info)
474 ConvertInfo *conv = g_new0 (ConvertInfo, 1);
476 matrix_set_identity (&conv->to_RGB_matrix);
477 matrix_set_identity (&conv->convert_matrix);
478 matrix_set_identity (&conv->to_YUV_matrix);
480 memcpy (&conv->in_info, in_info, sizeof (*in_info));
481 memcpy (&conv->out_info, out_info, sizeof (*out_info));
483 convert_to_RGB (conv, &conv->to_RGB_matrix);
484 /* by default videoconvert does not convert primaries
485 convert_primaries (conv); */
486 convert_to_YUV (conv, &conv->to_YUV_matrix);
492 video_format_to_reorder (GstVideoFormat v_format, gint * reorder,
496 case GST_VIDEO_FORMAT_RGBA:
497 case GST_VIDEO_FORMAT_RGBx:
498 case GST_VIDEO_FORMAT_BGRA:
499 case GST_VIDEO_FORMAT_BGRx:
500 case GST_VIDEO_FORMAT_ARGB:
501 case GST_VIDEO_FORMAT_xRGB:
502 case GST_VIDEO_FORMAT_ABGR:
503 case GST_VIDEO_FORMAT_xBGR:
504 case GST_VIDEO_FORMAT_AYUV:
505 get_rgb_format_swizzle_order (v_format, reorder);
507 case GST_VIDEO_FORMAT_UYVY:
510 reorder[2] = input ? 3 : 2;
513 case GST_VIDEO_FORMAT_YUY2:
517 reorder[3] = input ? 3 : 2;
519 case GST_VIDEO_FORMAT_NV12:
526 g_assert_not_reached ();
530 GST_TRACE ("swizzle: %u, %u, %u, %u", reorder[0], reorder[1], reorder[2],
535 finfo_get_plane_n_components (const GstVideoFormatInfo * finfo, guint plane)
537 guint n_components = 0, i;
539 switch (finfo->format) {
540 case GST_VIDEO_FORMAT_RGBx:
541 case GST_VIDEO_FORMAT_xRGB:
542 case GST_VIDEO_FORMAT_BGRx:
543 case GST_VIDEO_FORMAT_xBGR:
544 /* fixup spaced RGB formats as we treat the space as a normal alpha
546 return plane == 0 ? 4 : 0;
551 for (i = 0; i < finfo->n_components; i++) {
552 if (finfo->plane[i] == plane)
560 get_vulkan_format_swizzle_order (GstVideoFormat v_format,
561 VkFormat vk_format[GST_VIDEO_MAX_PLANES],
562 gint swizzle[GST_VIDEO_MAX_COMPONENTS])
564 const GstVideoFormatInfo *finfo;
565 int i, prev_in_i = 0;
567 finfo = gst_video_format_get_info (v_format);
568 for (i = 0; i < finfo->n_planes; i++) {
569 guint plane_components = finfo_get_plane_n_components (finfo, i);
570 get_vulkan_rgb_format_swizzle_order (vk_format[i],
571 &swizzle[prev_in_i], plane_components, prev_in_i);
572 prev_in_i += plane_components;
575 if (v_format == GST_VIDEO_FORMAT_YUY2 || v_format == GST_VIDEO_FORMAT_UYVY) {
576 /* Fixup these packed YUV formats as we use a two component format for
577 * a 4-component pixel and access two samples in the shader */
578 g_assert (swizzle[0] == 0);
579 g_assert (swizzle[1] == 1);
584 GST_TRACE ("%s: %i, %i, %i, %i", finfo->name, swizzle[0], swizzle[1],
585 swizzle[2], swizzle[3]);
589 calculate_reorder_indexes (GstVideoFormat in_format,
590 GstVulkanImageView * in_views[GST_VIDEO_MAX_COMPONENTS],
591 GstVideoFormat out_format,
592 GstVulkanImageView * out_views[GST_VIDEO_MAX_COMPONENTS],
593 int ret_in[GST_VIDEO_MAX_COMPONENTS], int ret_out[GST_VIDEO_MAX_COMPONENTS])
595 const GstVideoFormatInfo *in_finfo, *out_finfo;
596 VkFormat in_vk_formats[GST_VIDEO_MAX_COMPONENTS];
597 VkFormat out_vk_formats[GST_VIDEO_MAX_COMPONENTS];
598 int in_vk_order[GST_VIDEO_MAX_COMPONENTS] = { 0, };
599 int in_reorder[GST_VIDEO_MAX_COMPONENTS] = { 0, };
600 int out_vk_order[GST_VIDEO_MAX_COMPONENTS] = { 0, };
601 int out_reorder[GST_VIDEO_MAX_COMPONENTS] = { 0, };
602 int tmp[GST_VIDEO_MAX_PLANES] = { 0, };
605 in_finfo = gst_video_format_get_info (in_format);
606 out_finfo = gst_video_format_get_info (out_format);
608 for (i = 0; i < in_finfo->n_planes; i++)
609 in_vk_formats[i] = in_views[i]->image->create_info.format;
610 for (i = 0; i < out_finfo->n_planes; i++)
611 out_vk_formats[i] = out_views[i]->image->create_info.format;
613 get_vulkan_format_swizzle_order (in_format, in_vk_formats, in_vk_order);
614 video_format_to_reorder (in_format, in_reorder, TRUE);
616 video_format_to_reorder (out_format, out_reorder, FALSE);
617 get_vulkan_format_swizzle_order (out_format, out_vk_formats, out_vk_order);
619 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++)
620 tmp[i] = out_vk_order[out_reorder[i]];
621 /* find the identity order for RGBA->$format */
622 GST_TRACE ("pre-invert: %u, %u, %u, %u", tmp[0], tmp[1], tmp[2], tmp[3]);
623 if (out_format == GST_VIDEO_FORMAT_YUY2
624 || out_format == GST_VIDEO_FORMAT_UYVY) {
625 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++)
628 swizzle_identity_order (tmp, ret_out);
631 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++)
632 ret_in[i] = in_reorder[in_vk_order[i]];
633 GST_TRACE ("in reorder: %u, %u, %u, %u", ret_in[0], ret_in[1], ret_in[2],
635 GST_TRACE ("out reorder: %u, %u, %u, %u", ret_out[0], ret_out[1], ret_out[2],
646 swizzle_rgb_create_uniform_memory (GstVulkanColorConvert * conv,
647 shader_info * sinfo, GstVulkanImageView ** in_views,
648 GstVulkanImageView ** out_views)
650 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (conv);
652 if (sinfo->user_data) {
653 return gst_memory_ref (sinfo->user_data);
655 struct RGBUpdateData data = { 0, };
660 gst_vulkan_buffer_memory_alloc (vfilter->device,
661 sizeof (struct RGBUpdateData),
662 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
663 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
664 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
666 calculate_reorder_indexes (GST_VIDEO_INFO_FORMAT (&conv->quad->in_info),
667 in_views, GST_VIDEO_INFO_FORMAT (&conv->quad->out_info),
668 out_views, data.in_reorder, data.out_reorder);
670 if (!gst_memory_map (uniforms, &map_info, GST_MAP_WRITE)) {
671 gst_memory_unref (uniforms);
674 memcpy (map_info.data, &data, sizeof (data));
675 gst_memory_unmap (uniforms, &map_info);
677 sinfo->user_data = gst_memory_ref (uniforms);
694 /* each member is aligned on 4x previous component size boundaries */
696 struct ColorMatrices matrices;
700 yuv_to_rgb_create_uniform_memory (GstVulkanColorConvert * conv,
701 shader_info * sinfo, GstVulkanImageView ** in_views,
702 GstVulkanImageView ** out_views)
704 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (conv);
706 if (sinfo->user_data) {
707 return gst_memory_ref (sinfo->user_data);
709 struct YUVUpdateData data;
710 ConvertInfo *conv_info;
715 gst_vulkan_buffer_memory_alloc (vfilter->device,
716 sizeof (struct YUVUpdateData),
717 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
718 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
719 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
721 calculate_reorder_indexes (GST_VIDEO_INFO_FORMAT (&conv->quad->in_info),
722 in_views, GST_VIDEO_INFO_FORMAT (&conv->quad->out_info),
723 out_views, data.in_reorder, data.out_reorder);
725 conv_info = convert_info_new (&conv->quad->in_info, &conv->quad->out_info);
726 matrix_to_float (&conv_info->to_RGB_matrix, data.matrices.to_RGB);
727 matrix_to_float (&conv_info->convert_matrix, data.matrices.primaries);
728 matrix_to_float (&conv_info->to_YUV_matrix, data.matrices.to_YUV);
729 /* FIXME: keep this around */
732 data.tex_size[0] = GST_VIDEO_INFO_WIDTH (&conv->quad->in_info);
733 data.tex_size[1] = GST_VIDEO_INFO_HEIGHT (&conv->quad->in_info);
735 if (!gst_memory_map (uniforms, &map_info, GST_MAP_WRITE)) {
736 gst_memory_unref (uniforms);
739 memcpy (map_info.data, &data, sizeof (data));
740 gst_memory_unmap (uniforms, &map_info);
742 sinfo->user_data = gst_memory_ref (uniforms);
749 unref_memory_if_set (shader_info * sinfo)
751 if (sinfo->user_data)
752 gst_memory_unref (sinfo->user_data);
753 sinfo->user_data = NULL;
756 static gboolean gst_vulkan_color_convert_start (GstBaseTransform * bt);
757 static gboolean gst_vulkan_color_convert_stop (GstBaseTransform * bt);
759 static GstCaps *gst_vulkan_color_convert_transform_caps (GstBaseTransform * bt,
760 GstPadDirection direction, GstCaps * caps, GstCaps * filter);
761 static GstFlowReturn gst_vulkan_color_convert_transform (GstBaseTransform * bt,
762 GstBuffer * inbuf, GstBuffer * outbuf);
763 static gboolean gst_vulkan_color_convert_set_caps (GstBaseTransform * bt,
764 GstCaps * in_caps, GstCaps * out_caps);
766 static GstStaticPadTemplate gst_vulkan_sink_template =
767 GST_STATIC_PAD_TEMPLATE ("sink",
770 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
771 (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE,
772 "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, NV12 }")));
774 static GstStaticPadTemplate gst_vulkan_src_template =
775 GST_STATIC_PAD_TEMPLATE ("src",
778 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
779 (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE,
780 "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, NV12 }")));
793 /* static guint gst_vulkan_color_convert_signals[LAST_SIGNAL] = { 0 }; */
795 #define gst_vulkan_color_convert_parent_class parent_class
796 G_DEFINE_TYPE_WITH_CODE (GstVulkanColorConvert, gst_vulkan_color_convert,
797 GST_TYPE_VULKAN_VIDEO_FILTER,
798 GST_DEBUG_CATEGORY_INIT (gst_debug_vulkan_color_convert,
799 "vulkancolorconvert", 0, "Vulkan Color Convert"));
803 GstVideoFormat format;
805 gsize from_frag_size;
811 fill_shader_info (void)
813 GstVideoFormat rgbs[] = { GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_ARGB,
814 GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_RGBx,
815 GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_xBGR
817 struct yuv_info yuvs[] = {
818 {GST_VIDEO_FORMAT_AYUV, ayuv_to_rgb_frag, ayuv_to_rgb_frag_size,
819 rgb_to_ayuv_frag, rgb_to_ayuv_frag_size},
820 {GST_VIDEO_FORMAT_YUY2, yuy2_to_rgb_frag, yuy2_to_rgb_frag_size,
821 rgb_to_yuy2_frag, rgb_to_yuy2_frag_size},
822 /* {GST_VIDEO_FORMAT_UYVY, yuy2_to_rgb_frag, yuy2_to_rgb_frag_size,
823 rgb_to_yuy2_frag, rgb_to_yuy2_frag_size},*/
824 {GST_VIDEO_FORMAT_NV12, nv12_to_rgb_frag, nv12_to_rgb_frag_size,
825 rgb_to_nv12_frag, rgb_to_nv12_frag_size},
830 /* standard RGB with alpha conversion all components are copied */
832 for (i = 0; i < G_N_ELEMENTS (rgbs); i++) {
833 const GstVideoFormatInfo *from_finfo = gst_video_format_get_info (rgbs[i]);
835 for (j = 0; j < G_N_ELEMENTS (rgbs); j++) {
836 const GstVideoFormatInfo *to_finfo = gst_video_format_get_info (rgbs[j]);
837 gboolean clobber_alpha = FALSE;
839 GST_TRACE ("Initializing info for %s -> %s", from_finfo->name, to_finfo->name);
841 /* copying to an RGBx variant means we can store whatever we like in the 'x'
842 * component we choose to copy the alpha component like a standard RGBA->RGBA
844 * Copying from an rgbx to a rgba format means we need to reset the
846 clobber_alpha = !GST_VIDEO_FORMAT_INFO_HAS_ALPHA (from_finfo) && GST_VIDEO_FORMAT_INFO_HAS_ALPHA (to_finfo);
847 shader_infos[info_i++] = (shader_info) {
850 .cmd_create_uniform = swizzle_rgb_create_uniform_memory,
851 .frag_code = clobber_alpha ? swizzle_and_clobber_alpha_frag : swizzle_frag,
852 .frag_size = clobber_alpha ? swizzle_and_clobber_alpha_frag_size : swizzle_frag_size,
853 .uniform_size = sizeof (struct RGBUpdateData),
854 .notify = (GDestroyNotify) unref_memory_if_set,
859 for (j = 0; j < G_N_ELEMENTS (yuvs); j++) {
860 const GstVideoFormatInfo *to_finfo = gst_video_format_get_info (yuvs[j].format);
861 GST_TRACE ("Initializing info for %s -> %s", from_finfo->name, to_finfo->name);
862 shader_infos[info_i++] = (shader_info) {
864 .to = yuvs[j].format,
865 .cmd_create_uniform = yuv_to_rgb_create_uniform_memory,
866 .frag_code = yuvs[j].to_frag,
867 .frag_size = yuvs[j].to_frag_size,
868 .uniform_size = sizeof(struct YUVUpdateData),
869 .notify = (GDestroyNotify) unref_memory_if_set,
872 GST_TRACE ("Initializing info for %s -> %s", to_finfo->name, from_finfo->name);
873 shader_infos[info_i++] = (shader_info) {
874 .from = yuvs[j].format,
876 .cmd_create_uniform = yuv_to_rgb_create_uniform_memory,
877 .frag_code = yuvs[j].from_frag,
878 .frag_size = yuvs[j].from_frag_size,
879 .uniform_size = sizeof(struct YUVUpdateData),
880 .notify = (GDestroyNotify) unref_memory_if_set,
886 GST_TRACE ("initialized %u formats", info_i);
888 g_assert (info_i == N_SHADER_INFO);
892 gst_vulkan_color_convert_class_init (GstVulkanColorConvertClass * klass)
894 GstElementClass *gstelement_class;
895 GstBaseTransformClass *gstbasetransform_class;
897 gstelement_class = (GstElementClass *) klass;
898 gstbasetransform_class = (GstBaseTransformClass *) klass;
900 gst_element_class_set_metadata (gstelement_class, "Vulkan Uploader",
901 "Filter/Video/Convert", "A Vulkan Color Convert",
902 "Matthew Waters <matthew@centricular.com>");
904 gst_element_class_add_static_pad_template (gstelement_class,
905 &gst_vulkan_sink_template);
906 gst_element_class_add_static_pad_template (gstelement_class,
907 &gst_vulkan_src_template);
909 gstbasetransform_class->start =
910 GST_DEBUG_FUNCPTR (gst_vulkan_color_convert_start);
911 gstbasetransform_class->stop =
912 GST_DEBUG_FUNCPTR (gst_vulkan_color_convert_stop);
913 gstbasetransform_class->transform_caps =
914 gst_vulkan_color_convert_transform_caps;
915 gstbasetransform_class->set_caps = gst_vulkan_color_convert_set_caps;
916 gstbasetransform_class->transform = gst_vulkan_color_convert_transform;
922 gst_vulkan_color_convert_init (GstVulkanColorConvert * conv)
927 _init_value_string_list (GValue * list, ...)
929 GValue item = G_VALUE_INIT;
933 g_value_init (list, GST_TYPE_LIST);
935 va_start (args, list);
936 while ((str = va_arg (args, gchar *))) {
937 g_value_init (&item, G_TYPE_STRING);
938 g_value_set_string (&item, str);
940 gst_value_list_append_value (list, &item);
941 g_value_unset (&item);
947 _append_value_string_list (GValue * list, ...)
949 GValue item = G_VALUE_INIT;
953 va_start (args, list);
954 while ((str = va_arg (args, gchar *))) {
955 g_value_init (&item, G_TYPE_STRING);
956 g_value_set_string (&item, str);
958 gst_value_list_append_value (list, &item);
959 g_value_unset (&item);
965 _init_supported_formats (GstVulkanDevice * device, gboolean output,
966 GValue * supported_formats)
968 /* Assume if device == NULL that we don't have a Vulkan device and can
969 * do the conversion */
971 /* Always supported input and output formats */
972 _init_value_string_list (supported_formats, "RGBA", "RGB", "RGBx", "BGR",
973 "BGRx", "BGRA", "xRGB", "xBGR", "ARGB", "ABGR", NULL);
975 _append_value_string_list (supported_formats, "AYUV", "YUY2", /*"UYVY", */
979 /* copies the given caps */
981 gst_vulkan_color_convert_transform_format_info (GstVulkanDevice * device,
982 gboolean output, GstCaps * caps)
988 GValue supported_formats = G_VALUE_INIT;
989 GValue rgb_formats = G_VALUE_INIT;
990 GValue supported_rgb_formats = G_VALUE_INIT;
992 /* There are effectively two modes here with the RGB/YUV transition:
993 * 1. There is a RGB-like format as input and we can transform to YUV or,
994 * 2. No RGB-like format as input so we can only transform to RGB-like formats
996 * We also filter down the list of formats depending on what the OpenGL
997 * device supports (when provided).
1000 _init_value_string_list (&rgb_formats, "RGBA", "ARGB", "BGRA", "ABGR", "RGBx",
1001 "xRGB", "BGRx", "xBGR", "RGB", "BGR", "ARGB64", NULL);
1002 _init_supported_formats (device, output, &supported_formats);
1003 gst_value_intersect (&supported_rgb_formats, &rgb_formats,
1004 &supported_formats);
1006 res = gst_caps_new_empty ();
1008 n = gst_caps_get_size (caps);
1009 for (i = 0; i < n; i++) {
1010 const GValue *format;
1012 st = gst_caps_get_structure (caps, i);
1013 f = gst_caps_get_features (caps, i);
1015 format = gst_structure_get_value (st, "format");
1016 st = gst_structure_copy (st);
1017 if (GST_VALUE_HOLDS_LIST (format)) {
1018 gboolean have_rgb_formats = FALSE;
1019 GValue passthrough_formats = G_VALUE_INIT;
1022 g_value_init (&passthrough_formats, GST_TYPE_LIST);
1023 len = gst_value_list_get_size (format);
1024 for (j = 0; j < len; j++) {
1027 val = gst_value_list_get_value (format, j);
1028 if (G_VALUE_HOLDS_STRING (val)) {
1029 const gchar *format_str = g_value_get_string (val);
1030 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1031 const GstVideoFormatInfo *t_info =
1032 gst_video_format_get_info (v_format);
1033 if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) & (GST_VIDEO_FORMAT_FLAG_YUV
1034 | GST_VIDEO_FORMAT_FLAG_GRAY)) {
1035 gst_value_list_append_value (&passthrough_formats, val);
1036 } else if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) &
1037 GST_VIDEO_FORMAT_FLAG_RGB) {
1038 have_rgb_formats = TRUE;
1043 if (have_rgb_formats) {
1044 gst_structure_set_value (st, "format", &supported_formats);
1046 /* add passthrough structure, then the rgb conversion structure */
1047 gst_structure_set_value (st, "format", &passthrough_formats);
1048 gst_caps_append_structure_full (res, gst_structure_copy (st),
1049 gst_caps_features_copy (f));
1050 gst_structure_set_value (st, "format", &supported_rgb_formats);
1052 g_value_unset (&passthrough_formats);
1053 } else if (G_VALUE_HOLDS_STRING (format)) {
1054 const gchar *format_str = g_value_get_string (format);
1055 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1056 const GstVideoFormatInfo *t_info = gst_video_format_get_info (v_format);
1057 if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) & (GST_VIDEO_FORMAT_FLAG_YUV |
1058 GST_VIDEO_FORMAT_FLAG_GRAY)) {
1059 /* add passthrough structure, then the rgb conversion structure */
1060 gst_structure_set_value (st, "format", format);
1061 gst_caps_append_structure_full (res, gst_structure_copy (st),
1062 gst_caps_features_copy (f));
1063 gst_structure_set_value (st, "format", &supported_rgb_formats);
1065 gst_structure_set_value (st, "format", &supported_formats);
1068 gst_structure_remove_fields (st, "colorimetry", "chroma-site", NULL);
1070 gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
1073 g_value_unset (&supported_formats);
1074 g_value_unset (&rgb_formats);
1075 g_value_unset (&supported_rgb_formats);
1081 gst_vulkan_color_convert_transform_caps (GstBaseTransform * bt,
1082 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1084 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (bt);
1086 caps = gst_vulkan_color_convert_transform_format_info (vfilter->device,
1087 direction == GST_PAD_SRC, caps);
1092 tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1093 gst_caps_unref (caps);
1101 gst_vulkan_color_convert_start (GstBaseTransform * bt)
1103 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1104 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (conv);
1106 if (!GST_BASE_TRANSFORM_CLASS (parent_class)->start (bt))
1109 conv->quad = gst_vulkan_full_screen_quad_new (vfilter->queue);
1115 gst_vulkan_color_convert_set_caps (GstBaseTransform * bt, GstCaps * in_caps,
1118 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (bt);
1119 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1120 GstVulkanHandle *vert, *frag;
1123 if (!GST_BASE_TRANSFORM_CLASS (parent_class)->set_caps (bt, in_caps,
1127 if (!gst_vulkan_full_screen_quad_set_info (conv->quad, &vfilter->in_info,
1128 &vfilter->out_info))
1131 if (conv->current_shader) {
1132 conv->current_shader->notify (conv->current_shader);
1133 conv->current_shader = NULL;
1136 for (i = 0; i < G_N_ELEMENTS (shader_infos); i++) {
1137 if (shader_infos[i].from != GST_VIDEO_INFO_FORMAT (&vfilter->in_info))
1139 if (shader_infos[i].to != GST_VIDEO_INFO_FORMAT (&vfilter->out_info))
1142 GST_INFO_OBJECT (conv,
1143 "Found compatible conversion information from %s to %s",
1144 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&vfilter->in_info)),
1145 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
1146 (&vfilter->out_info)));
1147 conv->current_shader = &shader_infos[i];
1150 if (!conv->current_shader) {
1151 GST_ERROR_OBJECT (conv, "Could not find a conversion info for the "
1152 "requested formats");
1157 _vk_create_shader (vfilter->device, identity_vert, identity_vert_size,
1162 _vk_create_shader (vfilter->device, conv->current_shader->frag_code,
1163 conv->current_shader->frag_size, NULL))) {
1164 gst_vulkan_handle_unref (vert);
1168 if (!gst_vulkan_full_screen_quad_set_shaders (conv->quad, vert, frag)) {
1169 gst_vulkan_handle_unref (vert);
1170 gst_vulkan_handle_unref (frag);
1174 gst_vulkan_handle_unref (vert);
1175 gst_vulkan_handle_unref (frag);
1181 gst_vulkan_color_convert_stop (GstBaseTransform * bt)
1183 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1185 if (conv->current_shader) {
1186 conv->current_shader->notify (conv->current_shader);
1187 conv->current_shader = NULL;
1190 gst_clear_object (&conv->quad);
1192 return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (bt);
1195 static GstFlowReturn
1196 gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
1199 GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
1200 GstVulkanVideoFilter *vfilter = GST_VULKAN_VIDEO_FILTER (bt);
1201 GstVulkanImageView *in_img_views[GST_VIDEO_MAX_PLANES] = { NULL, };
1202 GstVulkanImageMemory *render_img_mems[GST_VIDEO_MAX_PLANES] = { NULL, };
1203 GstVulkanImageView *render_img_views[GST_VIDEO_MAX_PLANES] = { NULL, };
1204 GstVulkanImageMemory *out_img_mems[GST_VIDEO_MAX_PLANES] = { NULL, };
1205 GstBuffer *render_buf = NULL;
1206 GstVulkanFence *fence = NULL;
1207 GstVulkanCommandBuffer *cmd_buf;
1208 GError *error = NULL;
1212 fence = gst_vulkan_device_create_fence (vfilter->device, &error);
1216 if (!gst_vulkan_full_screen_quad_set_input_buffer (conv->quad, inbuf, &error))
1219 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->in_info); i++) {
1220 GstMemory *img_mem = gst_buffer_peek_memory (inbuf, i);
1221 if (!gst_is_vulkan_image_memory (img_mem)) {
1222 g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
1223 "Input memory must be a GstVulkanImageMemory");
1227 get_or_create_image_view ((GstVulkanImageMemory *) img_mem);
1228 gst_vulkan_trash_list_add (conv->quad->trash_list,
1229 gst_vulkan_trash_list_acquire (conv->quad->trash_list, fence,
1230 gst_vulkan_trash_mini_object_unref,
1231 (GstMiniObject *) in_img_views[i]));
1235 gboolean need_render_buf = FALSE;
1237 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->out_info); i++) {
1238 GstMemory *mem = gst_buffer_peek_memory (outbuf, i);
1239 if (!gst_is_vulkan_image_memory (mem)) {
1240 g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
1241 "Output memory must be a GstVulkanImageMemory");
1244 out_img_mems[i] = (GstVulkanImageMemory *) mem;
1246 if (GST_VIDEO_INFO_WIDTH (&conv->quad->out_info) ==
1247 GST_VIDEO_INFO_COMP_WIDTH (&conv->quad->out_info, i)
1248 && GST_VIDEO_INFO_HEIGHT (&conv->quad->out_info) ==
1249 GST_VIDEO_INFO_COMP_HEIGHT (&conv->quad->out_info, i)) {
1250 render_img_mems[i] = out_img_mems[i];
1251 GST_LOG_OBJECT (conv, "using original output memory %p for plane %u",
1252 out_img_mems[i], i);
1254 /* we need a scratch buffer because framebuffers can only output to
1255 * attachments of at least the same size which means no sub-sampled
1257 VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
1262 gst_vulkan_format_from_video_info (&conv->quad->out_info, i);
1264 mem = gst_vulkan_image_memory_alloc (vfilter->device,
1265 vk_format, GST_VIDEO_INFO_WIDTH (&conv->quad->out_info),
1266 GST_VIDEO_INFO_HEIGHT (&conv->quad->out_info), tiling,
1267 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1268 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1269 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
1270 render_img_mems[i] = (GstVulkanImageMemory *) mem;
1271 need_render_buf = TRUE;
1272 GST_LOG_OBJECT (conv, "using replacement output memory %p for plane %u",
1277 if (need_render_buf) {
1278 render_buf = gst_buffer_new ();
1279 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->out_info); i++) {
1280 gst_buffer_append_memory (render_buf,
1281 gst_memory_ref ((GstMemory *) render_img_mems[i]));
1283 gst_vulkan_trash_list_add (conv->quad->trash_list,
1284 gst_vulkan_trash_list_acquire (conv->quad->trash_list, fence,
1285 gst_vulkan_trash_mini_object_unref,
1286 (GstMiniObject *) render_buf));
1288 render_buf = outbuf;
1291 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&conv->quad->out_info); i++) {
1292 GstMemory *img_mem = gst_buffer_peek_memory (render_buf, i);
1293 if (!gst_is_vulkan_image_memory (img_mem)) {
1294 g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
1295 "Input memory must be a GstVulkanImageMemory");
1298 render_img_views[i] =
1299 get_or_create_image_view ((GstVulkanImageMemory *) img_mem);
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;