From 4d9e7d30b00fb0bf33968781276533c178e38ab0 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 19 Jul 2023 06:14:55 +0200 Subject: [PATCH] vulkan: Add premultiply step to texture upload 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 | 1 + gsk/vulkan/gskvulkanconvertop.c | 100 ++++++++++++++ gsk/vulkan/gskvulkanconvertopprivate.h | 16 +++ gsk/vulkan/gskvulkanimage.c | 181 ++++++++++++++++--------- gsk/vulkan/gskvulkanimageprivate.h | 8 ++ gsk/vulkan/gskvulkanrenderpass.c | 53 +++++++- gsk/vulkan/gskvulkanuploadop.c | 1 + gsk/vulkan/resources/convert.frag | 29 ++++ gsk/vulkan/resources/convert.vert | 26 ++++ gsk/vulkan/resources/meson.build | 2 + 10 files changed, 351 insertions(+), 66 deletions(-) create mode 100644 gsk/vulkan/gskvulkanconvertop.c create mode 100644 gsk/vulkan/gskvulkanconvertopprivate.h create mode 100644 gsk/vulkan/resources/convert.frag create mode 100644 gsk/vulkan/resources/convert.vert diff --git a/gsk/meson.build b/gsk/meson.build index 5a86498679..489024572a 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -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 index 0000000000..f1280e4345 --- /dev/null +++ b/gsk/vulkan/gskvulkanconvertop.c @@ -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 index 0000000000..d52fb4c2dd --- /dev/null +++ b/gsk/vulkan/gskvulkanconvertopprivate.h @@ -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 + diff --git a/gsk/vulkan/gskvulkanimage.c b/gsk/vulkan/gskvulkanimage.c index 80a0502094..b9e744538b 100644 --- a/gsk/vulkan/gskvulkanimage.c +++ b/gsk/vulkan/gskvulkanimage.c @@ -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) { diff --git a/gsk/vulkan/gskvulkanimageprivate.h b/gsk/vulkan/gskvulkanimageprivate.h index d0c9e6bc45..53055531ba 100644 --- a/gsk/vulkan/gskvulkanimageprivate.h +++ b/gsk/vulkan/gskvulkanimageprivate.h @@ -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); diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 476d533daf..b680b8c9b0 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -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); } diff --git a/gsk/vulkan/gskvulkanuploadop.c b/gsk/vulkan/gskvulkanuploadop.c index ea5388a6f0..428590f559 100644 --- a/gsk/vulkan/gskvulkanuploadop.c +++ b/gsk/vulkan/gskvulkanuploadop.c @@ -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 index 0000000000..862285b1df --- /dev/null +++ b/gsk/vulkan/resources/convert.frag @@ -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 index 0000000000..d0777b9785 --- /dev/null +++ b/gsk/vulkan/resources/convert.vert @@ -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; +} diff --git a/gsk/vulkan/resources/meson.build b/gsk/vulkan/resources/meson.build index 146120d8fb..444a1dce38 100644 --- a/gsk/vulkan/resources/meson.build +++ b/gsk/vulkan/resources/meson.build @@ -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', -- 2.30.2