diff options
author | Benjamin Otte <otte@redhat.com> | 2016-12-26 17:11:13 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2016-12-26 17:22:02 +0100 |
commit | af917c4ade51dff5ffb934c5d6d8f366c4977dd4 (patch) | |
tree | 32f48583dc31c95da25aa8886dafe6ed6e5f993b | |
parent | c0c44c7b9cfb33ead68a31ac13319f82e22128b3 (diff) | |
download | gtk+-af917c4ade51dff5ffb934c5d6d8f366c4977dd4.tar.gz |
vulkan: Handle linear gradients
Note: We interpolate premultiplied colors as per the CSS spec. This i
different from Cairo, which interpolates unpremultiplied.
So in testcases with translucent gradients, it's actually Cairo that is
wrong.
20 files changed, 771 insertions, 1 deletions
diff --git a/gsk/Makefile.am b/gsk/Makefile.am index 31f9eacf21..31dc094eba 100644 --- a/gsk/Makefile.am +++ b/gsk/Makefile.am @@ -29,6 +29,7 @@ gsk_private_vulkan_source_h = \ gskvulkanclipprivate.h \ gskvulkancolorpipelineprivate.h \ gskvulkancommandpoolprivate.h \ + gskvulkanlineargradientpipelineprivate.h \ gskvulkanimageprivate.h \ gskvulkanmemoryprivate.h \ gskvulkanpipelineprivate.h \ @@ -43,6 +44,7 @@ gsk_private_vulkan_source_c = \ gskvulkanclip.c \ gskvulkancolorpipeline.c \ gskvulkancommandpool.c \ + gskvulkanlineargradientpipeline.c \ gskvulkanimage.c \ gskvulkanmemory.c \ gskvulkanpipeline.c \ diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 4e0254625c..cade17a956 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -383,6 +383,38 @@ gsk_repeating_linear_gradient_node_new (const graphene_rect_t *bounds, return &self->render_node; } +const graphene_point_t * +gsk_linear_gradient_node_peek_start (GskRenderNode *node) +{ + GskLinearGradientNode *self = (GskLinearGradientNode *) node; + + return &self->start; +} + +const graphene_point_t * +gsk_linear_gradient_node_peek_end (GskRenderNode *node) +{ + GskLinearGradientNode *self = (GskLinearGradientNode *) node; + + return &self->end; +} + +const gsize +gsk_linear_gradient_node_get_n_color_stops (GskRenderNode *node) +{ + GskLinearGradientNode *self = (GskLinearGradientNode *) node; + + return self->n_stops; +} + +const GskColorStop * +gsk_linear_gradient_node_peek_color_stops (GskRenderNode *node) +{ + GskLinearGradientNode *self = (GskLinearGradientNode *) node; + + return self->stops; +} + /*** GSK_BORDER_NODE ***/ typedef struct _GskBorderNode GskBorderNode; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 1139e51da8..729026370e 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -46,6 +46,11 @@ GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type, GVaria double gsk_opacity_node_get_opacity (GskRenderNode *node); +const graphene_point_t * gsk_linear_gradient_node_peek_start (GskRenderNode *node); +const graphene_point_t * gsk_linear_gradient_node_peek_end (GskRenderNode *node); +const gsize gsk_linear_gradient_node_get_n_color_stops (GskRenderNode *node); +const GskColorStop * gsk_linear_gradient_node_peek_color_stops (GskRenderNode *node); + const GskRoundedRect * gsk_border_node_peek_outline (GskRenderNode *node); float gsk_border_node_get_width (GskRenderNode *node, guint i); const GdkRGBA * gsk_border_node_peek_color (GskRenderNode *node, guint i); diff --git a/gsk/gskvulkanlineargradientpipeline.c b/gsk/gskvulkanlineargradientpipeline.c new file mode 100644 index 0000000000..cc699495fa --- /dev/null +++ b/gsk/gskvulkanlineargradientpipeline.c @@ -0,0 +1,224 @@ +#include "config.h" + +#include "gskvulkanlineargradientpipelineprivate.h" + +struct _GskVulkanLinearGradientPipeline +{ + GObject parent_instance; +}; + +typedef struct _GskVulkanLinearGradientInstance GskVulkanLinearGradientInstance; + +struct _GskVulkanLinearGradientInstance +{ + float rect[4]; + float start[2]; + float end[2]; + gint32 repeating; + 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) + +static const VkPipelineVertexInputStateCreateInfo * +gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info (GskVulkanPipeline *self) +{ + static const VkVertexInputBindingDescription vertexBindingDescriptions[] = { + { + .binding = 0, + .stride = sizeof (GskVulkanLinearGradientInstance), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE + } + }; + static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, start), + }, + { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, end), + }, + { + .location = 3, + .binding = 0, + .format = VK_FORMAT_R32_SINT, + .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, repeating), + }, + { + .location = 4, + .binding = 0, + .format = VK_FORMAT_R32_SINT, + .offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count), + }, + { + .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]), + } + }; + static const VkPipelineVertexInputStateCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions), + .pVertexBindingDescriptions = vertexBindingDescriptions, + .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription), + .pVertexAttributeDescriptions = vertexInputAttributeDescription + }; + + return &info; +} + +static void +gsk_vulkan_linear_gradient_pipeline_finalize (GObject *gobject) +{ + //GskVulkanLinearGradientPipeline *self = GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (gobject); + + G_OBJECT_CLASS (gsk_vulkan_linear_gradient_pipeline_parent_class)->finalize (gobject); +} + +static void +gsk_vulkan_linear_gradient_pipeline_class_init (GskVulkanLinearGradientPipelineClass *klass) +{ + GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_linear_gradient_pipeline_finalize; + + pipeline_class->get_input_state_create_info = gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info; +} + +static void +gsk_vulkan_linear_gradient_pipeline_init (GskVulkanLinearGradientPipeline *self) +{ +} + +GskVulkanPipeline * +gsk_vulkan_linear_gradient_pipeline_new (GskVulkanPipelineLayout *layout, + const char *shader_name, + VkRenderPass render_pass) +{ + return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE, layout, shader_name, render_pass); +} + +gsize +gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GskVulkanLinearGradientPipeline *pipeline) +{ + return sizeof (GskVulkanLinearGradientInstance); +} + +void +gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradientPipeline *pipeline, + guchar *data, + const graphene_rect_t *rect, + const graphene_point_t *start, + const graphene_point_t *end, + gboolean repeating, + gsize n_stops, + const GskColorStop *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; + instance->rect[1] = rect->origin.y; + instance->rect[2] = rect->size.width; + instance->rect[3] = rect->size.height; + instance->start[0] = start->x; + instance->start[1] = start->y; + instance->end[0] = end->x; + instance->end[1] = end->y; + instance->repeating = repeating; + 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 +gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands) +{ + vkCmdDraw (command_buffer, + 6, n_commands, + 0, offset); + + return n_commands; +} diff --git a/gsk/gskvulkanlineargradientpipelineprivate.h b/gsk/gskvulkanlineargradientpipelineprivate.h new file mode 100644 index 0000000000..50b986e3d5 --- /dev/null +++ b/gsk/gskvulkanlineargradientpipelineprivate.h @@ -0,0 +1,41 @@ +#ifndef __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__ +#define __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__ + +#include <graphene.h> + +#include "gskvulkanpipelineprivate.h" +#include "gskrendernode.h" + +G_BEGIN_DECLS + +#define GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS 8 + +typedef struct _GskVulkanLinearGradientPipelineLayout GskVulkanLinearGradientPipelineLayout; + +#define GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE (gsk_vulkan_linear_gradient_pipeline_get_type ()) + +G_DECLARE_FINAL_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK, VULKAN_LINEAR_GRADIENT_PIPELINE, GskVulkanPipeline) + +GskVulkanPipeline * gsk_vulkan_linear_gradient_pipeline_new (GskVulkanPipelineLayout * layout, + const char *shader_name, + VkRenderPass render_pass); + +gsize gsk_vulkan_linear_gradient_pipeline_count_vertex_data + (GskVulkanLinearGradientPipeline*pipeline); +void gsk_vulkan_linear_gradient_pipeline_collect_vertex_data + (GskVulkanLinearGradientPipeline*pipeline, + guchar *data, + const graphene_rect_t *rect, + const graphene_point_t *start, + const graphene_point_t *end, + gboolean repeating, + gsize n_stops, + const GskColorStop *stops); +gsize gsk_vulkan_linear_gradient_pipeline_draw (GskVulkanLinearGradientPipeline*pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands); + +G_END_DECLS + +#endif /* __GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_PRIVATE_H__ */ diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c index 59c592408e..a2968cc11e 100644 --- a/gsk/gskvulkanrender.c +++ b/gsk/gskvulkanrender.c @@ -10,6 +10,7 @@ #include "gskvulkanblendpipelineprivate.h" #include "gskvulkancolorpipelineprivate.h" +#include "gskvulkanlineargradientpipelineprivate.h" #define ORTHO_NEAR_PLANE -10000 #define ORTHO_FAR_PLANE 10000 @@ -316,7 +317,10 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self, { "blit", gsk_vulkan_blend_pipeline_new }, { "color", gsk_vulkan_color_pipeline_new }, { "color-clip", gsk_vulkan_color_pipeline_new }, - { "color-clip-rounded", gsk_vulkan_color_pipeline_new } + { "color-clip-rounded", gsk_vulkan_color_pipeline_new }, + { "linear", gsk_vulkan_linear_gradient_pipeline_new }, + { "linear-clip", gsk_vulkan_linear_gradient_pipeline_new }, + { "linear-clip-rounded", gsk_vulkan_linear_gradient_pipeline_new } }; g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL); diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c index 0721e9a74a..44bc7f9052 100644 --- a/gsk/gskvulkanrenderpass.c +++ b/gsk/gskvulkanrenderpass.c @@ -9,6 +9,7 @@ #include "gskvulkanblendpipelineprivate.h" #include "gskvulkanclipprivate.h" #include "gskvulkancolorpipelineprivate.h" +#include "gskvulkanlineargradientpipelineprivate.h" #include "gskvulkanimageprivate.h" #include "gskvulkanpushconstantsprivate.h" #include "gskvulkanrendererprivate.h" @@ -25,6 +26,7 @@ typedef enum { GSK_VULKAN_OP_SURFACE, GSK_VULKAN_OP_TEXTURE, GSK_VULKAN_OP_COLOR, + GSK_VULKAN_OP_LINEAR_GRADIENT, /* GskVulkanOpPushConstants */ GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS } GskVulkanOpType; @@ -140,6 +142,25 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, g_array_append_val (self->render_ops, op); return; + case GSK_LINEAR_GRADIENT_NODE: + case GSK_REPEATING_LINEAR_GRADIENT_NODE: + 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\n", + gsk_linear_gradient_node_get_n_color_stops (node), + GSK_VULKAN_LINEAR_GRADIENT_PIPELINE_MAX_COLOR_STOPS); + if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds)) + pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT; + else if (constants->clip.type == GSK_VULKAN_CLIP_RECT) + pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP; + else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR) + pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED; + else + FALLBACK ("Linear gradient nodes can't deal with clip type %u\n", constants->clip.type); + op.type = GSK_VULKAN_OP_LINEAR_GRADIENT; + op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type); + g_array_append_val (self->render_ops, op); + return; + case GSK_CONTAINER_NODE: { guint i; @@ -350,6 +371,7 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: + case GSK_VULKAN_OP_LINEAR_GRADIENT: case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: break; } @@ -384,6 +406,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self) n_bytes += op->render.vertex_count; break; + case GSK_VULKAN_OP_LINEAR_GRADIENT: + op->render.vertex_count = gsk_vulkan_linear_gradient_pipeline_count_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline)); + n_bytes += op->render.vertex_count; + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -436,6 +463,21 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_LINEAR_GRADIENT: + { + op->render.vertex_offset = offset + n_bytes; + gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (op->render.pipeline), + data + n_bytes + offset, + &op->render.node->bounds, + gsk_linear_gradient_node_peek_start (op->render.node), + gsk_linear_gradient_node_peek_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_peek_color_stops (op->render.node)); + n_bytes += op->render.vertex_count; + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -472,6 +514,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: + case GSK_VULKAN_OP_LINEAR_GRADIENT: case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: break; } @@ -563,6 +606,27 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, current_draw_index, step); break; + case GSK_VULKAN_OP_LINEAR_GRADIENT: + if (current_pipeline != op->render.pipeline) + { + current_pipeline = op->render.pipeline; + vkCmdBindPipeline (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline (current_pipeline)); + vkCmdBindVertexBuffers (command_buffer, + 0, + 1, + (VkBuffer[1]) { + gsk_vulkan_buffer_get_buffer (vertex_buffer) + }, + (VkDeviceSize[1]) { op->render.vertex_offset }); + current_draw_index = 0; + } + current_draw_index += gsk_vulkan_linear_gradient_pipeline_draw (GSK_VULKAN_LINEAR_GRADIENT_PIPELINE (current_pipeline), + command_buffer, + current_draw_index, 1); + break; + case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: gsk_vulkan_push_constants_push_vertex (&op->constants.constants, command_buffer, diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h index f707c2a736..72c4314492 100644 --- a/gsk/gskvulkanrenderprivate.h +++ b/gsk/gskvulkanrenderprivate.h @@ -14,6 +14,9 @@ typedef enum { GSK_VULKAN_PIPELINE_COLOR, GSK_VULKAN_PIPELINE_COLOR_CLIP, GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED, + GSK_VULKAN_PIPELINE_LINEAR_GRADIENT, + GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP, + GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED, /* add more */ GSK_VULKAN_N_PIPELINES } GskVulkanPipelineType; diff --git a/gsk/resources/vulkan/linear-clip-rounded.frag.glsl b/gsk/resources/vulkan/linear-clip-rounded.frag.glsl new file mode 100644 index 0000000000..3c5fade7e3 --- /dev/null +++ b/gsk/resources/vulkan/linear-clip-rounded.frag.glsl @@ -0,0 +1,78 @@ +#version 420 core + +struct ColorStop { + float offset; + vec4 color; +}; + +struct RoundedRect { + vec4 bounds; + vec4 corners; +}; + +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 vec4 inClipBounds; +layout(location = 5) in flat vec4 inClipWidths; +layout(location = 6) in flat ColorStop inStops[8]; + +layout(location = 0) out vec4 outColor; + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +float clip(vec2 pos, RoundedRect r) { + vec2 ref_tl = r.bounds.xy + vec2( r.corners.x, r.corners.x); + vec2 ref_tr = r.bounds.zy + vec2(-r.corners.y, r.corners.y); + vec2 ref_br = r.bounds.zw + vec2(-r.corners.z, -r.corners.z); + vec2 ref_bl = r.bounds.xw + vec2( r.corners.w, -r.corners.w); + + float d_tl = distance(pos, ref_tl); + float d_tr = distance(pos, ref_tr); + float d_br = distance(pos, ref_br); + float d_bl = distance(pos, ref_bl); + + float pixels_per_fragment = length(fwidth(pos.xy)); + float nudge = 0.5 * pixels_per_fragment; + vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - r.corners + nudge; + + bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y, + pos.x > ref_tr.x && pos.y < ref_tr.y, + pos.x > ref_br.x && pos.y > ref_br.y, + pos.x < ref_bl.x && pos.y > ref_bl.y); + + float distance_from_border = dot(vec4(is_out), + max(vec4(0.0, 0.0, 0.0, 0.0), distances)); + + // Move the distance back into pixels. + distance_from_border /= pixels_per_fragment; + // Apply a more gradual fade out to transparent. + //distance_from_border -= 0.5; + + return 1.0 - smoothstep(0.0, 1.0, distance_from_border); +} + +void main() +{ + RoundedRect r = RoundedRect(vec4(inClipBounds.xy, inClipBounds.xy + inClipBounds.zw), inClipWidths); + + float pos; + if (inRepeating != 0) + pos = fract (inGradientPos); + else + pos = clamp (inGradientPos, 0, 1); + + vec4 color = inStops[0].color; + int n = clamp (inStopCount, 2, 8); + for (int i = 1; i < n; i++) + { + 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)); + } + + //outColor = vec4(pos, pos, pos, 1.0); + outColor = color * clip (inPos, r); +} diff --git a/gsk/resources/vulkan/linear-clip-rounded.frag.spv b/gsk/resources/vulkan/linear-clip-rounded.frag.spv Binary files differnew file mode 100644 index 0000000000..ce8a52a43d --- /dev/null +++ b/gsk/resources/vulkan/linear-clip-rounded.frag.spv diff --git a/gsk/resources/vulkan/linear-clip-rounded.vert.glsl b/gsk/resources/vulkan/linear-clip-rounded.vert.glsl new file mode 100644 index 0000000000..3426ccef91 --- /dev/null +++ b/gsk/resources/vulkan/linear-clip-rounded.vert.glsl @@ -0,0 +1,84 @@ +#version 420 core + +struct ColorStop { + float offset; + vec4 color; +}; + +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(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +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 vec4 outClipBounds; +layout(location = 5) out flat vec4 outClipWidths; +layout(location = 6) out flat ColorStop outStops[8]; + +out gl_PerVertex { + vec4 gl_Position; +}; + +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) }; + +float +get_gradient_pos (vec2 pos) +{ + pos = pos - inStart; + vec2 grad = inEnd - inStart; + + return dot (pos, grad) / dot (grad, grad); +} + +void main() { + vec2 pos = inRect.xy + inRect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + outPos = pos; + outGradientPos = get_gradient_pos (pos); + outClipBounds = push.clip_bounds; + outClipWidths = push.clip_widths; + outRepeating = inRepeating; + 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/resources/vulkan/linear-clip-rounded.vert.spv b/gsk/resources/vulkan/linear-clip-rounded.vert.spv Binary files differnew file mode 100644 index 0000000000..901fff9ef1 --- /dev/null +++ b/gsk/resources/vulkan/linear-clip-rounded.vert.spv diff --git a/gsk/resources/vulkan/linear-clip.frag.glsl b/gsk/resources/vulkan/linear-clip.frag.glsl new file mode 100644 index 0000000000..1d03553705 --- /dev/null +++ b/gsk/resources/vulkan/linear-clip.frag.glsl @@ -0,0 +1,33 @@ +#version 420 core + +struct ColorStop { + float offset; + vec4 color; +}; + +layout(location = 0) in float inGradientPos; +layout(location = 1) in flat int inRepeating; +layout(location = 2) in flat int inStopCount; +layout(location = 3) in flat ColorStop inStops[8]; + +layout(location = 0) out vec4 outColor; + +void main() +{ + float pos; + if (inRepeating != 0) + pos = fract (inGradientPos); + else + pos = clamp (inGradientPos, 0, 1); + + vec4 color = inStops[0].color; + int n = clamp (inStopCount, 2, 8); + for (int i = 1; i < n; i++) + { + 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)); + } + + //outColor = vec4(pos, pos, pos, 1.0); + outColor = color; +} diff --git a/gsk/resources/vulkan/linear-clip.frag.spv b/gsk/resources/vulkan/linear-clip.frag.spv Binary files differnew file mode 100644 index 0000000000..a95b58f59b --- /dev/null +++ b/gsk/resources/vulkan/linear-clip.frag.spv diff --git a/gsk/resources/vulkan/linear-clip.vert.glsl b/gsk/resources/vulkan/linear-clip.vert.glsl new file mode 100644 index 0000000000..818d5abf4c --- /dev/null +++ b/gsk/resources/vulkan/linear-clip.vert.glsl @@ -0,0 +1,78 @@ +#version 420 core + +struct ColorStop { + float offset; + vec4 color; +}; + +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(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +layout(location = 0) out float outGradientPos; +layout(location = 1) out flat int outRepeating; +layout(location = 2) out flat int outStopCount; +layout(location = 3) out flat ColorStop outStops[8]; + +out gl_PerVertex { + vec4 gl_Position; +}; + +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) }; + +float +get_gradient_pos (vec2 pos) +{ + pos = pos - inStart; + vec2 grad = inEnd - inStart; + + return dot (pos, grad) / dot (grad, grad); +} + +void main() { + vec2 pos = inRect.xy + inRect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + outGradientPos = get_gradient_pos (pos); + outRepeating = inRepeating; + 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/resources/vulkan/linear-clip.vert.spv b/gsk/resources/vulkan/linear-clip.vert.spv Binary files differnew file mode 100644 index 0000000000..57199f9ec6 --- /dev/null +++ b/gsk/resources/vulkan/linear-clip.vert.spv diff --git a/gsk/resources/vulkan/linear.frag.glsl b/gsk/resources/vulkan/linear.frag.glsl new file mode 100644 index 0000000000..1d03553705 --- /dev/null +++ b/gsk/resources/vulkan/linear.frag.glsl @@ -0,0 +1,33 @@ +#version 420 core + +struct ColorStop { + float offset; + vec4 color; +}; + +layout(location = 0) in float inGradientPos; +layout(location = 1) in flat int inRepeating; +layout(location = 2) in flat int inStopCount; +layout(location = 3) in flat ColorStop inStops[8]; + +layout(location = 0) out vec4 outColor; + +void main() +{ + float pos; + if (inRepeating != 0) + pos = fract (inGradientPos); + else + pos = clamp (inGradientPos, 0, 1); + + vec4 color = inStops[0].color; + int n = clamp (inStopCount, 2, 8); + for (int i = 1; i < n; i++) + { + 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)); + } + + //outColor = vec4(pos, pos, pos, 1.0); + outColor = color; +} diff --git a/gsk/resources/vulkan/linear.frag.spv b/gsk/resources/vulkan/linear.frag.spv Binary files differnew file mode 100644 index 0000000000..a95b58f59b --- /dev/null +++ b/gsk/resources/vulkan/linear.frag.spv diff --git a/gsk/resources/vulkan/linear.vert.glsl b/gsk/resources/vulkan/linear.vert.glsl new file mode 100644 index 0000000000..d9d107e2ea --- /dev/null +++ b/gsk/resources/vulkan/linear.vert.glsl @@ -0,0 +1,89 @@ +#version 420 core + +struct ColorStop { + float offset; + vec4 color; +}; + +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(push_constant) uniform PushConstants { + mat4 mvp; + vec4 clip_bounds; + vec4 clip_widths; + vec4 clip_heights; +} push; + +layout(location = 0) out float outGradientPos; +layout(location = 1) out flat int outRepeating; +layout(location = 2) out flat int outStopCount; +layout(location = 3) out flat ColorStop outStops[8]; + +out gl_PerVertex { + vec4 gl_Position; +}; + +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) }; + +vec4 intersect(vec4 a, vec4 b) +{ + a = vec4(a.xy, a.xy + a.zw); + b = vec4(b.xy, b.xy + b.zw); + vec4 result = vec4(max(a.xy, b.xy), min(a.zw, b.zw)); + if (any (greaterThanEqual (result.xy, result.zw))) + return vec4(0.0,0.0,0.0,0.0); + return vec4(result.xy, result.zw - result.xy); +} + +float +get_gradient_pos (vec2 pos) +{ + pos = pos - inStart; + vec2 grad = inEnd - inStart; + + return dot (pos, grad) / dot (grad, grad); +} + +void main() { + vec4 rect = intersect(inRect, push.clip_bounds); + vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex]; + gl_Position = push.mvp * vec4 (pos, 0.0, 1.0); + outGradientPos = get_gradient_pos (pos); + outRepeating = inRepeating; + 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/resources/vulkan/linear.vert.spv b/gsk/resources/vulkan/linear.vert.spv Binary files differnew file mode 100644 index 0000000000..ab3b4ac9a5 --- /dev/null +++ b/gsk/resources/vulkan/linear.vert.spv |