gpu: Make blend modes configurable

For now, we only have OVER and ADD blend modes. This commit doesn't use
ADD, it just sets up all the machinery and refactors things.
This commit is contained in:
Benjamin Otte 2023-12-25 05:21:13 +01:00
parent a031011e5e
commit 5cf3c70db0
13 changed files with 190 additions and 26 deletions

View File

@ -146,11 +146,7 @@ gsk_gl_frame_submit (GskGpuFrame *frame,
glEnable (GL_DEPTH_TEST); glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LEQUAL); glDepthFunc (GL_LEQUAL);
/* Pre-multiplied alpha */
glEnable (GL_BLEND); glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation (GL_FUNC_ADD);
if (vertex_buffer) if (vertex_buffer)
gsk_gl_buffer_bind (GSK_GL_BUFFER (vertex_buffer)); gsk_gl_buffer_bind (GSK_GL_BUFFER (vertex_buffer));

103
gsk/gpu/gskgpublendop.c Normal file
View File

@ -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;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "gskgputypesprivate.h"
G_BEGIN_DECLS
void gsk_gpu_blend_op (GskGpuFrame *frame,
GskGpuBlend blend);
G_END_DECLS

View File

@ -4,6 +4,7 @@
#include "gskgpuborderopprivate.h" #include "gskgpuborderopprivate.h"
#include "gskgpuboxshadowopprivate.h" #include "gskgpuboxshadowopprivate.h"
#include "gskgpublendopprivate.h"
#include "gskgpublitopprivate.h" #include "gskgpublitopprivate.h"
#include "gskgpubluropprivate.h" #include "gskgpubluropprivate.h"
#include "gskgpuclearopprivate.h" #include "gskgpuclearopprivate.h"
@ -89,6 +90,7 @@ typedef enum {
GSK_GPU_GLOBAL_SCALE = (1 << 1), GSK_GPU_GLOBAL_SCALE = (1 << 1),
GSK_GPU_GLOBAL_CLIP = (1 << 2), GSK_GPU_GLOBAL_CLIP = (1 << 2),
GSK_GPU_GLOBAL_SCISSOR = (1 << 3), GSK_GPU_GLOBAL_SCISSOR = (1 << 3),
GSK_GPU_GLOBAL_BLEND = (1 << 4),
} GskGpuGlobals; } GskGpuGlobals;
struct _GskGpuNodeProcessor struct _GskGpuNodeProcessor
@ -96,6 +98,7 @@ struct _GskGpuNodeProcessor
GskGpuFrame *frame; GskGpuFrame *frame;
GskGpuDescriptors *desc; GskGpuDescriptors *desc;
cairo_rectangle_int_t scissor; cairo_rectangle_int_t scissor;
GskGpuBlend blend;
graphene_point_t offset; graphene_point_t offset;
graphene_matrix_t projection; graphene_matrix_t projection;
graphene_vec2_t scale; graphene_vec2_t scale;
@ -154,6 +157,7 @@ gsk_gpu_node_processor_init (GskGpuNodeProcessor *self,
self->desc = NULL; self->desc = NULL;
self->scissor = *clip; 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)); gsk_gpu_clip_init_empty (&self->clip, &GRAPHENE_RECT_INIT (0, 0, viewport->size.width, viewport->size.height));
self->modelview = NULL; self->modelview = NULL;
@ -163,7 +167,7 @@ gsk_gpu_node_processor_init (GskGpuNodeProcessor *self,
self->offset = GRAPHENE_POINT_INIT (-viewport->origin.x, self->offset = GRAPHENE_POINT_INIT (-viewport->origin.x,
-viewport->origin.y); -viewport->origin.y);
self->opacity = 1.0; 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 static void
@ -195,6 +199,13 @@ gsk_gpu_node_processor_emit_scissor_op (GskGpuNodeProcessor *self)
self->pending_globals &= ~GSK_GPU_GLOBAL_SCISSOR; 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 static void
gsk_gpu_node_processor_sync_globals (GskGpuNodeProcessor *self, gsk_gpu_node_processor_sync_globals (GskGpuNodeProcessor *self,
GskGpuGlobals ignored) GskGpuGlobals ignored)
@ -207,6 +218,8 @@ gsk_gpu_node_processor_sync_globals (GskGpuNodeProcessor *self,
gsk_gpu_node_processor_emit_globals_op (self); gsk_gpu_node_processor_emit_globals_op (self);
if (required & GSK_GPU_GLOBAL_SCISSOR) if (required & GSK_GPU_GLOBAL_SCISSOR)
gsk_gpu_node_processor_emit_scissor_op (self); gsk_gpu_node_processor_emit_scissor_op (self);
if (required & GSK_GPU_GLOBAL_BLEND)
gsk_gpu_node_processor_emit_blend_op (self);
} }
static guint32 static guint32
@ -3075,7 +3088,7 @@ static const struct
NULL, NULL,
}, },
[GSK_TRANSFORM_NODE] = { [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_HANDLE_OPACITY,
gsk_gpu_node_processor_add_transform_node, gsk_gpu_node_processor_add_transform_node,
gsk_gpu_node_processor_create_transform_pattern, gsk_gpu_node_processor_create_transform_pattern,
@ -3099,13 +3112,13 @@ static const struct
gsk_gpu_node_processor_create_repeat_pattern gsk_gpu_node_processor_create_repeat_pattern
}, },
[GSK_CLIP_NODE] = { [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_HANDLE_OPACITY,
gsk_gpu_node_processor_add_clip_node, gsk_gpu_node_processor_add_clip_node,
gsk_gpu_node_processor_create_clip_pattern, gsk_gpu_node_processor_create_clip_pattern,
}, },
[GSK_ROUNDED_CLIP_NODE] = { [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_HANDLE_OPACITY,
gsk_gpu_node_processor_add_rounded_clip_node, gsk_gpu_node_processor_add_rounded_clip_node,
NULL, NULL,
@ -3141,7 +3154,7 @@ static const struct
NULL, NULL,
}, },
[GSK_DEBUG_NODE] = { [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_HANDLE_OPACITY,
gsk_gpu_node_processor_add_debug_node, gsk_gpu_node_processor_add_debug_node,
gsk_gpu_node_processor_create_debug_pattern, gsk_gpu_node_processor_create_debug_pattern,
@ -3177,7 +3190,7 @@ static const struct
NULL, NULL,
}, },
[GSK_SUBSURFACE_NODE] = { [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_HANDLE_OPACITY,
gsk_gpu_node_processor_add_subsurface_node, gsk_gpu_node_processor_add_subsurface_node,
gsk_gpu_node_processor_create_subsurface_pattern, gsk_gpu_node_processor_create_subsurface_pattern,

View File

@ -37,6 +37,7 @@ struct _GskVulkanCommandState
VkRenderPass vk_render_pass; VkRenderPass vk_render_pass;
VkFormat vk_format; VkFormat vk_format;
VkCommandBuffer vk_command_buffer; VkCommandBuffer vk_command_buffer;
GskGpuBlend blend;
GskVulkanDescriptors *desc; GskVulkanDescriptors *desc;
GskVulkanSemaphores *semaphores; GskVulkanSemaphores *semaphores;

View File

@ -22,6 +22,14 @@ gsk_gpu_print_op (GString *string,
g_string_append_c (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 void
gsk_gpu_print_rect (GString *string, gsk_gpu_print_rect (GString *string,
const float rect[4]) const float rect[4])

View File

@ -15,6 +15,8 @@ void gsk_gpu_print_op (GString
void gsk_gpu_print_newline (GString *string); void gsk_gpu_print_newline (GString *string);
void gsk_gpu_print_string (GString *string,
const char *s);
void gsk_gpu_print_rect (GString *string, void gsk_gpu_print_rect (GString *string,
const float rect[4]); const float rect[4]);
void gsk_gpu_print_int_rect (GString *string, void gsk_gpu_print_int_rect (GString *string,

View File

@ -71,6 +71,7 @@ gsk_gpu_shader_op_vk_command_n (GskGpuOp *op,
gsk_vulkan_descriptors_get_pipeline_layout (state->desc), gsk_vulkan_descriptors_get_pipeline_layout (state->desc),
shader_op_class, shader_op_class,
self->clip, self->clip,
state->blend,
state->vk_format, state->vk_format,
state->vk_render_pass)); state->vk_render_pass));

View File

@ -47,6 +47,11 @@ typedef enum {
GSK_GPU_SHADER_CLIP_ROUNDED GSK_GPU_SHADER_CLIP_ROUNDED
} GskGpuShaderClip; } GskGpuShaderClip;
typedef enum {
GSK_GPU_BLEND_OVER,
GSK_GPU_BLEND_ADD
} GskGpuBlend;
typedef enum { typedef enum {
GSK_GPU_PATTERN_DONE, GSK_GPU_PATTERN_DONE,
GSK_GPU_PATTERN_COLOR, GSK_GPU_PATTERN_COLOR,

View File

@ -77,6 +77,7 @@ struct _PipelineCacheKey
{ {
const GskGpuShaderOpClass *op_class; const GskGpuShaderOpClass *op_class;
GskGpuShaderClip clip; GskGpuShaderClip clip;
GskGpuBlend blend;
VkFormat format; VkFormat format;
}; };
@ -112,7 +113,8 @@ pipeline_cache_key_hash (gconstpointer data)
return GPOINTER_TO_UINT (key->op_class) ^ return GPOINTER_TO_UINT (key->op_class) ^
key->clip ^ key->clip ^
(key->format << 2); (key->blend << 2) ^
(key->format << 4);
} }
static gboolean static gboolean
@ -124,6 +126,7 @@ pipeline_cache_key_equal (gconstpointer a,
return keya->op_class == keyb->op_class && return keya->op_class == keyb->op_class &&
keya->clip == keyb->clip && keya->clip == keyb->clip &&
keya->blend == keyb->blend &&
keya->format == keyb->format; keya->format == keyb->format;
} }
@ -879,11 +882,41 @@ struct _GskVulkanShaderSpecialization
guint32 n_buffers; 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 VkPipeline
gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self, gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
GskVulkanPipelineLayout *layout, GskVulkanPipelineLayout *layout,
const GskGpuShaderOpClass *op_class, const GskGpuShaderOpClass *op_class,
GskGpuShaderClip clip, GskGpuShaderClip clip,
GskGpuBlend blend,
VkFormat format, VkFormat format,
VkRenderPass render_pass) VkRenderPass render_pass)
{ {
@ -896,6 +929,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
cache_key = (PipelineCacheKey) { cache_key = (PipelineCacheKey) {
.op_class = op_class, .op_class = op_class,
.clip = clip, .clip = clip,
.blend = blend,
.format = format, .format = format,
}; };
pipeline = g_hash_table_lookup (layout->pipeline_cache, &cache_key); pipeline = g_hash_table_lookup (layout->pipeline_cache, &cache_key);
@ -1035,21 +1069,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = (VkPipelineColorBlendAttachmentState []) { .pAttachments = &blend_attachment_states[blend],
{
.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
},
}
}, },
.pDynamicState = &(VkPipelineDynamicStateCreateInfo) { .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,

View File

@ -74,6 +74,7 @@ VkPipeline gsk_vulkan_device_get_vk_pipeline (GskVulk
GskVulkanPipelineLayout*layout, GskVulkanPipelineLayout*layout,
const GskGpuShaderOpClass *op_class, const GskGpuShaderOpClass *op_class,
GskGpuShaderClip clip, GskGpuShaderClip clip,
GskGpuBlend blend,
VkFormat format, VkFormat format,
VkRenderPass render_pass); VkRenderPass render_pass);

View File

@ -316,6 +316,7 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame,
state.vk_command_buffer = self->vk_command_buffer; state.vk_command_buffer = self->vk_command_buffer;
state.vk_render_pass = VK_NULL_HANDLE; state.vk_render_pass = VK_NULL_HANDLE;
state.vk_format = VK_FORMAT_UNDEFINED; 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.desc = GSK_VULKAN_DESCRIPTORS (gsk_descriptors_get (&self->descriptors, 0));
state.semaphores = &semaphores; state.semaphores = &semaphores;

View File

@ -72,6 +72,7 @@ gsk_private_sources = files([
'gpu/gskgldescriptors.c', 'gpu/gskgldescriptors.c',
'gpu/gskglframe.c', 'gpu/gskglframe.c',
'gpu/gskglimage.c', 'gpu/gskglimage.c',
'gpu/gskgpublendop.c',
'gpu/gskgpublitop.c', 'gpu/gskgpublitop.c',
'gpu/gskgpublurop.c', 'gpu/gskgpublurop.c',
'gpu/gskgpuborderop.c', 'gpu/gskgpuborderop.c',