From: Benjamin Otte Date: Sun, 25 Jun 2023 21:04:43 +0000 (+0200) Subject: vulkan: Add offscreen and color-matrix op X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~1^2~60^2~78 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=aaa219497b9252e40c22619866d4e259c50d12be;p=gtk4.git vulkan: Add offscreen and color-matrix op .. and use them for color-matrix operations. --- diff --git a/gsk/meson.build b/gsk/meson.build index b24108c6b2..fd201a583f 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -114,6 +114,7 @@ if have_vulkan 'vulkan/gskvulkanbuffer.c', 'vulkan/gskvulkanclip.c', 'vulkan/gskvulkancolorpipeline.c', + 'vulkan/gskvulkancolormatrixop.c', 'vulkan/gskvulkancolortextpipeline.c', 'vulkan/gskvulkancommandpool.c', 'vulkan/gskvulkancrossfadepipeline.c', @@ -122,6 +123,7 @@ if have_vulkan 'vulkan/gskvulkanimage.c', 'vulkan/gskvulkanlineargradientpipeline.c', 'vulkan/gskvulkanmemory.c', + 'vulkan/gskvulkanoffscreenop.c', 'vulkan/gskvulkanop.c', 'vulkan/gskvulkanpipeline.c', 'vulkan/gskvulkanpushconstants.c', diff --git a/gsk/vulkan/gskvulkancolormatrixop.c b/gsk/vulkan/gskvulkancolormatrixop.c new file mode 100644 index 0000000000..87edc24602 --- /dev/null +++ b/gsk/vulkan/gskvulkancolormatrixop.c @@ -0,0 +1,153 @@ +#include "config.h" + +#include "gskvulkancolormatrixopprivate.h" + +#include "gskvulkaneffectpipelineprivate.h" + +typedef struct _GskVulkanColorMatrixOp GskVulkanColorMatrixOp; + +struct _GskVulkanColorMatrixOp +{ + GskVulkanOp op; + + GskVulkanImage *image; + graphene_matrix_t color_matrix; + graphene_vec4_t color_offset; + graphene_rect_t rect; + graphene_rect_t tex_rect; + + guint32 image_descriptor; + guint32 sampler_descriptor; + GskVulkanPipeline *pipeline; + gsize vertex_offset; +}; + +static void +gsk_vulkan_color_matrix_op_finish (GskVulkanOp *op) +{ + GskVulkanColorMatrixOp *self = (GskVulkanColorMatrixOp *) op; + + g_object_unref (self->image); +} + +static void +gsk_vulkan_color_matrix_op_upload (GskVulkanOp *op, + GskVulkanRenderPass *pass, + GskVulkanRender *render, + GskVulkanUploader *uploader, + const graphene_rect_t *clip, + const graphene_vec2_t *scale) +{ +} + +static inline gsize +round_up (gsize number, gsize divisor) +{ + return (number + divisor - 1) / divisor * divisor; +} + +static gsize +gsk_vulkan_color_matrix_op_count_vertex_data (GskVulkanOp *op, + gsize n_bytes) +{ + GskVulkanColorMatrixOp *self = (GskVulkanColorMatrixOp *) op; + gsize vertex_stride; + + vertex_stride = gsk_vulkan_pipeline_get_vertex_stride (self->pipeline); + n_bytes = round_up (n_bytes, vertex_stride); + self->vertex_offset = n_bytes; + n_bytes += vertex_stride; + return n_bytes; +} + +static void +gsk_vulkan_color_matrix_op_collect_vertex_data (GskVulkanOp *op, + GskVulkanRenderPass *pass, + GskVulkanRender *render, + guchar *data) +{ + GskVulkanColorMatrixOp *self = (GskVulkanColorMatrixOp *) op; + + gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (self->pipeline), + data + self->vertex_offset, + (guint32[2]) { + self->image_descriptor, + self->sampler_descriptor, + }, + graphene_point_zero (), + &self->rect, + &self->tex_rect, + &self->color_matrix, + &self->color_offset); +} + +static void +gsk_vulkan_color_matrix_op_reserve_descriptor_sets (GskVulkanOp *op, + GskVulkanRender *render) +{ + GskVulkanColorMatrixOp *self = (GskVulkanColorMatrixOp *) op; + + self->image_descriptor = gsk_vulkan_render_get_image_descriptor (render, self->image); + self->sampler_descriptor = gsk_vulkan_render_get_sampler_descriptor (render, GSK_VULKAN_SAMPLER_DEFAULT); +} + +static GskVulkanPipeline * +gsk_vulkan_color_matrix_op_get_pipeline (GskVulkanOp *op) +{ + GskVulkanColorMatrixOp *self = (GskVulkanColorMatrixOp *) op; + + return self->pipeline; +} + +static void +gsk_vulkan_color_matrix_op_command (GskVulkanOp *op, + GskVulkanRender *render, + VkPipelineLayout pipeline_layout, + VkCommandBuffer command_buffer) +{ + GskVulkanColorMatrixOp *self = (GskVulkanColorMatrixOp *) op; + + gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (self->pipeline), + command_buffer, + self->vertex_offset / gsk_vulkan_pipeline_get_vertex_stride (self->pipeline), + 1); +} + +static const GskVulkanOpClass GSK_VULKAN_COLOR_MATRIX_OP_CLASS = { + GSK_VULKAN_OP_SIZE (GskVulkanColorMatrixOp), + gsk_vulkan_color_matrix_op_finish, + gsk_vulkan_color_matrix_op_upload, + gsk_vulkan_color_matrix_op_count_vertex_data, + gsk_vulkan_color_matrix_op_collect_vertex_data, + gsk_vulkan_color_matrix_op_reserve_descriptor_sets, + gsk_vulkan_color_matrix_op_get_pipeline, + gsk_vulkan_color_matrix_op_command +}; + +gsize +gsk_vulkan_color_matrix_op_size (void) +{ + return GSK_VULKAN_COLOR_MATRIX_OP_CLASS.size; +} + +void +gsk_vulkan_color_matrix_op_init (GskVulkanOp *op, + GskVulkanPipeline *pipeline, + GskVulkanImage *image, + const graphene_rect_t *rect, + const graphene_point_t *offset, + const graphene_rect_t *tex_rect, + const graphene_matrix_t *color_matrix, + const graphene_vec4_t *color_offset) +{ + GskVulkanColorMatrixOp *self = (GskVulkanColorMatrixOp *) op; + + gsk_vulkan_op_init (op, &GSK_VULKAN_COLOR_MATRIX_OP_CLASS); + + self->pipeline = pipeline; + self->image = g_object_ref (image); + graphene_rect_offset_r (rect, offset->x, offset->y, &self->rect); + gsk_vulkan_normalize_tex_coords (&self->tex_rect, rect, tex_rect); + self->color_matrix = *color_matrix; + self->color_offset = *color_offset; +} diff --git a/gsk/vulkan/gskvulkancolormatrixopprivate.h b/gsk/vulkan/gskvulkancolormatrixopprivate.h new file mode 100644 index 0000000000..3e6f104b76 --- /dev/null +++ b/gsk/vulkan/gskvulkancolormatrixopprivate.h @@ -0,0 +1,20 @@ +#pragma once + +#include "gskvulkanopprivate.h" + +G_BEGIN_DECLS + +gsize gsk_vulkan_color_matrix_op_size (void) G_GNUC_CONST; + +void gsk_vulkan_color_matrix_op_init (GskVulkanOp *op, + GskVulkanPipeline *pipeline, + GskVulkanImage *image, + const graphene_rect_t *rect, + const graphene_point_t *offset, + const graphene_rect_t *tex_rect, + const graphene_matrix_t *color_matrix, + const graphene_vec4_t *color_offset); + + +G_END_DECLS + diff --git a/gsk/vulkan/gskvulkanoffscreenop.c b/gsk/vulkan/gskvulkanoffscreenop.c new file mode 100644 index 0000000000..2b5c982dd8 --- /dev/null +++ b/gsk/vulkan/gskvulkanoffscreenop.c @@ -0,0 +1,145 @@ +#include "config.h" + +#include "gskvulkanoffscreenopprivate.h" + +#include "gskrendernodeprivate.h" + +#include "gdk/gdkvulkancontextprivate.h" + +typedef struct _GskVulkanOffscreenOp GskVulkanOffscreenOp; + +struct _GskVulkanOffscreenOp +{ + GskVulkanOp op; + + GskVulkanImage *image; + GskVulkanRenderPass *render_pass; +}; + +static void +gsk_vulkan_offscreen_op_finish (GskVulkanOp *op) +{ + GskVulkanOffscreenOp *self = (GskVulkanOffscreenOp *) op; + + g_object_unref (self->image); + gsk_vulkan_render_pass_free (self->render_pass); +} + +static void +gsk_vulkan_offscreen_op_upload (GskVulkanOp *op, + GskVulkanRenderPass *pass, + GskVulkanRender *render, + GskVulkanUploader *uploader, + const graphene_rect_t *clip, + const graphene_vec2_t *scale) +{ + GskVulkanOffscreenOp *self = (GskVulkanOffscreenOp *) op; + + gsk_vulkan_render_pass_upload (self->render_pass, render, uploader); +} + +static gsize +gsk_vulkan_offscreen_op_count_vertex_data (GskVulkanOp *op, + gsize n_bytes) +{ + return n_bytes; +} + +static void +gsk_vulkan_offscreen_op_collect_vertex_data (GskVulkanOp *op, + GskVulkanRenderPass *pass, + GskVulkanRender *render, + guchar *data) +{ +} + +static void +gsk_vulkan_offscreen_op_reserve_descriptor_sets (GskVulkanOp *op, + GskVulkanRender *render) +{ + GskVulkanOffscreenOp *self = (GskVulkanOffscreenOp *) op; + + gsk_vulkan_render_pass_reserve_descriptor_sets (self->render_pass, render); +} + +static GskVulkanPipeline * +gsk_vulkan_offscreen_op_get_pipeline (GskVulkanOp *op) +{ + return NULL; +} + +static void +gsk_vulkan_offscreen_op_command (GskVulkanOp *op, + GskVulkanRender *render, + VkPipelineLayout pipeline_layout, + VkCommandBuffer command_buffer) +{ + GskVulkanOffscreenOp *self = (GskVulkanOffscreenOp *) op; + + gsk_vulkan_render_draw_pass (render, self->render_pass, VK_NULL_HANDLE); +} + +static const GskVulkanOpClass GSK_VULKAN_OFFSCREEN_OP_CLASS = { + GSK_VULKAN_OP_SIZE (GskVulkanOffscreenOp), + gsk_vulkan_offscreen_op_finish, + gsk_vulkan_offscreen_op_upload, + gsk_vulkan_offscreen_op_count_vertex_data, + gsk_vulkan_offscreen_op_collect_vertex_data, + gsk_vulkan_offscreen_op_reserve_descriptor_sets, + gsk_vulkan_offscreen_op_get_pipeline, + gsk_vulkan_offscreen_op_command +}; + +gsize +gsk_vulkan_offscreen_op_size (void) +{ + return GSK_VULKAN_OFFSCREEN_OP_CLASS.size; +} + +GskVulkanImage * +gsk_vulkan_offscreen_op_init (GskVulkanOp *op, + GdkVulkanContext *context, + GskVulkanRender *render, + const graphene_vec2_t *scale, + const graphene_rect_t *viewport, + VkSemaphore signal_semaphore, + GskRenderNode *node) +{ + GskVulkanOffscreenOp *self = (GskVulkanOffscreenOp *) op; + graphene_rect_t view; + cairo_region_t *clip; + float scale_x, scale_y; + + scale_x = graphene_vec2_get_x (scale); + scale_y = graphene_vec2_get_y (scale); + view = GRAPHENE_RECT_INIT (scale_x * viewport->origin.x, + scale_y * viewport->origin.y, + ceil (scale_x * viewport->size.width), + ceil (scale_y * viewport->size.height)); + + gsk_vulkan_op_init (op, &GSK_VULKAN_OFFSCREEN_OP_CLASS); + + self->image = gsk_vulkan_image_new_for_offscreen (context, + gdk_vulkan_context_get_offscreen_format (context, + gsk_render_node_get_preferred_depth (node)), + view.size.width, view.size.height); + + clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { + 0, 0, + gsk_vulkan_image_get_width (self->image), + gsk_vulkan_image_get_height (self->image) + }); + + self->render_pass = gsk_vulkan_render_pass_new (context, + self->image, + scale, + &view, + clip, + signal_semaphore); + + cairo_region_destroy (clip); + + gsk_vulkan_render_pass_add (self->render_pass, render, node); + + return self->image; +} diff --git a/gsk/vulkan/gskvulkanoffscreenopprivate.h b/gsk/vulkan/gskvulkanoffscreenopprivate.h new file mode 100644 index 0000000000..16687ead35 --- /dev/null +++ b/gsk/vulkan/gskvulkanoffscreenopprivate.h @@ -0,0 +1,18 @@ +#pragma once + +#include "gskvulkanopprivate.h" + +G_BEGIN_DECLS + +gsize gsk_vulkan_offscreen_op_size (void) G_GNUC_CONST; + +GskVulkanImage * gsk_vulkan_offscreen_op_init (GskVulkanOp *op, + GdkVulkanContext *context, + GskVulkanRender *render, + const graphene_vec2_t *scale, + const graphene_rect_t *viewport, + VkSemaphore signal_semaphore, + GskRenderNode *node); + +G_END_DECLS + diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 7885a3329c..6c12861bcb 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -14,6 +14,7 @@ #include "gskvulkanborderpipelineprivate.h" #include "gskvulkanboxshadowpipelineprivate.h" #include "gskvulkanclipprivate.h" +#include "gskvulkancolormatrixopprivate.h" #include "gskvulkancolorpipelineprivate.h" #include "gskvulkancolortextpipelineprivate.h" #include "gskvulkancrossfadepipelineprivate.h" @@ -24,6 +25,7 @@ #include "gskvulkantextpipelineprivate.h" #include "gskvulkantexturepipelineprivate.h" #include "gskvulkanimageprivate.h" +#include "gskvulkanoffscreenopprivate.h" #include "gskvulkanpushconstantsprivate.h" #include "gskvulkanscissoropprivate.h" #include "gskvulkantextureopprivate.h" @@ -58,7 +60,6 @@ typedef enum { GSK_VULKAN_OP_LINEAR_GRADIENT, GSK_VULKAN_OP_OPACITY, GSK_VULKAN_OP_BLUR, - GSK_VULKAN_OP_COLOR_MATRIX, GSK_VULKAN_OP_BORDER, GSK_VULKAN_OP_INSET_SHADOW, GSK_VULKAN_OP_OUTSET_SHADOW, @@ -365,6 +366,73 @@ gsk_vulkan_render_pass_get_pipeline (GskVulkanRenderPass *self, self->render_pass); } +static GskVulkanImage * +gsk_vulkan_render_pass_get_node_as_image (GskVulkanRenderPass *self, + GskVulkanRender *render, + const GskVulkanParseState *state, + GskRenderNode *node, + graphene_rect_t *tex_bounds) +{ + VkSemaphore semaphore; + GskVulkanImage *result; + + switch ((guint) gsk_render_node_get_node_type (node)) + { + case GSK_TEXTURE_NODE: + { + GdkTexture *texture = gsk_texture_node_get_texture (node); + GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)); + result = gsk_vulkan_renderer_get_texture_image (renderer, texture); + if (result == NULL) + { + result = gsk_vulkan_upload_op_init_texture (gsk_vulkan_render_pass_alloc_op (self, gsk_vulkan_upload_op_size ()), + self->vulkan, + texture); + gsk_vulkan_renderer_add_texture_image (renderer, texture, result); + } + + *tex_bounds = node->bounds; + return result; + } + + default: + { + graphene_rect_t clipped; + + graphene_rect_offset_r (&state->clip.rect.bounds, - state->offset.x, - state->offset.y, &clipped); + graphene_rect_intersection (&clipped, &node->bounds, &clipped); + + if (clipped.size.width == 0 || clipped.size.height == 0) + return NULL; + + /* assuming the unclipped bounds should go to texture coordinates 0..1, + * calculate the coordinates for the clipped texture size + */ + *tex_bounds = clipped; + + vkCreateSemaphore (gdk_vulkan_context_get_device (self->vulkan), + &(VkSemaphoreCreateInfo) { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + NULL, + 0 + }, + NULL, + &semaphore); + g_array_append_val (self->wait_semaphores, semaphore); + + result = gsk_vulkan_offscreen_op_init (gsk_vulkan_render_pass_alloc_op (self, gsk_vulkan_offscreen_op_size ()), + self->vulkan, + render, + &state->scale, + &clipped, + semaphore, + node); + + return result; + } + } +} + static void gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, GskVulkanRender *render, @@ -859,11 +927,16 @@ gsk_vulkan_render_pass_add_color_matrix_node (GskVulkanRenderPass *self, GskRenderNode *node) { GskVulkanPipelineType pipeline_type; - GskVulkanOpRender op = { - .type = GSK_VULKAN_OP_COLOR_MATRIX, - .node = node, - .offset = state->offset, - }; + GskVulkanImage *image; + graphene_rect_t tex_rect; + + image = gsk_vulkan_render_pass_get_node_as_image (self, + render, + state, + gsk_color_matrix_node_get_child (node), + &tex_rect); + if (image == NULL) + return TRUE; if (gsk_vulkan_clip_contains_rect (&state->clip, &state->offset, &node->bounds)) pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX; @@ -872,8 +945,14 @@ gsk_vulkan_render_pass_add_color_matrix_node (GskVulkanRenderPass *self, else pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED; - op.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type); - gsk_vulkan_render_pass_add_op (self, (GskVulkanOp *) &op); + gsk_vulkan_color_matrix_op_init (gsk_vulkan_render_pass_alloc_op (self, gsk_vulkan_color_matrix_op_size ()), + gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type), + image, + &node->bounds, + &state->offset, + &tex_rect, + gsk_color_matrix_node_get_color_matrix (node), + gsk_color_matrix_node_get_color_offset (node)); return TRUE; } @@ -1743,23 +1822,6 @@ gsk_vulkan_render_op_upload (GskVulkanOp *op_, } break; - case GSK_VULKAN_OP_COLOR_MATRIX: - { - GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node); - graphene_rect_t tex_bounds; - - op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self, - render, - uploader, - child, - scale, - clip, - &op->render.offset, - &tex_bounds); - gsk_vulkan_normalize_tex_coords (&op->render.source_rect, &op->render.node->bounds, &tex_bounds); - } - break; - case GSK_VULKAN_OP_CROSS_FADE: { GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node); @@ -1882,7 +1944,6 @@ gsk_vulkan_render_op_count_vertex_data (GskVulkanOp *op_, case GSK_VULKAN_OP_COLOR: case GSK_VULKAN_OP_LINEAR_GRADIENT: case GSK_VULKAN_OP_OPACITY: - case GSK_VULKAN_OP_COLOR_MATRIX: case GSK_VULKAN_OP_BLUR: case GSK_VULKAN_OP_BORDER: case GSK_VULKAN_OP_INSET_SHADOW: @@ -2051,17 +2112,6 @@ gsk_vulkan_render_op_collect_vertex_data (GskVulkanOp *op_, gsk_blur_node_get_radius (op->render.node)); break; - case GSK_VULKAN_OP_COLOR_MATRIX: - gsk_vulkan_effect_pipeline_collect_vertex_data (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline), - data + op->render.vertex_offset, - op->render.image_descriptor, - &op->render.offset, - &op->render.node->bounds, - &op->render.source_rect, - gsk_color_matrix_node_get_color_matrix (op->render.node), - gsk_color_matrix_node_get_color_offset (op->render.node)); - break; - case GSK_VULKAN_OP_BORDER: gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline), data + op->render.vertex_offset, @@ -2196,7 +2246,6 @@ gsk_vulkan_render_op_reserve_descriptor_sets (GskVulkanOp *op_, case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP: case GSK_VULKAN_OP_OPACITY: case GSK_VULKAN_OP_BLUR: - case GSK_VULKAN_OP_COLOR_MATRIX: if (op->render.source) { op->render.image_descriptor[0] = gsk_vulkan_render_get_image_descriptor (render, op->render.source); @@ -2310,7 +2359,6 @@ gsk_vulkan_render_op_get_pipeline (GskVulkanOp *op_) case GSK_VULKAN_OP_COLOR: case GSK_VULKAN_OP_LINEAR_GRADIENT: case GSK_VULKAN_OP_OPACITY: - case GSK_VULKAN_OP_COLOR_MATRIX: case GSK_VULKAN_OP_BLUR: case GSK_VULKAN_OP_BORDER: case GSK_VULKAN_OP_INSET_SHADOW: @@ -2369,7 +2417,6 @@ gsk_vulkan_render_op_command (GskVulkanOp *op_, break; case GSK_VULKAN_OP_OPACITY: - case GSK_VULKAN_OP_COLOR_MATRIX: if (!op->render.source) break; gsk_vulkan_effect_pipeline_draw (GSK_VULKAN_EFFECT_PIPELINE (op->render.pipeline),