From 5b184a10a96663179ab8cb37b2875dd5b7a75922 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 9 Feb 2024 02:55:33 +0100 Subject: [PATCH] gpu: Add a CLEAR blend mode for subsurface hole punching The previous code was ignoring non-scissor clips, which would make it overeager at punching holes. It also was not working with fractional coordinates. Fixes #6375 --- gsk/gpu/gskgpublendop.c | 6 ++++++ gsk/gpu/gskgpunodeprocessor.c | 26 +++++++++++--------------- gsk/gpu/gskgputypesprivate.h | 3 ++- gsk/gpu/gskvulkandevice.c | 15 ++++++++++++++- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/gsk/gpu/gskgpublendop.c b/gsk/gpu/gskgpublendop.c index b1ecc4a96e..53dd0f1f29 100644 --- a/gsk/gpu/gskgpublendop.c +++ b/gsk/gpu/gskgpublendop.c @@ -36,6 +36,9 @@ gsk_gpu_blend_op_print (GskGpuOp *op, case GSK_GPU_BLEND_ADD: gsk_gpu_print_string (string, "add"); break; + case GSK_GPU_BLEND_CLEAR: + gsk_gpu_print_string (string, "clear"); + break; default: g_assert_not_reached (); break; @@ -72,6 +75,9 @@ gsk_gpu_blend_op_gl_command (GskGpuOp *op, case GSK_GPU_BLEND_ADD: glBlendFunc (GL_ONE, GL_ONE); break; + case GSK_GPU_BLEND_CLEAR: + glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + break; default: g_assert_not_reached (); break; diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 1ac1efa36a..d522665c35 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -3674,22 +3674,18 @@ gsk_gpu_node_processor_add_subsurface_node (GskGpuNodeProcessor *self, if (!gdk_subsurface_is_above_parent (subsurface)) { - cairo_rectangle_int_t int_rect; + self->blend = GSK_GPU_BLEND_CLEAR; + self->pending_globals |= GSK_GPU_GLOBAL_BLEND; + gsk_gpu_node_processor_sync_globals (self, 0); - if (!gsk_gpu_node_processor_rect_is_integer (self, - &GRAPHENE_RECT_INIT ( - node->bounds.origin.x + self->offset.x, - node->bounds.origin.y + self->offset.y, - node->bounds.size.width, - node->bounds.size.height - ), - &int_rect)) - { - g_warning ("FIXME: non-integer aligned subsurface?!"); - } - gsk_gpu_clear_op (self->frame, - &int_rect, - &GDK_RGBA_TRANSPARENT); + gsk_gpu_color_op (self->frame, + gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds), + &node->bounds, + &self->offset, + &GDK_RGBA_WHITE); + + self->blend = GSK_GPU_BLEND_OVER; + self->pending_globals |= GSK_GPU_GLOBAL_BLEND; } } diff --git a/gsk/gpu/gskgputypesprivate.h b/gsk/gpu/gskgputypesprivate.h index 1ca780a217..a3f6c1d159 100644 --- a/gsk/gpu/gskgputypesprivate.h +++ b/gsk/gpu/gskgputypesprivate.h @@ -49,7 +49,8 @@ typedef enum { typedef enum { GSK_GPU_BLEND_OVER, - GSK_GPU_BLEND_ADD + GSK_GPU_BLEND_ADD, + GSK_GPU_BLEND_CLEAR } GskGpuBlend; typedef enum { diff --git a/gsk/gpu/gskvulkandevice.c b/gsk/gpu/gskvulkandevice.c index cc929f16e5..a542f937c2 100644 --- a/gsk/gpu/gskvulkandevice.c +++ b/gsk/gpu/gskvulkandevice.c @@ -892,7 +892,7 @@ struct _GskVulkanShaderSpecialization guint32 variation; }; -static VkPipelineColorBlendAttachmentState blend_attachment_states[2] = { +static VkPipelineColorBlendAttachmentState blend_attachment_states[3] = { [GSK_GPU_BLEND_OVER] = { .blendEnable = VK_TRUE, .colorBlendOp = VK_BLEND_OP_ADD, @@ -919,6 +919,19 @@ static VkPipelineColorBlendAttachmentState blend_attachment_states[2] = { | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT }, + [GSK_GPU_BLEND_CLEAR] = { + .blendEnable = VK_TRUE, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorWriteMask = VK_COLOR_COMPONENT_A_BIT + | VK_COLOR_COMPONENT_R_BIT + | VK_COLOR_COMPONENT_G_BIT + | VK_COLOR_COMPONENT_B_BIT + }, }; VkPipeline