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.
This commit is contained in:
Benjamin Otte 2023-05-19 03:08:43 +02:00
parent dd4c1167b2
commit 7fd94c1828

View File

@ -35,6 +35,7 @@ typedef union _GskVulkanOp GskVulkanOp;
typedef struct _GskVulkanOpRender GskVulkanOpRender; typedef struct _GskVulkanOpRender GskVulkanOpRender;
typedef struct _GskVulkanOpText GskVulkanOpText; typedef struct _GskVulkanOpText GskVulkanOpText;
typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants; typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
typedef struct _GskVulkanOpScissor GskVulkanOpScissor;
typedef enum { typedef enum {
/* GskVulkanOpRender */ /* GskVulkanOpRender */
@ -58,6 +59,8 @@ typedef enum {
GSK_VULKAN_OP_COLOR_TEXT, GSK_VULKAN_OP_COLOR_TEXT,
/* GskVulkanOpPushConstants */ /* GskVulkanOpPushConstants */
GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS, GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
/* GskVulkanOpScissor */
GSK_VULKAN_OP_SCISSOR,
} GskVulkanOpType; } GskVulkanOpType;
/* render ops with 0, 1 or 2 sources */ /* render ops with 0, 1 or 2 sources */
@ -102,12 +105,20 @@ struct _GskVulkanOpPushConstants
GskRoundedRect clip; GskRoundedRect clip;
}; };
struct _GskVulkanOpScissor
{
GskVulkanOpType type;
GskRenderNode *node; /* node that's the source of this op */
cairo_rectangle_int_t rect;
};
union _GskVulkanOp union _GskVulkanOp
{ {
GskVulkanOpType type; GskVulkanOpType type;
GskVulkanOpRender render; GskVulkanOpRender render;
GskVulkanOpText text; GskVulkanOpText text;
GskVulkanOpPushConstants constants; GskVulkanOpPushConstants constants;
GskVulkanOpScissor scissor;
}; };
struct _GskVulkanRenderPass struct _GskVulkanRenderPass
@ -130,11 +141,12 @@ struct _GskVulkanRenderPass
struct _GskVulkanParseState struct _GskVulkanParseState
{ {
graphene_point_t offset; cairo_rectangle_int_t scissor;
graphene_vec2_t scale; graphene_point_t offset;
GskTransform *modelview; graphene_vec2_t scale;
graphene_matrix_t projection; GskTransform *modelview;
GskVulkanClip clip; graphene_matrix_t projection;
GskVulkanClip clip;
}; };
#ifdef G_ENABLE_DEBUG #ifdef G_ENABLE_DEBUG
@ -242,6 +254,19 @@ gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
g_free (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 static void
gsk_vulkan_render_pass_append_push_constants (GskVulkanRenderPass *self, gsk_vulkan_render_pass_append_push_constants (GskVulkanRenderPass *self,
GskRenderNode *node, GskRenderNode *node,
@ -671,6 +696,7 @@ gsk_vulkan_render_pass_add_transform_node (GskVulkanRenderPass *self,
break; break;
} }
new_state.scissor = state->scissor;
graphene_matrix_init_from_matrix (&new_state.projection, &state->projection); graphene_matrix_init_from_matrix (&new_state.projection, &state->projection);
gsk_vulkan_render_pass_append_push_constants (self, node, &new_state); 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) if (new_state.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
return TRUE; return TRUE;
new_state.scissor = state->scissor;
new_state.offset = state->offset; new_state.offset = state->offset;
graphene_vec2_init_from_vec2 (&new_state.scale, &state->scale); graphene_vec2_init_from_vec2 (&new_state.scale, &state->scale);
new_state.modelview = state->modelview; 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) if (new_state.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
return TRUE; return TRUE;
new_state.scissor = state->scissor;
new_state.offset = state->offset; new_state.offset = state->offset;
graphene_vec2_init_from_vec2 (&new_state.scale, &state->scale); graphene_vec2_init_from_vec2 (&new_state.scale, &state->scale);
new_state.modelview = state->modelview; new_state.modelview = state->modelview;
@ -1095,38 +1123,33 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
} }
void void
gsk_vulkan_render_pass_add (GskVulkanRenderPass *self, gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
GskVulkanRender *render, GskVulkanRender *render,
GskRenderNode *node) GskRenderNode *node)
{ {
GskVulkanParseState state; GskVulkanParseState state;
cairo_rectangle_int_t rect;
graphene_rect_t clip; graphene_rect_t clip;
float scale_x, scale_y;
cairo_region_get_extents (self->clip, &rect); scale_x = 1 / graphene_vec2_get_x (&self->scale);
clip = GRAPHENE_RECT_INIT(rect.x + self->viewport.origin.x, scale_y = 1 / graphene_vec2_get_y (&self->scale);
rect.y + self->viewport.origin.y, cairo_region_get_extents (self->clip, &state.scissor);
rect.width, rect.height); clip = GRAPHENE_RECT_INIT(state.scissor.x, state.scissor.y,
if (graphene_rect_equal (&clip, &self->viewport)) state.scissor.width, state.scissor.height);
{ graphene_rect_scale (&clip, scale_x, scale_y, &clip);
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, &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);
}
state.modelview = NULL; state.modelview = NULL;
graphene_matrix_init_ortho (&state.projection, graphene_matrix_init_ortho (&state.projection,
self->viewport.origin.x, self->viewport.origin.x + self->viewport.size.width, 0, self->viewport.size.width,
self->viewport.origin.y, self->viewport.origin.y + self->viewport.size.height, 0, self->viewport.size.height,
2 * ORTHO_NEAR_PLANE - ORTHO_FAR_PLANE, 2 * ORTHO_NEAR_PLANE - ORTHO_FAR_PLANE,
ORTHO_FAR_PLANE); ORTHO_FAR_PLANE);
graphene_vec2_init_from_vec2 (&state.scale, &self->scale); 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_append_push_constants (self, node, &state);
gsk_vulkan_render_pass_add_node (self, render, &state, node); 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_BORDER:
case GSK_VULKAN_OP_INSET_SHADOW: case GSK_VULKAN_OP_INSET_SHADOW:
case GSK_VULKAN_OP_OUTSET_SHADOW: case GSK_VULKAN_OP_OUTSET_SHADOW:
case GSK_VULKAN_OP_SCISSOR:
break; break;
} }
} }
@ -1672,6 +1696,7 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
g_assert_not_reached (); g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
case GSK_VULKAN_OP_SCISSOR:
continue; continue;
} }
} }
@ -1866,6 +1891,7 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
default: default:
g_assert_not_reached (); g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
case GSK_VULKAN_OP_SCISSOR:
continue; continue;
} }
} }
@ -1957,10 +1983,11 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
case GSK_VULKAN_OP_COLOR: case GSK_VULKAN_OP_COLOR:
case GSK_VULKAN_OP_LINEAR_GRADIENT: case GSK_VULKAN_OP_LINEAR_GRADIENT:
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
case GSK_VULKAN_OP_BORDER: case GSK_VULKAN_OP_BORDER:
case GSK_VULKAN_OP_INSET_SHADOW: case GSK_VULKAN_OP_INSET_SHADOW:
case GSK_VULKAN_OP_OUTSET_SHADOW: case GSK_VULKAN_OP_OUTSET_SHADOW:
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
case GSK_VULKAN_OP_SCISSOR:
break; break;
} }
} }
@ -2209,6 +2236,16 @@ gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass *self,
&op->constants.clip); &op->constants.clip);
break; 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: case GSK_VULKAN_OP_CROSS_FADE:
if (!op->render.source || !op->render.source2) if (!op->render.source || !op->render.source2)
continue; continue;
@ -2296,14 +2333,6 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
cairo_region_get_extents (self->clip, &rect); cairo_region_get_extents (self->clip, &rect);
vkCmdSetScissor (command_buffer,
0,
1,
&(VkRect2D) {
{ rect.x, rect.y },
{ rect.width, rect.height }
});
vkCmdBeginRenderPass (command_buffer, vkCmdBeginRenderPass (command_buffer,
&(VkRenderPassBeginInfo) { &(VkRenderPassBeginInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,