mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
vulkan: Make gradient shader use buffers
This allows putting any number of color stops into the buffer, so fallbacks with too many stops are no longer necessary.
This commit is contained in:
parent
d1135f9e3c
commit
e3cc3f7841
@ -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 = {
|
||||
@ -175,17 +120,11 @@ gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradient
|
||||
const graphene_point_t *start,
|
||||
const graphene_point_t *end,
|
||||
gboolean repeating,
|
||||
gsize n_stops,
|
||||
const GskColorStop *stops)
|
||||
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
|
||||
|
@ -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,
|
||||
|
@ -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,7 +407,7 @@ gsk_vulkan_render_pass_add_color_node (GskVulkanRenderPass *self,
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gsk_vulkan_render_pass_add_repeating_linear_gradient_node (GskVulkanRenderPass *self,
|
||||
gsk_vulkan_render_pass_add_linear_gradient_node (GskVulkanRenderPass *self,
|
||||
GskVulkanRender *render,
|
||||
const GskVulkanParseState *state,
|
||||
GskRenderNode *node)
|
||||
@ -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:
|
||||
|
@ -1,6 +1,8 @@
|
||||
#version 450
|
||||
|
||||
#include "common.frag.glsl"
|
||||
#include "clip.frag.glsl"
|
||||
#include "rect.frag.glsl"
|
||||
|
||||
struct ColorStop {
|
||||
float offset;
|
||||
@ -8,29 +10,55 @@ struct ColorStop {
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user