diff --git a/gsk/vulkan/gskvulkanbuffer.c b/gsk/vulkan/gskvulkanbuffer.c index 21ce89bd31..4b8e6b8cc7 100644 --- a/gsk/vulkan/gskvulkanbuffer.c +++ b/gsk/vulkan/gskvulkanbuffer.c @@ -64,6 +64,13 @@ gsk_vulkan_buffer_new (GdkVulkanContext *context, | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); } +GskVulkanBuffer * +gsk_vulkan_buffer_new_storage (GdkVulkanContext *context, + gsize size) +{ + return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); +} + GskVulkanBuffer * gsk_vulkan_buffer_new_staging (GdkVulkanContext *context, gsize size) diff --git a/gsk/vulkan/gskvulkanbufferprivate.h b/gsk/vulkan/gskvulkanbufferprivate.h index bdccf597c4..bba3f2c227 100644 --- a/gsk/vulkan/gskvulkanbufferprivate.h +++ b/gsk/vulkan/gskvulkanbufferprivate.h @@ -8,6 +8,8 @@ typedef struct _GskVulkanBuffer GskVulkanBuffer; GskVulkanBuffer * gsk_vulkan_buffer_new (GdkVulkanContext *context, gsize size); +GskVulkanBuffer * gsk_vulkan_buffer_new_storage (GdkVulkanContext *context, + gsize size); GskVulkanBuffer * gsk_vulkan_buffer_new_staging (GdkVulkanContext *context, gsize size); GskVulkanBuffer * gsk_vulkan_buffer_new_download (GdkVulkanContext *context, diff --git a/gsk/vulkan/gskvulkanlineargradientpipeline.c b/gsk/vulkan/gskvulkanlineargradientpipeline.c index 79de43720c..1a790de475 100644 --- a/gsk/vulkan/gskvulkanlineargradientpipeline.c +++ b/gsk/vulkan/gskvulkanlineargradientpipeline.c @@ -15,9 +15,8 @@ struct _GskVulkanLinearGradientInstance float start[2]; float end[2]; gint32 repeating; + gint32 offset; gint32 stop_count; - float offsets[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS]; - float colors[GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS][4]; }; G_DEFINE_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK_TYPE_VULKAN_PIPELINE) @@ -61,67 +60,13 @@ gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info (GskVulkanPipeli .location = 4, .binding = 0, .format = VK_FORMAT_R32_SINT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count), + .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offset), }, { .location = 5, .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets), - }, - { - .location = 6, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offsets) + sizeof (float) * 4, - }, - { - .location = 7, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[0]), - }, - { - .location = 8, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[1]), - }, - { - .location = 9, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[2]), - }, - { - .location = 10, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[3]), - }, - { - .location = 11, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[4]), - }, - { - .location = 12, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[5]), - }, - { - .location = 13, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[6]), - }, - { - .location = 14, - .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, colors[7]), + .format = VK_FORMAT_R32_SINT, + .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count), } }; static const VkPipelineVertexInputStateCreateInfo info = { @@ -169,23 +114,17 @@ gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext *context, void gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradientPipeline *pipeline, - guchar *data, - const graphene_point_t *offset, - const graphene_rect_t *rect, - const graphene_point_t *start, - const graphene_point_t *end, - gboolean repeating, - gsize n_stops, - const GskColorStop *stops) + guchar *data, + const graphene_point_t *offset, + const graphene_rect_t *rect, + const graphene_point_t *start, + const graphene_point_t *end, + gboolean repeating, + gsize gradient_offset, + gsize n_stops) { GskVulkanLinearGradientInstance *instance = (GskVulkanLinearGradientInstance *) data; - gsize i; - if (n_stops > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS) - { - g_warning ("Only %u color stops supported.", GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS); - n_stops = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS; - } instance->rect[0] = rect->origin.x + offset->x; instance->rect[1] = rect->origin.y + offset->y; instance->rect[2] = rect->size.width; @@ -195,15 +134,8 @@ gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradient instance->end[0] = end->x + offset->x; instance->end[1] = end->y + offset->y; instance->repeating = repeating; + instance->offset = gradient_offset; instance->stop_count = n_stops; - for (i = 0; i < n_stops; i++) - { - instance->offsets[i] = stops[i].offset; - instance->colors[i][0] = stops[i].color.red; - instance->colors[i][1] = stops[i].color.green; - instance->colors[i][2] = stops[i].color.blue; - instance->colors[i][3] = stops[i].color.alpha; - } } gsize diff --git a/gsk/vulkan/gskvulkanlineargradientpipelineprivate.h b/gsk/vulkan/gskvulkanlineargradientpipelineprivate.h index f33448a91f..21bf10066f 100644 --- a/gsk/vulkan/gskvulkanlineargradientpipelineprivate.h +++ b/gsk/vulkan/gskvulkanlineargradientpipelineprivate.h @@ -28,8 +28,8 @@ void gsk_vulkan_linear_gradient_pipeline_collect_vertex_data const graphene_point_t *start, const graphene_point_t *end, gboolean repeating, - gsize n_stops, - const GskColorStop *stops); + gsize gradient_offset, + gsize n_stops); gsize gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline*pipeline, VkCommandBuffer command_buffer, gsize offset, diff --git a/gsk/vulkan/gskvulkanrender.c b/gsk/vulkan/gskvulkanrender.c index 0e3d7dfaa4..da32f42639 100644 --- a/gsk/vulkan/gskvulkanrender.c +++ b/gsk/vulkan/gskvulkanrender.c @@ -33,6 +33,14 @@ #define GDK_ARRAY_NO_MEMSET 1 #include "gdk/gdkarrayimpl.c" +#define GDK_ARRAY_NAME gsk_descriptor_buffer_infos +#define GDK_ARRAY_TYPE_NAME GskDescriptorBufferInfos +#define GDK_ARRAY_ELEMENT_TYPE VkDescriptorBufferInfo +#define GDK_ARRAY_BY_VALUE 1 +#define GDK_ARRAY_PREALLOC 1024 +#define GDK_ARRAY_NO_MEMSET 1 +#include "gdk/gdkarrayimpl.c" + struct _GskVulkanRender { GskRenderer *renderer; @@ -52,6 +60,7 @@ struct _GskVulkanRender GskDescriptorImageInfos descriptor_images; GskDescriptorImageInfos descriptor_samplers; + GskDescriptorBufferInfos descriptor_buffers; VkDescriptorPool descriptor_pool; VkDescriptorSet descriptor_set; GskVulkanPipeline *pipelines[GSK_VULKAN_N_PIPELINES]; @@ -59,6 +68,9 @@ struct _GskVulkanRender GskVulkanImage *target; VkSampler samplers[3]; + GskVulkanBuffer *storage_buffer; + guchar *storage_buffer_memory; + gsize storage_buffer_used; GList *render_passes; GSList *cleanup_images; @@ -122,6 +134,7 @@ gsk_vulkan_render_new (GskRenderer *renderer, self->framebuffers = g_hash_table_new (g_direct_hash, g_direct_equal); gsk_descriptor_image_infos_init (&self->descriptor_images); gsk_descriptor_image_infos_init (&self->descriptor_samplers); + gsk_descriptor_buffer_infos_init (&self->descriptor_buffers); device = gdk_vulkan_context_get_device (self->vulkan); @@ -139,8 +152,8 @@ gsk_vulkan_render_new (GskRenderer *renderer, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, .flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, .maxSets = 1, - .poolSizeCount = 2, - .pPoolSizes = (VkDescriptorPoolSize[2]) { + .poolSizeCount = 3, + .pPoolSizes = (VkDescriptorPoolSize[3]) { { .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, .descriptorCount = DESCRIPTOR_POOL_MAXITEMS @@ -148,6 +161,10 @@ gsk_vulkan_render_new (GskRenderer *renderer, { .type = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = DESCRIPTOR_POOL_MAXITEMS + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = DESCRIPTOR_POOL_MAXITEMS } } }, @@ -197,9 +214,9 @@ gsk_vulkan_render_new (GskRenderer *renderer, GSK_VK_CHECK (vkCreateDescriptorSetLayout, device, &(VkDescriptorSetLayoutCreateInfo) { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = 2, + .bindingCount = 3, .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, - .pBindings = (VkDescriptorSetLayoutBinding[2]) { + .pBindings = (VkDescriptorSetLayoutBinding[3]) { { .binding = 0, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, @@ -211,12 +228,21 @@ gsk_vulkan_render_new (GskRenderer *renderer, .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, .descriptorCount = DESCRIPTOR_POOL_MAXITEMS, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT - } + }, + { + .binding = 2, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = DESCRIPTOR_POOL_MAXITEMS, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT + }, }, .pNext = &(VkDescriptorSetLayoutBindingFlagsCreateInfo) { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, - .bindingCount = 2, - .pBindingFlags = (VkDescriptorBindingFlags[2]) { + .bindingCount = 3, + .pBindingFlags = (VkDescriptorBindingFlags[3]) { + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT + | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT + | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, @@ -520,10 +546,81 @@ gsk_vulkan_render_get_image_descriptor (GskVulkanRender *self, return result; } +static void +gsk_vulkan_render_ensure_storage_buffer (GskVulkanRender *self) +{ + if (self->storage_buffer_memory != NULL) + return; + + if (self->storage_buffer == NULL) + { + self->storage_buffer = gsk_vulkan_buffer_new_storage (self->vulkan, + /* random */ + sizeof (float) * 1024 * 1024); + } + + self->storage_buffer_memory = gsk_vulkan_buffer_map (self->storage_buffer); + + if (gsk_vulkan_render_get_buffer_descriptor (self, self->storage_buffer) != 0) + { + g_assert_not_reached (); + } +} + +gsize +gsk_vulkan_render_get_buffer_descriptor (GskVulkanRender *self, + GskVulkanBuffer *buffer) +{ + gsize result; + + gsk_vulkan_render_ensure_storage_buffer (self); + + result = gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers); + gsk_descriptor_buffer_infos_append (&self->descriptor_buffers, + &(VkDescriptorBufferInfo) { + .buffer = gsk_vulkan_buffer_get_buffer (buffer), + .offset = 0, + .range = VK_WHOLE_SIZE + }); + + g_assert (result < DESCRIPTOR_POOL_MAXITEMS); + + return result; +} + +static inline gsize +round_up (gsize number, gsize divisor) +{ + return (number + divisor - 1) / divisor * divisor; +} + +guchar * +gsk_vulkan_render_get_buffer_memory (GskVulkanRender *self, + gsize size, + gsize alignment, + gsize *out_offset) +{ + guchar *result; + + g_assert (alignment >= sizeof (float)); + + gsk_vulkan_render_ensure_storage_buffer (self); + + self->storage_buffer_used = round_up (self->storage_buffer_used, alignment); + result = self->storage_buffer_memory + self->storage_buffer_used; + *out_offset = self->storage_buffer_used / sizeof (float); + + self->storage_buffer_used += size; + + return result; +} + static void gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self) { VkDevice device; + VkWriteDescriptorSet descriptor_sets[3]; + gsize n_descriptor_sets; GList *l; device = gdk_vulkan_context_get_device (self->vulkan); @@ -535,9 +632,16 @@ gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self) } if (gsk_descriptor_image_infos_get_size (&self->descriptor_samplers) == 0 && - gsk_descriptor_image_infos_get_size (&self->descriptor_images) == 0) + gsk_descriptor_image_infos_get_size (&self->descriptor_images) == 0 && + gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers) == 0) return; + if (self->storage_buffer_memory) + { + gsk_vulkan_buffer_unmap (self->storage_buffer); + self->storage_buffer_memory = NULL; + } + GSK_VK_CHECK (vkAllocateDescriptorSets, device, &(VkDescriptorSetAllocateInfo) { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, @@ -550,33 +654,53 @@ gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self) .pDescriptorCounts = (uint32_t[1]) { gsk_descriptor_image_infos_get_size (&self->descriptor_images) + gsk_descriptor_image_infos_get_size (&self->descriptor_samplers) + + gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers) } } }, &self->descriptor_set); + n_descriptor_sets = 0; + if (gsk_descriptor_image_infos_get_size (&self->descriptor_images) > 0) + { + descriptor_sets[n_descriptor_sets++] = (VkWriteDescriptorSet) { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = self->descriptor_set, + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = gsk_descriptor_image_infos_get_size (&self->descriptor_images), + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = gsk_descriptor_image_infos_get_data (&self->descriptor_images) + }; + } + if (gsk_descriptor_image_infos_get_size (&self->descriptor_samplers) > 0) + { + descriptor_sets[n_descriptor_sets++] = (VkWriteDescriptorSet) { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = self->descriptor_set, + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorCount = gsk_descriptor_image_infos_get_size (&self->descriptor_samplers), + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .pImageInfo = gsk_descriptor_image_infos_get_data (&self->descriptor_samplers) + }; + } + if (gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers) > 0) + { + descriptor_sets[n_descriptor_sets++] = (VkWriteDescriptorSet) { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = self->descriptor_set, + .dstBinding = 2, + .dstArrayElement = 0, + .descriptorCount = gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers), + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .pBufferInfo = gsk_descriptor_buffer_infos_get_data (&self->descriptor_buffers) + }; + } + vkUpdateDescriptorSets (device, - 2, - (VkWriteDescriptorSet[2]) { - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = self->descriptor_set, - .dstBinding = 0, - .dstArrayElement = 0, - .descriptorCount = gsk_descriptor_image_infos_get_size (&self->descriptor_images), - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .pImageInfo = gsk_descriptor_image_infos_get_data (&self->descriptor_images) - }, - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = self->descriptor_set, - .dstBinding = 1, - .dstArrayElement = 0, - .descriptorCount = gsk_descriptor_image_infos_get_size (&self->descriptor_samplers), - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, - .pImageInfo = gsk_descriptor_image_infos_get_data (&self->descriptor_samplers) - } - }, + n_descriptor_sets, + descriptor_sets, 0, NULL); } @@ -672,6 +796,7 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self) 0); gsk_descriptor_image_infos_set_size (&self->descriptor_images, 0); gsk_descriptor_image_infos_set_size (&self->descriptor_samplers, 0); + gsk_descriptor_buffer_infos_set_size (&self->descriptor_buffers, 0); g_list_free_full (self->render_passes, (GDestroyNotify) gsk_vulkan_render_pass_free); self->render_passes = NULL; @@ -727,6 +852,7 @@ gsk_vulkan_render_free (GskVulkanRender *self) NULL); gsk_descriptor_image_infos_clear (&self->descriptor_images); gsk_descriptor_image_infos_clear (&self->descriptor_samplers); + gsk_descriptor_buffer_infos_clear (&self->descriptor_buffers); vkDestroyDescriptorSetLayout (device, self->descriptor_set_layout, diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index cacbfd3e4c..67338b74cd 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -77,6 +77,7 @@ struct _GskVulkanOpRender gsize vertex_offset; /* offset into vertex buffer */ guint32 image_descriptor[2]; /* index into descriptor for the (image, sampler) */ guint32 image_descriptor2[2]; /* index into descriptor for the 2nd image (if relevant) */ + gsize buffer_offset; /* offset into buffer */ graphene_rect_t source_rect; /* area that source maps to */ graphene_rect_t source2_rect; /* area that source2 maps to */ }; @@ -406,10 +407,10 @@ gsk_vulkan_render_pass_add_color_node (GskVulkanRenderPass *self, } static inline gboolean -gsk_vulkan_render_pass_add_repeating_linear_gradient_node (GskVulkanRenderPass *self, - GskVulkanRender *render, - const GskVulkanParseState *state, - GskRenderNode *node) +gsk_vulkan_render_pass_add_linear_gradient_node (GskVulkanRenderPass *self, + GskVulkanRender *render, + const GskVulkanParseState *state, + GskRenderNode *node) { GskVulkanPipelineType pipeline_type; GskVulkanOp op = { @@ -418,11 +419,6 @@ gsk_vulkan_render_pass_add_repeating_linear_gradient_node (GskVulkanRenderPass .render.offset = state->offset, }; - if (gsk_linear_gradient_node_get_n_color_stops (node) > GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS) - FALLBACK ("Linear gradient with %zu color stops, hardcoded limit is %u", - gsk_linear_gradient_node_get_n_color_stops (node), - GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS); - if (gsk_vulkan_clip_contains_rect (&state->clip, &state->offset, &node->bounds)) pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT; else if (state->clip.type == GSK_VULKAN_CLIP_RECT) @@ -1138,8 +1134,8 @@ static const GskVulkanRenderPassNodeFunc nodes_vtable[N_RENDER_NODES] = { [GSK_CONTAINER_NODE] = gsk_vulkan_render_pass_add_container_node, [GSK_CAIRO_NODE] = gsk_vulkan_render_pass_add_cairo_node, [GSK_COLOR_NODE] = gsk_vulkan_render_pass_add_color_node, - [GSK_LINEAR_GRADIENT_NODE] = gsk_vulkan_render_pass_add_repeating_linear_gradient_node, - [GSK_REPEATING_LINEAR_GRADIENT_NODE] = gsk_vulkan_render_pass_add_repeating_linear_gradient_node, + [GSK_LINEAR_GRADIENT_NODE] = gsk_vulkan_render_pass_add_linear_gradient_node, + [GSK_REPEATING_LINEAR_GRADIENT_NODE] = gsk_vulkan_render_pass_add_linear_gradient_node, [GSK_RADIAL_GRADIENT_NODE] = NULL, [GSK_REPEATING_RADIAL_GRADIENT_NODE] = NULL, [GSK_CONIC_GRADIENT_NODE] = NULL, @@ -1896,8 +1892,8 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, gsk_linear_gradient_node_get_start (op->render.node), gsk_linear_gradient_node_get_end (op->render.node), gsk_render_node_get_node_type (op->render.node) == GSK_REPEATING_LINEAR_GRADIENT_NODE, - gsk_linear_gradient_node_get_n_color_stops (op->render.node), - gsk_linear_gradient_node_get_color_stops (op->render.node, NULL)); + op->render.buffer_offset, + gsk_linear_gradient_node_get_n_color_stops (op->render.node)); break; case GSK_VULKAN_OP_OPACITY: @@ -2125,11 +2121,25 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_LINEAR_GRADIENT: + { + gsize n_stops = gsk_linear_gradient_node_get_n_color_stops (op->render.node); + guchar *mem; + + mem = gsk_vulkan_render_get_buffer_memory (render, + n_stops * sizeof (GskColorStop), + G_ALIGNOF (GskColorStop), + &op->render.buffer_offset); + memcpy (mem, + gsk_linear_gradient_node_get_color_stops (op->render.node, NULL), + n_stops * sizeof (GskColorStop)); + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: - case GSK_VULKAN_OP_LINEAR_GRADIENT: case GSK_VULKAN_OP_BORDER: case GSK_VULKAN_OP_INSET_SHADOW: case GSK_VULKAN_OP_OUTSET_SHADOW: diff --git a/gsk/vulkan/gskvulkanrenderprivate.h b/gsk/vulkan/gskvulkanrenderprivate.h index dc7031b405..41b911a03e 100644 --- a/gsk/vulkan/gskvulkanrenderprivate.h +++ b/gsk/vulkan/gskvulkanrenderprivate.h @@ -86,6 +86,12 @@ gsize gsk_vulkan_render_get_sampler_descriptor (GskVulk GskVulkanRenderSampler render_sampler); gsize gsk_vulkan_render_get_image_descriptor (GskVulkanRender *self, GskVulkanImage *source); +gsize gsk_vulkan_render_get_buffer_descriptor (GskVulkanRender *self, + GskVulkanBuffer *buffer); +guchar * gsk_vulkan_render_get_buffer_memory (GskVulkanRender *self, + gsize size, + gsize alignment, + gsize *out_offset); VkDescriptorSet gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self); void gsk_vulkan_render_draw (GskVulkanRender *self); diff --git a/gsk/vulkan/resources/blendmode.frag b/gsk/vulkan/resources/blendmode.frag index 7cc88d972a..d8179c2932 100644 --- a/gsk/vulkan/resources/blendmode.frag +++ b/gsk/vulkan/resources/blendmode.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.frag.glsl" #include "clip.frag.glsl" diff --git a/gsk/vulkan/resources/blendmode.vert b/gsk/vulkan/resources/blendmode.vert index e25a7c947d..4a8581afed 100644 --- a/gsk/vulkan/resources/blendmode.vert +++ b/gsk/vulkan/resources/blendmode.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.vert.glsl" #include "rect.vert.glsl" diff --git a/gsk/vulkan/resources/blur.frag b/gsk/vulkan/resources/blur.frag index 5d2039a508..b3acac9e26 100644 --- a/gsk/vulkan/resources/blur.frag +++ b/gsk/vulkan/resources/blur.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.frag.glsl" #include "clip.frag.glsl" diff --git a/gsk/vulkan/resources/blur.vert b/gsk/vulkan/resources/blur.vert index e097683731..4b2b8e0f7e 100644 --- a/gsk/vulkan/resources/blur.vert +++ b/gsk/vulkan/resources/blur.vert @@ -1,5 +1,5 @@ -#version 420 core +#version 450 #include "clip.vert.glsl" diff --git a/gsk/vulkan/resources/border.frag b/gsk/vulkan/resources/border.frag index 460d8262ff..b54f516da6 100644 --- a/gsk/vulkan/resources/border.frag +++ b/gsk/vulkan/resources/border.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.frag.glsl" #include "rounded-rect.glsl" diff --git a/gsk/vulkan/resources/border.vert b/gsk/vulkan/resources/border.vert index 95f0b24645..6f242f2ea7 100644 --- a/gsk/vulkan/resources/border.vert +++ b/gsk/vulkan/resources/border.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.vert.glsl" #include "rounded-rect.glsl" diff --git a/gsk/vulkan/resources/color-matrix.frag b/gsk/vulkan/resources/color-matrix.frag index 047aaaa573..c52eb27226 100644 --- a/gsk/vulkan/resources/color-matrix.frag +++ b/gsk/vulkan/resources/color-matrix.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.frag.glsl" #include "clip.frag.glsl" diff --git a/gsk/vulkan/resources/color-matrix.vert b/gsk/vulkan/resources/color-matrix.vert index d892ac6427..c62a728720 100644 --- a/gsk/vulkan/resources/color-matrix.vert +++ b/gsk/vulkan/resources/color-matrix.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.vert.glsl" diff --git a/gsk/vulkan/resources/color.vert b/gsk/vulkan/resources/color.vert index bda02426e9..a1baf2f5ca 100644 --- a/gsk/vulkan/resources/color.vert +++ b/gsk/vulkan/resources/color.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.vert.glsl" #include "rect.vert.glsl" diff --git a/gsk/vulkan/resources/common.frag.glsl b/gsk/vulkan/resources/common.frag.glsl index 326406296e..043d15a22e 100644 --- a/gsk/vulkan/resources/common.frag.glsl +++ b/gsk/vulkan/resources/common.frag.glsl @@ -1,6 +1,10 @@ - layout(set = 0, binding = 0) uniform texture2D textures[50000]; layout(set = 0, binding = 1) uniform sampler samplers[50000]; +layout(set = 0, binding = 2) readonly buffer FloatBuffers { + float floats[]; +} buffers[50000]; #define get_sampler(id) sampler2D(textures[id.x], samplers[id.y]) +#define get_buffer(id) buffers[id] +#define get_float(id) get_buffer(0).floats[id] diff --git a/gsk/vulkan/resources/crossfade.frag b/gsk/vulkan/resources/crossfade.frag index fc631f091f..9cb3939a31 100644 --- a/gsk/vulkan/resources/crossfade.frag +++ b/gsk/vulkan/resources/crossfade.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.frag.glsl" #include "clip.frag.glsl" diff --git a/gsk/vulkan/resources/crossfade.vert b/gsk/vulkan/resources/crossfade.vert index 579e38fef1..ffa9921760 100644 --- a/gsk/vulkan/resources/crossfade.vert +++ b/gsk/vulkan/resources/crossfade.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.vert.glsl" #include "rect.vert.glsl" diff --git a/gsk/vulkan/resources/inset-shadow.frag b/gsk/vulkan/resources/inset-shadow.frag index 594b325c47..104a0d69d5 100644 --- a/gsk/vulkan/resources/inset-shadow.frag +++ b/gsk/vulkan/resources/inset-shadow.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.frag.glsl" #include "rounded-rect.glsl" diff --git a/gsk/vulkan/resources/inset-shadow.vert b/gsk/vulkan/resources/inset-shadow.vert index 13fa8d669f..29bec22843 100644 --- a/gsk/vulkan/resources/inset-shadow.vert +++ b/gsk/vulkan/resources/inset-shadow.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.vert.glsl" diff --git a/gsk/vulkan/resources/linear.frag b/gsk/vulkan/resources/linear.frag index cb7727f641..9cc0c8c83a 100644 --- a/gsk/vulkan/resources/linear.frag +++ b/gsk/vulkan/resources/linear.frag @@ -1,36 +1,128 @@ -#version 420 core +#version 450 +#include "common.frag.glsl" #include "clip.frag.glsl" - -struct ColorStop { - float offset; - vec4 color; -}; +#include "rect.frag.glsl" layout(location = 0) in vec2 inPos; -layout(location = 1) in float inGradientPos; -layout(location = 2) in flat int inRepeating; -layout(location = 3) in flat int inStopCount; -layout(location = 4) in flat ColorStop inStops[8]; +layout(location = 1) in flat Rect inRect; +layout(location = 2) in float inGradientPos; +layout(location = 3) in flat int inRepeating; +layout(location = 4) in flat int inStopOffset; +layout(location = 5) in flat int inStopCount; -layout(location = 0) out vec4 outColor; +layout(location = 0) out vec4 color; + +float +get_offset (int i) +{ + return get_float (inStopOffset + i * 5); +} + +vec4 +get_color (int i) +{ + i = clamp (i, 0, inStopCount - 1); + return color = vec4 (get_float (inStopOffset + i * 5 + 1), + get_float (inStopOffset + i * 5 + 2), + get_float (inStopOffset + i * 5 + 3), + get_float (inStopOffset + i * 5 + 4)); +} + +vec4 +get_color_for_range_unscaled (float start, + float end) +{ + vec4 result = vec4 (0); + float offset; + int i; + + for (i = 0; i < inStopCount; i++) + { + offset = get_offset (i); + if (offset >= start) + break; + } + if (i == inStopCount) + offset = 1; + + float last_offset = i > 0 ? get_offset (i - 1) : 0; + vec4 last_color = get_color (i - 1); + vec4 color = get_color (i); + if (last_offset < start) + { + last_color = mix (last_color, color, (start - last_offset) / (offset - last_offset)); + last_offset = start; + } + if (end <= start) + return last_color; + + for (; i < inStopCount; i++) + { + offset = get_offset (i); + color = get_color (i); + if (offset >= end) + break; + result += 0.5 * (color + last_color) * (offset - last_offset); + last_offset = offset; + last_color = color; + } + if (i == inStopCount) + { + offset = 1; + color = get_color (i); + } + if (offset > end) + { + color = mix (last_color, color, (end - last_offset) / (offset - last_offset)); + offset = end; + } + result += 0.5 * (color + last_color) * (offset - last_offset); + + return result; +} + +vec4 +get_color_for_range (float start, + float end) +{ + return get_color_for_range_unscaled (start, end) / (end - start); +} void main() { - float pos; - if (inRepeating != 0) - pos = fract (inGradientPos); - else - pos = clamp (inGradientPos, 0, 1); + vec4 c; + float pos_start, pos_end; + float dPos = 0.5 * abs (fwidth (inGradientPos)); - vec4 color = inStops[0].color; - int n = clamp (inStopCount, 2, 8); - for (int i = 1; i < n; i++) + if (inRepeating != 0) { - if (inStops[i].offset > inStops[i-1].offset) - color = mix (color, inStops[i].color, clamp((pos - inStops[i-1].offset) / (inStops[i].offset - inStops[i-1].offset), 0, 1)); + pos_start = inGradientPos - dPos; + pos_end = inGradientPos + dPos; + if (floor (pos_end) > floor (pos_start)) + { + float fract_end = fract(pos_end); + float fract_start = fract(pos_start); + float n = floor (pos_end) - floor (pos_start); + if (fract_end > fract_start + 0.01) + c = get_color_for_range_unscaled (fract_start, fract_end); + else if (fract_start > fract_end + 0.01) + c = -get_color_for_range_unscaled (fract_end, fract_start); + c += get_color_for_range_unscaled (0.0, 1.0) * n; + c /= pos_end - pos_start; + } + else + { + c = get_color_for_range (fract (pos_start), fract (pos_end)); + } } - - //outColor = vec4(pos, pos, pos, 1.0); - outColor = clip (inPos, color); + else + { + pos_start = clamp (inGradientPos - dPos, 0, 1); + pos_end = clamp (inGradientPos + dPos, 0, 1); + c = get_color_for_range (pos_start, pos_end); + } + + float alpha = c.a * rect_coverage (inRect, inPos); + color = clip_scaled (inPos, vec4(c.rgb, 1) * alpha); } diff --git a/gsk/vulkan/resources/linear.vert b/gsk/vulkan/resources/linear.vert index 3d14b876f6..d2cb76fed9 100644 --- a/gsk/vulkan/resources/linear.vert +++ b/gsk/vulkan/resources/linear.vert @@ -1,6 +1,7 @@ -#version 420 core +#version 450 -#include "clip.vert.glsl" +#include "common.vert.glsl" +#include "rect.vert.glsl" struct ColorStop { float offset; @@ -11,62 +12,32 @@ layout(location = 0) in vec4 inRect; layout(location = 1) in vec2 inStart; layout(location = 2) in vec2 inEnd; layout(location = 3) in int inRepeating; -layout(location = 4) in int inStopCount; -layout(location = 5) in vec4 inOffsets0; -layout(location = 6) in vec4 inOffsets1; -layout(location = 7) in vec4 inColors0; -layout(location = 8) in vec4 inColors1; -layout(location = 9) in vec4 inColors2; -layout(location = 10) in vec4 inColors3; -layout(location = 11) in vec4 inColors4; -layout(location = 12) in vec4 inColors5; -layout(location = 13) in vec4 inColors6; -layout(location = 14) in vec4 inColors7; +layout(location = 4) in int inStopOffset; +layout(location = 5) in int inStopCount; layout(location = 0) out vec2 outPos; -layout(location = 1) out float outGradientPos; -layout(location = 2) out flat int outRepeating; -layout(location = 3) out flat int outStopCount; -layout(location = 4) out flat ColorStop outStops[8]; - -vec2 offsets[6] = { vec2(0.0, 0.0), - vec2(1.0, 0.0), - vec2(0.0, 1.0), - vec2(0.0, 1.0), - vec2(1.0, 0.0), - vec2(1.0, 1.0) }; +layout(location = 1) out flat Rect outRect; +layout(location = 2) out float outGradientPos; +layout(location = 3) out flat int outRepeating; +layout(location = 4) out flat int outStopOffset; +layout(location = 5) out flat int outStopCount; float get_gradient_pos (vec2 pos) { - pos = pos - inStart; - vec2 grad = inEnd - inStart; + pos = pos - inStart * push.scale; + vec2 grad = (inEnd - inStart) * push.scale; return dot (pos, grad) / dot (grad, grad); } void main() { - vec4 rect = clip (inRect); - vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex]; - gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0); + Rect r = rect_from_gsk (inRect); + vec2 pos = set_position_from_rect (r); outPos = pos; + outRect = r; outGradientPos = get_gradient_pos (pos); outRepeating = inRepeating; + outStopOffset = inStopOffset; outStopCount = inStopCount; - outStops[0].offset = inOffsets0[0]; - outStops[0].color = inColors0 * vec4(inColors0.aaa, 1.0); - outStops[1].offset = inOffsets0[1]; - outStops[1].color = inColors1 * vec4(inColors1.aaa, 1.0); - outStops[2].offset = inOffsets0[2]; - outStops[2].color = inColors2 * vec4(inColors2.aaa, 1.0); - outStops[3].offset = inOffsets0[3]; - outStops[3].color = inColors3 * vec4(inColors3.aaa, 1.0); - outStops[4].offset = inOffsets1[0]; - outStops[4].color = inColors4 * vec4(inColors4.aaa, 1.0); - outStops[5].offset = inOffsets1[1]; - outStops[5].color = inColors5 * vec4(inColors5.aaa, 1.0); - outStops[6].offset = inOffsets1[2]; - outStops[6].color = inColors6 * vec4(inColors6.aaa, 1.0); - outStops[7].offset = inOffsets1[3]; - outStops[7].color = inColors7 * vec4(inColors7.aaa, 1.0); } diff --git a/gsk/vulkan/resources/mask.frag b/gsk/vulkan/resources/mask.frag index a0a4ee9982..7a72cf6db9 100644 --- a/gsk/vulkan/resources/mask.frag +++ b/gsk/vulkan/resources/mask.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.frag.glsl" #include "clip.frag.glsl" diff --git a/gsk/vulkan/resources/mask.vert b/gsk/vulkan/resources/mask.vert index e37669170a..3c89f159bb 100644 --- a/gsk/vulkan/resources/mask.vert +++ b/gsk/vulkan/resources/mask.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.vert.glsl" diff --git a/gsk/vulkan/resources/outset-shadow.frag b/gsk/vulkan/resources/outset-shadow.frag index 30b0f9d94b..9dc2c42c47 100644 --- a/gsk/vulkan/resources/outset-shadow.frag +++ b/gsk/vulkan/resources/outset-shadow.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.frag.glsl" #include "rounded-rect.glsl" diff --git a/gsk/vulkan/resources/outset-shadow.vert b/gsk/vulkan/resources/outset-shadow.vert index 18ec6f2774..67b3ed2d55 100644 --- a/gsk/vulkan/resources/outset-shadow.vert +++ b/gsk/vulkan/resources/outset-shadow.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "clip.vert.glsl" diff --git a/gsk/vulkan/resources/texture.frag b/gsk/vulkan/resources/texture.frag index 9f5dfdcc02..dea157332a 100644 --- a/gsk/vulkan/resources/texture.frag +++ b/gsk/vulkan/resources/texture.frag @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.frag.glsl" #include "clip.frag.glsl" diff --git a/gsk/vulkan/resources/texture.vert b/gsk/vulkan/resources/texture.vert index ff66519320..739f32e3b6 100644 --- a/gsk/vulkan/resources/texture.vert +++ b/gsk/vulkan/resources/texture.vert @@ -1,4 +1,4 @@ -#version 420 core +#version 450 #include "common.vert.glsl" #include "rect.vert.glsl" diff --git a/testsuite/gsk/compare/repeating-gradient-scaled.node b/testsuite/gsk/compare/repeating-gradient-scaled.node new file mode 100644 index 0000000000..41946bf875 --- /dev/null +++ b/testsuite/gsk/compare/repeating-gradient-scaled.node @@ -0,0 +1,9 @@ +transform { + transform: scale(10); + child: repeating-linear-gradient { + bounds: 0 0 5 5; + start: 0 0; + end: 0 1; + stops: 0 white, 0.5 white, 0.5 black, 1 black; + } +} diff --git a/testsuite/gsk/compare/repeating-gradient-scaled.png b/testsuite/gsk/compare/repeating-gradient-scaled.png new file mode 100644 index 0000000000..509c677e1b Binary files /dev/null and b/testsuite/gsk/compare/repeating-gradient-scaled.png differ diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index eec36d5fac..1a57cfa3ad 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -80,6 +80,7 @@ compare_render_tests = [ 'repeat-empty-child-bounds', 'repeat-negative-coords', 'repeat-texture', + 'repeating-gradient-scaled', 'scale-textures-negative-ngl', 'scale-up-down', 'scaled-cairo',