diff --git a/gsk/gpu/gskgpuclearop.c b/gsk/gpu/gskgpuclearop.c new file mode 100644 index 0000000000..81306d722e --- /dev/null +++ b/gsk/gpu/gskgpuclearop.c @@ -0,0 +1,127 @@ +#include "config.h" + +#include "gskgpuclearopprivate.h" + +#include "gskgpuopprivate.h" +#include "gskgpuprintprivate.h" +/* for gsk_gpu_rgba_to_float() */ +#include "gskgpushaderopprivate.h" + +typedef struct _GskGpuClearOp GskGpuClearOp; + +struct _GskGpuClearOp +{ + GskGpuOp op; + + cairo_rectangle_int_t rect; + GdkRGBA color; +}; + +static void +gsk_gpu_clear_op_finish (GskGpuOp *op) +{ +} + +static void +gsk_gpu_clear_op_print (GskGpuOp *op, + GskGpuFrame *frame, + GString *string, + guint indent) +{ + GskGpuClearOp *self = (GskGpuClearOp *) op; + float rgba[4]; + + gsk_gpu_print_op (string, indent, "clear"); + gsk_gpu_print_int_rect (string, &self->rect); + gsk_gpu_rgba_to_float (&self->color, rgba); + gsk_gpu_print_rgba (string, rgba); + gsk_gpu_print_newline (string); +} + +#ifdef GDK_RENDERING_VULKAN +static void +gsk_gpu_init_clear_value (VkClearValue *value, + const GdkRGBA *rgba) +{ + gsk_gpu_rgba_to_float (rgba, value->color.float32); +} + +static GskGpuOp * +gsk_gpu_clear_op_vk_command (GskGpuOp *op, + GskGpuFrame *frame, + VkRenderPass render_pass, + VkFormat format, + VkCommandBuffer command_buffer) +{ + GskGpuClearOp *self = (GskGpuClearOp *) op; + VkClearValue clear_value; + + gsk_gpu_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; +} +#endif + +static GskGpuOp * +gsk_gpu_clear_op_gl_command (GskGpuOp *op, + GskGpuFrame *frame, + gsize flip_y) +{ + GskGpuClearOp *self = (GskGpuClearOp *) op; + int scissor[4]; + + glGetIntegerv (GL_SCISSOR_BOX, scissor); + + if (flip_y) + glScissor (self->rect.x, flip_y - self->rect.y - self->rect.height, self->rect.width, self->rect.height); + else + glScissor (self->rect.x, self->rect.y, self->rect.width, self->rect.height); + + glClearColor (self->color.red, self->color.green, self->color.blue, self->color.alpha); + glClear (GL_COLOR_BUFFER_BIT); + + glScissor (scissor[0], scissor[1], scissor[2], scissor[3]); + + return op->next; +} + +static const GskGpuOpClass GSK_GPU_CLEAR_OP_CLASS = { + GSK_GPU_OP_SIZE (GskGpuClearOp), + GSK_GPU_STAGE_COMMAND, + gsk_gpu_clear_op_finish, + gsk_gpu_clear_op_print, +#ifdef GDK_RENDERING_VULKAN + gsk_gpu_clear_op_vk_command, +#endif + gsk_gpu_clear_op_gl_command +}; + +void +gsk_gpu_clear_op (GskGpuFrame *frame, + const cairo_rectangle_int_t *rect, + const GdkRGBA *color) +{ + GskGpuClearOp *self; + + self = (GskGpuClearOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_CLEAR_OP_CLASS); + + self->rect = *rect; + self->color = *color; +} diff --git a/gsk/gpu/gskgpuclearopprivate.h b/gsk/gpu/gskgpuclearopprivate.h new file mode 100644 index 0000000000..dc07dee83c --- /dev/null +++ b/gsk/gpu/gskgpuclearopprivate.h @@ -0,0 +1,13 @@ +#pragma once + +#include "gskgputypesprivate.h" + +G_BEGIN_DECLS + +void gsk_gpu_clear_op (GskGpuFrame *frame, + const cairo_rectangle_int_t *rect, + const GdkRGBA *color); + + +G_END_DECLS + diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 75380b7eec..bb6c0b94a3 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -4,6 +4,7 @@ #include "gskgpuborderopprivate.h" #include "gskgpubluropprivate.h" +#include "gskgpuclearopprivate.h" #include "gskgpuclipprivate.h" #include "gskgpucolorizeopprivate.h" #include "gskgpucoloropprivate.h" @@ -945,6 +946,104 @@ static void gsk_gpu_node_processor_add_color_node (GskGpuNodeProcessor *self, 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, + self->offset.x, self->offset.y, + &rect); + gsk_rect_intersection (&self->clip.rect.bounds, &rect, &clipped); + + if (gdk_rgba_is_opaque (color) && + node->bounds.size.width * node->bounds.size.height > 100 * 100 && /* not worth the effort for small images */ + gsk_gpu_node_processor_rect_is_integer (self, &clipped, &int_clipped)) + { + /* now handle all the clip */ + if (!gdk_rectangle_intersect (&int_clipped, &self->scissor, &int_clipped)) + return; + + /* we have handled the bounds, now do the corners */ + if (self->clip.type == GSK_GPU_CLIP_ROUNDED) + { + graphene_rect_t cover; + GskGpuShaderClip shader_clip; + float scale_x, scale_y; + + if (self->modelview) + { + /* Yuck, rounded clip and modelview. I give up. */ + gsk_gpu_color_op (self->frame, + gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds), + &node->bounds, + &self->offset, + gsk_color_node_get_color (node)); + return; + } + + scale_x = graphene_vec2_get_x (&self->scale); + scale_y = graphene_vec2_get_y (&self->scale); + clipped = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y, + int_clipped.width / scale_x, int_clipped.height / scale_y); + shader_clip = gsk_gpu_clip_get_shader_clip (&self->clip, graphene_point_zero(), &clipped); + if (shader_clip != GSK_GPU_SHADER_CLIP_NONE) + { + gsk_rounded_rect_get_largest_cover (&self->clip.rect, &clipped, &cover); + int_clipped.x = ceil (cover.origin.x * scale_x); + int_clipped.y = ceil (cover.origin.y * scale_y); + int_clipped.width = floor ((cover.origin.x + cover.size.width) * scale_x) - int_clipped.x; + int_clipped.height = floor ((cover.origin.y + cover.size.height) * scale_y) - int_clipped.y; + if (int_clipped.width == 0 || int_clipped.height == 0) + { + gsk_gpu_color_op (self->frame, + shader_clip, + &clipped, + graphene_point_zero (), + color); + return; + } + cover = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y, + int_clipped.width / scale_x, int_clipped.height / scale_y); + if (clipped.origin.x != cover.origin.x) + gsk_gpu_color_op (self->frame, + shader_clip, + &GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, cover.origin.x - clipped.origin.x, clipped.size.height), + graphene_point_zero (), + color); + if (clipped.origin.y != cover.origin.y) + gsk_gpu_color_op (self->frame, + shader_clip, + &GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, clipped.size.width, cover.origin.y - clipped.origin.y), + graphene_point_zero (), + color); + if (clipped.origin.x + clipped.size.width != cover.origin.x + cover.size.width) + gsk_gpu_color_op (self->frame, + shader_clip, + &GRAPHENE_RECT_INIT (cover.origin.x + cover.size.width, + clipped.origin.y, + clipped.origin.x + clipped.size.width - cover.origin.x - cover.size.width, + clipped.size.height), + graphene_point_zero (), + color); + if (clipped.origin.y + clipped.size.height != cover.origin.y + cover.size.height) + gsk_gpu_color_op (self->frame, + shader_clip, + &GRAPHENE_RECT_INIT (clipped.origin.x, + cover.origin.y + cover.size.height, + clipped.size.width, + clipped.origin.y + clipped.size.height - cover.origin.y - cover.size.height), + graphene_point_zero (), + color); + } + } + + gsk_gpu_clear_op (self->frame, + &int_clipped, + color); + return; + } + gsk_gpu_color_op (self->frame, gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds), &node->bounds, diff --git a/gsk/meson.build b/gsk/meson.build index 0abd29bcab..a4b6606876 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -76,6 +76,7 @@ gsk_private_sources = files([ 'gpu/gskgpuborderop.c', 'gpu/gskgpubuffer.c', 'gpu/gskgpubufferwriter.c', + 'gpu/gskgpuclearop.c', 'gpu/gskgpuclip.c', 'gpu/gskgpucolorizeop.c', 'gpu/gskgpucolorop.c',