vulkan: Add a clear op

The op emits a vkCmdClearAttachments() with a given color. That can be
used with color nodes that are pixel-aligned and opaque to significantly
speed up rendering when the window background is a solid color.

However, currently this fails a bit outside of fullscreen when rounded
clip rectangles are in use to draw rounded corners.
This commit is contained in:
Benjamin Otte 2023-07-12 09:26:24 +02:00
parent 5e1fd56345
commit bb2cd7225e
4 changed files with 177 additions and 3 deletions

View File

@ -111,6 +111,7 @@ if have_vulkan
'vulkan/gskvulkanblurop.c',
'vulkan/gskvulkanborderop.c',
'vulkan/gskvulkanbuffer.c',
'vulkan/gskvulkanclearop.c',
'vulkan/gskvulkanclip.c',
'vulkan/gskvulkancolormatrixop.c',
'vulkan/gskvulkancolorop.c',

View File

@ -0,0 +1,124 @@
#include "config.h"
#include "gskvulkanclearopprivate.h"
#include "gskvulkanprivate.h"
typedef struct _GskVulkanClearOp GskVulkanClearOp;
struct _GskVulkanClearOp
{
GskVulkanOp op;
cairo_rectangle_int_t rect;
GdkRGBA color;
};
static void
gsk_vulkan_clear_op_finish (GskVulkanOp *op)
{
}
static void
gsk_vulkan_clear_op_print (GskVulkanOp *op,
GString *string,
guint indent)
{
GskVulkanClearOp *self = (GskVulkanClearOp *) op;
print_indent (string, indent);
print_int_rect (string, &self->rect);
g_string_append_printf (string, "clear ");
print_rgba (string, &self->color);
print_newline (string);
}
static void
gsk_vulkan_clear_op_upload (GskVulkanOp *op,
GskVulkanUploader *uploader)
{
}
static gsize
gsk_vulkan_clear_op_count_vertex_data (GskVulkanOp *op,
gsize n_bytes)
{
return n_bytes;
}
static void
gsk_vulkan_clear_op_collect_vertex_data (GskVulkanOp *op,
guchar *data)
{
}
static void
gsk_vulkan_clear_op_reserve_descriptor_sets (GskVulkanOp *op,
GskVulkanRender *render)
{
}
static void
gsk_vulkan_init_clear_value (VkClearValue *value,
const GdkRGBA *rgba)
{
gsk_vulkan_rgba_to_float (rgba, value->color.float32);
}
static GskVulkanOp *
gsk_vulkan_clear_op_command (GskVulkanOp *op,
GskVulkanRender *render,
VkPipelineLayout pipeline_layout,
VkCommandBuffer command_buffer)
{
GskVulkanClearOp *self = (GskVulkanClearOp *) op;
VkClearValue clear_value;
gsk_vulkan_init_clear_value (&clear_value, &self->color);
vkCmdClearAttachments (command_buffer,
1,
&(VkClearAttachment) {
VK_IMAGE_ASPECT_COLOR_BIT,
0,
clear_value,
},
1,
&(VkClearRect) {
{
{ self->rect.x, self->rect.y },
{ self->rect.width, self->rect.height },
},
0,
1
});
return op->next;
}
static const GskVulkanOpClass GSK_VULKAN_SCISSOR_OP_CLASS = {
GSK_VULKAN_OP_SIZE (GskVulkanClearOp),
GSK_VULKAN_STAGE_COMMAND,
NULL,
NULL,
gsk_vulkan_clear_op_finish,
gsk_vulkan_clear_op_print,
gsk_vulkan_clear_op_upload,
gsk_vulkan_clear_op_count_vertex_data,
gsk_vulkan_clear_op_collect_vertex_data,
gsk_vulkan_clear_op_reserve_descriptor_sets,
gsk_vulkan_clear_op_command
};
void
gsk_vulkan_clear_op (GskVulkanRender *render,
const cairo_rectangle_int_t *rect,
const GdkRGBA *color)
{
GskVulkanClearOp *self;
self = (GskVulkanClearOp *) gsk_vulkan_op_alloc (render, &GSK_VULKAN_SCISSOR_OP_CLASS);
self->rect = *rect;
self->color = *color;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "gskvulkanopprivate.h"
G_BEGIN_DECLS
void gsk_vulkan_clear_op (GskVulkanRender *render,
const cairo_rectangle_int_t *rect,
const GdkRGBA *color);
G_END_DECLS

View File

@ -12,6 +12,7 @@
#include "gskvulkanblendmodeopprivate.h"
#include "gskvulkanbluropprivate.h"
#include "gskvulkanborderopprivate.h"
#include "gskvulkanclearopprivate.h"
#include "gskvulkanclipprivate.h"
#include "gskvulkancolormatrixopprivate.h"
#include "gskvulkancoloropprivate.h"
@ -349,11 +350,46 @@ gsk_vulkan_render_pass_add_color_node (GskVulkanRenderPass *self,
const GskVulkanParseState *state,
GskRenderNode *node)
{
cairo_rectangle_int_t int_clipped;
graphene_rect_t rect, clipped;
const GdkRGBA *color;
color = gsk_color_node_get_color (node);
graphene_rect_offset_r (&node->bounds,
state->offset.x, state->offset.y,
&rect);
graphene_rect_intersection (&state->clip.rect.bounds, &rect, &clipped);
if (gdk_rgba_is_opaque (color) &&
gsk_vulkan_parse_rect_is_integer (state, &clipped, &int_clipped))
{
/* now handle all the clip */
if (!gdk_rectangle_intersect (&int_clipped, &state->scissor, &int_clipped))
return TRUE;
/* we have handled the bounds, now do the corners */
if (state->clip.type != GSK_VULKAN_CLIP_ROUNDED ||
gsk_vulkan_clip_contains_rect (&state->clip,
graphene_point_zero (),
&GRAPHENE_RECT_INIT (
int_clipped.x / graphene_vec2_get_x (&state->scale),
int_clipped.y / graphene_vec2_get_y (&state->scale),
int_clipped.width / graphene_vec2_get_x (&state->scale),
int_clipped.height / graphene_vec2_get_y (&state->scale)
)))
{
gsk_vulkan_clear_op (render,
&int_clipped,
color);
return TRUE;
}
}
gsk_vulkan_color_op (render,
gsk_vulkan_clip_get_clip_type (&state->clip, &state->offset, &node->bounds),
&node->bounds,
&state->offset,
gsk_color_node_get_color (node));
&rect,
graphene_point_zero (),
color);
return TRUE;
}