From 7fd94c1828fd6ff26d597f5916399ff27e61c98a Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 19 May 2023 03:08:43 +0200 Subject: [PATCH] vulkan: Make scissoring an explicit operation The idea is to use it for clip nodes when they are integer-aligned. To do that, we need to track the scissor rect in the parse state, so we do that, too. Also move the viewport offset out of the projection matrix, as it is part of the transform between clip and scissor, so it needs to live in the offset. --- gsk/vulkan/gskvulkanrenderpass.c | 99 +++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 35 deletions(-) diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index b02db065a7..e4e7c1ea0e 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -35,6 +35,7 @@ typedef union _GskVulkanOp GskVulkanOp; typedef struct _GskVulkanOpRender GskVulkanOpRender; typedef struct _GskVulkanOpText GskVulkanOpText; typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants; +typedef struct _GskVulkanOpScissor GskVulkanOpScissor; typedef enum { /* GskVulkanOpRender */ @@ -58,6 +59,8 @@ typedef enum { GSK_VULKAN_OP_COLOR_TEXT, /* GskVulkanOpPushConstants */ GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS, + /* GskVulkanOpScissor */ + GSK_VULKAN_OP_SCISSOR, } GskVulkanOpType; /* render ops with 0, 1 or 2 sources */ @@ -102,12 +105,20 @@ struct _GskVulkanOpPushConstants GskRoundedRect clip; }; +struct _GskVulkanOpScissor +{ + GskVulkanOpType type; + GskRenderNode *node; /* node that's the source of this op */ + cairo_rectangle_int_t rect; +}; + union _GskVulkanOp { GskVulkanOpType type; GskVulkanOpRender render; GskVulkanOpText text; GskVulkanOpPushConstants constants; + GskVulkanOpScissor scissor; }; struct _GskVulkanRenderPass @@ -130,11 +141,12 @@ struct _GskVulkanRenderPass struct _GskVulkanParseState { - graphene_point_t offset; - graphene_vec2_t scale; - GskTransform *modelview; - graphene_matrix_t projection; - GskVulkanClip clip; + cairo_rectangle_int_t scissor; + graphene_point_t offset; + graphene_vec2_t scale; + GskTransform *modelview; + graphene_matrix_t projection; + GskVulkanClip clip; }; #ifdef G_ENABLE_DEBUG @@ -242,6 +254,19 @@ gsk_vulkan_render_pass_free (GskVulkanRenderPass *self) g_free (self); } +static void +gsk_vulkan_render_pass_append_scissor (GskVulkanRenderPass *self, + GskRenderNode *node, + const GskVulkanParseState *state) +{ + GskVulkanOp op = { + .scissor.type = GSK_VULKAN_OP_SCISSOR, + .scissor.node = node, + .scissor.rect = state->scissor + }; + g_array_append_val (self->render_ops, op); +} + static void gsk_vulkan_render_pass_append_push_constants (GskVulkanRenderPass *self, GskRenderNode *node, @@ -671,6 +696,7 @@ gsk_vulkan_render_pass_add_transform_node (GskVulkanRenderPass *self, break; } + new_state.scissor = state->scissor; graphene_matrix_init_from_matrix (&new_state.projection, &state->projection); gsk_vulkan_render_pass_append_push_constants (self, node, &new_state); @@ -759,6 +785,7 @@ gsk_vulkan_render_pass_add_clip_node (GskVulkanRenderPass *self, if (new_state.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED) return TRUE; + new_state.scissor = state->scissor; new_state.offset = state->offset; graphene_vec2_init_from_vec2 (&new_state.scale, &state->scale); new_state.modelview = state->modelview; @@ -791,6 +818,7 @@ gsk_vulkan_render_pass_add_rounded_clip_node (GskVulkanRenderPass *self, if (new_state.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED) return TRUE; + new_state.scissor = state->scissor; new_state.offset = state->offset; graphene_vec2_init_from_vec2 (&new_state.scale, &state->scale); new_state.modelview = state->modelview; @@ -1095,38 +1123,33 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, } void -gsk_vulkan_render_pass_add (GskVulkanRenderPass *self, - GskVulkanRender *render, - GskRenderNode *node) +gsk_vulkan_render_pass_add (GskVulkanRenderPass *self, + GskVulkanRender *render, + GskRenderNode *node) { GskVulkanParseState state; - cairo_rectangle_int_t rect; graphene_rect_t clip; + float scale_x, scale_y; - cairo_region_get_extents (self->clip, &rect); - clip = GRAPHENE_RECT_INIT(rect.x + self->viewport.origin.x, - rect.y + self->viewport.origin.y, - rect.width, rect.height); - if (graphene_rect_equal (&clip, &self->viewport)) - { - graphene_rect_scale (&clip, 1 / graphene_vec2_get_x (&self->scale), 1 / graphene_vec2_get_y (&self->scale), &clip); - gsk_vulkan_clip_init_empty (&state.clip, &self->viewport); - } - else - { - graphene_rect_scale (&clip, 1 / graphene_vec2_get_x (&self->scale), 1 / graphene_vec2_get_y (&self->scale), &clip); - gsk_vulkan_clip_init_rect (&state.clip, &clip); - } + scale_x = 1 / graphene_vec2_get_x (&self->scale); + scale_y = 1 / graphene_vec2_get_y (&self->scale); + cairo_region_get_extents (self->clip, &state.scissor); + clip = GRAPHENE_RECT_INIT(state.scissor.x, state.scissor.y, + state.scissor.width, state.scissor.height); + graphene_rect_scale (&clip, scale_x, scale_y, &clip); + gsk_vulkan_clip_init_empty (&state.clip, &clip); state.modelview = NULL; graphene_matrix_init_ortho (&state.projection, - self->viewport.origin.x, self->viewport.origin.x + self->viewport.size.width, - self->viewport.origin.y, self->viewport.origin.y + self->viewport.size.height, + 0, self->viewport.size.width, + 0, self->viewport.size.height, 2 * ORTHO_NEAR_PLANE - ORTHO_FAR_PLANE, ORTHO_FAR_PLANE); graphene_vec2_init_from_vec2 (&state.scale, &self->scale); - state.offset = *graphene_point_zero (); + state.offset = GRAPHENE_POINT_INIT (-self->viewport.origin.x * scale_x, + -self->viewport.origin.y * scale_y); + gsk_vulkan_render_pass_append_scissor (self, node, &state); gsk_vulkan_render_pass_append_push_constants (self, node, &state); gsk_vulkan_render_pass_add_node (self, render, &state, node); @@ -1614,6 +1637,7 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, case GSK_VULKAN_OP_BORDER: case GSK_VULKAN_OP_INSET_SHADOW: case GSK_VULKAN_OP_OUTSET_SHADOW: + case GSK_VULKAN_OP_SCISSOR: break; } } @@ -1672,6 +1696,7 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self) g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: + case GSK_VULKAN_OP_SCISSOR: continue; } } @@ -1866,6 +1891,7 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: + case GSK_VULKAN_OP_SCISSOR: continue; } } @@ -1957,10 +1983,11 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, case GSK_VULKAN_OP_COLOR: case GSK_VULKAN_OP_LINEAR_GRADIENT: - case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: case GSK_VULKAN_OP_BORDER: case GSK_VULKAN_OP_INSET_SHADOW: case GSK_VULKAN_OP_OUTSET_SHADOW: + case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: + case GSK_VULKAN_OP_SCISSOR: break; } } @@ -2209,6 +2236,16 @@ gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass *self, &op->constants.clip); break; + case GSK_VULKAN_OP_SCISSOR: + vkCmdSetScissor (command_buffer, + 0, + 1, + &(VkRect2D) { + { op->scissor.rect.x, op->scissor.rect.y }, + { op->scissor.rect.width, op->scissor.rect.height }, + }); + break; + case GSK_VULKAN_OP_CROSS_FADE: if (!op->render.source || !op->render.source2) continue; @@ -2296,14 +2333,6 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, cairo_region_get_extents (self->clip, &rect); - vkCmdSetScissor (command_buffer, - 0, - 1, - &(VkRect2D) { - { rect.x, rect.y }, - { rect.width, rect.height } - }); - vkCmdBeginRenderPass (command_buffer, &(VkRenderPassBeginInfo) { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,