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)
.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 = {
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;
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
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,
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 */
};
}
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 = {
.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)
[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,
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:
}
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:
#version 450
+#include "common.frag.glsl"
#include "clip.frag.glsl"
+#include "rect.frag.glsl"
struct ColorStop {
float offset;
};
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;
+
+ColorStop
+get_stop(int i)
+{
+ ColorStop result;
+
+ result.offset = get_float(inStopOffset + i * 5);
+ result.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));
+
+ return result;
+}
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++)
+ ColorStop stop = get_stop (0);
+ float last_offset = stop.offset;
+ color = stop.color;
+ for (int i = 1; i < inStopCount; 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));
+ stop = get_stop(i);
+ if (stop.offset < pos)
+ color = stop.color;
+ else
+ color = mix (color, stop.color, clamp((pos - last_offset) / (stop.offset - last_offset), 0, 1));
+ last_offset = stop.offset;
+ if (last_offset >= pos)
+ break;
}
- //outColor = vec4(pos, pos, pos, 1.0);
- outColor = clip (inPos, color);
+ if (last_offset < pos)
+ color = mix (color, stop.color, clamp((pos - last_offset) / (1 - last_offset), 0, 1));
+
+ float alpha = color.a * rect_coverage (inRect, inPos);
+ color = clip_scaled (inPos, vec4(color.rgb, 1) * alpha);
}
#version 450
-#include "clip.vert.glsl"
+#include "common.vert.glsl"
+#include "rect.vert.glsl"
struct ColorStop {
float offset;
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);
}