diff --git a/gsk/gpu/gskglframe.c b/gsk/gpu/gskglframe.c index 79008d07d8..d5f1c591a3 100644 --- a/gsk/gpu/gskglframe.c +++ b/gsk/gpu/gskglframe.c @@ -146,11 +146,7 @@ gsk_gl_frame_submit (GskGpuFrame *frame, glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LEQUAL); - - /* Pre-multiplied alpha */ glEnable (GL_BLEND); - glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation (GL_FUNC_ADD); if (vertex_buffer) gsk_gl_buffer_bind (GSK_GL_BUFFER (vertex_buffer)); diff --git a/gsk/gpu/gskgpublendop.c b/gsk/gpu/gskgpublendop.c new file mode 100644 index 0000000000..b1ecc4a96e --- /dev/null +++ b/gsk/gpu/gskgpublendop.c @@ -0,0 +1,103 @@ +#include "config.h" + +#include "gskgpublendopprivate.h" + +#include "gskgpuopprivate.h" +#include "gskgpuprintprivate.h" + +typedef struct _GskGpuBlendOp GskGpuBlendOp; + +struct _GskGpuBlendOp +{ + GskGpuOp op; + + GskGpuBlend blend; +}; + +static void +gsk_gpu_blend_op_finish (GskGpuOp *op) +{ +} + +static void +gsk_gpu_blend_op_print (GskGpuOp *op, + GskGpuFrame *frame, + GString *string, + guint indent) +{ + GskGpuBlendOp *self = (GskGpuBlendOp *) op; + + gsk_gpu_print_op (string, indent, "blend"); + switch (self->blend) + { + case GSK_GPU_BLEND_OVER: + gsk_gpu_print_string (string, "over"); + break; + case GSK_GPU_BLEND_ADD: + gsk_gpu_print_string (string, "add"); + break; + default: + g_assert_not_reached (); + break; + } + gsk_gpu_print_newline (string); +} + +#ifdef GDK_RENDERING_VULKAN +static GskGpuOp * +gsk_gpu_blend_op_vk_command (GskGpuOp *op, + GskGpuFrame *frame, + GskVulkanCommandState *state) +{ + GskGpuBlendOp *self = (GskGpuBlendOp *) op; + + state->blend = self->blend; + + return op->next; +} +#endif + +static GskGpuOp * +gsk_gpu_blend_op_gl_command (GskGpuOp *op, + GskGpuFrame *frame, + GskGLCommandState *state) +{ + GskGpuBlendOp *self = (GskGpuBlendOp *) op; + + switch (self->blend) + { + case GSK_GPU_BLEND_OVER: + glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + break; + case GSK_GPU_BLEND_ADD: + glBlendFunc (GL_ONE, GL_ONE); + break; + default: + g_assert_not_reached (); + break; + } + + return op->next; +} + +static const GskGpuOpClass GSK_GPU_BLEND_OP_CLASS = { + GSK_GPU_OP_SIZE (GskGpuBlendOp), + GSK_GPU_STAGE_COMMAND, + gsk_gpu_blend_op_finish, + gsk_gpu_blend_op_print, +#ifdef GDK_RENDERING_VULKAN + gsk_gpu_blend_op_vk_command, +#endif + gsk_gpu_blend_op_gl_command +}; + +void +gsk_gpu_blend_op (GskGpuFrame *frame, + GskGpuBlend blend) +{ + GskGpuBlendOp *self; + + self = (GskGpuBlendOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_BLEND_OP_CLASS); + + self->blend = blend; +} diff --git a/gsk/gpu/gskgpublendopprivate.h b/gsk/gpu/gskgpublendopprivate.h new file mode 100644 index 0000000000..eb1b765d44 --- /dev/null +++ b/gsk/gpu/gskgpublendopprivate.h @@ -0,0 +1,12 @@ +#pragma once + +#include "gskgputypesprivate.h" + +G_BEGIN_DECLS + +void gsk_gpu_blend_op (GskGpuFrame *frame, + GskGpuBlend blend); + + +G_END_DECLS + diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 8053961d41..1e8ae61d8d 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -4,6 +4,7 @@ #include "gskgpuborderopprivate.h" #include "gskgpuboxshadowopprivate.h" +#include "gskgpublendopprivate.h" #include "gskgpublitopprivate.h" #include "gskgpubluropprivate.h" #include "gskgpuclearopprivate.h" @@ -89,6 +90,7 @@ typedef enum { GSK_GPU_GLOBAL_SCALE = (1 << 1), GSK_GPU_GLOBAL_CLIP = (1 << 2), GSK_GPU_GLOBAL_SCISSOR = (1 << 3), + GSK_GPU_GLOBAL_BLEND = (1 << 4), } GskGpuGlobals; struct _GskGpuNodeProcessor @@ -96,6 +98,7 @@ struct _GskGpuNodeProcessor GskGpuFrame *frame; GskGpuDescriptors *desc; cairo_rectangle_int_t scissor; + GskGpuBlend blend; graphene_point_t offset; graphene_matrix_t projection; graphene_vec2_t scale; @@ -154,6 +157,7 @@ gsk_gpu_node_processor_init (GskGpuNodeProcessor *self, self->desc = NULL; self->scissor = *clip; + self->blend = GSK_GPU_BLEND_OVER; gsk_gpu_clip_init_empty (&self->clip, &GRAPHENE_RECT_INIT (0, 0, viewport->size.width, viewport->size.height)); self->modelview = NULL; @@ -163,7 +167,7 @@ gsk_gpu_node_processor_init (GskGpuNodeProcessor *self, self->offset = GRAPHENE_POINT_INIT (-viewport->origin.x, -viewport->origin.y); self->opacity = 1.0; - self->pending_globals = GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR; + self->pending_globals = GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND; } static void @@ -195,6 +199,13 @@ gsk_gpu_node_processor_emit_scissor_op (GskGpuNodeProcessor *self) self->pending_globals &= ~GSK_GPU_GLOBAL_SCISSOR; } +static void +gsk_gpu_node_processor_emit_blend_op (GskGpuNodeProcessor *self) +{ + gsk_gpu_blend_op (self->frame, self->blend); + self->pending_globals &= ~GSK_GPU_GLOBAL_BLEND; +} + static void gsk_gpu_node_processor_sync_globals (GskGpuNodeProcessor *self, GskGpuGlobals ignored) @@ -207,6 +218,8 @@ gsk_gpu_node_processor_sync_globals (GskGpuNodeProcessor *self, gsk_gpu_node_processor_emit_globals_op (self); if (required & GSK_GPU_GLOBAL_SCISSOR) gsk_gpu_node_processor_emit_scissor_op (self); + if (required & GSK_GPU_GLOBAL_BLEND) + gsk_gpu_node_processor_emit_blend_op (self); } static guint32 @@ -3075,7 +3088,7 @@ static const struct NULL, }, [GSK_TRANSFORM_NODE] = { - GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR, + GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND, GSK_GPU_HANDLE_OPACITY, gsk_gpu_node_processor_add_transform_node, gsk_gpu_node_processor_create_transform_pattern, @@ -3099,13 +3112,13 @@ static const struct gsk_gpu_node_processor_create_repeat_pattern }, [GSK_CLIP_NODE] = { - GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR, + GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND, GSK_GPU_HANDLE_OPACITY, gsk_gpu_node_processor_add_clip_node, gsk_gpu_node_processor_create_clip_pattern, }, [GSK_ROUNDED_CLIP_NODE] = { - GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR, + GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND, GSK_GPU_HANDLE_OPACITY, gsk_gpu_node_processor_add_rounded_clip_node, NULL, @@ -3141,7 +3154,7 @@ static const struct NULL, }, [GSK_DEBUG_NODE] = { - GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR, + GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND, GSK_GPU_HANDLE_OPACITY, gsk_gpu_node_processor_add_debug_node, gsk_gpu_node_processor_create_debug_pattern, @@ -3177,7 +3190,7 @@ static const struct NULL, }, [GSK_SUBSURFACE_NODE] = { - GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR, + GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR | GSK_GPU_GLOBAL_BLEND, GSK_GPU_HANDLE_OPACITY, gsk_gpu_node_processor_add_subsurface_node, gsk_gpu_node_processor_create_subsurface_pattern, diff --git a/gsk/gpu/gskgpuopprivate.h b/gsk/gpu/gskgpuopprivate.h index 7cfc9f0675..5853c15206 100644 --- a/gsk/gpu/gskgpuopprivate.h +++ b/gsk/gpu/gskgpuopprivate.h @@ -37,6 +37,7 @@ struct _GskVulkanCommandState VkRenderPass vk_render_pass; VkFormat vk_format; VkCommandBuffer vk_command_buffer; + GskGpuBlend blend; GskVulkanDescriptors *desc; GskVulkanSemaphores *semaphores; diff --git a/gsk/gpu/gskgpuprint.c b/gsk/gpu/gskgpuprint.c index fe9c460d20..0ed05a8f88 100644 --- a/gsk/gpu/gskgpuprint.c +++ b/gsk/gpu/gskgpuprint.c @@ -22,6 +22,14 @@ gsk_gpu_print_op (GString *string, g_string_append_c (string, ' '); } +void +gsk_gpu_print_string (GString *string, + const char *s) +{ + g_string_append (string, s); + g_string_append_c (string, ' '); +} + void gsk_gpu_print_rect (GString *string, const float rect[4]) diff --git a/gsk/gpu/gskgpuprintprivate.h b/gsk/gpu/gskgpuprintprivate.h index 5c4f318d70..8f85e34e51 100644 --- a/gsk/gpu/gskgpuprintprivate.h +++ b/gsk/gpu/gskgpuprintprivate.h @@ -15,6 +15,8 @@ void gsk_gpu_print_op (GString void gsk_gpu_print_newline (GString *string); +void gsk_gpu_print_string (GString *string, + const char *s); void gsk_gpu_print_rect (GString *string, const float rect[4]); void gsk_gpu_print_int_rect (GString *string, diff --git a/gsk/gpu/gskgpushaderop.c b/gsk/gpu/gskgpushaderop.c index a2a806e799..d944879657 100644 --- a/gsk/gpu/gskgpushaderop.c +++ b/gsk/gpu/gskgpushaderop.c @@ -71,6 +71,7 @@ gsk_gpu_shader_op_vk_command_n (GskGpuOp *op, gsk_vulkan_descriptors_get_pipeline_layout (state->desc), shader_op_class, self->clip, + state->blend, state->vk_format, state->vk_render_pass)); diff --git a/gsk/gpu/gskgputypesprivate.h b/gsk/gpu/gskgputypesprivate.h index 23d7f44fb5..6ab5bd79e8 100644 --- a/gsk/gpu/gskgputypesprivate.h +++ b/gsk/gpu/gskgputypesprivate.h @@ -47,6 +47,11 @@ typedef enum { GSK_GPU_SHADER_CLIP_ROUNDED } GskGpuShaderClip; +typedef enum { + GSK_GPU_BLEND_OVER, + GSK_GPU_BLEND_ADD +} GskGpuBlend; + typedef enum { GSK_GPU_PATTERN_DONE, GSK_GPU_PATTERN_COLOR, diff --git a/gsk/gpu/gskvulkandevice.c b/gsk/gpu/gskvulkandevice.c index 4b7531c822..ecc5138fc1 100644 --- a/gsk/gpu/gskvulkandevice.c +++ b/gsk/gpu/gskvulkandevice.c @@ -77,6 +77,7 @@ struct _PipelineCacheKey { const GskGpuShaderOpClass *op_class; GskGpuShaderClip clip; + GskGpuBlend blend; VkFormat format; }; @@ -112,7 +113,8 @@ pipeline_cache_key_hash (gconstpointer data) return GPOINTER_TO_UINT (key->op_class) ^ key->clip ^ - (key->format << 2); + (key->blend << 2) ^ + (key->format << 4); } static gboolean @@ -124,6 +126,7 @@ pipeline_cache_key_equal (gconstpointer a, return keya->op_class == keyb->op_class && keya->clip == keyb->clip && + keya->blend == keyb->blend && keya->format == keyb->format; } @@ -879,11 +882,41 @@ struct _GskVulkanShaderSpecialization guint32 n_buffers; }; +static VkPipelineColorBlendAttachmentState blend_attachment_states[2] = { + [GSK_GPU_BLEND_OVER] = { + .blendEnable = VK_TRUE, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .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 + }, + [GSK_GPU_BLEND_ADD] = { + .blendEnable = VK_TRUE, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE, + .alphaBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .colorWriteMask = VK_COLOR_COMPONENT_A_BIT + | VK_COLOR_COMPONENT_R_BIT + | VK_COLOR_COMPONENT_G_BIT + | VK_COLOR_COMPONENT_B_BIT + }, +}; + VkPipeline gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self, GskVulkanPipelineLayout *layout, const GskGpuShaderOpClass *op_class, GskGpuShaderClip clip, + GskGpuBlend blend, VkFormat format, VkRenderPass render_pass) { @@ -896,6 +929,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self, cache_key = (PipelineCacheKey) { .op_class = op_class, .clip = clip, + .blend = blend, .format = format, }; pipeline = g_hash_table_lookup (layout->pipeline_cache, &cache_key); @@ -1035,21 +1069,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self, .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .attachmentCount = 1, - .pAttachments = (VkPipelineColorBlendAttachmentState []) { - { - .blendEnable = VK_TRUE, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .alphaBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .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 - }, - } + .pAttachments = &blend_attachment_states[blend], }, .pDynamicState = &(VkPipelineDynamicStateCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, diff --git a/gsk/gpu/gskvulkandeviceprivate.h b/gsk/gpu/gskvulkandeviceprivate.h index e9b4c5aa62..8e3f7059f3 100644 --- a/gsk/gpu/gskvulkandeviceprivate.h +++ b/gsk/gpu/gskvulkandeviceprivate.h @@ -74,6 +74,7 @@ VkPipeline gsk_vulkan_device_get_vk_pipeline (GskVulk GskVulkanPipelineLayout*layout, const GskGpuShaderOpClass *op_class, GskGpuShaderClip clip, + GskGpuBlend blend, VkFormat format, VkRenderPass render_pass); diff --git a/gsk/gpu/gskvulkanframe.c b/gsk/gpu/gskvulkanframe.c index bbaaea8e77..9dad7d4e16 100644 --- a/gsk/gpu/gskvulkanframe.c +++ b/gsk/gpu/gskvulkanframe.c @@ -316,6 +316,7 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame, state.vk_command_buffer = self->vk_command_buffer; state.vk_render_pass = VK_NULL_HANDLE; state.vk_format = VK_FORMAT_UNDEFINED; + state.blend = GSK_GPU_BLEND_OVER; /* should we have a BLEND_NONE? */ state.desc = GSK_VULKAN_DESCRIPTORS (gsk_descriptors_get (&self->descriptors, 0)); state.semaphores = &semaphores; diff --git a/gsk/meson.build b/gsk/meson.build index 5f90a90355..09460f8732 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -72,6 +72,7 @@ gsk_private_sources = files([ 'gpu/gskgldescriptors.c', 'gpu/gskglframe.c', 'gpu/gskglimage.c', + 'gpu/gskgpublendop.c', 'gpu/gskgpublitop.c', 'gpu/gskgpublurop.c', 'gpu/gskgpuborderop.c',