Merge branch 'wip/otte/vulkan' into 'main'

Vulkan hacking going overboard

See merge request GNOME/gtk!5992
This commit is contained in:
Benjamin Otte 2023-06-04 18:21:21 +00:00
commit fd5d15004e
75 changed files with 2428 additions and 1581 deletions

View File

@ -1053,26 +1053,30 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
device_extensions = g_ptr_array_new ();
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_SWAPCHAIN_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
if (has_incremental_present)
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
GDK_DISPLAY_DEBUG (display, VULKAN, "Using Vulkan device %u, queue %u", i, j);
if (GDK_VK_CHECK (vkCreateDevice, devices[i],
&(VkDeviceCreateInfo) {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
NULL,
0,
1,
&(VkDeviceQueueCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &(VkDeviceQueueCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = j,
.queueCount = 1,
.pQueuePriorities = (float []) { 1.0f },
},
0,
NULL,
device_extensions->len,
(const char * const *) device_extensions->pdata
.enabledExtensionCount = device_extensions->len,
.ppEnabledExtensionNames = (const char * const *) device_extensions->pdata,
.pNext = &(VkPhysicalDeviceDescriptorIndexingFeatures) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
.descriptorBindingPartiallyBound = VK_TRUE,
.descriptorBindingVariableDescriptorCount = VK_TRUE,
.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
}
},
NULL,
&display->vk_device) != VK_SUCCESS)
@ -1144,6 +1148,7 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
used_extensions = g_ptr_array_new ();
g_ptr_array_add (used_extensions, (gpointer) VK_KHR_SURFACE_EXTENSION_NAME);
g_ptr_array_add (used_extensions, (gpointer) VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
g_ptr_array_add (used_extensions, (gpointer) GDK_DISPLAY_GET_CLASS (display)->vk_extension_name);
for (i = 0; i < n_extensions; i++)
@ -1215,7 +1220,7 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
.enabledLayerCount = used_layers->len,
.ppEnabledLayerNames = (const char * const *) used_layers->pdata,
.enabledExtensionCount = used_extensions->len,
.ppEnabledExtensionNames = (const char * const *) used_extensions->pdata
.ppEnabledExtensionNames = (const char * const *) used_extensions->pdata,
},
NULL,
&display->vk_instance);

View File

@ -372,6 +372,8 @@ gsk_renderer_render_texture (GskRenderer *renderer,
gsk_render_node_get_bounds (root, &real_viewport);
viewport = &real_viewport;
}
g_return_val_if_fail (viewport->size.width > 0, NULL);
g_return_val_if_fail (viewport->size.height > 0, NULL);
texture = GSK_RENDERER_GET_CLASS (renderer)->render_texture (renderer, root, viewport);

View File

@ -689,6 +689,134 @@ gsk_rounded_rect_intersect_with_rect (const GskRoundedRect *self,
return GSK_INTERSECTION_NONEMPTY;
}
static gboolean
check_nonintersecting_corner (const GskRoundedRect *out,
const GskRoundedRect *in,
GskCorner corner,
float diff_x,
float diff_y,
GskRoundedRect *result)
{
g_assert (diff_x >= 0);
g_assert (diff_y >= 0);
if (out->corner[corner].width < diff_x ||
out->corner[corner].height < diff_y ||
(out->corner[corner].width <= in->corner[corner].width + diff_x &&
out->corner[corner].height <= in->corner[corner].height + diff_y))
{
result->corner[corner] = in->corner[corner];
return TRUE;
}
if (diff_x > 0 || diff_y > 0)
return FALSE;
if (out->corner[corner].width > in->corner[corner].width &&
out->corner[corner].height > in->corner[corner].height)
{
result->corner[corner] = out->corner[corner];
return TRUE;
}
return FALSE;
}
/* a is outside in x direction, b is outside in y direction */
static gboolean
check_intersecting_corner (const GskRoundedRect *a,
const GskRoundedRect *b,
GskCorner corner,
float diff_x,
float diff_y,
GskRoundedRect *result)
{
g_assert (diff_x > 0);
g_assert (diff_y > 0);
if (diff_x < a->corner[corner].width ||
diff_x > a->bounds.size.width - a->corner[corner].width - a->corner[OPPOSITE_CORNER_X (corner)].width ||
diff_y < b->corner[corner].height ||
diff_y > b->bounds.size.height - b->corner[corner].height - b->corner[OPPOSITE_CORNER_Y (corner)].height)
return FALSE;
result->corner[corner] = GRAPHENE_SIZE_INIT (0, 0);
return TRUE;
}
static gboolean
check_corner (const GskRoundedRect *a,
const GskRoundedRect *b,
GskCorner corner,
float diff_x,
float diff_y,
GskRoundedRect *result)
{
if (diff_x >= 0)
{
if (diff_y >= 0)
{
return check_nonintersecting_corner (a, b, corner, diff_x, diff_y, result);
}
else if (diff_x == 0)
{
return check_nonintersecting_corner (b, a, corner, 0, - diff_y, result);
}
else
{
return check_intersecting_corner (a, b, corner, diff_x, - diff_y, result);
}
}
else
{
if (diff_y <= 0)
{
return check_nonintersecting_corner (b, a, corner, - diff_x, - diff_y, result);
}
else
{
return check_intersecting_corner (b, a, corner, - diff_x, diff_y, result);
}
}
}
GskRoundedRectIntersection
gsk_rounded_rect_intersection (const GskRoundedRect *a,
const GskRoundedRect *b,
GskRoundedRect *result)
{
float top, left, bottom, right;
if (!graphene_rect_intersection (&a->bounds, &b->bounds, &result->bounds))
return GSK_INTERSECTION_EMPTY;
left = b->bounds.origin.x - a->bounds.origin.x;
top = b->bounds.origin.y - a->bounds.origin.y;
right = a->bounds.origin.x + a->bounds.size.width - b->bounds.origin.x - b->bounds.size.width;
bottom = a->bounds.origin.y + a->bounds.size.height - b->bounds.origin.y - b->bounds.size.height;
if (check_corner (a, b,
GSK_CORNER_TOP_LEFT,
left, top,
result) &&
check_corner (a, b,
GSK_CORNER_TOP_RIGHT,
right, top,
result) &&
check_corner (a, b,
GSK_CORNER_BOTTOM_LEFT,
left, bottom,
result) &&
check_corner (a, b,
GSK_CORNER_BOTTOM_RIGHT,
right, bottom,
result))
return GSK_INTERSECTION_NONEMPTY;
return GSK_INTERSECTION_NOT_REPRESENTABLE;
}
static void
append_arc (cairo_t *cr, double angle1, double angle2, gboolean negative)
{
@ -766,13 +894,14 @@ gsk_rounded_rect_path (const GskRoundedRect *self,
* only look at the last vec4 if they have to.
*/
void
gsk_rounded_rect_to_float (const GskRoundedRect *self,
float rect[12])
gsk_rounded_rect_to_float (const GskRoundedRect *self,
const graphene_point_t *offset,
float rect[12])
{
guint i;
rect[0] = self->bounds.origin.x;
rect[1] = self->bounds.origin.y;
rect[0] = self->bounds.origin.x + offset->x;
rect[1] = self->bounds.origin.y + offset->y;
rect[2] = self->bounds.size.width;
rect[3] = self->bounds.size.height;

View File

@ -6,6 +6,24 @@
G_BEGIN_DECLS
#define OPPOSITE_CORNER(corner) ((corner) ^ 2)
G_STATIC_ASSERT (OPPOSITE_CORNER (GSK_CORNER_TOP_LEFT) == GSK_CORNER_BOTTOM_RIGHT);
G_STATIC_ASSERT (OPPOSITE_CORNER (GSK_CORNER_TOP_RIGHT) == GSK_CORNER_BOTTOM_LEFT);
G_STATIC_ASSERT (OPPOSITE_CORNER (GSK_CORNER_BOTTOM_LEFT) == GSK_CORNER_TOP_RIGHT);
G_STATIC_ASSERT (OPPOSITE_CORNER (GSK_CORNER_BOTTOM_RIGHT) == GSK_CORNER_TOP_LEFT);
#define OPPOSITE_CORNER_X(corner) ((corner) ^ 1)
G_STATIC_ASSERT (OPPOSITE_CORNER_X (GSK_CORNER_TOP_LEFT) == GSK_CORNER_TOP_RIGHT);
G_STATIC_ASSERT (OPPOSITE_CORNER_X (GSK_CORNER_TOP_RIGHT) == GSK_CORNER_TOP_LEFT);
G_STATIC_ASSERT (OPPOSITE_CORNER_X (GSK_CORNER_BOTTOM_LEFT) == GSK_CORNER_BOTTOM_RIGHT);
G_STATIC_ASSERT (OPPOSITE_CORNER_X (GSK_CORNER_BOTTOM_RIGHT) == GSK_CORNER_BOTTOM_LEFT);
#define OPPOSITE_CORNER_Y(corner) ((corner) ^ 3)
G_STATIC_ASSERT (OPPOSITE_CORNER_Y (GSK_CORNER_TOP_LEFT) == GSK_CORNER_BOTTOM_LEFT);
G_STATIC_ASSERT (OPPOSITE_CORNER_Y (GSK_CORNER_TOP_RIGHT) == GSK_CORNER_BOTTOM_RIGHT);
G_STATIC_ASSERT (OPPOSITE_CORNER_Y (GSK_CORNER_BOTTOM_LEFT) == GSK_CORNER_TOP_LEFT);
G_STATIC_ASSERT (OPPOSITE_CORNER_Y (GSK_CORNER_BOTTOM_RIGHT) == GSK_CORNER_TOP_RIGHT);
#define GSK_ROUNDED_RECT_INIT_FROM_RECT(_r) \
(GskRoundedRect) { .bounds = _r, \
.corner = { \
@ -28,6 +46,7 @@ gboolean gsk_rounded_rect_is_circular (const GskRounde
void gsk_rounded_rect_path (const GskRoundedRect *self,
cairo_t *cr);
void gsk_rounded_rect_to_float (const GskRoundedRect *self,
const graphene_point_t *offset,
float rect[12]);
gboolean gsk_rounded_rect_equal (gconstpointer rect1,
@ -43,6 +62,9 @@ typedef enum {
GskRoundedRectIntersection gsk_rounded_rect_intersect_with_rect (const GskRoundedRect *self,
const graphene_rect_t *rect,
GskRoundedRect *result) G_GNUC_PURE;
GskRoundedRectIntersection gsk_rounded_rect_intersection (const GskRoundedRect *a,
const GskRoundedRect *b,
GskRoundedRect *result);
G_END_DECLS

View File

@ -12,8 +12,12 @@ typedef struct _GskVulkanBlendModeInstance GskVulkanBlendModeInstance;
struct _GskVulkanBlendModeInstance
{
float rect[4];
float start_tex_rect[4];
float end_tex_rect[4];
float top_rect[4];
float bottom_rect[4];
float top_tex_rect[4];
float bottom_tex_rect[4];
guint32 top_tex_id[2];
guint32 bottom_tex_id[2];
guint32 blend_mode;
};
@ -40,18 +44,42 @@ gsk_vulkan_blend_mode_pipeline_get_input_state_create_info (GskVulkanPipeline *s
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, start_tex_rect),
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, top_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, end_tex_rect),
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, bottom_rect),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, top_tex_rect),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, bottom_tex_rect),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, top_tex_id),
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, bottom_tex_id),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, blend_mode),
}
};
@ -98,37 +126,50 @@ gsk_vulkan_blend_mode_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLEND_MODE_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline)
{
return sizeof (GskVulkanBlendModeInstance);
}
void
gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
guchar *data,
const graphene_rect_t *bounds,
const graphene_rect_t *start_tex_rect,
const graphene_rect_t *end_tex_rect,
GskBlendMode blend_mode)
guchar *data,
guint32 top_tex_id[2],
guint32 bottom_tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *bounds,
const graphene_rect_t *top_bounds,
const graphene_rect_t *bottom_bounds,
const graphene_rect_t *top_tex_rect,
const graphene_rect_t *bottom_tex_rect,
GskBlendMode blend_mode)
{
GskVulkanBlendModeInstance *instance = (GskVulkanBlendModeInstance *) data;
instance->rect[0] = bounds->origin.x;
instance->rect[1] = bounds->origin.y;
instance->rect[0] = bounds->origin.x + offset->x;
instance->rect[1] = bounds->origin.y + offset->y;
instance->rect[2] = bounds->size.width;
instance->rect[3] = bounds->size.height;
instance->start_tex_rect[0] = start_tex_rect->origin.x;
instance->start_tex_rect[1] = start_tex_rect->origin.y;
instance->start_tex_rect[2] = start_tex_rect->size.width;
instance->start_tex_rect[3] = start_tex_rect->size.height;
instance->top_rect[0] = top_bounds->origin.x + offset->x;
instance->top_rect[1] = top_bounds->origin.y + offset->y;
instance->top_rect[2] = top_bounds->size.width;
instance->top_rect[3] = top_bounds->size.height;
instance->end_tex_rect[0] = end_tex_rect->origin.x;
instance->end_tex_rect[1] = end_tex_rect->origin.y;
instance->end_tex_rect[2] = end_tex_rect->size.width;
instance->end_tex_rect[3] = end_tex_rect->size.height;
instance->bottom_rect[0] = bottom_bounds->origin.x + offset->x;
instance->bottom_rect[1] = bottom_bounds->origin.y + offset->y;
instance->bottom_rect[2] = bottom_bounds->size.width;
instance->bottom_rect[3] = bottom_bounds->size.height;
instance->top_tex_rect[0] = top_tex_rect->origin.x;
instance->top_tex_rect[1] = top_tex_rect->origin.y;
instance->top_tex_rect[2] = top_tex_rect->size.width;
instance->top_tex_rect[3] = top_tex_rect->size.height;
instance->bottom_tex_rect[0] = bottom_tex_rect->origin.x;
instance->bottom_tex_rect[1] = bottom_tex_rect->origin.y;
instance->bottom_tex_rect[2] = bottom_tex_rect->size.width;
instance->bottom_tex_rect[3] = bottom_tex_rect->size.height;
instance->top_tex_id[0] = top_tex_id[0];
instance->top_tex_id[1] = top_tex_id[1];
instance->bottom_tex_id[0] = bottom_tex_id[0];
instance->bottom_tex_id[1] = bottom_tex_id[1];
instance->blend_mode = blend_mode;
}

View File

@ -18,12 +18,16 @@ GskVulkanPipeline * gsk_vulkan_blend_mode_pipeline_new (GdkVulka
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_blend_mode_pipeline_count_vertex_data (GskVulkanBlendModePipeline *pipeline);
void gsk_vulkan_blend_mode_pipeline_collect_vertex_data (GskVulkanBlendModePipeline *pipeline,
guchar *data,
guint32 top_tex_id[2],
guint32 bottom_tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *bounds,
const graphene_rect_t *start_bounds,
const graphene_rect_t *end_bounds,
const graphene_rect_t *top_bounds,
const graphene_rect_t *bottom_bounds,
const graphene_rect_t *top_tex_rect,
const graphene_rect_t *bottom_tex_rect,
GskBlendMode blend_mode);
gsize gsk_vulkan_blend_mode_pipeline_draw (GskVulkanBlendModePipeline *pipeline,
VkCommandBuffer command_buffer,

View File

@ -14,6 +14,7 @@ struct _GskVulkanBlurInstance
float rect[4];
float tex_rect[4];
float blur_radius;
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK_TYPE_VULKAN_PIPELINE)
@ -46,6 +47,12 @@ gsk_vulkan_blur_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, blur_radius),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
@ -91,23 +98,19 @@ gsk_vulkan_blur_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BLUR_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline)
{
return sizeof (GskVulkanBlurInstance);
}
void
gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
guchar *data,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect,
double blur_radius)
gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
guchar *data,
guint32 tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect,
double blur_radius)
{
GskVulkanBlurInstance *instance = (GskVulkanBlurInstance *) data;
instance->rect[0] = rect->origin.x;
instance->rect[1] = rect->origin.y;
instance->rect[0] = rect->origin.x + offset->x;
instance->rect[1] = rect->origin.y + offset->y;
instance->rect[2] = rect->size.width;
instance->rect[3] = rect->size.height;
instance->tex_rect[0] = tex_rect->origin.x;
@ -115,6 +118,8 @@ gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
instance->tex_rect[2] = tex_rect->size.width;
instance->tex_rect[3] = tex_rect->size.height;
instance->blur_radius = blur_radius;
instance->tex_id[0] = tex_id[0];
instance->tex_id[1] = tex_id[1];
}
gsize

View File

@ -17,9 +17,10 @@ GskVulkanPipeline * gsk_vulkan_blur_pipeline_new (GdkVulka
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_blur_pipeline_count_vertex_data (GskVulkanBlurPipeline *pipeline);
void gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
guchar *data,
guint32 tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect,
double radius);

View File

@ -123,15 +123,10 @@ gsk_vulkan_border_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BORDER_PIPELINE, context, 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 graphene_point_t *offset,
const GskRoundedRect *rect,
const float widths[4],
const GdkRGBA colors[4])
@ -139,7 +134,7 @@ gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipelin
GskVulkanBorderInstance *instance = (GskVulkanBorderInstance *) data;
guint i;
gsk_rounded_rect_to_float (rect, instance->rect);
gsk_rounded_rect_to_float (rect, offset, instance->rect);
for (i = 0; i < 4; i++)
{
instance->widths[i] = widths[i];

View File

@ -18,9 +18,9 @@ GskVulkanPipeline * gsk_vulkan_border_pipeline_new (GdkVulk
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 graphene_point_t *offset,
const GskRoundedRect *rect,
const float widths[4],
const GdkRGBA colors[4]);

View File

@ -119,15 +119,10 @@ gsk_vulkan_box_shadow_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_BOX_SHADOW_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline)
{
return sizeof (GskVulkanBoxShadowInstance);
}
void
gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
guchar *data,
const graphene_point_t *offset,
const GskRoundedRect *outline,
const GdkRGBA *color,
float dx,
@ -137,7 +132,7 @@ gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *
{
GskVulkanBoxShadowInstance *instance = (GskVulkanBoxShadowInstance *) data;
gsk_rounded_rect_to_float (outline, instance->outline);
gsk_rounded_rect_to_float (outline, offset, instance->outline);
instance->color[0] = color->red;
instance->color[1] = color->green;
instance->color[2] = color->blue;

View File

@ -18,9 +18,9 @@ GskVulkanPipeline * gsk_vulkan_box_shadow_pipeline_new (GdkVulk
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_box_shadow_pipeline_count_vertex_data (GskVulkanBoxShadowPipeline *pipeline);
void gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *pipeline,
guchar *data,
const graphene_point_t *offset,
const GskRoundedRect *outline,
const GdkRGBA *color,
float dx,

View File

@ -13,7 +13,15 @@ gsk_vulkan_clip_init_empty (GskVulkanClip *clip,
gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
}
static void
void
gsk_vulkan_clip_init_rect (GskVulkanClip *clip,
const graphene_rect_t *rect)
{
clip->type = GSK_VULKAN_CLIP_RECT;
gsk_rounded_rect_init_from_rect (&clip->rect, rect, 0);
}
void
gsk_vulkan_clip_init_copy (GskVulkanClip *self,
const GskVulkanClip *src)
{
@ -21,11 +29,30 @@ gsk_vulkan_clip_init_copy (GskVulkanClip *self,
gsk_rounded_rect_init_copy (&self->rect, &src->rect);
}
static gboolean
gsk_vulkan_clip_init_after_intersection (GskVulkanClip *self,
GskRoundedRectIntersection res)
{
if (res == GSK_INTERSECTION_NOT_REPRESENTABLE)
return FALSE;
if (res == GSK_INTERSECTION_EMPTY)
self->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
else if (gsk_rounded_rect_is_rectilinear (&self->rect))
self->type = GSK_VULKAN_CLIP_RECT;
else
self->type = GSK_VULKAN_CLIP_ROUNDED;
return TRUE;
}
gboolean
gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
const GskVulkanClip *src,
const graphene_rect_t *rect)
{
GskRoundedRectIntersection res;
if (graphene_rect_contains_rect (rect, &src->rect.bounds))
{
gsk_vulkan_clip_init_copy (dest, src);
@ -57,22 +84,10 @@ gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
dest->type = GSK_VULKAN_CLIP_ALL_CLIPPED;
break;
case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
case GSK_VULKAN_CLIP_ROUNDED:
if (gsk_rounded_rect_contains_rect (&src->rect, rect))
{
dest->type = GSK_VULKAN_CLIP_RECT;
gsk_rounded_rect_init_from_rect (&dest->rect, rect, 0);
}
else
{
/* some points of rect are inside src's rounded rect,
* some are outside. */
/* XXX: If the 2 rects don't intersect on rounded corners,
* we could actually compute a new clip here.
*/
return FALSE;
}
res = gsk_rounded_rect_intersect_with_rect (&src->rect, rect, &dest->rect);
if (!gsk_vulkan_clip_init_after_intersection (dest, res))
return FALSE;
break;
default:
@ -88,6 +103,8 @@ gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
const GskVulkanClip *src,
const GskRoundedRect *rounded)
{
GskRoundedRectIntersection res;
if (gsk_rounded_rect_contains_rect (rounded, &src->rect.bounds))
{
gsk_vulkan_clip_init_copy (dest, src);
@ -106,34 +123,21 @@ gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
break;
case GSK_VULKAN_CLIP_NONE:
dest->type = gsk_rounded_rect_is_circular (rounded) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
dest->type = GSK_VULKAN_CLIP_ROUNDED;
gsk_rounded_rect_init_copy (&dest->rect, rounded);
break;
case GSK_VULKAN_CLIP_RECT:
if (graphene_rect_contains_rect (&src->rect.bounds, &rounded->bounds))
{
dest->type = gsk_rounded_rect_is_circular (rounded) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
gsk_rounded_rect_init_copy (&dest->rect, rounded);
return TRUE;
}
/* some points of rect are inside src's rounded rect,
* some are outside. */
/* XXX: If the 2 rects don't intersect on rounded corners,
* we could actually compute a new clip here.
*/
return FALSE;
res = gsk_rounded_rect_intersect_with_rect (rounded, &src->rect.bounds, &dest->rect);
if (!gsk_vulkan_clip_init_after_intersection (dest, res))
return FALSE;
break;
case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
case GSK_VULKAN_CLIP_ROUNDED:
if (gsk_rounded_rect_contains_rect (&src->rect, &rounded->bounds))
{
dest->type = gsk_rounded_rect_is_circular (rounded) ? GSK_VULKAN_CLIP_ROUNDED_CIRCULAR : GSK_VULKAN_CLIP_ROUNDED;
gsk_rounded_rect_init_copy (&dest->rect, rounded);
return TRUE;
}
/* XXX: Can be improved for the case where one of the rects is a slightly shrunk version of the other */
return FALSE;
res = gsk_rounded_rect_intersection (&src->rect, rounded, &dest->rect);
if (!gsk_vulkan_clip_init_after_intersection (dest, res))
return FALSE;
break;
default:
g_assert_not_reached ();
@ -143,6 +147,19 @@ gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
return TRUE;
}
void
gsk_vulkan_clip_scale (GskVulkanClip *dest,
const GskVulkanClip *src,
float scale_x,
float scale_y)
{
dest->type = src->type;
gsk_rounded_rect_scale_affine (&dest->rect,
&src->rect,
1.0f / scale_x, 1.0f / scale_y,
0, 0);
}
gboolean
gsk_vulkan_clip_transform (GskVulkanClip *dest,
const GskVulkanClip *src,
@ -164,7 +181,6 @@ gsk_vulkan_clip_transform (GskVulkanClip *dest,
return TRUE;
case GSK_VULKAN_CLIP_RECT:
case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
case GSK_VULKAN_CLIP_ROUNDED:
switch (gsk_transform_get_category (transform))
{
@ -220,9 +236,14 @@ gsk_vulkan_clip_transform (GskVulkanClip *dest,
}
gboolean
gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
const graphene_rect_t *rect)
gsk_vulkan_clip_intersects_rect (const GskVulkanClip *self,
const graphene_point_t *offset,
const graphene_rect_t *rect)
{
graphene_rect_t r = *rect;
r.origin.x += offset->x;
r.origin.y += offset->y;
switch (self->type)
{
default:
@ -234,10 +255,36 @@ gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
return TRUE;
case GSK_VULKAN_CLIP_RECT:
return graphene_rect_contains_rect (&self->rect.bounds, rect);
return graphene_rect_intersection (&self->rect.bounds, &r, NULL);
case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
case GSK_VULKAN_CLIP_ROUNDED:
return gsk_rounded_rect_contains_rect (&self->rect, rect);
return gsk_rounded_rect_intersects_rect (&self->rect, &r);
}
}
gboolean
gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
const graphene_point_t *offset,
const graphene_rect_t *rect)
{
graphene_rect_t r = *rect;
r.origin.x += offset->x;
r.origin.y += offset->y;
switch (self->type)
{
default:
g_assert_not_reached();
case GSK_VULKAN_CLIP_ALL_CLIPPED:
return FALSE;
case GSK_VULKAN_CLIP_NONE:
return TRUE;
case GSK_VULKAN_CLIP_RECT:
return graphene_rect_contains_rect (&self->rect.bounds, &r);
case GSK_VULKAN_CLIP_ROUNDED:
return gsk_rounded_rect_contains_rect (&self->rect, &r);
}
}

View File

@ -18,10 +18,6 @@ typedef enum {
GSK_VULKAN_CLIP_NONE,
/* The clip is a rectangular area */
GSK_VULKAN_CLIP_RECT,
/* The clip is a rounded rectangle, and for every corner
* corner.width == corner.height is true
*/
GSK_VULKAN_CLIP_ROUNDED_CIRCULAR,
/* The clip is a rounded rectangle */
GSK_VULKAN_CLIP_ROUNDED
} GskVulkanClipComplexity;
@ -36,6 +32,10 @@ struct _GskVulkanClip
void gsk_vulkan_clip_init_empty (GskVulkanClip *clip,
const graphene_rect_t *rect);
void gsk_vulkan_clip_init_copy (GskVulkanClip *self,
const GskVulkanClip *src);
void gsk_vulkan_clip_init_rect (GskVulkanClip *clip,
const graphene_rect_t *rect);
gboolean gsk_vulkan_clip_intersect_rect (GskVulkanClip *dest,
const GskVulkanClip *src,
@ -43,12 +43,20 @@ gboolean gsk_vulkan_clip_intersect_rect (GskVulk
gboolean gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
const GskVulkanClip *src,
const GskRoundedRect *rounded) G_GNUC_WARN_UNUSED_RESULT;
void gsk_vulkan_clip_scale (GskVulkanClip *dest,
const GskVulkanClip *src,
float scale_x,
float scale_y);
gboolean gsk_vulkan_clip_transform (GskVulkanClip *dest,
const GskVulkanClip *src,
GskTransform *transform,
const graphene_rect_t *viewport) G_GNUC_WARN_UNUSED_RESULT;
gboolean gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
const graphene_point_t *offset,
const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;
gboolean gsk_vulkan_clip_intersects_rect (const GskVulkanClip *self,
const graphene_point_t *offset,
const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;
G_END_DECLS

View File

@ -84,22 +84,17 @@ gsk_vulkan_color_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_COLOR_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline)
{
return sizeof (GskVulkanColorInstance);
}
void
gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
guchar *data,
const graphene_point_t *offset,
const graphene_rect_t *rect,
const GdkRGBA *color)
{
GskVulkanColorInstance *instance = (GskVulkanColorInstance *) data;
instance->rect[0] = rect->origin.x;
instance->rect[1] = rect->origin.y;
instance->rect[0] = rect->origin.x + offset->x;
instance->rect[1] = rect->origin.y + offset->y;
instance->rect[2] = rect->size.width;
instance->rect[3] = rect->size.height;
instance->color[0] = color->red;

View File

@ -17,9 +17,9 @@ GskVulkanPipeline * gsk_vulkan_color_pipeline_new (GdkVulk
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_color_pipeline_count_vertex_data (GskVulkanColorPipeline *pipeline);
void gsk_vulkan_color_pipeline_collect_vertex_data (GskVulkanColorPipeline *pipeline,
guchar *data,
const graphene_point_t *offset,
const graphene_rect_t *rect,
const GdkRGBA *color);
gsize gsk_vulkan_color_pipeline_draw (GskVulkanColorPipeline *pipeline,

View File

@ -13,6 +13,7 @@ struct _GskVulkanColorTextInstance
{
float rect[4];
float tex_rect[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
@ -40,6 +41,12 @@ gsk_vulkan_color_text_pipeline_get_input_state_create_info (GskVulkanPipeline *s
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
@ -84,18 +91,12 @@ gsk_vulkan_color_text_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_COLOR_TEXT_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
int num_instances)
{
return sizeof (GskVulkanColorTextInstance) * num_instances;
}
void
gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
guchar *data,
GskVulkanRenderer *renderer,
const graphene_rect_t *rect,
guint tex_id[2],
PangoFont *font,
guint total_glyphs,
const PangoGlyphInfo *glyphs,
@ -140,6 +141,9 @@ gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *
instance->tex_rect[2] = glyph->tw;
instance->tex_rect[3] = glyph->th;
instance->tex_id[0] = tex_id[0];
instance->tex_id[1] = tex_id[1];
count++;
}
x_position += gi->geometry.width;

View File

@ -18,12 +18,11 @@ GskVulkanPipeline * gsk_vulkan_color_text_pipeline_new (Gd
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_color_text_pipeline_count_vertex_data (GskVulkanColorTextPipeline *pipeline,
int num_instances);
void gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *pipeline,
guchar *data,
GskVulkanRenderer *renderer,
const graphene_rect_t *rect,
guint tex_id[2],
PangoFont *font,
guint total_glyphs,
const PangoGlyphInfo *glyphs,

View File

@ -12,8 +12,12 @@ typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance;
struct _GskVulkanCrossFadeInstance
{
float rect[4];
float start_rect[4];
float end_rect[4];
float start_tex_rect[4];
float end_tex_rect[4];
guint32 start_tex_id[2];
guint32 end_tex_id[2];
float progress;
};
@ -40,17 +44,41 @@ gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *s
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect),
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_rect),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_id),
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_id),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress),
}
@ -98,27 +126,36 @@ gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline)
{
return sizeof (GskVulkanCrossFadeInstance);
}
void
gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
guchar *data,
const graphene_rect_t *bounds,
const graphene_rect_t *start_tex_rect,
const graphene_rect_t *end_tex_rect,
double progress)
guchar *data,
guint32 start_tex_id[2],
guint32 end_tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *bounds,
const graphene_rect_t *start_bounds,
const graphene_rect_t *end_bounds,
const graphene_rect_t *start_tex_rect,
const graphene_rect_t *end_tex_rect,
double progress)
{
GskVulkanCrossFadeInstance *instance = (GskVulkanCrossFadeInstance *) data;
instance->rect[0] = bounds->origin.x;
instance->rect[1] = bounds->origin.y;
instance->rect[0] = bounds->origin.x + offset->x;
instance->rect[1] = bounds->origin.y + offset->y;
instance->rect[2] = bounds->size.width;
instance->rect[3] = bounds->size.height;
instance->start_rect[0] = start_bounds->origin.x + offset->x;
instance->start_rect[1] = start_bounds->origin.y + offset->y;
instance->start_rect[2] = start_bounds->size.width;
instance->start_rect[3] = start_bounds->size.height;
instance->end_rect[0] = end_bounds->origin.x + offset->x;
instance->end_rect[1] = end_bounds->origin.y + offset->y;
instance->end_rect[2] = end_bounds->size.width;
instance->end_rect[3] = end_bounds->size.height;
instance->start_tex_rect[0] = start_tex_rect->origin.x;
instance->start_tex_rect[1] = start_tex_rect->origin.y;
instance->start_tex_rect[2] = start_tex_rect->size.width;
@ -129,6 +166,10 @@ gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *
instance->end_tex_rect[2] = end_tex_rect->size.width;
instance->end_tex_rect[3] = end_tex_rect->size.height;
instance->start_tex_id[0] = start_tex_id[0];
instance->start_tex_id[1] = start_tex_id[1];
instance->end_tex_id[0] = end_tex_id[0];
instance->end_tex_id[1] = end_tex_id[1];
instance->progress = progress;
}

View File

@ -17,12 +17,16 @@ GskVulkanPipeline * gsk_vulkan_cross_fade_pipeline_new (GdkVulka
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline);
void gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
guchar *data,
guint32 start_tex_id[2],
guint32 end_tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *bounds,
const graphene_rect_t *start_bounds,
const graphene_rect_t *end_bounds,
const graphene_rect_t *start_tex_rect,
const graphene_rect_t *end_tex_rect,
double progress);
gsize gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
VkCommandBuffer command_buffer,

View File

@ -15,6 +15,7 @@ struct _GskVulkanEffectInstance
float tex_rect[4];
float color_matrix[16];
float color_offset[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE)
@ -71,6 +72,12 @@ gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_offset),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
@ -116,15 +123,11 @@ gsk_vulkan_effect_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_EFFECT_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline)
{
return sizeof (GskVulkanEffectInstance);
}
void
gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
guchar *data,
guint32 tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect,
const graphene_matrix_t *color_matrix,
@ -132,8 +135,8 @@ gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipelin
{
GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data;
instance->rect[0] = rect->origin.x;
instance->rect[1] = rect->origin.y;
instance->rect[0] = rect->origin.x + offset->x;
instance->rect[1] = rect->origin.y + offset->y;
instance->rect[2] = rect->size.width;
instance->rect[3] = rect->size.height;
instance->tex_rect[0] = tex_rect->origin.x;
@ -142,6 +145,8 @@ gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipelin
instance->tex_rect[3] = tex_rect->size.height;
graphene_matrix_to_float (color_matrix, instance->color_matrix);
graphene_vec4_to_float (color_offset, instance->color_offset);
instance->tex_id[0] = tex_id[0];
instance->tex_id[1] = tex_id[1];
}
gsize

View File

@ -17,9 +17,10 @@ GskVulkanPipeline * gsk_vulkan_effect_pipeline_new (GdkVulk
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_effect_pipeline_count_vertex_data (GskVulkanEffectPipeline *pipeline);
void gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipeline,
guchar *data,
guint32 tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect,
const graphene_matrix_t *color_matrix,

View File

@ -209,6 +209,8 @@ gsk_vulkan_image_new (GdkVulkanContext *context,
VkMemoryRequirements requirements;
GskVulkanImage *self;
g_assert (width > 0 && height > 0);
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
self->vulkan = g_object_ref (context);
@ -606,9 +608,9 @@ gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
}
GskVulkanImage *
gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
gsize width,
gsize height)
gsk_vulkan_image_new_for_offscreen (GdkVulkanContext *context,
gsize width,
gsize height)
{
GskVulkanImage *self;
@ -620,7 +622,7 @@ gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
0,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);

View File

@ -49,7 +49,7 @@ GskVulkanImage * gsk_vulkan_image_new_for_framebuffer (GdkVulk
GskVulkanImage * gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
gsize width,
gsize height);
GskVulkanImage * gsk_vulkan_image_new_for_texture (GdkVulkanContext *context,
GskVulkanImage * gsk_vulkan_image_new_for_offscreen (GdkVulkanContext *context,
gsize width,
gsize height);

View File

@ -167,15 +167,10 @@ gsk_vulkan_linear_gradient_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_LINEAR_GRADIENT_PIPELINE, context, 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_point_t *offset,
const graphene_rect_t *rect,
const graphene_point_t *start,
const graphene_point_t *end,
@ -191,14 +186,14 @@ gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradient
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[0] = rect->origin.x + offset->x;
instance->rect[1] = rect->origin.y + offset->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->start[0] = start->x + offset->x;
instance->start[1] = start->y + offset->y;
instance->end[0] = end->x + offset->x;
instance->end[1] = end->y + offset->y;
instance->repeating = repeating;
instance->stop_count = n_stops;
for (i = 0; i < n_stops; i++)

View File

@ -20,11 +20,10 @@ GskVulkanPipeline * gsk_vulkan_linear_gradient_pipeline_new (GdkVulk
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_point_t *offset,
const graphene_rect_t *rect,
const graphene_point_t *start,
const graphene_point_t *end,

View File

@ -16,10 +16,11 @@ struct _GskVulkanPipelinePrivate
GdkVulkanContext *context;
VkPipeline pipeline;
VkPipelineLayout layout;
GskVulkanShader *vertex_shader;
GskVulkanShader *fragment_shader;
gsize vertex_stride;
};
G_DEFINE_TYPE_WITH_PRIVATE (GskVulkanPipeline, gsk_vulkan_pipeline, G_TYPE_OBJECT)
@ -54,12 +55,13 @@ gsk_vulkan_pipeline_init (GskVulkanPipeline *self)
}
GskVulkanPipeline *
gsk_vulkan_pipeline_new (GType pipeline_type,
GdkVulkanContext *context,
VkPipelineLayout layout,
const char *shader_name,
VkRenderPass render_pass)
gsk_vulkan_pipeline_new (GType pipeline_type,
GdkVulkanContext *context,
VkPipelineLayout layout,
const char *shader_name,
VkRenderPass render_pass)
{
const VkPipelineVertexInputStateCreateInfo *vertex_input_state;
GskVulkanPipelinePrivate *priv;
GskVulkanPipeline *self;
VkDevice device;
@ -76,11 +78,14 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
device = gdk_vulkan_context_get_device (context);
priv->context = context;
priv->layout = layout;
priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, NULL);
priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, shader_name, NULL);
vertex_input_state = GSK_VULKAN_PIPELINE_GET_CLASS (self)->get_input_state_create_info (self);
g_assert (vertex_input_state->vertexBindingDescriptionCount == 1);
priv->vertex_stride = vertex_input_state->pVertexBindingDescriptions[0].stride;
GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
VK_NULL_HANDLE,
1,
@ -91,7 +96,7 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->vertex_shader),
GST_VULKAN_SHADER_STAGE_CREATE_INFO (priv->fragment_shader)
},
.pVertexInputState = GSK_VULKAN_PIPELINE_GET_CLASS (self)->get_input_state_create_info (self),
.pVertexInputState = vertex_input_state,
.pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
@ -108,7 +113,7 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_BACK_BIT,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
.lineWidth = 1.0f,
},
@ -146,7 +151,7 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
VK_DYNAMIC_STATE_SCISSOR
},
},
.layout = priv->layout,
.layout = layout,
.renderPass = render_pass,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
@ -166,10 +171,10 @@ gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self)
return priv->pipeline;
}
VkPipelineLayout
gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self)
gsize
gsk_vulkan_pipeline_get_vertex_stride (GskVulkanPipeline *self)
{
GskVulkanPipelinePrivate *priv = gsk_vulkan_pipeline_get_instance_private (self);
return priv->layout;
return priv->vertex_stride;
}

View File

@ -37,7 +37,7 @@ GskVulkanPipeline * gsk_vulkan_pipeline_new (GType
const char *shader_name,
VkRenderPass render_pass);
VkPipeline gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self);
VkPipelineLayout gsk_vulkan_pipeline_get_pipeline_layout (GskVulkanPipeline *self);
gsize gsk_vulkan_pipeline_get_vertex_stride (GskVulkanPipeline *self);
G_END_DECLS

View File

@ -12,83 +12,37 @@ struct _GskVulkanPushConstantsWire
struct {
float mvp[16];
float clip[12];
float scale[2];
} common;
};
void
gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
const graphene_matrix_t *mvp,
const graphene_rect_t *viewport)
{
graphene_matrix_init_from_matrix (&constants->mvp, mvp);
gsk_vulkan_clip_init_empty (&constants->clip, viewport);
}
void
gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src)
{
*self = *src;
}
gboolean
gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
GskTransform *transform,
const graphene_rect_t *viewport)
{
graphene_matrix_t matrix;
if (!gsk_vulkan_clip_transform (&self->clip, &src->clip, transform, viewport))
return FALSE;
gsk_transform_to_matrix (transform, &matrix);
graphene_matrix_multiply (&matrix, &src->mvp, &self->mvp);
return TRUE;
}
gboolean
gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
const graphene_rect_t *rect)
{
if (!gsk_vulkan_clip_intersect_rect (&self->clip, &src->clip, rect))
return FALSE;
graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
return TRUE;
}
gboolean
gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
const GskRoundedRect *rect)
{
if (!gsk_vulkan_clip_intersect_rounded_rect (&self->clip, &src->clip, rect))
return FALSE;
graphene_matrix_init_from_matrix (&self->mvp, &src->mvp);
return TRUE;
}
/* This is the value we know every conformant GPU must provide.
* See value for maxPushConstantsSize in table 55 of
* https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#limits-minmax
*/
G_STATIC_ASSERT (sizeof (GskVulkanPushConstantsWire) <= 128);
static void
gsk_vulkan_push_constants_wire_init (GskVulkanPushConstantsWire *wire,
const GskVulkanPushConstants *self)
gsk_vulkan_push_constants_wire_init (GskVulkanPushConstantsWire *wire,
const graphene_vec2_t *scale,
const graphene_matrix_t *mvp,
const GskRoundedRect *clip)
{
graphene_matrix_to_float (&self->mvp, wire->common.mvp);
gsk_rounded_rect_to_float (&self->clip.rect, wire->common.clip);
graphene_matrix_to_float (mvp, wire->common.mvp);
gsk_rounded_rect_to_float (clip, graphene_point_zero (), wire->common.clip);
graphene_vec2_to_float (scale, wire->common.scale);
}
void
gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
VkCommandBuffer command_buffer,
VkPipelineLayout pipeline_layout)
gsk_vulkan_push_constants_push (VkCommandBuffer command_buffer,
VkPipelineLayout pipeline_layout,
const graphene_vec2_t *scale,
const graphene_matrix_t *mvp,
const GskRoundedRect *clip)
{
GskVulkanPushConstantsWire wire;
gsk_vulkan_push_constants_wire_init (&wire, self);
gsk_vulkan_push_constants_wire_init (&wire, scale, mvp, clip);
vkCmdPushConstants (command_buffer,
pipeline_layout,

View File

@ -6,38 +6,15 @@
G_BEGIN_DECLS
typedef struct _GskVulkanPushConstants GskVulkanPushConstants;
struct _GskVulkanPushConstants
{
graphene_matrix_t mvp;
GskVulkanClip clip;
};
const VkPushConstantRange *
gsk_vulkan_push_constants_get_ranges (void) G_GNUC_PURE;
uint32_t gsk_vulkan_push_constants_get_range_count (void) G_GNUC_PURE;
void gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
void gsk_vulkan_push_constants_push (VkCommandBuffer command_buffer,
VkPipelineLayout pipeline_layout,
const graphene_vec2_t *scale,
const graphene_matrix_t *mvp,
const graphene_rect_t *viewport);
void gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src);
gboolean gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
GskTransform *transform,
const graphene_rect_t *viewport);
gboolean gsk_vulkan_push_constants_intersect_rect (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
const graphene_rect_t *rect);
gboolean gsk_vulkan_push_constants_intersect_rounded (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
const GskRoundedRect *rect);
void gsk_vulkan_push_constants_push (const GskVulkanPushConstants *self,
VkCommandBuffer command_buffer,
VkPipelineLayout pipeline_layout);
const GskRoundedRect *clip);
G_END_DECLS

View File

@ -23,8 +23,15 @@
#include "gskvulkantexturepipelineprivate.h"
#include "gskvulkanpushconstantsprivate.h"
#define DESCRIPTOR_POOL_MAXSETS 128
#define DESCRIPTOR_POOL_MAXSETS_INCREASE 128
#define DESCRIPTOR_POOL_MAXITEMS 50000
#define GDK_ARRAY_NAME gsk_descriptor_image_infos
#define GDK_ARRAY_TYPE_NAME GskDescriptorImageInfos
#define GDK_ARRAY_ELEMENT_TYPE VkDescriptorImageInfo
#define GDK_ARRAY_BY_VALUE 1
#define GDK_ARRAY_PREALLOC 1024
#define GDK_ARRAY_NO_MEMSET 1
#include "gdk/gdkarrayimpl.c"
struct _GskVulkanRender
{
@ -40,20 +47,18 @@ struct _GskVulkanRender
VkFence fence;
VkRenderPass render_pass;
VkDescriptorSetLayout descriptor_set_layout;
VkPipelineLayout pipeline_layout[3]; /* indexed by number of textures */
VkPipelineLayout pipeline_layout;
GskVulkanUploader *uploader;
GHashTable *descriptor_set_indexes;
GskDescriptorImageInfos descriptor_images;
GskDescriptorImageInfos descriptor_samplers;
VkDescriptorPool descriptor_pool;
uint32_t descriptor_pool_maxsets;
VkDescriptorSet *descriptor_sets;
gsize n_descriptor_sets;
VkDescriptorSet descriptor_set;
GskVulkanPipeline *pipelines[GSK_VULKAN_N_PIPELINES];
GskVulkanImage *target;
VkSampler sampler;
VkSampler repeating_sampler;
VkSampler samplers[3];
GList *render_passes;
GSList *cleanup_images;
@ -103,9 +108,6 @@ gsk_vulkan_render_setup (GskVulkanRender *self,
}
}
static guint desc_set_index_hash (gconstpointer v);
static gboolean desc_set_index_equal (gconstpointer v1, gconstpointer v2);
GskVulkanRender *
gsk_vulkan_render_new (GskRenderer *renderer,
GdkVulkanContext *context)
@ -118,7 +120,8 @@ gsk_vulkan_render_new (GskRenderer *renderer,
self->vulkan = context;
self->renderer = renderer;
self->framebuffers = g_hash_table_new (g_direct_hash, g_direct_equal);
self->descriptor_set_indexes = g_hash_table_new_full (desc_set_index_hash, desc_set_index_equal, NULL, g_free);
gsk_descriptor_image_infos_init (&self->descriptor_images);
gsk_descriptor_image_infos_init (&self->descriptor_samplers);
device = gdk_vulkan_context_get_device (self->vulkan);
@ -131,16 +134,20 @@ gsk_vulkan_render_new (GskRenderer *renderer,
NULL,
&self->fence);
self->descriptor_pool_maxsets = DESCRIPTOR_POOL_MAXSETS;
GSK_VK_CHECK (vkCreateDescriptorPool, device,
&(VkDescriptorPoolCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = self->descriptor_pool_maxsets,
.poolSizeCount = 1,
.pPoolSizes = (VkDescriptorPoolSize[1]) {
.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT,
.maxSets = 1,
.poolSizeCount = 2,
.pPoolSizes = (VkDescriptorPoolSize[2]) {
{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = self->descriptor_pool_maxsets
.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = DESCRIPTOR_POOL_MAXITEMS
},
{
.type = VK_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = DESCRIPTOR_POOL_MAXITEMS
}
}
},
@ -190,53 +197,65 @@ gsk_vulkan_render_new (GskRenderer *renderer,
GSK_VK_CHECK (vkCreateDescriptorSetLayout, device,
&(VkDescriptorSetLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1,
.pBindings = (VkDescriptorSetLayoutBinding[1]) {
.bindingCount = 2,
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.pBindings = (VkDescriptorSetLayoutBinding[2]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = DESCRIPTOR_POOL_MAXITEMS,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.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]) {
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,
},
}
},
NULL,
&self->descriptor_set_layout);
for (guint i = 0; i < 3; i++)
{
VkDescriptorSetLayout layouts[3] = {
self->descriptor_set_layout,
self->descriptor_set_layout,
self->descriptor_set_layout
};
GSK_VK_CHECK (vkCreatePipelineLayout, device,
&(VkPipelineLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = i,
.pSetLayouts = layouts,
.pushConstantRangeCount = gsk_vulkan_push_constants_get_range_count (),
.pPushConstantRanges = gsk_vulkan_push_constants_get_ranges ()
GSK_VK_CHECK (vkCreatePipelineLayout, device,
&(VkPipelineLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = (VkDescriptorSetLayout[1]) {
self->descriptor_set_layout
},
NULL,
&self->pipeline_layout[i]);
}
.pushConstantRangeCount = gsk_vulkan_push_constants_get_range_count (),
.pPushConstantRanges = gsk_vulkan_push_constants_get_ranges ()
},
NULL,
&self->pipeline_layout);
GSK_VK_CHECK (vkCreateSampler, device,
&(VkSamplerCreateInfo) {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
.unnormalizedCoordinates = VK_FALSE,
.maxAnisotropy = 1.0,
},
NULL,
&self->sampler);
&self->samplers[GSK_VULKAN_SAMPLER_DEFAULT]);
GSK_VK_CHECK (vkCreateSampler, device,
&(VkSamplerCreateInfo) {
@ -251,7 +270,23 @@ gsk_vulkan_render_new (GskRenderer *renderer,
.maxAnisotropy = 1.0,
},
NULL,
&self->repeating_sampler);
&self->samplers[GSK_VULKAN_SAMPLER_REPEAT]);
GSK_VK_CHECK (vkCreateSampler, device,
&(VkSamplerCreateInfo) {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_NEAREST,
.minFilter = VK_FILTER_NEAREST,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
.unnormalizedCoordinates = VK_FALSE,
.maxAnisotropy = 1.0,
},
NULL,
&self->samplers[GSK_VULKAN_SAMPLER_NEAREST]);
self->uploader = gsk_vulkan_uploader_new (self->vulkan, self->command_pool);
@ -315,6 +350,12 @@ gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
return fb->framebuffer;
}
VkFence
gsk_vulkan_render_get_fence (GskVulkanRender *self)
{
return self->fence;
}
void
gsk_vulkan_render_add_cleanup_image (GskVulkanRender *self,
GskVulkanImage *image)
@ -338,15 +379,13 @@ gsk_vulkan_render_add_node (GskVulkanRender *self,
GskRenderNode *node)
{
GskVulkanRenderPass *pass;
graphene_matrix_t mv;
graphene_vec2_t scale;
graphene_matrix_init_scale (&mv, self->scale, self->scale, 1.0);
graphene_vec2_init (&scale, self->scale, self->scale);
pass = gsk_vulkan_render_pass_new (self->vulkan,
self->target,
self->scale,
self->scale,
&mv,
&scale,
&self->viewport,
self->clip,
VK_NULL_HANDLE);
@ -425,7 +464,7 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
if (self->pipelines[type] == NULL)
self->pipelines[type] = pipeline_info[type].create_func (self->vulkan,
self->pipeline_layout[pipeline_info[type].num_textures],
self->pipeline_layout,
pipeline_info[type].name,
self->render_pass);
@ -433,71 +472,59 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
}
VkDescriptorSet
gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
gsize id)
gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self)
{
g_assert (id < self->n_descriptor_sets);
return self->descriptor_sets[id];
}
typedef struct {
gsize index;
GskVulkanImage *image;
gboolean repeat;
} HashDescriptorSetIndexEntry;
static guint
desc_set_index_hash (gconstpointer v)
{
const HashDescriptorSetIndexEntry *e = v;
return GPOINTER_TO_UINT (e->image) + e->repeat;
}
static gboolean
desc_set_index_equal (gconstpointer v1, gconstpointer v2)
{
const HashDescriptorSetIndexEntry *e1 = v1;
const HashDescriptorSetIndexEntry *e2 = v2;
return e1->image == e2->image && e1->repeat == e2->repeat;
return self->descriptor_set;
}
gsize
gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
GskVulkanImage *source,
gboolean repeat)
gsk_vulkan_render_get_sampler_descriptor (GskVulkanRender *self,
GskVulkanRenderSampler render_sampler)
{
HashDescriptorSetIndexEntry lookup;
HashDescriptorSetIndexEntry *entry;
VkSampler sampler = self->samplers[render_sampler];
gsize i;
g_assert (source != NULL);
/* If this ever shows up in profiles, add a hash table */
for (i = 0; i < gsk_descriptor_image_infos_get_size (&self->descriptor_samplers); i++)
{
if (gsk_descriptor_image_infos_get (&self->descriptor_samplers, i)->sampler == sampler)
return i;
}
lookup.image = source;
lookup.repeat = repeat;
g_assert (i < DESCRIPTOR_POOL_MAXITEMS);
entry = g_hash_table_lookup (self->descriptor_set_indexes, &lookup);
if (entry)
return entry->index;
gsk_descriptor_image_infos_append (&self->descriptor_samplers,
&(VkDescriptorImageInfo) {
.sampler = sampler,
});
entry = g_new (HashDescriptorSetIndexEntry, 1);
entry->image = source;
entry->repeat = repeat;
entry->index = g_hash_table_size (self->descriptor_set_indexes);
g_hash_table_add (self->descriptor_set_indexes, entry);
return i;
}
return entry->index;
gsize
gsk_vulkan_render_get_image_descriptor (GskVulkanRender *self,
GskVulkanImage *image)
{
gsize result;
result = gsk_descriptor_image_infos_get_size (&self->descriptor_images);
gsk_descriptor_image_infos_append (&self->descriptor_images,
&(VkDescriptorImageInfo) {
.sampler = VK_NULL_HANDLE,
.imageView = gsk_vulkan_image_get_image_view (image),
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
});
g_assert (result < DESCRIPTOR_POOL_MAXITEMS);
return result;
}
static void
gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
{
GHashTableIter iter;
gpointer key;
VkDevice device;
GList *l;
guint i, needed_sets;
device = gdk_vulkan_context_get_device (self->vulkan);
@ -507,85 +534,50 @@ gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
gsk_vulkan_render_pass_reserve_descriptor_sets (pass, self);
}
needed_sets = g_hash_table_size (self->descriptor_set_indexes);
if (needed_sets > self->n_descriptor_sets)
{
if (needed_sets > self->descriptor_pool_maxsets)
{
guint added_sets = needed_sets - self->descriptor_pool_maxsets;
added_sets = added_sets + DESCRIPTOR_POOL_MAXSETS_INCREASE - 1;
added_sets -= added_sets % DESCRIPTOR_POOL_MAXSETS_INCREASE;
vkDestroyDescriptorPool (device,
self->descriptor_pool,
NULL);
self->descriptor_pool_maxsets += added_sets;
GSK_VK_CHECK (vkCreateDescriptorPool, device,
&(VkDescriptorPoolCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = self->descriptor_pool_maxsets,
.poolSizeCount = 1,
.pPoolSizes = (VkDescriptorPoolSize[1]) {
{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = self->descriptor_pool_maxsets
}
}
},
NULL,
&self->descriptor_pool);
}
else
{
GSK_VK_CHECK (vkResetDescriptorPool, device,
self->descriptor_pool,
0);
}
self->n_descriptor_sets = needed_sets;
self->descriptor_sets = g_renew (VkDescriptorSet, self->descriptor_sets, needed_sets);
}
VkDescriptorSetLayout *layouts = g_newa (VkDescriptorSetLayout, needed_sets);
for (i = 0; i < needed_sets; i++)
layouts[i] = self->descriptor_set_layout;
if (gsk_descriptor_image_infos_get_size (&self->descriptor_samplers) == 0 &&
gsk_descriptor_image_infos_get_size (&self->descriptor_images) == 0)
return;
GSK_VK_CHECK (vkAllocateDescriptorSets, device,
&(VkDescriptorSetAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = self->descriptor_pool,
.descriptorSetCount = needed_sets,
.pSetLayouts = layouts
.descriptorSetCount = 1,
.pSetLayouts = &self->descriptor_set_layout,
.pNext = &(VkDescriptorSetVariableDescriptorCountAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
.descriptorSetCount = 1,
.pDescriptorCounts = (uint32_t[1]) {
gsk_descriptor_image_infos_get_size (&self->descriptor_images)
+ gsk_descriptor_image_infos_get_size (&self->descriptor_samplers)
}
}
},
self->descriptor_sets);
&self->descriptor_set);
g_hash_table_iter_init (&iter, self->descriptor_set_indexes);
while (g_hash_table_iter_next (&iter, &key, NULL))
{
HashDescriptorSetIndexEntry *entry = key;
GskVulkanImage *image = entry->image;
gsize id = entry->index;
gboolean repeat = entry->repeat;
vkUpdateDescriptorSets (device,
1,
(VkWriteDescriptorSet[1]) {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = self->descriptor_sets[id],
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &(VkDescriptorImageInfo) {
.sampler = repeat ? self->repeating_sampler : self->sampler,
.imageView = gsk_vulkan_image_get_image_view (image),
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
}
}
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)
},
0, NULL);
}
{
.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)
}
},
0, NULL);
}
void
@ -614,7 +606,7 @@ gsk_vulkan_render_draw (GskVulkanRender *self)
command_buffer = gsk_vulkan_command_pool_get_buffer (self->command_pool);
gsk_vulkan_render_pass_draw (pass, self, 3, self->pipeline_layout, command_buffer);
gsk_vulkan_render_pass_draw (pass, self, self->pipeline_layout, command_buffer);
gsk_vulkan_command_pool_submit_buffer (self->command_pool,
command_buffer,
@ -675,10 +667,11 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self)
gsk_vulkan_command_pool_reset (self->command_pool);
g_hash_table_remove_all (self->descriptor_set_indexes);
GSK_VK_CHECK (vkResetDescriptorPool, device,
self->descriptor_pool,
0);
gsk_descriptor_image_infos_set_size (&self->descriptor_images, 0);
gsk_descriptor_image_infos_set_size (&self->descriptor_samplers, 0);
g_list_free_full (self->render_passes, (GDestroyNotify) gsk_vulkan_render_pass_free);
self->render_passes = NULL;
@ -720,10 +713,10 @@ gsk_vulkan_render_free (GskVulkanRender *self)
g_clear_pointer (&self->uploader, gsk_vulkan_uploader_free);
for (i = 0; i < 3; i++)
vkDestroyPipelineLayout (device,
self->pipeline_layout[i],
NULL);
vkDestroyPipelineLayout (device,
self->pipeline_layout,
NULL);
vkDestroyRenderPass (device,
self->render_pass,
@ -732,8 +725,8 @@ gsk_vulkan_render_free (GskVulkanRender *self)
vkDestroyDescriptorPool (device,
self->descriptor_pool,
NULL);
g_free (self->descriptor_sets);
g_hash_table_unref (self->descriptor_set_indexes);
gsk_descriptor_image_infos_clear (&self->descriptor_images);
gsk_descriptor_image_infos_clear (&self->descriptor_samplers);
vkDestroyDescriptorSetLayout (device,
self->descriptor_set_layout,
@ -743,13 +736,12 @@ gsk_vulkan_render_free (GskVulkanRender *self)
self->fence,
NULL);
vkDestroySampler (device,
self->sampler,
NULL);
vkDestroySampler (device,
self->repeating_sampler,
NULL);
for (i = 0; i < G_N_ELEMENTS (self->samplers); i++)
{
vkDestroySampler (device,
self->samplers[i],
NULL);
}
gsk_vulkan_command_pool_free (self->command_pool);

View File

@ -17,6 +17,8 @@
#include <graphene.h>
#define GSK_VULKAN_MAX_RENDERS 4
typedef struct _GskVulkanTextureData GskVulkanTextureData;
struct _GskVulkanTextureData {
@ -51,7 +53,7 @@ struct _GskVulkanRenderer
guint n_targets;
GskVulkanImage **targets;
GskVulkanRender *render;
GskVulkanRender *renders[GSK_VULKAN_MAX_RENDERS];
GSList *textures;
@ -161,6 +163,38 @@ gsk_vulkan_renderer_update_images_cb (GdkVulkanContext *context,
}
}
static GskVulkanRender *
gsk_vulkan_renderer_get_render (GskVulkanRenderer *self)
{
VkFence fences[G_N_ELEMENTS (self->renders)];
VkDevice device;
guint i;
device = gdk_vulkan_context_get_device (self->vulkan);
while (TRUE)
{
for (i = 0; i < G_N_ELEMENTS (self->renders); i++)
{
if (self->renders[i] == NULL)
{
self->renders[i] = gsk_vulkan_render_new (GSK_RENDERER (self), self->vulkan);
return self->renders[i];
}
fences[i] = gsk_vulkan_render_get_fence (self->renders[i]);
if (vkGetFenceStatus (device, fences[i]) == VK_SUCCESS)
return self->renders[i];
}
GSK_VK_CHECK (vkWaitForFences, device,
G_N_ELEMENTS (fences),
fences,
VK_FALSE,
INT64_MAX);
}
}
static gboolean
gsk_vulkan_renderer_realize (GskRenderer *renderer,
GdkSurface *surface,
@ -185,8 +219,6 @@ gsk_vulkan_renderer_realize (GskRenderer *renderer,
self);
gsk_vulkan_renderer_update_images_cb (self->vulkan, self);
self->render = gsk_vulkan_render_new (renderer, self->vulkan);
self->glyph_cache = gsk_vulkan_glyph_cache_new (renderer, self->vulkan);
return TRUE;
@ -197,6 +229,7 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
{
GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
GSList *l;
guint i;
g_clear_object (&self->glyph_cache);
@ -209,7 +242,8 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
}
g_clear_pointer (&self->textures, g_slist_free);
g_clear_pointer (&self->render, gsk_vulkan_render_free);
for (i = 0; i < G_N_ELEMENTS (self->renders); i++)
g_clear_pointer (&self->renders[i], gsk_vulkan_render_free);
gsk_vulkan_renderer_free_targets (self);
g_signal_handlers_disconnect_by_func(self->vulkan,
@ -228,6 +262,7 @@ gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
GskVulkanRender *render;
GskVulkanImage *image;
GdkTexture *texture;
graphene_rect_t rounded_viewport;
#ifdef G_ENABLE_DEBUG
GskProfiler *profiler;
gint64 cpu_time;
@ -244,11 +279,15 @@ gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
render = gsk_vulkan_render_new (renderer, self->vulkan);
rounded_viewport = GRAPHENE_RECT_INIT (viewport->origin.x,
viewport->origin.y,
ceil (viewport->size.width),
ceil (viewport->size.height));
image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
ceil (viewport->size.width),
ceil (viewport->size.height));
rounded_viewport.size.width,
rounded_viewport.size.height);
gsk_vulkan_render_reset (render, image, viewport, NULL);
gsk_vulkan_render_reset (render, image, &rounded_viewport, NULL);
gsk_vulkan_render_add_node (render, root);
gsk_vulkan_render_upload (render);
gsk_vulkan_render_draw (render);
@ -301,7 +340,7 @@ gsk_vulkan_renderer_render (GskRenderer *renderer,
#endif
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->vulkan), region);
render = self->render;
render = gsk_vulkan_renderer_get_render (self);
render_region = get_render_region (self);
draw_index = gdk_vulkan_context_get_draw_index (self->vulkan);

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,8 @@ G_BEGIN_DECLS
GskVulkanRenderPass * gsk_vulkan_render_pass_new (GdkVulkanContext *context,
GskVulkanImage *target,
float scale_x,
float scale_y,
graphene_matrix_t *mv,
graphene_rect_t *viewport,
const graphene_vec2_t *scale,
const graphene_rect_t *viewport,
cairo_region_t *clip,
VkSemaphore signal_semaphore);
@ -32,8 +30,7 @@ void gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulk
GskVulkanRender *render);
void gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
GskVulkanRender *render,
guint layout_count,
VkPipelineLayout *pipeline_layout,
VkPipelineLayout pipeline_layout,
VkCommandBuffer command_buffer);
gsize gsk_vulkan_render_pass_get_wait_semaphores (GskVulkanRenderPass *self,
VkSemaphore **semaphores);

View File

@ -51,6 +51,12 @@ typedef enum {
GSK_VULKAN_N_PIPELINES
} GskVulkanPipelineType;
typedef enum {
GSK_VULKAN_SAMPLER_DEFAULT,
GSK_VULKAN_SAMPLER_REPEAT,
GSK_VULKAN_SAMPLER_NEAREST
} GskVulkanRenderSampler;
GskVulkanRender * gsk_vulkan_render_new (GskRenderer *renderer,
GdkVulkanContext *context);
void gsk_vulkan_render_free (GskVulkanRender *self);
@ -76,11 +82,12 @@ void gsk_vulkan_render_upload (GskVulk
GskVulkanPipeline * gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
GskVulkanPipelineType pipeline_type);
VkDescriptorSet gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
gsize id);
gsize gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
GskVulkanImage *source,
gboolean repeat);
gsize gsk_vulkan_render_get_sampler_descriptor (GskVulkanRender *self,
GskVulkanRenderSampler render_sampler);
gsize gsk_vulkan_render_get_image_descriptor (GskVulkanRender *self,
GskVulkanImage *source);
VkDescriptorSet gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self);
void gsk_vulkan_render_draw (GskVulkanRender *self);
void gsk_vulkan_render_submit (GskVulkanRender *self);
@ -88,6 +95,7 @@ void gsk_vulkan_render_submit (GskVulk
GdkTexture * gsk_vulkan_render_download_target (GskVulkanRender *self);
VkFramebuffer gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
GskVulkanImage *image);
VkFence gsk_vulkan_render_get_fence (GskVulkanRender *self);
G_END_DECLS

View File

@ -14,6 +14,7 @@ struct _GskVulkanTextInstance
float rect[4];
float tex_rect[4];
float color[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
@ -46,6 +47,12 @@ gsk_vulkan_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, color),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
@ -91,18 +98,12 @@ gsk_vulkan_text_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_TEXT_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
int num_instances)
{
return sizeof (GskVulkanTextInstance) * num_instances;
}
void
gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
guchar *data,
GskVulkanRenderer *renderer,
const graphene_rect_t *rect,
guint tex_id[2],
PangoFont *font,
guint total_glyphs,
const PangoGlyphInfo *glyphs,
@ -153,6 +154,9 @@ gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
instance->color[2] = color->blue;
instance->color[3] = color->alpha;
instance->tex_id[0] = tex_id[0];
instance->tex_id[1] = tex_id[1];
count++;
}
x_position += gi->geometry.width;

View File

@ -18,24 +18,23 @@ GskVulkanPipeline * gsk_vulkan_text_pipeline_new (GdkVulka
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_text_pipeline_count_vertex_data (GskVulkanTextPipeline *pipeline,
int num_instances);
void gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
guchar *data,
GskVulkanRenderer *renderer,
const graphene_rect_t *rect,
PangoFont *font,
guint total_glyphs,
const PangoGlyphInfo *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset,
guint start_glyph,
guint num_glyphs,
float scale);
guchar *data,
GskVulkanRenderer *renderer,
const graphene_rect_t *rect,
guint32 tex_id[2],
PangoFont *font,
guint total_glyphs,
const PangoGlyphInfo *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset,
guint start_glyph,
guint num_glyphs,
float scale);
gsize gsk_vulkan_text_pipeline_draw (GskVulkanTextPipeline *pipeline,
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands);
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands);
G_END_DECLS

View File

@ -13,6 +13,7 @@ struct _GskVulkanTextureInstance
{
float rect[4];
float tex_rect[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK_TYPE_VULKAN_PIPELINE)
@ -39,6 +40,12 @@ gsk_vulkan_texture_pipeline_get_input_state_create_info (GskVulkanPipeline *self
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
@ -84,28 +91,26 @@ gsk_vulkan_texture_pipeline_new (GdkVulkanContext *context,
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_TEXTURE_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline)
{
return sizeof (GskVulkanTextureInstance);
}
void
gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
guchar *data,
guint32 tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect)
{
GskVulkanTextureInstance *instance = (GskVulkanTextureInstance *) data;
instance->rect[0] = rect->origin.x;
instance->rect[1] = rect->origin.y;
instance->rect[0] = rect->origin.x + offset->x;
instance->rect[1] = rect->origin.y + offset->y;
instance->rect[2] = rect->size.width;
instance->rect[3] = rect->size.height;
instance->tex_rect[0] = tex_rect->origin.x;
instance->tex_rect[1] = tex_rect->origin.y;
instance->tex_rect[2] = tex_rect->size.width;
instance->tex_rect[3] = tex_rect->size.height;
instance->tex_id[0] = tex_id[0];
instance->tex_id[1] = tex_id[1];
}
gsize

View File

@ -17,9 +17,10 @@ GskVulkanPipeline * gsk_vulkan_texture_pipeline_new (GdkVulk
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_texture_pipeline_count_vertex_data (GskVulkanTexturePipeline *pipeline);
void gsk_vulkan_texture_pipeline_collect_vertex_data (GskVulkanTexturePipeline *pipeline,
guchar *data,
guint32 tex_id[2],
const graphene_point_t *offset,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect);
gsize gsk_vulkan_texture_pipeline_draw (GskVulkanTexturePipeline *pipeline,

View File

@ -1,16 +1,19 @@
#version 420 core
#include "common.frag.glsl"
#include "clip.frag.glsl"
#include "rect.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inStartTexCoord;
layout(location = 2) in vec2 inEndTexCoord;
layout(location = 3) flat in uint inBlendMode;
layout(location = 1) in Rect inTopRect;
layout(location = 2) in Rect inBottomRect;
layout(location = 3) in vec2 inTopTexCoord;
layout(location = 4) in vec2 inBottomTexCoord;
layout(location = 5) flat in uvec2 inTopTexId;
layout(location = 6) flat in uvec2 inBottomTexId;
layout(location = 7) flat in uint inBlendMode;
layout(set = 0, binding = 0) uniform sampler2D startTexture;
layout(set = 1, binding = 0) uniform sampler2D endTexture;
layout(location = 0) out vec4 outColor;
layout(location = 0) out vec4 color;
float
combine (float source, float backdrop)
@ -242,7 +245,7 @@ set_sat (vec3 c, float s)
}
vec4
color (vec4 Cs, vec4 Cb)
colorize (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
return composite (Cs, Cb, B);
@ -271,8 +274,10 @@ luminosity (vec4 Cs, vec4 Cb)
void main()
{
vec4 source = texture (startTexture, inStartTexCoord);
vec4 backdrop = texture (endTexture, inEndTexCoord);
float source_alpha = rect_coverage (inTopRect, inPos);
vec4 source = texture (get_sampler (inTopTexId), inTopTexCoord) * source_alpha;
float backdrop_alpha = rect_coverage (inBottomRect, inPos);
vec4 backdrop = texture (get_sampler (inBottomTexId), inBottomTexCoord) * backdrop_alpha;
vec4 result;
if (inBlendMode == 0)
@ -300,7 +305,7 @@ void main()
else if (inBlendMode == 11)
result = exclusion (source, backdrop);
else if (inBlendMode == 12)
result = color (source, backdrop);
result = colorize (source, backdrop);
else if (inBlendMode == 13)
result = hue (source, backdrop);
else if (inBlendMode == 14)
@ -310,5 +315,5 @@ void main()
else
discard;
outColor = clip (inPos, result);
color = clip_scaled (inPos, result);
}

View File

@ -1,40 +1,36 @@
#version 420 core
#include "clip.vert.glsl"
#include "common.vert.glsl"
#include "rect.vert.glsl"
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inStartTexRect;
layout(location = 2) in vec4 inEndTexRect;
layout(location = 3) in uint inBlendMode;
layout(location = 1) in vec4 inTopRect;
layout(location = 2) in vec4 inBottomRect;
layout(location = 3) in vec4 inTopTexRect;
layout(location = 4) in vec4 inBottomTexRect;
layout(location = 5) in uvec2 inTopTexId;
layout(location = 6) in uvec2 inBottomTexId;
layout(location = 7) in uint inBlendMode;
layout(location = 0) out vec2 outPos;
layout(location = 1) out vec2 outStartTexCoord;
layout(location = 2) out vec2 outEndTexCoord;
layout(location = 3) flat out uint outBlendMode;
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) flat out Rect outTopRect;
layout(location = 2) flat out Rect outBottomRect;
layout(location = 3) out vec2 outTopTexCoord;
layout(location = 4) out vec2 outBottomTexCoord;
layout(location = 5) flat out uvec2 outTopTexId;
layout(location = 6) flat out uvec2 outBottomTexId;
layout(location = 7) flat out uint outBlendMode;
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
Rect r = rect_from_gsk (inRect);
vec2 pos = set_position_from_rect (r);
outPos = pos;
vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw,
rect.zw / inRect.zw);
vec4 starttexrect = vec4(inStartTexRect.xy + inStartTexRect.zw * texrect.xy,
inStartTexRect.zw * texrect.zw);
vec4 endtexrect = vec4(inEndTexRect.xy + inEndTexRect.zw * texrect.xy,
inEndTexRect.zw * texrect.zw);
outStartTexCoord = starttexrect.xy + starttexrect.zw * offsets[gl_VertexIndex];
outEndTexCoord = endtexrect.xy + endtexrect.zw * offsets[gl_VertexIndex];
outTopRect = rect_from_gsk (inTopRect);
outBottomRect = rect_from_gsk (inBottomRect);
outTopTexCoord = scale_tex_coord (pos, r, inTopTexRect);
outBottomTexCoord = scale_tex_coord (pos, r, inBottomTexRect);
outTopTexId = inTopTexId;
outBottomTexId = inBottomTexId;
outBlendMode = inBlendMode;
}

View File

@ -1,13 +1,13 @@
#version 420 core
#include "common.frag.glsl"
#include "clip.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in flat vec2 inSize;
layout(location = 2) in vec2 inTexCoord;
layout(location = 3) in float inRadius;
layout(set = 0, binding = 0) uniform sampler2D inTexture;
layout(location = 4) in flat uvec2 inTexId;
layout(location = 0) out vec4 color;
@ -38,7 +38,7 @@ vec4 blur_pixel (in vec2 uv)
float fx = Gaussian (inRadius, float(x) - float(half_samples_x));
float offset_x = float(x - half_samples_x) * pixel_size_x;
total += fx * fy;
ret += texture(inTexture, uv + vec2(offset_x, offset_y)) * fx * fy;
ret += texture(get_sampler (inTexId), uv + vec2(offset_x, offset_y)) * fx * fy;
}
}
return ret / total;

View File

@ -6,11 +6,13 @@
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inTexRect;
layout(location = 2) in float inRadius;
layout(location = 3) in uvec2 inTexId;
layout(location = 0) out vec2 outPos;
layout(location = 1) out flat vec2 outSize;
layout(location = 2) out vec2 outTexCoord;
layout(location = 3) out flat float outRadius;
layout(location = 4) out flat uvec2 outTexId;
vec2 offsets[6] = { vec2(0.0, 0.0),
vec2(1.0, 0.0),
@ -22,7 +24,7 @@ vec2 offsets[6] = { vec2(0.0, 0.0),
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
outSize = inRect.zw;
@ -32,6 +34,6 @@ void main() {
texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy,
inTexRect.zw * texrect.zw);
outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex];
outTexId = inTexId;
outRadius = inRadius;
}

View File

@ -5,20 +5,18 @@
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 = 2) in RoundedRect inRect;
layout(location = 5) in vec4 inBorderWidths;
layout(location = 0) out vec4 color;
void main()
{
RoundedRect routside = RoundedRect (vec4(inRect.xy, inRect.xy + inRect.zw), inCornerWidths, inCornerHeights);
RoundedRect routside = inRect;
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 (inPos, vec4(inColor.rgb * inColor.a, inColor.a) * alpha);
color = clip_scaled (inPos, vec4(inColor.rgb * inColor.a, inColor.a) * alpha);
}

View File

@ -1,6 +1,7 @@
#version 420 core
#include "clip.vert.glsl"
#include "rounded-rect.glsl"
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inCornerWidths;
@ -10,9 +11,7 @@ layout(location = 4) in mat4 inBorderColors;
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 = 2) out flat RoundedRect outRect;
layout(location = 5) out flat vec4 outBorderWidths;
vec2 offsets[6] = { vec2(0.0, 0.0),
@ -48,51 +47,59 @@ void main() {
vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
vec4 rect;
Rect rect;
switch (slice_index)
{
case SLICE_TOP_LEFT:
rect = vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]);
rect = rect_from_gsk (vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]));
rect = rect_round_larger (rect);
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]);
rect = rect_from_gsk (vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]));
rect = rect_round_smaller_larger (rect);
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]);
rect = rect_from_gsk (vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]));
rect = rect_round_larger (rect);
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]);
rect = rect_from_gsk (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]));
rect = rect_round_larger_smaller (rect);
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]);
rect = rect_from_gsk (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]));
rect = rect_round_larger (rect);
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]);
rect = rect_from_gsk (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]));
rect = rect_round_smaller_larger (rect);
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]);
rect = rect_from_gsk (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;
rect = rect_round_larger (rect);
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]);
rect = rect_from_gsk (vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]));
rect = rect_round_larger_smaller (rect);
break;
}
rect = clip (rect);
rect = clip_rect (rect);
vec2 pos;
if ((slice_index % 4) != 0 || (vert_index % 3) != 2)
pos = rect.xy + rect.zw * offsets[vert_index];
pos = mix (rect.bounds.xy, rect.bounds.zw, offsets[vert_index]);
else
pos = rect.xy + rect.zw * vec2(1.0 - offsets[vert_index].x, offsets[vert_index].y);
pos = mix (rect.bounds.zy, rect.bounds.xw, offsets[vert_index]);
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;
outRect = RoundedRect(inRect.xyxy + vec4(0,0,inRect.zw), inCornerWidths, inCornerHeights);
outRect = rounded_rect_scale (outRect, push.scale);
outBorderWidths = inBorderWidths * push.scale.yxyx;
}

View File

@ -1,29 +1,45 @@
#include "constants.glsl"
#include "rounded-rect.glsl"
#include "rounded-rect.frag.glsl"
#ifndef _CLIP_
#define _CLIP_
#ifdef CLIP_ROUNDED_RECT
vec4 clip(vec2 pos, vec4 color)
vec4
clip_scaled (vec2 pos, vec4 color)
{
RoundedRect r = RoundedRect(vec4(push.clip_bounds.xy, push.clip_bounds.xy + push.clip_bounds.zw), push.clip_widths, push.clip_heights);
r = rounded_rect_scale (r, push.scale);
return color * rounded_rect_coverage (r, pos);
}
#elif defined(CLIP_RECT)
vec4 clip(vec2 pos, vec4 color)
vec4
clip_scaled (vec2 pos, vec4 color)
{
/* clipped in vertex shader already */
return color;
}
#elif defined(CLIP_NONE)
vec4 clip(vec2 pos, vec4 color)
vec4
clip_scaled (vec2 pos, vec4 color)
{
return color;
}
#else
#error "No clipping define given. Need CLIP_NONE, CLIP_RECT or CLIP_ROUNDED_RECT"
#endif
vec4
clip (vec2 pos, vec4 color)
{
return clip_scaled (pos * push.scale, color);
}
#endif

View File

@ -1,4 +1,5 @@
#include "constants.glsl"
#include "rect.vert.glsl"
#ifndef _CLIP_
#define _CLIP_
@ -14,21 +15,47 @@ vec4 intersect(vec4 a, vec4 b)
}
#ifdef CLIP_ROUNDED_RECT
vec4 clip(vec4 rect)
vec4
clip(vec4 rect)
{
/* rounded corner clipping is done in fragment shader */
return intersect(rect, push.clip_bounds);
}
Rect
clip_rect (Rect r)
{
/* rounded corner clipping is done in fragment shader */
return rect_intersect (r, rect_round_larger (rect_from_gsk (push.clip_bounds)));
}
#elif defined(CLIP_RECT)
vec4 clip(vec4 rect)
vec4
clip(vec4 rect)
{
return intersect(rect, push.clip_bounds);
}
Rect
clip_rect (Rect r)
{
return rect_intersect (r, rect_round_larger (rect_from_gsk (push.clip_bounds)));
}
#elif defined(CLIP_NONE)
vec4 clip(vec4 rect)
{
return rect;
}
Rect
clip_rect (Rect r)
{
return r;
}
#else
#error "No clipping define given. Need CLIP_NONE, CLIP_RECT or CLIP_ROUNDED_RECT"
#endif

View File

@ -1,13 +1,13 @@
#version 420 core
#include "common.frag.glsl"
#include "clip.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inTexCoord;
layout(location = 2) in flat mat4 inColorMatrix;
layout(location = 6) in flat vec4 inColorOffset;
layout(set = 0, binding = 0) uniform sampler2D inTexture;
layout(location = 7) in flat uvec2 inTexId;
layout(location = 0) out vec4 color;
@ -29,5 +29,5 @@ color_matrix (vec4 color, mat4 color_matrix, vec4 color_offset)
void main()
{
color = clip (inPos, color_matrix (texture (inTexture, inTexCoord), inColorMatrix, inColorOffset));
color = clip (inPos, color_matrix (texture (get_sampler (inTexId), inTexCoord), inColorMatrix, inColorOffset));
}

View File

@ -6,11 +6,13 @@ layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inTexRect;
layout(location = 2) in mat4 inColorMatrix;
layout(location = 6) in vec4 inColorOffset;
layout(location = 7) in uvec2 inTexId;
layout(location = 0) out vec2 outPos;
layout(location = 1) out vec2 outTexCoord;
layout(location = 2) out flat mat4 outColorMatrix;
layout(location = 6) out flat vec4 outColorOffset;
layout(location = 7) out flat uvec2 outTexId;
vec2 offsets[6] = { vec2(0.0, 0.0),
vec2(1.0, 0.0),
@ -22,7 +24,7 @@ vec2 offsets[6] = { vec2(0.0, 0.0),
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
@ -31,6 +33,7 @@ void main() {
texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy,
inTexRect.zw * texrect.zw);
outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex];
outTexId = inTexId;
outColorMatrix = inColorMatrix;
outColorOffset = inColorOffset;
}

View File

@ -1,13 +1,16 @@
#version 420 core
#include "clip.frag.glsl"
#include "rect.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec4 inColor;
layout(location = 1) in Rect inRect;
layout(location = 2) in vec4 inColor;
layout(location = 0) out vec4 color;
void main()
{
color = clip (inPos, vec4(inColor.rgb * inColor.a, inColor.a));
float alpha = inColor.a * rect_coverage (inRect, inPos);
color = clip_scaled (inPos, vec4(inColor.rgb, 1) * alpha);
}

View File

@ -1,25 +1,18 @@
#version 420 core
#include "clip.vert.glsl"
#include "common.vert.glsl"
#include "rect.vert.glsl"
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inColor;
layout(location = 0) out vec2 outPos;
layout(location = 1) out flat vec4 outColor;
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 flat vec4 outColor;
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
outPos = pos;
Rect r = rect_from_gsk (inRect);
outPos = set_position_from_rect (r);
outRect = r;
outColor = inColor;
}

View File

@ -0,0 +1,6 @@
layout(set = 0, binding = 0) uniform texture2D textures[50000];
layout(set = 0, binding = 1) uniform sampler samplers[50000];
#define get_sampler(id) sampler2D(textures[id.x], samplers[id.y])

View File

@ -0,0 +1,34 @@
#ifndef _COMMON_VERT_
#define _COMMON_VERT_
#include "clip.vert.glsl"
#include "constants.glsl"
#include "rect.glsl"
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) };
vec2
set_position_from_rect (Rect rect)
{
Rect r = rect_round_larger (clip_rect (rect));
vec2 pos = mix (r.bounds.xy, r.bounds.zw, offsets[gl_VertexIndex]);
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
return pos;
}
vec2
scale_tex_coord (vec2 in_pos,
Rect in_rect,
vec4 tex_rect)
{
return tex_rect.xy + (in_pos - in_rect.bounds.xy) / rect_size (in_rect) * tex_rect.zw;
}
#endif

View File

@ -6,6 +6,7 @@ layout(push_constant) uniform PushConstants {
vec4 clip_bounds;
vec4 clip_widths;
vec4 clip_heights;
vec2 scale;
} push;
#endif

View File

@ -1,21 +1,26 @@
#version 420 core
#include "common.frag.glsl"
#include "clip.frag.glsl"
#include "rect.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inStartTexCoord;
layout(location = 2) in vec2 inEndTexCoord;
layout(location = 3) in float inProgress;
layout(set = 0, binding = 0) uniform sampler2D startTexture;
layout(set = 1, binding = 0) uniform sampler2D endTexture;
layout(location = 1) in Rect inStartRect;
layout(location = 2) in Rect inEndRect;
layout(location = 3) in vec2 inStartTexCoord;
layout(location = 4) in vec2 inEndTexCoord;
layout(location = 5) flat in uvec2 inStartTexId;
layout(location = 6) flat in uvec2 inEndTexId;
layout(location = 7) in float inProgress;
layout(location = 0) out vec4 color;
void main()
{
vec4 start = texture (startTexture, inStartTexCoord);
vec4 end = texture (endTexture, inEndTexCoord);
float start_alpha = rect_coverage (inStartRect, inPos);
vec4 start = texture (get_sampler (inStartTexId), inStartTexCoord) * start_alpha;
float end_alpha = rect_coverage (inEndRect, inPos);
vec4 end = texture (get_sampler (inEndTexId), inEndTexCoord) * end_alpha;
color = clip (inPos, mix (start, end, inProgress));
color = clip_scaled (inPos, mix (start, end, inProgress));
}

View File

@ -1,40 +1,36 @@
#version 420 core
#include "clip.vert.glsl"
#include "common.vert.glsl"
#include "rect.vert.glsl"
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inStartTexRect;
layout(location = 2) in vec4 inEndTexRect;
layout(location = 3) in float inProgress;
layout(location = 1) in vec4 inStartRect;
layout(location = 2) in vec4 inEndRect;
layout(location = 3) in vec4 inStartTexRect;
layout(location = 4) in vec4 inEndTexRect;
layout(location = 5) in uvec2 inStartTexId;
layout(location = 6) in uvec2 inEndTexId;
layout(location = 7) in float inProgress;
layout(location = 0) out vec2 outPos;
layout(location = 1) out vec2 outStartTexCoord;
layout(location = 2) out vec2 outEndTexCoord;
layout(location = 3) out float outProgress;
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) flat out Rect outStartRect;
layout(location = 2) flat out Rect outEndRect;
layout(location = 3) out vec2 outStartTexCoord;
layout(location = 4) out vec2 outEndTexCoord;
layout(location = 5) flat out uvec2 outStartTexId;
layout(location = 6) flat out uvec2 outEndTexId;
layout(location = 7) flat out float outProgress;
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
Rect r = rect_from_gsk (inRect);
vec2 pos = set_position_from_rect (r);
outPos = pos;
vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw,
rect.zw / inRect.zw);
vec4 starttexrect = vec4(inStartTexRect.xy + inStartTexRect.zw * texrect.xy,
inStartTexRect.zw * texrect.zw);
vec4 endtexrect = vec4(inEndTexRect.xy + inEndTexRect.zw * texrect.xy,
inEndTexRect.zw * texrect.zw);
outStartTexCoord = starttexrect.xy + starttexrect.zw * offsets[gl_VertexIndex];
outEndTexCoord = endtexrect.xy + endtexrect.zw * offsets[gl_VertexIndex];
outStartRect = rect_from_gsk (inStartRect);
outEndRect = rect_from_gsk (inEndRect);
outStartTexCoord = scale_tex_coord (pos, r, inStartTexRect);
outEndTexCoord = scale_tex_coord (pos, r, inEndTexRect);
outStartTexId = inStartTexId;
outEndTexId = inEndTexId;
outProgress = inProgress;
}

View File

@ -0,0 +1,38 @@
#ifndef _ELLIPSE_
#define _ELLIPSE_
struct Ellipse
{
vec2 center;
vec2 radius;
};
float
ellipse_distance (Ellipse r, vec2 p)
{
vec2 e = r.radius;
p = p - r.center;
if (e.x == e.y)
return length (p) - e.x;
/* from https://www.shadertoy.com/view/tt3yz7 */
vec2 pAbs = abs(p);
vec2 ei = 1.0 / e;
vec2 e2 = e*e;
vec2 ve = ei * vec2(e2.x - e2.y, e2.y - e2.x);
vec2 t = vec2(0.70710678118654752, 0.70710678118654752);
for (int i = 0; i < 3; i++) {
vec2 v = ve*t*t*t;
vec2 u = normalize(pAbs - v) * length(t * e - v);
vec2 w = ei * (v + u);
t = normalize(clamp(w, 0.0, 1.0));
}
vec2 nearestAbs = t * e;
float dist = length(pAbs - nearestAbs);
return dot(pAbs, pAbs) < dot(nearestAbs, nearestAbs) ? -dist : dist;
}
#endif

View File

@ -29,7 +29,7 @@ void main() {
vec4 rect = clip (inOutline);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
outOutline = inOutline;

View File

@ -48,7 +48,7 @@ get_gradient_pos (vec2 pos)
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
outGradientPos = get_gradient_pos (pos);
outRepeating = inRepeating;

View File

@ -1,16 +1,16 @@
#version 420 core
#include "common.frag.glsl"
#include "clip.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inTexCoord;
layout(location = 2) in vec4 inColor;
layout(set = 0, binding = 0) uniform sampler2D inTexture;
layout(location = 3) flat in uvec2 inTexId;
layout(location = 0) out vec4 color;
void main()
{
color = clip (inPos, vec4(inColor.rgb * inColor.a, inColor.a) * texture(inTexture, inTexCoord).a);
color = clip (inPos, vec4(inColor.rgb * inColor.a, inColor.a) * texture(get_sampler (inTexId), inTexCoord).a);
}

View File

@ -5,10 +5,12 @@
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inTexRect;
layout(location = 2) in vec4 inColor;
layout(location = 3) in uvec2 inTexId;
layout(location = 0) out vec2 outPos;
layout(location = 1) out vec2 outTexCoord;
layout(location = 2) out flat vec4 outColor;
layout(location = 3) out flat uvec2 outTexId;
vec2 offsets[6] = { vec2(0.0, 0.0),
vec2(1.0, 0.0),
@ -20,7 +22,7 @@ vec2 offsets[6] = { vec2(0.0, 0.0),
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
@ -29,6 +31,6 @@ void main() {
texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy,
inTexRect.zw * texrect.zw);
outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex];
outTexId = inTexId;
outColor = inColor;
}

View File

@ -1,8 +1,14 @@
gsk_private_vulkan_include_shaders = [
'clip.frag.glsl',
'clip.vert.glsl',
'common.frag.glsl',
'common.vert.glsl',
'constants.glsl',
'rect.glsl',
'rect.frag.glsl',
'rect.vert.glsl',
'rounded-rect.glsl',
'rounded-rect.frag.glsl',
]
gsk_private_vulkan_fragment_shaders = [

View File

@ -38,7 +38,7 @@ void main() {
clip (inOutline);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
outOutline = inOutline;

View File

@ -0,0 +1,16 @@
#ifndef _RECT_FRAG_
#define _RECT_FRAG_
#include "rect.glsl"
float
rect_coverage (Rect r, vec2 p)
{
vec2 dFdp = abs(fwidth (p));
Rect prect = Rect(vec4(p - 0.5 * dFdp, p + 0.5 * dFdp));
Rect coverect = rect_intersect (r, prect);
vec2 coverage = rect_size(coverect) / dFdp;
return coverage.x * coverage.y;
}
#endif

View File

@ -0,0 +1,58 @@
#ifndef _RECT_
#define _RECT_
struct Rect
{
/* x,y and y,w make up the 2 points of this rect,
note that this is not containing width or height */
vec4 bounds;
};
Rect
rect_from_gsk (vec4 xywh)
{
return Rect((xywh.xyxy + vec4(0,0,xywh.zw)) * push.scale.xyxy);
}
float
rect_distance (Rect r, vec2 p)
{
vec4 distance = (r.bounds - p.xyxy) * vec4(1.0, 1.0, -1.0, -1.0);
vec2 max2 = max (distance.xy, distance.zw);
return length (max (max2, 0)) + min (max(max2.x, max2.y), 0);
}
vec2
rect_size (Rect r)
{
return r.bounds.zw - r.bounds.xy;
}
Rect
rect_round_larger (Rect r)
{
return Rect (vec4 (floor(r.bounds.xy), ceil (r.bounds.zw)));
}
Rect
rect_round_larger_smaller (Rect r)
{
return Rect (mix (floor(r.bounds), ceil (r.bounds), bvec4(0, 1, 1, 0)));
}
Rect
rect_round_smaller_larger (Rect r)
{
return Rect (mix (floor(r.bounds), ceil (r.bounds), bvec4(1, 0, 0, 1)));
}
Rect
rect_intersect (Rect a, Rect b)
{
vec4 result = vec4(max(a.bounds.xy, b.bounds.xy), min(a.bounds.zw, b.bounds.zw));
if (any (greaterThanEqual (result.xy, result.zw)))
return Rect (vec4(0.0));
return Rect(result);
}
#endif

View File

@ -0,0 +1,6 @@
#ifndef _RECT_VERT_
#define _RECT_VERT_
#include "rect.glsl"
#endif

View File

@ -0,0 +1,17 @@
#ifndef _ROUNDED_RECT_FRAG_
#define _ROUNDED_RECT_FRAG_
#include "rounded-rect.glsl"
float
rounded_rect_coverage (RoundedRect r, vec2 p)
{
vec2 fw = abs (fwidth (p));
float distance_scale = max (fw.x, fw.y);
float distance = rounded_rect_distance (r, p) / distance_scale;
float coverage = 0.5 - distance;
return clamp (coverage, 0, 1);
}
#endif

View File

@ -1,6 +1,9 @@
#ifndef _ROUNDED_RECT_
#define _ROUNDED_RECT_
#include "ellipse.glsl"
#include "rect.glsl"
struct RoundedRect
{
vec4 bounds;
@ -9,59 +12,52 @@ struct RoundedRect
};
float
ellipsis_dist (vec2 p, vec2 radius)
rounded_rect_distance (RoundedRect r, vec2 p)
{
vec2 p0 = p / radius;
vec2 p1 = 2.0 * p0 / radius;
return (dot(p0, p0) - 1.0) / length (p1);
}
Rect bounds = Rect(vec4(r.bounds));
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;
float bounds_distance = rect_distance (bounds, p);
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);
Ellipse tl = Ellipse (r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x),
vec2(r.corner_widths.x, r.corner_heights.x));
Ellipse tr = Ellipse (r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y),
vec2(r.corner_widths.y, r.corner_heights.y));
Ellipse br = Ellipse (r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z),
vec2(r.corner_widths.z, r.corner_heights.z));
Ellipse bl = Ellipse (r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w),
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 distances = vec4(ellipse_distance (tl, p),
ellipse_distance (tr, p),
ellipse_distance (br, p),
ellipse_distance (bl, p));
vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
bvec4 is_out = bvec4(p.x < tl.center.x && p.y < tl.center.y,
p.x > tr.center.x && p.y < tr.center.y,
p.x > br.center.x && p.y > br.center.y,
p.x < bl.center.x && p.y > bl.center.y);
distances = mix (vec4(bounds_distance), distances, is_out);
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);
vec2 max2 = max (distances.xy, distances.zw);
return max (max2.x, max2.y);
}
return 1.0 - dot(vec4(is_out), corner_coverages);
RoundedRect
rounded_rect_scale (RoundedRect r, vec2 scale)
{
r.bounds *= scale.xyxy;
r.corner_widths *= scale.xxxx;
r.corner_heights *= scale.yyyy;
return r;
}
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);
vec4 new_widths = max (r.corner_widths - sign (r.corner_widths) * amount.wyyw, 0.0);
vec4 new_heights = max (r.corner_heights - sign (r.corner_heights) * amount.xxzz, 0.0);
return RoundedRect (new_bounds, new_widths, new_heights);
}

View File

@ -1,15 +1,18 @@
#version 420 core
#include "common.frag.glsl"
#include "clip.frag.glsl"
#include "rect.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inTexCoord;
layout(set = 0, binding = 0) uniform sampler2D inTexture;
layout(location = 1) in Rect inRect;
layout(location = 2) in vec2 inTexCoord;
layout(location = 3) flat in uvec2 inTexId;
layout(location = 0) out vec4 color;
void main()
{
color = clip (inPos, texture (inTexture, inTexCoord));
float alpha = rect_coverage (inRect, inPos);
color = clip_scaled (inPos, texture (get_sampler (inTexId), inTexCoord) * alpha);
}

View File

@ -1,30 +1,23 @@
#version 420 core
#include "clip.vert.glsl"
#include "common.vert.glsl"
#include "rect.vert.glsl"
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inTexRect;
layout(location = 2) in uvec2 inTexId;
layout(location = 0) out vec2 outPos;
layout(location = 1) out vec2 outTexCoord;
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 vec2 outTexCoord;
layout(location = 3) out flat uvec2 outTexId;
void main() {
vec4 rect = clip (inRect);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
Rect r = rect_from_gsk (inRect);
vec2 pos = set_position_from_rect (r);
outPos = pos;
vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw,
rect.zw / inRect.zw);
texrect = vec4(inTexRect.xy + inTexRect.zw * texrect.xy,
inTexRect.zw * texrect.zw);
outTexCoord = texrect.xy + texrect.zw * offsets[gl_VertexIndex];
outRect = r;
outTexCoord = scale_tex_coord (pos, r, inTexRect);
outTexId = inTexId;
}

View File

@ -1267,7 +1267,7 @@ populate_render_node_properties (GListStore *store,
float radius = gsk_outset_shadow_node_get_blur_radius (node);
float rect[12];
gsk_rounded_rect_to_float (outline, rect);
gsk_rounded_rect_to_float (outline, graphene_point_zero (), rect);
tmp = g_strdup_printf ("%.2f x %.2f + %.2f + %.2f",
rect[2], rect[3], rect[0], rect[1]);
add_text_row (store, "Outline", tmp);

View File

@ -0,0 +1,24 @@
repeat {
bounds: 0 0 100 100;
child-bounds: 0 0 0 0;
child: color {
bounds: 0 0 20 20;
color: rgb(255,0,0);
}
}
repeat {
bounds: 0 0 100 100;
child-bounds: 0 0 20 0;
child: color {
bounds: 0 0 20 20;
color: rgb(0,128,0);
}
}
repeat {
bounds: 0 0 100 100;
child-bounds: 0 0 0 20;
child: color {
bounds: 0 0 20 20;
color: rgb(0,0,255);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

View File

@ -77,6 +77,7 @@ compare_render_tests = [
'outset_shadow_simple',
'repeat',
'repeat-no-repeat',
'repeat-empty-child-bounds',
'repeat-negative-coords',
'repeat-texture',
'scale-textures-negative-ngl',

View File

@ -152,12 +152,19 @@ test_to_float (void)
&GRAPHENE_SIZE_INIT (8, 9),
&GRAPHENE_SIZE_INIT (10, 11));
gsk_rounded_rect_to_float (&rect, flt);
gsk_rounded_rect_to_float (&rect, &GRAPHENE_POINT_INIT(0, 0), flt);
g_assert_true (flt[0] == 0. && flt[1] == 11. && flt[2] == 22. && flt[3] == 33.);
g_assert_true (flt[4] == 4. && flt[5] == 6.);
g_assert_true (flt[6] == 8. && flt[7] == 10.);
g_assert_true (flt[8] == 5. && flt[9] == 7.);
g_assert_true (flt[10] == 9. && flt[11] == 11.);
gsk_rounded_rect_to_float (&rect, &GRAPHENE_POINT_INIT(100, 200), flt);
g_assert_true (flt[0] == 100. && flt[1] == 211. && flt[2] == 22. && flt[3] == 33.);
g_assert_true (flt[4] == 4. && flt[5] == 6.);
g_assert_true (flt[6] == 8. && flt[7] == 10.);
g_assert_true (flt[8] == 5. && flt[9] == 7.);
g_assert_true (flt[10] == 9. && flt[11] == 11.);
}
#define ROUNDED_RECT_INIT_FULL(x,y,w,h,w0,h0,w1,h1,w2,h2,w3,h3) \
@ -234,6 +241,145 @@ test_intersect_with_rect (void)
}
}
static void
test_intersect (void)
{
struct {
GskRoundedRect a;
GskRoundedRect b;
GskRoundedRectIntersection result;
GskRoundedRect expected;
} test[] = {
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 0),
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(50, 50, 100, 100, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT_UNIFORM(50, 50, 50, 50, 20, 0, 20, 0),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(50, 0, 100, 100, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT(50, 0, 50, 100, 20),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(0, 50, 100, 100, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT(0, 50, 100, 50, 20),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(-50, -50, 100, 100, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT_UNIFORM(0, 0, 50, 50, 20, 0, 20, 0),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(0, -50, 100, 100, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT(0, 0, 100, 50, 20),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(-50, 0, 100, 100, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT(0, 0, 50, 100, 20),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(10, 10, 80, 80, 20),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT(10, 10, 80, 80, 20),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 20),
ROUNDED_RECT_INIT(10, 10, 80, 80, 10),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT(10, 10, 80, 80, 10),
},
{
ROUNDED_RECT_INIT(0, 0, 100, 100, 40),
ROUNDED_RECT_INIT(10, 10, 80, 80, 0),
GSK_INTERSECTION_NOT_REPRESENTABLE,
},
{
ROUNDED_RECT_INIT(10, 10, 100, 100, 40),
ROUNDED_RECT_INIT(30, 0, 40, 40, 0),
GSK_INTERSECTION_NOT_REPRESENTABLE,
},
{
ROUNDED_RECT_INIT(10, 10, 100, 100, 40),
ROUNDED_RECT_INIT(0, 0, 100, 20, 0),
GSK_INTERSECTION_NOT_REPRESENTABLE,
},
{
ROUNDED_RECT_INIT_UNIFORM(647, 18, 133, 35, 5, 0, 0, 5),
ROUNDED_RECT_INIT_UNIFORM(14, 12, 1666, 889, 8, 8, 0, 0),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT_UNIFORM(647, 18, 133, 35, 5, 0, 0, 5),
},
{
ROUNDED_RECT_INIT_UNIFORM(0, 0, 100, 100, 100, 0, 0, 0),
ROUNDED_RECT_INIT_UNIFORM(0, 0, 100, 100, 0, 0, 100, 0),
GSK_INTERSECTION_NONEMPTY,
ROUNDED_RECT_INIT_UNIFORM(0, 0, 100, 100, 100, 0, 100, 0),
},
{
ROUNDED_RECT_INIT_UNIFORM(0, 0, 100, 100, 100, 0, 0, 0),
ROUNDED_RECT_INIT_UNIFORM(-20, -20, 100, 100, 0, 0, 100, 0),
GSK_INTERSECTION_NOT_REPRESENTABLE,
},
{
ROUNDED_RECT_INIT_UNIFORM(0, 0, 50, 50, 0, 0, 50, 0),
ROUNDED_RECT_INIT_UNIFORM(0, 0, 20, 20, 20, 0, 0, 0),
GSK_INTERSECTION_NOT_REPRESENTABLE, /* FIXME: should be empty */
},
{
ROUNDED_RECT_INIT_UNIFORM(0, 0, 50, 50, 0, 0, 50, 0),
ROUNDED_RECT_INIT_UNIFORM(0, 0, 21, 21, 21, 0, 0, 0),
GSK_INTERSECTION_NOT_REPRESENTABLE,
},
};
gsize i;
for (i = 0; i < G_N_ELEMENTS (test); i++)
{
GskRoundedRect out;
GskRoundedRectIntersection res;
if (g_test_verbose ())
g_test_message ("intersection test %zu", i);
memset (&out, 0, sizeof (GskRoundedRect));
res = gsk_rounded_rect_intersection (&test[i].a, &test[i].b, &out);
g_assert_cmpint (res, ==, test[i].result);
if (res == GSK_INTERSECTION_NONEMPTY)
{
if (!gsk_rounded_rect_equal (&out, &test[i].expected))
{
char *a = gsk_rounded_rect_to_string (&test[i].a);
char *b = gsk_rounded_rect_to_string (&test[i].b);
char *expected = gsk_rounded_rect_to_string (&test[i].expected);
char *result = gsk_rounded_rect_to_string (&out);
g_test_message (" A = %s\n"
" B = %s\n"
"expected %s\n"
" got %s\n",
a, b, expected, result);
}
g_assert_true (gsk_rounded_rect_equal (&out, &test[i].expected));
}
}
}
int
main (int argc,
char *argv[])
@ -246,6 +392,7 @@ main (int argc,
g_test_add_func ("/rounded-rect/is-circular", test_is_circular);
g_test_add_func ("/rounded-rect/to-float", test_to_float);
g_test_add_func ("/rounded-rect/intersect-with-rect", test_intersect_with_rect);
g_test_add_func ("/rounded-rect/intersect", test_intersect);
return g_test_run ();
}