vulkan: Add premultiply step to texture upload
authorBenjamin Otte <otte@redhat.com>
Wed, 19 Jul 2023 04:14:55 +0000 (06:14 +0200)
committerBenjamin Otte <otte@redhat.com>
Wed, 19 Jul 2023 19:30:35 +0000 (21:30 +0200)
When a GdkMemoryFormat is not supported natively and there's
postprocessing required, add a way to mark a VulkanImage as such via the
new postprocess flags.

Also allow texting such iamges only with new_for_upload() and detect
when that is the case and then run a postprocessing step that converts
that image to a suitable format.
This is done with a new "convert" shader/op.

This now supports all formats natively, no conversions happen on the CPU
anymore (unless the GPU is old).

gsk/meson.build
gsk/vulkan/gskvulkanconvertop.c [new file with mode: 0644]
gsk/vulkan/gskvulkanconvertopprivate.h [new file with mode: 0644]
gsk/vulkan/gskvulkanimage.c
gsk/vulkan/gskvulkanimageprivate.h
gsk/vulkan/gskvulkanrenderpass.c
gsk/vulkan/gskvulkanuploadop.c
gsk/vulkan/resources/convert.frag [new file with mode: 0644]
gsk/vulkan/resources/convert.vert [new file with mode: 0644]
gsk/vulkan/resources/meson.build

index 5a86498679ab3b8b501944ed92a2b32ff037338e..489024572a429c8878880a43b5a2c00de23fa969 100644 (file)
@@ -116,6 +116,7 @@ if have_vulkan
     'vulkan/gskvulkancolormatrixop.c',
     'vulkan/gskvulkancolorop.c',
     'vulkan/gskvulkancommandpool.c',
+    'vulkan/gskvulkanconvertop.c',
     'vulkan/gskvulkancrossfadeop.c',
     'vulkan/gskvulkandownloadop.c',
     'vulkan/gskvulkanglyphcache.c',
diff --git a/gsk/vulkan/gskvulkanconvertop.c b/gsk/vulkan/gskvulkanconvertop.c
new file mode 100644 (file)
index 0000000..f1280e4
--- /dev/null
@@ -0,0 +1,100 @@
+#include "config.h"
+
+#include "gskvulkanconvertopprivate.h"
+
+#include "gskvulkanprivate.h"
+#include "gskvulkanshaderopprivate.h"
+
+#include "vulkan/resources/convert.vert.h"
+
+typedef struct _GskVulkanConvertOp GskVulkanConvertOp;
+
+struct _GskVulkanConvertOp
+{
+  GskVulkanShaderOp op;
+
+  graphene_rect_t rect;
+  graphene_rect_t tex_rect;
+
+  guint32 image_descriptor;
+};
+
+static void
+gsk_vulkan_convert_op_print (GskVulkanOp *op,
+                             GString     *string,
+                             guint        indent)
+{
+  GskVulkanConvertOp *self = (GskVulkanConvertOp *) op;
+  GskVulkanShaderOp *shader = (GskVulkanShaderOp *) op;
+
+  print_indent (string, indent);
+  print_rect (string, &self->rect);
+  g_string_append (string, "convert ");
+  print_image (string, shader->images[0]);
+  print_newline (string);
+}
+
+static void
+gsk_vulkan_convert_op_collect_vertex_data (GskVulkanOp *op,
+                                           guchar      *data)
+{
+  GskVulkanConvertOp *self = (GskVulkanConvertOp *) op;
+  GskVulkanConvertInstance *instance = (GskVulkanConvertInstance *) (data + ((GskVulkanShaderOp *) op)->vertex_offset);
+  GskVulkanShaderOp *shader = (GskVulkanShaderOp *) op;
+
+  instance->rect[0] = self->rect.origin.x;
+  instance->rect[1] = self->rect.origin.y;
+  instance->rect[2] = self->rect.size.width;
+  instance->rect[3] = self->rect.size.height;
+  instance->tex_rect[0] = self->tex_rect.origin.x;
+  instance->tex_rect[1] = self->tex_rect.origin.y;
+  instance->tex_rect[2] = self->tex_rect.size.width;
+  instance->tex_rect[3] = self->tex_rect.size.height;
+  instance->tex_id = self->image_descriptor;
+  instance->postprocess = gsk_vulkan_image_get_postprocess (shader->images[0]);
+}
+
+static void
+gsk_vulkan_convert_op_reserve_descriptor_sets (GskVulkanOp     *op,
+                                               GskVulkanRender *render)
+{
+  GskVulkanConvertOp *self = (GskVulkanConvertOp *) op;
+  GskVulkanShaderOp *shader = (GskVulkanShaderOp *) op;
+
+  self->image_descriptor = gsk_vulkan_render_get_image_descriptor (render, shader->images[0], GSK_VULKAN_SAMPLER_NEAREST);
+}
+
+static const GskVulkanShaderOpClass GSK_VULKAN_CONVERT_OP_CLASS = {
+  {
+    GSK_VULKAN_OP_SIZE (GskVulkanConvertOp),
+    GSK_VULKAN_STAGE_SHADER,
+    gsk_vulkan_shader_op_finish,
+    gsk_vulkan_convert_op_print,
+    gsk_vulkan_shader_op_count_vertex_data,
+    gsk_vulkan_convert_op_collect_vertex_data,
+    gsk_vulkan_convert_op_reserve_descriptor_sets,
+    gsk_vulkan_shader_op_command
+  },
+  "convert",
+  1,
+  &gsk_vulkan_convert_info,
+};
+
+void
+gsk_vulkan_convert_op (GskVulkanRender        *render,
+                       GskVulkanShaderClip     clip,
+                       GskVulkanImage         *image,
+                       const graphene_rect_t  *rect,
+                       const graphene_point_t *offset,
+                       const graphene_rect_t  *tex_rect)
+{
+  GskVulkanConvertOp *self;
+
+  self = (GskVulkanConvertOp *) gsk_vulkan_shader_op_alloc (render,
+                                                            &GSK_VULKAN_CONVERT_OP_CLASS,
+                                                            clip,
+                                                            &image);
+
+  graphene_rect_offset_r (rect, offset->x, offset->y, &self->rect);
+  gsk_vulkan_normalize_tex_coords (&self->tex_rect, rect, tex_rect);
+}
diff --git a/gsk/vulkan/gskvulkanconvertopprivate.h b/gsk/vulkan/gskvulkanconvertopprivate.h
new file mode 100644 (file)
index 0000000..d52fb4c
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "gskvulkanopprivate.h"
+
+G_BEGIN_DECLS
+
+void                    gsk_vulkan_convert_op                           (GskVulkanRender                *render,
+                                                                         GskVulkanShaderClip             clip,
+                                                                         GskVulkanImage                 *image,
+                                                                         const graphene_rect_t          *rect,
+                                                                         const graphene_point_t         *offset,
+                                                                         const graphene_rect_t          *tex_rect);
+
+
+G_END_DECLS
+
index 80a0502094410939fde0c9cecf2648b7afa8e09c..b9e744538b89de7f73d0335e38024849341f6b52 100644 (file)
@@ -24,6 +24,7 @@ struct _GskVulkanImage
   VkImage vk_image;
   VkImageView vk_image_view;
   VkFramebuffer vk_framebuffer;
+  GskVulkanImagePostprocess postprocess;
 
   VkPipelineStageFlags vk_pipeline_stage;
   VkImageLayout vk_image_layout;
@@ -40,6 +41,7 @@ struct _GskMemoryFormatInfo
 {
   VkFormat format;
   VkComponentMapping components;
+  GskVulkanImagePostprocess postprocess;
 };
 
 static const GskMemoryFormatInfo *
@@ -52,8 +54,8 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_B8G8R8A8_UNORM, DEFAULT_SWIZZLE },
-          { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(B, G, R, A) },
+          { VK_FORMAT_B8G8R8A8_UNORM, DEFAULT_SWIZZLE,     0 },
+          { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(B, G, R, A), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -62,7 +64,7 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(G, B, A, R) },
+          { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(G, B, A, R), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -71,23 +73,53 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R8G8B8A8_UNORM, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R8G8B8A8_UNORM, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-#if 0
-  GDK_MEMORY_B8G8R8A8,
-  GDK_MEMORY_A8R8G8B8,
-  GDK_MEMORY_R8G8B8A8,
-  GDK_MEMORY_A8B8G8R8,
-#endif
+    case GDK_MEMORY_B8G8R8A8:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_B8G8R8A8_UNORM, DEFAULT_SWIZZLE,     GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(B, G, R, A), GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
+
+    case GDK_MEMORY_A8R8G8B8:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(G, B, A, R), GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
+
+    case GDK_MEMORY_R8G8B8A8:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R8G8B8A8_UNORM, DEFAULT_SWIZZLE, GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
+
+    case GDK_MEMORY_A8B8G8R8:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(A, B, G, R), GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
 
     case GDK_MEMORY_R8G8B8:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R8G8B8_UNORM, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R8G8B8_UNORM, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -96,8 +128,8 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_B8G8R8:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_B8G8R8_UNORM, DEFAULT_SWIZZLE },
-          { VK_FORMAT_R8G8B8_UNORM, SWIZZLE(B, G, R, A) },
+          { VK_FORMAT_B8G8R8_UNORM, DEFAULT_SWIZZLE,     0 },
+          { VK_FORMAT_R8G8B8_UNORM, SWIZZLE(B, G, R, A), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -106,7 +138,7 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_R16G16B16:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R16G16B16_UNORM, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R16G16B16_UNORM, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -115,20 +147,25 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R16G16B16A16_UNORM, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R16G16B16A16_UNORM, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-#if 0
-  GDK_MEMORY_R16G16B16A16,
-#endif
+    case GDK_MEMORY_R16G16B16A16:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R16G16B16A16_UNORM, DEFAULT_SWIZZLE, GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
 
     case GDK_MEMORY_R16G16B16_FLOAT:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R16G16B16_SFLOAT, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R16G16B16_SFLOAT, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -137,20 +174,25 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R16G16B16A16_SFLOAT, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R16G16B16A16_SFLOAT, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-#if 0
-  GDK_MEMORY_R16G16B16A16_FLOAT,
-#endif
+    case GDK_MEMORY_R16G16B16A16_FLOAT:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R16G16B16A16_SFLOAT, DEFAULT_SWIZZLE, GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
 
     case GDK_MEMORY_R32G32B32_FLOAT:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R32G32B32_SFLOAT, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R32G32B32_SFLOAT, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -159,33 +201,43 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R32G32B32A32_SFLOAT, DEFAULT_SWIZZLE },
+          { VK_FORMAT_R32G32B32A32_SFLOAT, DEFAULT_SWIZZLE, 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-#if 0
-  GDK_MEMORY_R32G32B32A32_FLOAT,
-#endif
+    case GDK_MEMORY_R32G32B32A32_FLOAT:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R32G32B32A32_SFLOAT, DEFAULT_SWIZZLE, GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
 
     case GDK_MEMORY_G8A8_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R8G8_UNORM, SWIZZLE (R, R, R, G) },
+          { VK_FORMAT_R8G8_UNORM, SWIZZLE (R, R, R, G), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-#if 0
-  GDK_MEMORY_G8A8,
-#endif
+    case GDK_MEMORY_G8A8:
+      {
+        static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R8G8_UNORM, SWIZZLE (R, R, R, G), GSK_VULKAN_IMAGE_PREMULTIPLY },
+          { VK_FORMAT_UNDEFINED }
+        };
+        return info;
+      }
 
     case GDK_MEMORY_G8:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, ONE) },
+          { VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, ONE), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -194,54 +246,43 @@ gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
     case GDK_MEMORY_G16A16_PREMULTIPLIED:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R16G16_UNORM, SWIZZLE (R, R, R, G) },
+          { VK_FORMAT_R16G16_UNORM, SWIZZLE (R, R, R, G), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-#if 0
-  GDK_MEMORY_G16A16
-#endif
-
-    case GDK_MEMORY_G16:
+    case GDK_MEMORY_G16A16:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, ONE) },
+          { VK_FORMAT_R16G16_UNORM, SWIZZLE (R, R, R, G), GSK_VULKAN_IMAGE_PREMULTIPLY },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-    case GDK_MEMORY_A8:
+    case GDK_MEMORY_G16:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, R) },
+          { VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, ONE), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-    case GDK_MEMORY_A16:
+    case GDK_MEMORY_A8:
       {
         static const GskMemoryFormatInfo info[] = {
-          { VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, R) },
+          { VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, R), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
       }
 
-    case GDK_MEMORY_B8G8R8A8:
-    case GDK_MEMORY_A8R8G8B8:
-    case GDK_MEMORY_R8G8B8A8:
-    case GDK_MEMORY_A8B8G8R8:
-    case GDK_MEMORY_R16G16B16A16:
-    case GDK_MEMORY_R16G16B16A16_FLOAT:
-    case GDK_MEMORY_R32G32B32A32_FLOAT:
-    case GDK_MEMORY_G8A8:
-    case GDK_MEMORY_G16A16:
+    case GDK_MEMORY_A16:
       {
         static const GskMemoryFormatInfo info[] = {
+          { VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, R), 0 },
           { VK_FORMAT_UNDEFINED }
         };
         return info;
@@ -361,16 +402,17 @@ gsk_vulkan_image_create_view (GskVulkanImage            *self,
 }
 
 static GskVulkanImage *
-gsk_vulkan_image_new (GdkVulkanContext      *context,
-                      GdkMemoryFormat        format,
-                      gsize                  width,
-                      gsize                  height,
-                      VkImageTiling          tiling,
-                      VkImageUsageFlags      usage,
-                      VkPipelineStageFlags   stage,
-                      VkImageLayout          layout,
-                      VkAccessFlags          access,
-                      VkMemoryPropertyFlags  memory)
+gsk_vulkan_image_new (GdkVulkanContext          *context,
+                      GdkMemoryFormat            format,
+                      gsize                      width,
+                      gsize                      height,
+                      GskVulkanImagePostprocess  allowed_postprocess,
+                      VkImageTiling              tiling,
+                      VkImageUsageFlags          usage,
+                      VkPipelineStageFlags       stage,
+                      VkImageLayout              layout,
+                      VkAccessFlags              access,
+                      VkMemoryPropertyFlags      memory)
 {
   VkMemoryRequirements requirements;
   GskVulkanImage *self;
@@ -384,6 +426,9 @@ gsk_vulkan_image_new (GdkVulkanContext      *context,
            vk_format->format != VK_FORMAT_UNDEFINED;
            vk_format++)
         {
+          if (vk_format->postprocess & ~allowed_postprocess)
+            continue;
+
           if (gsk_vulkan_context_supports_format (context, vk_format->format))
             break;
         }
@@ -398,6 +443,7 @@ gsk_vulkan_image_new (GdkVulkanContext      *context,
   self->vulkan = g_object_ref (context);
   self->format = format;
   self->vk_format = vk_format->format;
+  self->postprocess = vk_format->postprocess;
   self->width = width;
   self->height = height;
   self->vk_usage = usage;
@@ -454,6 +500,7 @@ gsk_vulkan_image_new_for_upload (GdkVulkanContext  *context,
                                format,
                                width,
                                height,
+                               -1,
                                VK_IMAGE_TILING_LINEAR,
                                VK_IMAGE_USAGE_TRANSFER_DST_BIT |
                                VK_IMAGE_USAGE_SAMPLED_BIT,
@@ -555,6 +602,7 @@ gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
                                GDK_MEMORY_DEFAULT,
                                width,
                                height,
+                               0,
                                VK_IMAGE_TILING_OPTIMAL,
                                VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
                                VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
@@ -577,6 +625,7 @@ gsk_vulkan_image_new_for_offscreen (GdkVulkanContext *context,
                                preferred_format,
                                width,
                                height,
+                               0,
                                VK_IMAGE_TILING_LINEAR,
                                VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
                                VK_IMAGE_USAGE_SAMPLED_BIT |
@@ -663,6 +712,12 @@ gsk_vulkan_image_get_height (GskVulkanImage *self)
   return self->height;
 }
 
+GskVulkanImagePostprocess
+gsk_vulkan_image_get_postprocess (GskVulkanImage *self)
+{
+  return self->postprocess;
+}
+
 VkImage
 gsk_vulkan_image_get_vk_image (GskVulkanImage *self)
 {
index d0c9e6bc45491c06d8d73aa68d84da8de3a71f51..53055531ba3af6ad75940fb2a76162bca4cb1d3c 100644 (file)
@@ -8,6 +8,12 @@
 
 G_BEGIN_DECLS
 
+/* required postprocessing steps before the image van be used */
+typedef enum
+{
+  GSK_VULKAN_IMAGE_PREMULTIPLY = (1 << 0),
+} GskVulkanImagePostprocess;
+
 #define GSK_TYPE_VULKAN_IMAGE (gsk_vulkan_image_get_type ())
 
 G_DECLARE_FINAL_TYPE (GskVulkanImage, gsk_vulkan_image, GSK, VULKAN_IMAGE, GObject)
@@ -48,6 +54,8 @@ void                    gsk_vulkan_image_unmap                          (GskVulk
 
 gsize                   gsk_vulkan_image_get_width                      (GskVulkanImage         *self);
 gsize                   gsk_vulkan_image_get_height                     (GskVulkanImage         *self);
+GskVulkanImagePostprocess
+                        gsk_vulkan_image_get_postprocess                (GskVulkanImage         *self);
 VkPipelineStageFlags    gsk_vulkan_image_get_vk_pipeline_stage          (GskVulkanImage         *self);
 VkImageLayout           gsk_vulkan_image_get_vk_image_layout            (GskVulkanImage         *self);
 VkAccessFlags           gsk_vulkan_image_get_vk_access                  (GskVulkanImage         *self);
index 476d533dafc94e97b40e907b395e50a4b4c6b813..b680b8c9b0338f9ce91e2d8f9ee3e3901759b5f3 100644 (file)
@@ -16,6 +16,7 @@
 #include "gskvulkanclipprivate.h"
 #include "gskvulkancolormatrixopprivate.h"
 #include "gskvulkancoloropprivate.h"
+#include "gskvulkanconvertopprivate.h"
 #include "gskvulkancrossfadeopprivate.h"
 #include "gskvulkanglyphopprivate.h"
 #include "gskvulkaninsetshadowopprivate.h"
@@ -140,6 +141,52 @@ gsk_vulkan_parse_rect_is_integer (const GskVulkanParseState *state,
       && int_rect->height == rect->size.height * scale_y;
 }
 
+static GskVulkanImage *
+gsk_vulkan_render_pass_upload_texture (GskVulkanRender *render,
+                                       GdkTexture      *texture)
+{
+  GskVulkanImage *image, *better_image;
+  int width, height;
+  GskVulkanImagePostprocess postproc;
+  graphene_matrix_t projection;
+  graphene_vec2_t scale;
+
+  image = gsk_vulkan_upload_texture_op (render, texture);
+  postproc = gsk_vulkan_image_get_postprocess (image);
+  if (postproc == 0)
+    return image;
+
+  width = gdk_texture_get_width (texture);
+  height = gdk_texture_get_height (texture);
+  better_image = gsk_vulkan_image_new_for_offscreen (gsk_vulkan_render_get_context (render),
+                                                     gdk_texture_get_format (texture),
+                                                     width, height);
+  gsk_vulkan_render_pass_begin_op (render,
+                                   g_object_ref (better_image),
+                                   &(cairo_rectangle_int_t) { 0, 0, width, height },
+                                   &GRAPHENE_SIZE_INIT(width, height),
+                                   VK_IMAGE_LAYOUT_UNDEFINED,
+                                   VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+  gsk_vulkan_scissor_op (render, &(cairo_rectangle_int_t) { 0, 0, width, height });
+  graphene_matrix_init_ortho (&projection,
+                              0, width,
+                              0, height,
+                              2 * ORTHO_NEAR_PLANE - ORTHO_FAR_PLANE,
+                              ORTHO_FAR_PLANE);
+  graphene_vec2_init (&scale, 1.0, 1.0);
+  gsk_vulkan_push_constants_op (render, &scale, &projection, &GSK_ROUNDED_RECT_INIT(0, 0, width, height));
+  gsk_vulkan_convert_op (render,
+                         GSK_VULKAN_SHADER_CLIP_NONE,
+                         image,
+                         &GRAPHENE_RECT_INIT (0, 0, width, height),
+                         &GRAPHENE_POINT_INIT (0, 0),
+                         &GRAPHENE_RECT_INIT (0, 0, width, height));
+  gsk_vulkan_render_pass_end_op (render,
+                                 better_image,
+                                 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+  return better_image;
+}
+
 static GskVulkanImage *
 gsk_vulkan_render_pass_get_node_as_image (GskVulkanRenderPass       *self,
                                           GskVulkanRender           *render,
@@ -158,7 +205,7 @@ gsk_vulkan_render_pass_get_node_as_image (GskVulkanRenderPass       *self,
         result = gsk_vulkan_renderer_get_texture_image (renderer, texture);
         if (result == NULL)
           {
-            result = gsk_vulkan_upload_texture_op (render, texture);
+            result = gsk_vulkan_render_pass_upload_texture (render, texture);
             gsk_vulkan_renderer_add_texture_image (renderer, texture, result);
           }
 
@@ -433,7 +480,7 @@ gsk_vulkan_render_pass_add_texture_node (GskVulkanRenderPass       *self,
   image = gsk_vulkan_renderer_get_texture_image (renderer, texture);
   if (image == NULL)
     {
-      image = gsk_vulkan_upload_texture_op (render, texture);
+      image = gsk_vulkan_render_pass_upload_texture (render, texture);
       gsk_vulkan_renderer_add_texture_image (renderer, texture, image);
     }
 
@@ -476,7 +523,7 @@ gsk_vulkan_render_pass_add_texture_scale_node (GskVulkanRenderPass       *self,
   image = gsk_vulkan_renderer_get_texture_image (renderer, texture);
   if (image == NULL)
     {
-      image = gsk_vulkan_upload_texture_op (render, texture);
+      image = gsk_vulkan_render_pass_upload_texture (render, texture);
       gsk_vulkan_renderer_add_texture_image (renderer, texture, image);
     }
 
index ea5388a6f0174d5578db650d57bb24c067e544eb..428590f55917d45f07b51dc25a65b20c7ca10aaf 100644 (file)
@@ -339,6 +339,7 @@ gsk_vulkan_upload_cairo_op (GskVulkanRender       *render,
                                                  GDK_MEMORY_DEFAULT,
                                                  ceil (graphene_vec2_get_x (scale) * viewport->size.width),
                                                  ceil (graphene_vec2_get_y (scale) * viewport->size.height));
+  g_assert (gsk_vulkan_image_get_postprocess (self->image) == 0);
   self->viewport = *viewport;
 
   return self->image;
diff --git a/gsk/vulkan/resources/convert.frag b/gsk/vulkan/resources/convert.frag
new file mode 100644 (file)
index 0000000..862285b
--- /dev/null
@@ -0,0 +1,29 @@
+#version 450
+
+#include "common.frag.glsl"
+#include "clip.frag.glsl"
+#include "rect.frag.glsl"
+
+#define GSK_VULKAN_IMAGE_PREMULTIPLY (1 << 0)
+#
+layout(location = 0) in vec2 in_pos;
+layout(location = 1) in Rect in_rect;
+layout(location = 2) in vec2 in_tex_coord;
+layout(location = 3) flat in uint in_tex_id;
+layout(location = 4) in flat uint in_postprocess;
+
+layout(location = 0) out vec4 color;
+
+void main()
+{
+  float alpha = rect_coverage (in_rect, in_pos);
+
+  /* warning: This breaks with filters other than nearest,
+     as linear filtering needs premultiplied alpha */
+  vec4 pixel = texture (get_sampler (in_tex_id), in_tex_coord);
+
+  if ((in_postprocess & GSK_VULKAN_IMAGE_PREMULTIPLY) != 0)
+    pixel.rgb *= pixel.a;
+
+  color = clip_scaled (in_pos, pixel * alpha);
+}
diff --git a/gsk/vulkan/resources/convert.vert b/gsk/vulkan/resources/convert.vert
new file mode 100644 (file)
index 0000000..d0777b9
--- /dev/null
@@ -0,0 +1,26 @@
+#version 450
+
+#include "common.vert.glsl"
+#include "rect.vert.glsl"
+
+layout(location = 0) in vec4 in_rect;
+layout(location = 1) in vec4 in_tex_rect;
+layout(location = 2) in uint in_tex_id;
+layout(location = 3) in uint in_postprocess;
+
+layout(location = 0) out vec2 out_pos;
+layout(location = 1) out flat Rect out_rect;
+layout(location = 2) out vec2 out_tex_coord;
+layout(location = 3) out flat uint out_tex_id;
+layout(location = 4) out flat uint out_postprocess;
+
+void main() {
+  Rect r = rect_from_gsk (in_rect);
+  vec2 pos = set_position_from_rect (r);
+
+  out_pos = pos;
+  out_rect = r;
+  out_tex_coord = scale_tex_coord (pos, r, in_tex_rect);
+  out_tex_id = in_tex_id;
+  out_postprocess = in_postprocess;
+}
index 146120d8fbe46e6e49cfafcc8b788d5ac869e439..444a1dce38fb23bffb4595fbb83caf3cad336ec1 100644 (file)
@@ -17,6 +17,7 @@ gsk_private_vulkan_fragment_shaders = [
   'border.frag',
   'color.frag',
   'color-matrix.frag',
+  'convert.frag',
   'cross-fade.frag',
   'glyph.frag',
   'inset-shadow.frag',
@@ -32,6 +33,7 @@ gsk_private_vulkan_vertex_shaders = [
   'border.vert',
   'color.vert',
   'color-matrix.vert',
+  'convert.vert',
   'cross-fade.vert',
   'glyph.vert',
   'inset-shadow.vert',