vkcolorconvert: add support for RGB<->NV12
authorMatthew Waters <matthew@centricular.com>
Wed, 19 Jun 2019 15:39:53 +0000 (01:39 +1000)
committerMatthew Waters <matthew@centricular.com>
Wed, 19 Jun 2019 15:41:56 +0000 (01:41 +1000)
ext/vulkan/shaders/meson.build
ext/vulkan/shaders/nv12_to_rgb.frag [new file with mode: 0644]
ext/vulkan/shaders/rgb_to_nv12.frag [new file with mode: 0644]
ext/vulkan/shaders/upsample_nv12.glsl [new file with mode: 0644]
ext/vulkan/vkcolorconvert.c
ext/vulkan/vkfullscreenrender.c

index ae92a26..fdae040 100644 (file)
@@ -8,6 +8,8 @@ gst_vulkan_shader_sources = [
   'rgb_to_yuy2.frag',
   'ayuv_to_rgb.frag',
   'rgb_to_ayuv.frag',
+  'nv12_to_rgb.frag',
+  'rgb_to_nv12.frag',
 ]
 
 bin2array = find_program('bin2array.py')
diff --git a/ext/vulkan/shaders/nv12_to_rgb.frag b/ext/vulkan/shaders/nv12_to_rgb.frag
new file mode 100644 (file)
index 0000000..09e389c
--- /dev/null
@@ -0,0 +1,26 @@
+#version 450 core
+
+#include "color_convert_generic.glsl"
+#include "upsample_nv12.glsl"
+#include "swizzle.glsl"
+
+layout(location = 0) in vec2 inTexCoord;
+
+layout(set = 0, binding = 0) uniform sampler2D inTexture0;
+layout(set = 0, binding = 1) uniform sampler2D inTexture1;
+layout(set = 0, binding = 2) uniform reorder {
+  ivec4 in_reorder_idx;
+  ivec4 out_reorder_idx;
+  ivec2 texSize;
+  ColorMatrices matrices;
+};
+
+layout(location = 0) out vec4 outColor0;
+
+void main()
+{
+  vec3 yuv = upsample_NV12 (inTexture0, inTexture1, inTexCoord, in_reorder_idx);
+  vec4 rgba = vec4(1.0);
+  rgba.rgb = color_convert_texel (yuv, matrices);
+  outColor0 = swizzle(rgba, out_reorder_idx);
+}
diff --git a/ext/vulkan/shaders/rgb_to_nv12.frag b/ext/vulkan/shaders/rgb_to_nv12.frag
new file mode 100644 (file)
index 0000000..4c574b3
--- /dev/null
@@ -0,0 +1,29 @@
+#version 450 core
+
+#include "color_convert_generic.glsl"
+#include "swizzle.glsl"
+
+layout(location = 0) in vec2 inTexCoord;
+
+layout(set = 0, binding = 0) uniform sampler2D inTexture0;
+layout(set = 0, binding = 1) uniform reorder {
+  ivec4 in_reorder_idx;
+  ivec4 out_reorder_idx;
+  ivec2 texSize;
+  ColorMatrices matrices;
+};
+
+layout(location = 0) out vec4 outColor0;
+layout(location = 1) out vec4 outColor1;
+
+void main()
+{
+  vec4 texel = swizzle (texture(inTexture0, inTexCoord), in_reorder_idx);
+  vec4 uv_texel = swizzle (texture(inTexture0, inTexCoord * vec2(2.0)), in_reorder_idx);
+  vec3 yuv1 = color_convert_texel (texel.rgb, matrices);
+  vec3 yuv2 = color_convert_texel (uv_texel.rgb, matrices);
+  vec3 yuv = vec3(yuv1.x, yuv2.y, yuv2.z);
+
+  outColor0 = vec4(yuv[out_reorder_idx[0]], 0.0, 0.0, 1.0);
+  outColor1 = vec4(yuv[out_reorder_idx[1]], yuv[out_reorder_idx[2]], 0.0, 1.0);
+}
diff --git a/ext/vulkan/shaders/upsample_nv12.glsl b/ext/vulkan/shaders/upsample_nv12.glsl
new file mode 100644 (file)
index 0000000..7ca23fc
--- /dev/null
@@ -0,0 +1,10 @@
+#include "swizzle.glsl"
+
+vec3 upsample_NV12(in sampler2D Ytex, in sampler2D UVtex, in vec2 texCoord, in ivec4 inReorderIdx)
+{
+  vec3 yuv;
+  yuv.x = texture(Ytex, texCoord).x;
+  yuv.yz = texture(UVtex, texCoord).xy;
+
+  return swizzle(yuv, inReorderIdx.xyz);
+}
index 19fa5c5..bceaca3 100644 (file)
 #include "shaders/swizzle_and_clobber_alpha.frag.h"
 #include "shaders/yuy2_to_rgb.frag.h"
 #include "shaders/ayuv_to_rgb.frag.h"
+#include "shaders/nv12_to_rgb.frag.h"
 #include "shaders/rgb_to_ayuv.frag.h"
 #include "shaders/rgb_to_yuy2.frag.h"
+#include "shaders/rgb_to_nv12.frag.h"
 
 GST_DEBUG_CATEGORY (gst_debug_vulkan_color_convert);
 #define GST_CAT_DEFAULT gst_debug_vulkan_color_convert
 
-#define N_SHADER_INFO (8*14)
+#define N_SHADER_INFO (8*16)
 static shader_info shader_infos[N_SHADER_INFO];
 
 #define PUSH_CONSTANT_RANGE_NULL_INIT (VkPushConstantRange) { \
@@ -492,23 +494,26 @@ convert_info_new (GstVideoInfo * in_info, GstVideoInfo * out_info)
 }
 
 static void
-update_descriptor_set (GstVulkanColorConvert * conv, VkImageView view)
+update_descriptor_set (GstVulkanColorConvert * conv, VkImageView * views,
+    guint n_views)
 {
   GstVulkanFullScreenRender *render = GST_VULKAN_FULL_SCREEN_RENDER (conv);
   VkDescriptorBufferInfo buffer_info;
+  VkDescriptorImageInfo image_info[GST_VIDEO_MAX_PLANES];
   VkWriteDescriptorSet writes[5];
   guint i = 0;
 
-  /* *INDENT-OFF* */
-  VkDescriptorImageInfo image_info = {
-      .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
-      .imageView = view,
-      .sampler = conv->sampler
-  };
-  /* *INDENT-ON* */
-
   for (; i < GST_VIDEO_INFO_N_PLANES (&render->in_info); i++) {
     /* *INDENT-OFF* */
+    image_info[i] = (VkDescriptorImageInfo) {
+        .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+        .imageView = views[i],
+        .sampler = conv->sampler
+    };
+
+    g_assert (i < n_views);
+    g_assert (i < GST_VIDEO_MAX_PLANES);
+
     writes[i] = (VkWriteDescriptorSet) {
         .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
         .pNext = NULL,
@@ -517,7 +522,7 @@ update_descriptor_set (GstVulkanColorConvert * conv, VkImageView view)
         .dstArrayElement = 0,
         .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
         .descriptorCount = 1,
-        .pImageInfo = &image_info
+        .pImageInfo = &image_info[i]
     };
     /* *INDENT-ON* */
   }
@@ -574,6 +579,12 @@ video_format_to_reorder (GstVideoFormat v_format, gint * reorder,
       reorder[2] = 0;
       reorder[3] = input ? 3 : 2;
       break;
+    case GST_VIDEO_FORMAT_NV12:
+      reorder[0] = 0;
+      reorder[1] = 1;
+      reorder[2] = 2;
+      reorder[3] = 0;
+      break;
     default:
       g_assert_not_reached ();
       break;
@@ -703,7 +714,7 @@ swizzle_rgb_update_command_state (GstVulkanColorConvert * conv,
   vkCmdPushConstants (cmd, render->pipeline_layout,
       VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof (reorder),
       (const void *) reorder);
-  update_descriptor_set (conv, in_mems[0]->view);
+  update_descriptor_set (conv, &in_mems[0]->view, 1);
   vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
       render->pipeline_layout, 0, 1, &conv->descriptor_set, 0, NULL);
 
@@ -738,6 +749,8 @@ yuv_to_rgb_update_command_state (GstVulkanColorConvert * conv,
     struct YUVUpdateData data;
     ConvertInfo *conv_info;
     GstMapInfo map_info;
+    VkImageView views[GST_VIDEO_MAX_PLANES];
+    int i;
 
     calculate_reorder_indexes (GST_VIDEO_INFO_FORMAT (&render->in_info),
         in_mems, GST_VIDEO_INFO_FORMAT (&render->out_info),
@@ -759,7 +772,11 @@ yuv_to_rgb_update_command_state (GstVulkanColorConvert * conv,
     memcpy (map_info.data, &data, sizeof (data));
     gst_memory_unmap (conv->uniform, &map_info);
 
-    update_descriptor_set (conv, in_mems[0]->view);
+    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->in_info); i++)
+      views[i] = in_mems[i]->view;
+
+    update_descriptor_set (conv, views,
+        GST_VIDEO_INFO_N_PLANES (&render->in_info));
     sinfo->user_data = GINT_TO_POINTER (1);
   }
   vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -806,7 +823,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE,
-            "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, UYVY }")));
+            "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, UYVY, NV12 }")));
 
 static GstStaticPadTemplate gst_vulkan_src_template =
 GST_STATIC_PAD_TEMPLATE ("src",
@@ -814,7 +831,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE,
-            "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, UYVY }")));
+            "{ BGRA, RGBA, ABGR, ARGB, BGRx, RGBx, xBGR, xRGB, AYUV, YUY2, UYVY, NV12 }")));
 
 enum
 {
@@ -858,6 +875,8 @@ fill_shader_info (void)
         rgb_to_yuy2_frag, rgb_to_yuy2_frag_size},
     {GST_VIDEO_FORMAT_UYVY, yuy2_to_rgb_frag, yuy2_to_rgb_frag_size,
         rgb_to_yuy2_frag, rgb_to_yuy2_frag_size},
+    {GST_VIDEO_FORMAT_NV12, nv12_to_rgb_frag, nv12_to_rgb_frag_size,
+        rgb_to_nv12_frag, rgb_to_nv12_frag_size},
   };
   guint info_i = 0;
   guint i, j;
@@ -1028,7 +1047,8 @@ _init_supported_formats (GstVulkanDevice * device, gboolean output,
   _init_value_string_list (supported_formats, "RGBA", "RGB", "RGBx", "BGR",
       "BGRx", "BGRA", "xRGB", "xBGR", "ARGB", "ABGR", NULL);
 
-  _append_value_string_list (supported_formats, "AYUV", "YUY2", "UYVY", NULL);
+  _append_value_string_list (supported_formats, "AYUV", "YUY2", "UYVY", "NV12",
+      NULL);
 }
 
 /* copies the given caps */
@@ -1285,7 +1305,7 @@ static VkAttachmentReference
   VkAttachmentReference *attachments;
   int i;
 
-  *n_attachments = GST_VIDEO_INFO_N_PLANES (&render->in_info);
+  *n_attachments = GST_VIDEO_INFO_N_PLANES (&render->out_info);
   attachments = g_new0 (VkAttachmentReference, *n_attachments);
 
   for (i = 0; i < *n_attachments; i++) {
@@ -1307,7 +1327,7 @@ static VkAttachmentDescription
   VkAttachmentDescription *color_attachments;
   int i;
 
-  *n_descriptions = GST_VIDEO_INFO_N_PLANES (&render->in_info);
+  *n_descriptions = GST_VIDEO_INFO_N_PLANES (&render->out_info);
   color_attachments = g_new0 (VkAttachmentDescription, *n_descriptions);
   for (i = 0; i < *n_descriptions; i++) {
     /* *INDENT-OFF* */
@@ -1637,7 +1657,8 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
 {
   GstVulkanFullScreenRender *render = GST_VULKAN_FULL_SCREEN_RENDER (bt);
   GstVulkanColorConvert *conv = GST_VULKAN_COLOR_CONVERT (bt);
-  GstVulkanImageMemory *in_img_mems[4] = { NULL, };
+  GstVulkanImageMemory *in_img_mems[GST_VIDEO_MAX_PLANES] = { NULL, };
+  GstVulkanImageMemory *render_img_mems[GST_VIDEO_MAX_PLANES] = { NULL, };
   GstVulkanImageMemory *out_img_mems[4] = { NULL, };
   GstVulkanFence *fence = NULL;
   VkFramebuffer framebuffer;
@@ -1675,20 +1696,6 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
   if (!(cmd = gst_vulkan_command_pool_create (conv->cmd_pool, &error)))
     goto error;
 
-  {
-    VkImageView attachments[4] = { 0, };
-    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->out_info); i++) {
-      attachments[i] = out_img_mems[i]->view;
-    }
-
-    if (!(framebuffer = _create_framebuffer (conv,
-                GST_VIDEO_INFO_N_PLANES (&render->out_info), attachments))) {
-      g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
-          "Failed to create framebuffer");
-      goto error;
-    }
-  }
-
   fence = gst_vulkan_fence_new (render->device, 0, &error);
   if (!fence)
     goto error;
@@ -1738,40 +1745,175 @@ gst_vulkan_color_convert_transform (GstBaseTransform * bt, GstBuffer * inbuf,
     in_img_mems[i]->barrier.image_layout = in_image_memory_barrier.newLayout;
   }
 
-  for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->in_info); i++) {
+  for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->out_info); i++) {
+    VkImageMemoryBarrier render_image_memory_barrier;
+
+    if (GST_VIDEO_INFO_WIDTH (&render->out_info) ==
+        GST_VIDEO_INFO_COMP_WIDTH (&render->out_info, i)) {
+      render_img_mems[i] = out_img_mems[i];
+    } else {
+      /* we need a scratch buffer because framebuffers can only output to
+       * attachments of at least the same size which means no sub-sampled
+       * rendering */
+      GstVideoFormat v_format = GST_VIDEO_INFO_FORMAT (&render->out_info);
+      VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
+      VkFormat vk_format;
+      GstMemory *mem;
+
+      vk_format = gst_vulkan_format_from_video_format (v_format, i);
+
+      mem = gst_vulkan_image_memory_alloc (render->device,
+          vk_format, GST_VIDEO_INFO_WIDTH (&render->out_info),
+          GST_VIDEO_INFO_HEIGHT (&render->out_info), tiling,
+          VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+          VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+      render_img_mems[i] = (GstVulkanImageMemory *) mem;
+    }
+
     /* *INDENT-OFF* */
-    VkImageMemoryBarrier out_image_memory_barrier = {
+    render_image_memory_barrier = (VkImageMemoryBarrier) {
         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
         .pNext = NULL,
-        .srcAccessMask = out_img_mems[i]->barrier.parent.access_flags,
+        .srcAccessMask = render_img_mems[i]->barrier.parent.access_flags,
         .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
-        .oldLayout = out_img_mems[i]->barrier.image_layout,
+        .oldLayout = render_img_mems[i]->barrier.image_layout,
         .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
         /* FIXME: implement exclusive transfers */
         .srcQueueFamilyIndex = 0,
         .dstQueueFamilyIndex = 0,
-        .image = out_img_mems[i]->image,
-        .subresourceRange = out_img_mems[i]->barrier.subresource_range
+        .image = render_img_mems[i]->image,
+        .subresourceRange = render_img_mems[i]->barrier.subresource_range
     };
     /* *INDENT-ON* */
 
-    vkCmdPipelineBarrier (cmd, out_img_mems[i]->barrier.parent.pipeline_stages,
+    vkCmdPipelineBarrier (cmd,
+        render_img_mems[i]->barrier.parent.pipeline_stages,
         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1,
-        &out_image_memory_barrier);
+        &render_image_memory_barrier);
 
-    out_img_mems[i]->barrier.parent.pipeline_stages =
+    render_img_mems[i]->barrier.parent.pipeline_stages =
         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    out_img_mems[i]->barrier.parent.access_flags =
-        out_image_memory_barrier.dstAccessMask;
-    out_img_mems[i]->barrier.image_layout = out_image_memory_barrier.newLayout;
+    render_img_mems[i]->barrier.parent.access_flags =
+        render_image_memory_barrier.dstAccessMask;
+    render_img_mems[i]->barrier.image_layout =
+        render_image_memory_barrier.newLayout;
+  }
+
+  {
+    VkImageView attachments[4] = { 0, };
+    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->out_info); i++) {
+      attachments[i] = render_img_mems[i]->view;
+    }
+
+    if (!(framebuffer = _create_framebuffer (conv,
+                GST_VIDEO_INFO_N_PLANES (&render->out_info), attachments))) {
+      g_set_error_literal (&error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
+          "Failed to create framebuffer");
+      goto error;
+    }
   }
 
   conv->current_shader->cmd_state_update (conv, cmd, conv->current_shader,
-      in_img_mems, out_img_mems);
+      in_img_mems, render_img_mems);
   if (!gst_vulkan_full_screen_render_fill_command_buffer (render, cmd,
           framebuffer))
     return GST_FLOW_ERROR;
 
+  for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&render->out_info); i++) {
+    if (render_img_mems[i] != out_img_mems[i]) {
+      VkImageMemoryBarrier out_image_memory_barrier;
+      VkImageMemoryBarrier render_image_memory_barrier;
+      VkImageBlit blit;
+
+      /* *INDENT-OFF* */
+      render_image_memory_barrier = (VkImageMemoryBarrier) {
+          .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+          .pNext = NULL,
+          .srcAccessMask = render_img_mems[i]->barrier.parent.access_flags,
+          .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+          .oldLayout = render_img_mems[i]->barrier.image_layout,
+          .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+          /* FIXME: implement exclusive transfers */
+          .srcQueueFamilyIndex = 0,
+          .dstQueueFamilyIndex = 0,
+          .image = render_img_mems[i]->image,
+          .subresourceRange = render_img_mems[i]->barrier.subresource_range
+      };
+      out_image_memory_barrier = (VkImageMemoryBarrier) {
+          .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+          .pNext = NULL,
+          .srcAccessMask = out_img_mems[i]->barrier.parent.access_flags,
+          .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+          .oldLayout = out_img_mems[i]->barrier.image_layout,
+          .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+          /* FIXME: implement exclusive transfers */
+          .srcQueueFamilyIndex = 0,
+          .dstQueueFamilyIndex = 0,
+          .image = out_img_mems[i]->image,
+          .subresourceRange = out_img_mems[i]->barrier.subresource_range
+      };
+      blit = (VkImageBlit) {
+          .srcSubresource = {
+              .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+              .mipLevel = 0,
+              .baseArrayLayer = 0,
+              .layerCount = 1,
+          },
+          .srcOffsets = {
+              {0, 0, 0},
+              {GST_VIDEO_INFO_COMP_WIDTH (&render->out_info, i), GST_VIDEO_INFO_COMP_HEIGHT (&render->out_info, i), 1},
+          },
+          .dstSubresource = {
+              .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+              .mipLevel = 0,
+              .baseArrayLayer = 0,
+              .layerCount = 1,
+          },
+          .dstOffsets = {
+              {0, 0, 0},
+              {GST_VIDEO_INFO_COMP_WIDTH (&render->out_info, i), GST_VIDEO_INFO_COMP_HEIGHT (&render->out_info, i), 1},
+          },
+      };
+      /* *INDENT-ON* */
+
+      vkCmdPipelineBarrier (cmd,
+          render_img_mems[i]->barrier.parent.pipeline_stages,
+          VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
+          &render_image_memory_barrier);
+
+      render_img_mems[i]->barrier.parent.pipeline_stages =
+          VK_PIPELINE_STAGE_TRANSFER_BIT;
+      render_img_mems[i]->barrier.parent.access_flags =
+          render_image_memory_barrier.dstAccessMask;
+      render_img_mems[i]->barrier.image_layout =
+          render_image_memory_barrier.newLayout;
+
+      vkCmdPipelineBarrier (cmd,
+          out_img_mems[i]->barrier.parent.pipeline_stages,
+          VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
+          &out_image_memory_barrier);
+
+      out_img_mems[i]->barrier.parent.pipeline_stages =
+          VK_PIPELINE_STAGE_TRANSFER_BIT;
+      out_img_mems[i]->barrier.parent.access_flags =
+          out_image_memory_barrier.dstAccessMask;
+      out_img_mems[i]->barrier.image_layout =
+          out_image_memory_barrier.newLayout;
+
+      /* XXX: This is mostly right for a downsampling pass however if
+       * anything is more complicated, then we will need a new render pass */
+      vkCmdBlitImage (cmd, render_img_mems[i]->image,
+          render_img_mems[i]->barrier.image_layout, out_img_mems[i]->image,
+          out_img_mems[i]->barrier.image_layout, 1, &blit, VK_FILTER_LINEAR);
+
+      /* XXX: try to reuse this image later */
+      render->trash_list =
+          g_list_prepend (render->trash_list,
+          gst_vulkan_trash_new_mini_object_unref (gst_vulkan_fence_ref (fence),
+              (GstMiniObject *) render_img_mems[i]));
+    }
+  }
+
   err = vkEndCommandBuffer (cmd);
   if (gst_vulkan_error_to_g_error (err, &error, "vkEndCommandBuffer") < 0)
     goto error;
index f755e19..9880685 100644 (file)
@@ -278,7 +278,8 @@ _create_pipeline (GstVulkanFullScreenRender * render)
   VkPipelineViewportStateCreateInfo viewport_state;
   VkPipelineRasterizationStateCreateInfo rasterizer;
   VkPipelineMultisampleStateCreateInfo multisampling;
-  VkPipelineColorBlendAttachmentState color_blend_attachment;
+  VkPipelineColorBlendAttachmentState
+      color_blend_attachments[GST_VIDEO_MAX_PLANES];
   VkPipelineColorBlendStateCreateInfo color_blending;
   VkGraphicsPipelineCreateInfo pipeline_info;
   VkPipeline pipeline;
@@ -364,7 +365,19 @@ _create_pipeline (GstVulkanFullScreenRender * render)
       .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
   };
 
-  color_blend_attachment = (VkPipelineColorBlendAttachmentState) {
+  color_blend_attachments[0] = (VkPipelineColorBlendAttachmentState) {
+      .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+      .blendEnable = VK_FALSE
+  };
+  color_blend_attachments[1] = (VkPipelineColorBlendAttachmentState) {
+      .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+      .blendEnable = VK_FALSE
+  };
+  color_blend_attachments[2] = (VkPipelineColorBlendAttachmentState) {
+      .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
+      .blendEnable = VK_FALSE
+  };
+  color_blend_attachments[3] = (VkPipelineColorBlendAttachmentState) {
       .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
       .blendEnable = VK_FALSE
   };
@@ -374,8 +387,8 @@ _create_pipeline (GstVulkanFullScreenRender * render)
       .pNext = NULL,
       .logicOpEnable = VK_FALSE,
       .logicOp = VK_LOGIC_OP_COPY,
-      .attachmentCount = 1,
-      .pAttachments = &color_blend_attachment,
+      .attachmentCount = GST_VIDEO_INFO_N_PLANES (&render->out_info),
+      .pAttachments = color_blend_attachments,
       .blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }
   };
 
@@ -832,6 +845,9 @@ gst_vulkan_full_screen_render_fill_command_buffer (GstVulkanFullScreenRender *
 {
   /* *INDENT-OFF* */
   VkClearValue clearColor = {{{ 0.0f, 0.0f, 0.0f, 1.0f }}};
+  VkClearValue clearColors[GST_VIDEO_MAX_PLANES] = {
+    clearColor, clearColor, clearColor, clearColor,
+  };
   VkRenderPassBeginInfo render_pass_info = {
       .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
       .renderPass = render->render_pass,
@@ -841,8 +857,8 @@ gst_vulkan_full_screen_render_fill_command_buffer (GstVulkanFullScreenRender *
           GST_VIDEO_INFO_WIDTH (&render->out_info),
           GST_VIDEO_INFO_HEIGHT (&render->out_info)
       },
-      .clearValueCount = 1,
-      .pClearValues = &clearColor
+      .clearValueCount = GST_VIDEO_INFO_N_PLANES (&render->out_info),
+      .pClearValues = clearColors,
   };
   /* *INDENI-ON* */
   VkDeviceSize offsets[] = { 0 };