vulkan: Add shader for border rendering

This commit is contained in:
Benjamin Otte 2017-01-10 14:59:20 +01:00
parent c00f8dce9f
commit b186bce7ff
21 changed files with 775 additions and 12 deletions

View File

@ -25,6 +25,7 @@ noinst_LTLIBRARIES =
if HAVE_VULKAN
gsk_private_vulkan_source_h = \
gskvulkanblendpipelineprivate.h \
gskvulkanborderpipelineprivate.h \
gskvulkanbufferprivate.h \
gskvulkanclipprivate.h \
gskvulkancolorpipelineprivate.h \
@ -41,6 +42,7 @@ gsk_private_vulkan_source_h = \
gskvulkanshaderprivate.h
gsk_private_vulkan_source_c = \
gskvulkanblendpipeline.c \
gskvulkanborderpipeline.c \
gskvulkanbuffer.c \
gskvulkanclip.c \
gskvulkancolorpipeline.c \
@ -55,6 +57,8 @@ gsk_private_vulkan_source_c = \
gskvulkanrenderer.c \
gskvulkanrenderpass.c \
gskvulkanshader.c
gsk_private_vulkan_include_shaders = \
resources/vulkan/rounded-rect.glsl
gsk_private_vulkan_shaders = \
resources/vulkan/blend-clip.frag.glsl \
resources/vulkan/blend-clip-rounded.frag.glsl \
@ -62,6 +66,12 @@ gsk_private_vulkan_shaders = \
resources/vulkan/blend-clip.vert.glsl \
resources/vulkan/blend.frag.glsl \
resources/vulkan/blend.vert.glsl \
resources/vulkan/border-clip.frag.glsl \
resources/vulkan/border-clip.vert.glsl \
resources/vulkan/border-clip-rounded.frag.glsl \
resources/vulkan/border-clip-rounded.vert.glsl \
resources/vulkan/border.frag.glsl \
resources/vulkan/border.vert.glsl \
resources/vulkan/color-clip.frag.glsl \
resources/vulkan/color-clip-rounded.frag.glsl \
resources/vulkan/color-clip-rounded.vert.glsl \
@ -199,7 +209,7 @@ gskresources.c: gsk.resources.xml $(resource_files)
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< \
--target=$@ --sourcedir=$(srcdir) --c-name _gsk --generate-source --manual-register
EXTRA_DIST += $(resource_files)
EXTRA_DIST += $(resource_files) $(gsk_private_vulkan_include_shaders)
CLEANFILES += gsk.resources.xml
DISTCLEANFILES += gskresources.h gskresources.c

View File

@ -593,22 +593,20 @@ gsk_border_node_peek_outline (GskRenderNode *node)
return &self->outline;
}
float
gsk_border_node_get_width (GskRenderNode *node,
guint i)
const float *
gsk_border_node_peek_widths (GskRenderNode *node)
{
GskBorderNode *self = (GskBorderNode *) node;
return self->border_width[i];
return self->border_width;
}
const GdkRGBA *
gsk_border_node_peek_color (GskRenderNode *node,
guint i)
gsk_border_node_peek_colors (GskRenderNode *node)
{
GskBorderNode *self = (GskBorderNode *) node;
return &self->border_color[i];
return self->border_color;
}
/**

View File

@ -59,8 +59,8 @@ 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);
const float * gsk_border_node_peek_widths (GskRenderNode *node);
const GdkRGBA * gsk_border_node_peek_colors (GskRenderNode *node);
GskRenderNode *gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds, cairo_surface_t *surface);
cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);

View File

@ -0,0 +1,163 @@
#include "config.h"
#include "gskvulkanborderpipelineprivate.h"
#include "gskroundedrectprivate.h"
struct _GskVulkanBorderPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanBorderInstance GskVulkanBorderInstance;
struct _GskVulkanBorderInstance
{
float rect[12];
float widths[4];
float colors[16];
};
G_DEFINE_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_border_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanBorderInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 4 * sizeof (float),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 8 * sizeof (float),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, widths),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 4 * sizeof (float),
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 8 * sizeof (float),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 12 * sizeof (float),
}
};
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_border_pipeline_finalize (GObject *gobject)
{
//GskVulkanBorderPipeline *self = GSK_VULKAN_BORDER_PIPELINE (gobject);
G_OBJECT_CLASS (gsk_vulkan_border_pipeline_parent_class)->finalize (gobject);
}
static void
gsk_vulkan_border_pipeline_class_init (GskVulkanBorderPipelineClass *klass)
{
GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_border_pipeline_finalize;
pipeline_class->get_input_state_create_info = gsk_vulkan_border_pipeline_get_input_state_create_info;
}
static void
gsk_vulkan_border_pipeline_init (GskVulkanBorderPipeline *self)
{
}
GskVulkanPipeline *
gsk_vulkan_border_pipeline_new (GskVulkanPipelineLayout *layout,
const char *shader_name,
VkRenderPass render_pass)
{
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BORDER_PIPELINE, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline)
{
return sizeof (GskVulkanBorderInstance);
}
void
gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
guchar *data,
const GskRoundedRect *rect,
const float widths[4],
const GdkRGBA colors[4])
{
GskVulkanBorderInstance *instance = (GskVulkanBorderInstance *) data;
guint i;
gsk_rounded_rect_to_float (rect, instance->rect);
for (i = 0; i < 4; i++)
{
instance->widths[i] = widths[i];
instance->colors[4 * i + 0] = colors[i].red;
instance->colors[4 * i + 1] = colors[i].green;
instance->colors[4 * i + 2] = colors[i].blue;
instance->colors[4 * i + 3] = colors[i].alpha;
}
}
gsize
gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands)
{
vkCmdDraw (command_buffer,
6 * 8, n_commands,
0, offset);
return n_commands;
}

View File

@ -0,0 +1,34 @@
#ifndef __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
#define __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__
#include <graphene.h>
#include "gskvulkanpipelineprivate.h"
#include "gskroundedrect.h"
G_BEGIN_DECLS
typedef struct _GskVulkanBorderPipelineLayout GskVulkanBorderPipelineLayout;
#define GSK_TYPE_VULKAN_BORDER_PIPELINE (gsk_vulkan_border_pipeline_get_type ())
G_DECLARE_FINAL_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK, VULKAN_BORDER_PIPELINE, GskVulkanPipeline)
GskVulkanPipeline * gsk_vulkan_border_pipeline_new (GskVulkanPipelineLayout * layout,
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_border_pipeline_count_vertex_data (GskVulkanBorderPipeline *pipeline);
void gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipeline,
guchar *data,
const GskRoundedRect *rect,
const float widths[4],
const GdkRGBA colors[4]);
gsize gsk_vulkan_border_pipeline_draw (GskVulkanBorderPipeline *pipeline,
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands);
G_END_DECLS
#endif /* __GSK_VULKAN_BORDER_PIPELINE_PRIVATE_H__ */

View File

@ -9,6 +9,7 @@
#include "gskvulkanrenderpassprivate.h"
#include "gskvulkanblendpipelineprivate.h"
#include "gskvulkanborderpipelineprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
#include "gskvulkanlineargradientpipelineprivate.h"
@ -326,7 +327,10 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
{ "linear-clip-rounded", gsk_vulkan_linear_gradient_pipeline_new },
{ "color-matrix", gsk_vulkan_effect_pipeline_new },
{ "color-matrix-clip", gsk_vulkan_effect_pipeline_new },
{ "color-matrix-clip-rounded", gsk_vulkan_effect_pipeline_new }
{ "color-matrix-clip-rounded", gsk_vulkan_effect_pipeline_new },
{ "border", gsk_vulkan_border_pipeline_new },
{ "border-clip", gsk_vulkan_border_pipeline_new },
{ "border-clip-rounded", gsk_vulkan_border_pipeline_new }
};
g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);

View File

@ -7,6 +7,7 @@
#include "gskrenderer.h"
#include "gskroundedrectprivate.h"
#include "gskvulkanblendpipelineprivate.h"
#include "gskvulkanborderpipelineprivate.h"
#include "gskvulkanclipprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
@ -30,6 +31,7 @@ typedef enum {
GSK_VULKAN_OP_LINEAR_GRADIENT,
GSK_VULKAN_OP_OPACITY,
GSK_VULKAN_OP_COLOR_MATRIX,
GSK_VULKAN_OP_BORDER,
/* GskVulkanOpPushConstants */
GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS
} GskVulkanOpType;
@ -110,9 +112,9 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
case GSK_NOT_A_RENDER_NODE:
g_assert_not_reached ();
return;
case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
case GSK_REPEAT_NODE:
case GSK_SHADOW_NODE:
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
@ -210,6 +212,20 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
g_array_append_val (self->render_ops, op);
return;
case GSK_BORDER_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_BORDER;
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP;
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
else
FALLBACK ("Border nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_BORDER;
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;
@ -499,6 +515,7 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
case GSK_VULKAN_OP_COLOR:
case GSK_VULKAN_OP_LINEAR_GRADIENT:
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
case GSK_VULKAN_OP_BORDER:
break;
}
}
@ -543,6 +560,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
n_bytes += op->render.vertex_count;
break;
case GSK_VULKAN_OP_BORDER:
op->render.vertex_count = gsk_vulkan_border_pipeline_count_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline));
n_bytes += op->render.vertex_count;
break;
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
@ -644,6 +666,18 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
}
break;
case GSK_VULKAN_OP_BORDER:
{
op->render.vertex_offset = offset + n_bytes;
gsk_vulkan_border_pipeline_collect_vertex_data (GSK_VULKAN_BORDER_PIPELINE (op->render.pipeline),
data + n_bytes + offset,
gsk_border_node_peek_outline (op->render.node),
gsk_border_node_peek_widths (op->render.node),
gsk_border_node_peek_colors (op->render.node));
n_bytes += op->render.vertex_count;
}
break;
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
@ -684,6 +718,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
case GSK_VULKAN_OP_COLOR:
case GSK_VULKAN_OP_LINEAR_GRADIENT:
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
case GSK_VULKAN_OP_BORDER:
break;
}
}
@ -829,6 +864,27 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
current_draw_index, 1);
break;
case GSK_VULKAN_OP_BORDER:
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_border_pipeline_draw (GSK_VULKAN_BORDER_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,

View File

@ -22,6 +22,9 @@ typedef enum {
GSK_VULKAN_PIPELINE_COLOR_MATRIX,
GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP,
GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED,
GSK_VULKAN_PIPELINE_BORDER,
GSK_VULKAN_PIPELINE_BORDER_CLIP,
GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED,
/* add more */
GSK_VULKAN_N_PIPELINES
} GskVulkanPipelineType;

View File

@ -0,0 +1,34 @@
#version 420 core
#include "rounded-rect.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec4 inColor;
layout(location = 2) in vec4 inRect;
layout(location = 3) in vec4 inCornerWidths;
layout(location = 4) in vec4 inCornerHeights;
layout(location = 5) in vec4 inBorderWidths;
layout(location = 6) in flat vec4 inClipBounds;
layout(location = 7) in flat vec4 inClipWidths;
layout(location = 8) in flat vec4 inClipHeights;
layout(location = 0) out vec4 color;
vec4
clip (vec4 color)
{
RoundedRect r = RoundedRect (vec4(inClipBounds.xy, inClipBounds.xy + inClipBounds.zw), inClipWidths, inClipHeights);
return color * rounded_rect_coverage (r, inPos);
}
void main()
{
RoundedRect routside = RoundedRect (vec4(inRect.xy, inRect.xy + inRect.zw), inCornerWidths, inCornerHeights);
RoundedRect rinside = rounded_rect_shrink (routside, inBorderWidths);
float alpha = clamp (rounded_rect_coverage (routside, inPos) -
rounded_rect_coverage (rinside, inPos),
0.0, 1.0);
color = clip (inColor);
}

Binary file not shown.

View File

@ -0,0 +1,123 @@
#version 420 core
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inCornerWidths;
layout(location = 2) in vec4 inCornerHeights;
layout(location = 3) in vec4 inBorderWidths;
layout(location = 4) in mat4 inBorderColors;
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 flat vec4 outColor;
layout(location = 2) out flat vec4 outRect;
layout(location = 3) out flat vec4 outCornerWidths;
layout(location = 4) out flat vec4 outCornerHeights;
layout(location = 5) out flat vec4 outBorderWidths;
layout(location = 6) out flat vec4 outClipBounds;
layout(location = 7) out flat vec4 outClipWidths;
layout(location = 8) out flat vec4 outClipHeights;
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(1.0, 1.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0) };
#define TOP 0
#define RIGHT 1
#define BOTTOM 2
#define LEFT 3
#define TOP_LEFT 0
#define TOP_RIGHT 1
#define BOTTOM_RIGHT 2
#define BOTTOM_LEFT 3
#define SLICE_TOP_LEFT 0
#define SLICE_TOP 1
#define SLICE_TOP_RIGHT 2
#define SLICE_RIGHT 3
#define SLICE_BOTTOM_RIGHT 4
#define SLICE_BOTTOM 5
#define SLICE_BOTTOM_LEFT 6
#define SLICE_LEFT 7
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);
}
void main() {
int slice_index = gl_VertexIndex / 6;
int vert_index = gl_VertexIndex % 6;
vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
vec4 rect;
switch (slice_index)
{
case SLICE_TOP_LEFT:
rect = vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]);
vert_index = (vert_index + 3) % 6;
break;
case SLICE_TOP:
rect = vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]);
outColor = inBorderColors[TOP];
break;
case SLICE_TOP_RIGHT:
rect = vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]);
break;
case SLICE_RIGHT:
rect = vec4(inRect.x + inRect.z - inBorderWidths[RIGHT], inRect.y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect.w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]);
outColor = inBorderColors[RIGHT];
break;
case SLICE_BOTTOM_RIGHT:
rect = vec4(inRect.x + inRect.z - corner_widths[BOTTOM_RIGHT], inRect.y + inRect.w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]);
break;
case SLICE_BOTTOM:
rect = vec4(inRect.x + corner_widths[BOTTOM_LEFT], inRect.y + inRect.w - inBorderWidths[BOTTOM], inRect.z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]);
break;
case SLICE_BOTTOM_LEFT:
rect = vec4(inRect.x, inRect.y + inRect.w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]);
vert_index = (vert_index + 3) % 6;
break;
case SLICE_LEFT:
rect = vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]);
break;
}
rect = intersect (rect, push.clip_bounds);
vec2 pos;
if ((slice_index % 4) != 0 || (vert_index % 3) != 2)
pos = rect.xy + rect.zw * offsets[vert_index];
else
pos = rect.xy + rect.zw * vec2(1.0 - offsets[vert_index].x, offsets[vert_index].y);
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
outColor = inBorderColors[((gl_VertexIndex / 3 + 15) / 4) % 4];
outPos = pos;
outRect = inRect;
outCornerWidths = inCornerWidths;
outCornerHeights = inCornerHeights;
outBorderWidths = inBorderWidths;
outClipBounds = push.clip_bounds;
outClipWidths = push.clip_widths;
outClipHeights = push.clip_heights;
}

Binary file not shown.

View File

@ -0,0 +1,23 @@
#version 420 core
#include "rounded-rect.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in flat vec4 inColor;
layout(location = 2) in flat vec4 inRect;
layout(location = 3) in flat vec4 inCornerWidths;
layout(location = 4) in flat vec4 inCornerHeights;
layout(location = 5) in flat vec4 inBorderWidths;
layout(location = 0) out vec4 color;
void main()
{
RoundedRect routside = RoundedRect (vec4(inRect.xy, inRect.xy + inRect.zw), inCornerWidths, inCornerHeights);
RoundedRect rinside = rounded_rect_shrink (routside, inBorderWidths);
float alpha = clamp (rounded_rect_coverage (routside, inPos) -
rounded_rect_coverage (rinside, inPos),
0.0, 1.0);
color = inColor * alpha;
}

Binary file not shown.

View File

@ -0,0 +1,117 @@
#version 420 core
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inCornerWidths;
layout(location = 2) in vec4 inCornerHeights;
layout(location = 3) in vec4 inBorderWidths;
layout(location = 4) in mat4 inBorderColors;
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 flat vec4 outColor;
layout(location = 2) out flat vec4 outRect;
layout(location = 3) out flat vec4 outCornerWidths;
layout(location = 4) out flat vec4 outCornerHeights;
layout(location = 5) out flat vec4 outBorderWidths;
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(1.0, 1.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0) };
#define TOP 0
#define RIGHT 1
#define BOTTOM 2
#define LEFT 3
#define TOP_LEFT 0
#define TOP_RIGHT 1
#define BOTTOM_RIGHT 2
#define BOTTOM_LEFT 3
#define SLICE_TOP_LEFT 0
#define SLICE_TOP 1
#define SLICE_TOP_RIGHT 2
#define SLICE_RIGHT 3
#define SLICE_BOTTOM_RIGHT 4
#define SLICE_BOTTOM 5
#define SLICE_BOTTOM_LEFT 6
#define SLICE_LEFT 7
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);
}
void main() {
int slice_index = gl_VertexIndex / 6;
int vert_index = gl_VertexIndex % 6;
vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
vec4 rect;
switch (slice_index)
{
case SLICE_TOP_LEFT:
rect = vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]);
vert_index = (vert_index + 3) % 6;
break;
case SLICE_TOP:
rect = vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]);
outColor = inBorderColors[TOP];
break;
case SLICE_TOP_RIGHT:
rect = vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]);
break;
case SLICE_RIGHT:
rect = vec4(inRect.x + inRect.z - inBorderWidths[RIGHT], inRect.y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect.w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]);
outColor = inBorderColors[RIGHT];
break;
case SLICE_BOTTOM_RIGHT:
rect = vec4(inRect.x + inRect.z - corner_widths[BOTTOM_RIGHT], inRect.y + inRect.w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]);
break;
case SLICE_BOTTOM:
rect = vec4(inRect.x + corner_widths[BOTTOM_LEFT], inRect.y + inRect.w - inBorderWidths[BOTTOM], inRect.z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]);
break;
case SLICE_BOTTOM_LEFT:
rect = vec4(inRect.x, inRect.y + inRect.w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]);
vert_index = (vert_index + 3) % 6;
break;
case SLICE_LEFT:
rect = vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]);
break;
}
rect = intersect (rect, push.clip_bounds);
vec2 pos;
if ((slice_index % 4) != 0 || (vert_index % 3) != 2)
pos = rect.xy + rect.zw * offsets[vert_index];
else
pos = rect.xy + rect.zw * vec2(1.0 - offsets[vert_index].x, offsets[vert_index].y);
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
outColor = inBorderColors[((gl_VertexIndex / 3 + 15) / 4) % 4];
outPos = pos;
outRect = inRect;
outCornerWidths = inCornerWidths;
outCornerHeights = inCornerHeights;
outBorderWidths = inBorderWidths;
}

Binary file not shown.

View File

@ -0,0 +1,23 @@
#version 420 core
#include "rounded-rect.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in flat vec4 inColor;
layout(location = 2) in flat vec4 inRect;
layout(location = 3) in flat vec4 inCornerWidths;
layout(location = 4) in flat vec4 inCornerHeights;
layout(location = 5) in flat vec4 inBorderWidths;
layout(location = 0) out vec4 color;
void main()
{
RoundedRect routside = RoundedRect (vec4(inRect.xy, inRect.xy + inRect.zw), inCornerWidths, inCornerHeights);
RoundedRect rinside = rounded_rect_shrink (routside, inBorderWidths);
float alpha = clamp (rounded_rect_coverage (routside, inPos) -
rounded_rect_coverage (rinside, inPos),
0.0, 1.0);
color = inColor * alpha;
}

Binary file not shown.

View File

@ -0,0 +1,106 @@
#version 420 core
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inCornerWidths;
layout(location = 2) in vec4 inCornerHeights;
layout(location = 3) in vec4 inBorderWidths;
layout(location = 4) in mat4 inBorderColors;
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 flat vec4 outColor;
layout(location = 2) out flat vec4 outRect;
layout(location = 3) out flat vec4 outCornerWidths;
layout(location = 4) out flat vec4 outCornerHeights;
layout(location = 5) out flat vec4 outBorderWidths;
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(1.0, 1.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0) };
#define TOP 0
#define RIGHT 1
#define BOTTOM 2
#define LEFT 3
#define TOP_LEFT 0
#define TOP_RIGHT 1
#define BOTTOM_RIGHT 2
#define BOTTOM_LEFT 3
#define SLICE_TOP_LEFT 0
#define SLICE_TOP 1
#define SLICE_TOP_RIGHT 2
#define SLICE_RIGHT 3
#define SLICE_BOTTOM_RIGHT 4
#define SLICE_BOTTOM 5
#define SLICE_BOTTOM_LEFT 6
#define SLICE_LEFT 7
void main() {
int slice_index = gl_VertexIndex / 6;
int vert_index = gl_VertexIndex % 6;
vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
vec4 rect;
switch (slice_index)
{
case SLICE_TOP_LEFT:
rect = vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]);
vert_index = (vert_index + 3) % 6;
break;
case SLICE_TOP:
rect = vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]);
outColor = inBorderColors[TOP];
break;
case SLICE_TOP_RIGHT:
rect = vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]);
break;
case SLICE_RIGHT:
rect = vec4(inRect.x + inRect.z - inBorderWidths[RIGHT], inRect.y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect.w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]);
outColor = inBorderColors[RIGHT];
break;
case SLICE_BOTTOM_RIGHT:
rect = vec4(inRect.x + inRect.z - corner_widths[BOTTOM_RIGHT], inRect.y + inRect.w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]);
break;
case SLICE_BOTTOM:
rect = vec4(inRect.x + corner_widths[BOTTOM_LEFT], inRect.y + inRect.w - inBorderWidths[BOTTOM], inRect.z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]);
break;
case SLICE_BOTTOM_LEFT:
rect = vec4(inRect.x, inRect.y + inRect.w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]);
vert_index = (vert_index + 3) % 6;
break;
case SLICE_LEFT:
rect = vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]);
break;
}
vec2 pos;
if ((slice_index % 4) != 0 || (vert_index % 3) != 2)
pos = rect.xy + rect.zw * offsets[vert_index];
else
pos = rect.xy + rect.zw * vec2(1.0 - offsets[vert_index].x, offsets[vert_index].y);
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
outColor = inBorderColors[((gl_VertexIndex / 3 + 15) / 4) % 4];
outPos = pos;
outRect = inRect;
outCornerWidths = inCornerWidths;
outCornerHeights = inCornerHeights;
outBorderWidths = inBorderWidths;
}

Binary file not shown.

View File

@ -0,0 +1,69 @@
#ifndef _ROUNDED_RECT_
#define _ROUNDED_RECT_
struct RoundedRect
{
vec4 bounds;
vec4 corner_widths;
vec4 corner_heights;
};
float
ellipsis_dist (vec2 p, vec2 radius)
{
vec2 p0 = p / radius;
vec2 p1 = 2.0 * p0 / radius;
return (dot(p0, p0) - 1.0) / length (p1);
}
float
ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
{
float d = ellipsis_dist (point - center, radius);
return clamp (0.5 - d, 0.0, 1.0);
}
float
rounded_rect_coverage (RoundedRect r, vec2 p)
{
if (p.x < r.bounds.x || p.y < r.bounds.y ||
p.x >= r.bounds.z || p.y >= r.bounds.w)
return 0.0;
vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x);
vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y);
vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z);
vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w);
vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x);
vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y);
vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z);
vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w);
float d_tl = ellipsis_coverage(p, ref_tl, rad_tl);
float d_tr = ellipsis_coverage(p, ref_tr, rad_tr);
float d_br = ellipsis_coverage(p, ref_br, rad_br);
float d_bl = ellipsis_coverage(p, ref_bl, rad_bl);
vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
p.x > ref_tr.x && p.y < ref_tr.y,
p.x > ref_br.x && p.y > ref_br.y,
p.x < ref_bl.x && p.y > ref_bl.y);
return 1.0 - dot(vec4(is_out), corner_coverages);
}
RoundedRect
rounded_rect_shrink (RoundedRect r, vec4 amount)
{
vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz;
vec4 new_widths = max (r.corner_widths - amount.wyyw, 0.0);
vec4 new_heights = max (r.corner_heights - amount.xxzz, 0.0);
return RoundedRect (new_bounds, new_widths, new_heights);
}
#endif