vulkan: Fold clip into push constants

As a side effect, the clipping data is now available inside shaders.

Not that any shader would use them yet, but they could!
This commit is contained in:
Benjamin Otte 2016-12-24 04:58:51 +01:00
parent 18b65a2378
commit 81c487b841
11 changed files with 164 additions and 44 deletions

View File

@ -501,3 +501,33 @@ gsk_rounded_rect_path (const GskRoundedRect *self,
cairo_close_path (cr);
}
/*
* Converts to the format we use in our shaders:
* vec4 rect;
* vec4 corner_widths;
* vec4 corner_heights;
* rect is (x, y, width, height), the corners are the same
* order as in the rounded rect.
*
* This is so that shaders can use just the first vec4 for
* rectilinear rects, the 2nd vec4 for circular rects and
* only look at the last vec4 if they have to.
*/
void
gsk_rounded_rect_to_float (const GskRoundedRect *self,
float rect[12])
{
guint i;
rect[0] = self->bounds.origin.x;
rect[1] = self->bounds.origin.y;
rect[2] = self->bounds.size.width;
rect[3] = self->bounds.size.height;
for (i = 0; i < 4; i++)
{
rect[4 + i] = self->corner[i].width;
rect[8 + i] = self->corner[i].height;
}
}

View File

@ -11,6 +11,8 @@ 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,
float rect[12]);
G_END_DECLS

View File

@ -127,6 +127,34 @@ gsk_vulkan_clip_intersect_rounded_rect (GskVulkanClip *dest,
return TRUE;
}
gboolean
gsk_vulkan_clip_transform (GskVulkanClip *dest,
const GskVulkanClip *src,
const graphene_matrix_t *transform,
const graphene_rect_t *viewport)
{
switch (dest->type)
{
default:
g_assert_not_reached();
return FALSE;
case GSK_VULKAN_CLIP_ALL_CLIPPED:
gsk_vulkan_clip_init_copy (dest, src);
return TRUE;
case GSK_VULKAN_CLIP_NONE:
gsk_vulkan_clip_init_empty (dest, viewport);
return TRUE;
case GSK_VULKAN_CLIP_RECT:
case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
case GSK_VULKAN_CLIP_ROUNDED:
/* FIXME: Handle 2D operations, in particular transform and scale */
return FALSE;
}
}
gboolean
gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
const graphene_rect_t *rect)

View File

@ -44,6 +44,10 @@ 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;
gboolean gsk_vulkan_clip_transform (GskVulkanClip *dest,
const GskVulkanClip *src,
const graphene_matrix_t*transform,
const graphene_rect_t *viewport) G_GNUC_WARN_UNUSED_RESULT;
gboolean gsk_vulkan_clip_contains_rect (const GskVulkanClip *self,
const graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT;

View File

@ -2,13 +2,15 @@
#include "gskvulkanpushconstantsprivate.h"
#include <math.h>
#include "gskroundedrectprivate.h"
void
gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
const graphene_matrix_t *mvp)
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
@ -18,13 +20,42 @@ gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
*self = *src;
}
void
gsk_vulkan_push_constants_init_transform (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
const graphene_matrix_t *transform)
gboolean
gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
const graphene_matrix_t *transform,
const graphene_rect_t *viewport)
{
if (!gsk_vulkan_clip_transform (&self->clip, &src->clip, transform, viewport))
return FALSE;
graphene_matrix_multiply (transform, &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;
}
static void
@ -32,6 +63,7 @@ gsk_vulkan_push_constants_wire_init (GskVulkanPushConstantsWire *wire,
const GskVulkanPushConstants *self)
{
graphene_matrix_to_float (&self->mvp, wire->vertex.mvp);
gsk_rounded_rect_to_float (&self->clip.rect, wire->vertex.clip);
}
void

View File

@ -3,6 +3,7 @@
#include <gdk/gdk.h>
#include <graphene.h>
#include <gsk/gskvulkanclipprivate.h>
G_BEGIN_DECLS
@ -12,12 +13,14 @@ typedef struct _GskVulkanPushConstantsWire GskVulkanPushConstantsWire;
struct _GskVulkanPushConstants
{
graphene_matrix_t mvp;
GskVulkanClip clip;
};
struct _GskVulkanPushConstantsWire
{
struct {
float mvp[16];
float clip[12];
} vertex;
#if 0
struct {
@ -30,12 +33,21 @@ const VkPushConstantRange *
uint32_t gst_vulkan_push_constants_get_range_count (void) G_GNUC_PURE;
void gsk_vulkan_push_constants_init (GskVulkanPushConstants *constants,
const graphene_matrix_t *mvp);
const graphene_matrix_t *mvp,
const graphene_rect_t *viewport);
void gsk_vulkan_push_constants_init_copy (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src);
void gsk_vulkan_push_constants_init_transform (GskVulkanPushConstants *self,
gboolean gsk_vulkan_push_constants_transform (GskVulkanPushConstants *self,
const GskVulkanPushConstants *src,
const graphene_matrix_t *transform);
const graphene_matrix_t *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_vertex (const GskVulkanPushConstants *self,
VkCommandBuffer command_buffer,

View File

@ -92,7 +92,6 @@ void
gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
GskVulkanRender *render,
const GskVulkanPushConstants *constants,
const GskVulkanClip *clip,
GskRenderNode *node)
{
GskVulkanOp op = {
@ -111,24 +110,24 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
case GSK_CAIRO_NODE:
if (gsk_cairo_node_get_surface (node) == NULL)
return;
if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
FALLBACK ("Cairo nodes can't deal with clip type %u\n", clip->type);
if (!gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
FALLBACK ("Cairo nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_SURFACE;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_BLIT);
g_array_append_val (self->render_ops, op);
return;
case GSK_TEXTURE_NODE:
if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
FALLBACK ("Texture nodes can't deal with clip type %u\n", clip->type);
if (!gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
FALLBACK ("Texture nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_TEXTURE;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_BLIT);
g_array_append_val (self->render_ops, op);
return;
case GSK_COLOR_NODE:
if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
FALLBACK ("Color nodes can't deal with clip type %u\n", clip->type);
if (!gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
FALLBACK ("Color nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_COLOR;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_COLOR);
g_array_append_val (self->render_ops, op);
@ -140,7 +139,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
for (i = 0; i < gsk_container_node_get_n_children (node); i++)
{
gsk_vulkan_render_pass_add_node (self, render, constants, clip, gsk_container_node_get_child (node, i));
gsk_vulkan_render_pass_add_node (self, render, constants, gsk_container_node_get_child (node, i));
}
}
return;
@ -148,21 +147,21 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
case GSK_TRANSFORM_NODE:
{
graphene_matrix_t transform;
GskVulkanClip new_clip;
graphene_rect_t rect;
GskRenderNode *child;
#if 0
if (!gsk_vulkan_clip_contains_rect (clip, &node->bounds))
FALLBACK ("Transform nodes can't deal with clip type %u\n", clip->type);
#endif
gsk_transform_node_get_transform (node, &transform);
child = gsk_transform_node_get_child (node);
if (!gsk_vulkan_push_constants_transform (&op.constants.constants, constants, &transform, &child->bounds))
FALLBACK ("Transform nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
gsk_vulkan_push_constants_init_transform (&op.constants.constants, constants, &transform);
g_array_append_val (self->render_ops, op);
graphene_matrix_transform_bounds (&transform, &clip->rect.bounds, &rect);
gsk_vulkan_clip_init_empty (&new_clip, &rect);
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, &new_clip, gsk_transform_node_get_child (node));
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, child);
gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
g_array_append_val (self->render_ops, op);
}
@ -170,27 +169,37 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
case GSK_CLIP_NODE:
{
GskVulkanClip new_clip;
if (!gsk_vulkan_clip_intersect_rect (&new_clip, clip, gsk_clip_node_peek_clip (node)))
FALLBACK ("Failed to find intersection between clip of type %u and rectangle\n", clip->type);
if (new_clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
if (!gsk_vulkan_push_constants_intersect_rect (&op.constants.constants, constants, gsk_clip_node_peek_clip (node)))
FALLBACK ("Failed to find intersection between clip of type %u and rectangle\n", constants->clip.type);
if (&op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
return;
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, &new_clip, gsk_clip_node_get_child (node));
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
g_array_append_val (self->render_ops, op);
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_clip_node_get_child (node));
gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
g_array_append_val (self->render_ops, op);
}
return;
case GSK_ROUNDED_CLIP_NODE:
{
GskVulkanClip new_clip;
if (!gsk_vulkan_clip_intersect_rounded_rect (&new_clip, clip, gsk_rounded_clip_node_peek_clip (node)))
FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle\n", clip->type);
if (new_clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
if (!gsk_vulkan_push_constants_intersect_rounded (&op.constants.constants,
constants,
gsk_rounded_clip_node_peek_clip (node)))
FALLBACK ("Failed to find intersection between clip of type %u and rounded rectangle\n", constants->clip.type);
if (&op.constants.constants.clip.type == GSK_VULKAN_CLIP_ALL_CLIPPED)
return;
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, &new_clip, gsk_rounded_clip_node_get_child (node));
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
g_array_append_val (self->render_ops, op);
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, gsk_rounded_clip_node_get_child (node));
gsk_vulkan_push_constants_init_copy (&op.constants.constants, constants);
g_array_append_val (self->render_ops, op);
}
return;
}
@ -199,19 +208,19 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
return;
fallback:
switch (clip->type)
switch (constants->clip.type)
{
case GSK_VULKAN_CLIP_NONE:
op.type = GSK_VULKAN_OP_FALLBACK;
break;
case GSK_VULKAN_CLIP_RECT:
op.type = GSK_VULKAN_OP_FALLBACK_CLIP;
gsk_rounded_rect_init_copy (&op.render.clip, &clip->rect);
gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
break;
case GSK_VULKAN_CLIP_ROUNDED_CIRCULAR:
case GSK_VULKAN_CLIP_ROUNDED:
op.type = GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP;
gsk_rounded_rect_init_copy (&op.render.clip, &clip->rect);
gsk_rounded_rect_init_copy (&op.render.clip, &constants->clip.rect);
break;
case GSK_VULKAN_CLIP_ALL_CLIPPED:
default:
@ -231,15 +240,12 @@ gsk_vulkan_render_pass_add (GskVulkanRenderPass *self,
GskRenderNode *node)
{
GskVulkanOp op = { 0, };
GskVulkanClip clip;
op.type = GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS;
gsk_vulkan_push_constants_init (&op.constants.constants, mvp);
gsk_vulkan_push_constants_init (&op.constants.constants, mvp, viewport);
g_array_append_val (self->render_ops, op);
gsk_vulkan_clip_init_empty (&clip, viewport);
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, &clip, node);
gsk_vulkan_render_pass_add_node (self, render, &op.constants.constants, node);
}
static void

View File

@ -5,6 +5,9 @@ layout(location = 1) in vec2 inTexCoord;
layout(push_constant) uniform PushConstants {
mat4 mvp;
vec4 clip_bounds;
vec4 clip_widths;
vec4 clip_heights;
} push;
layout(location = 0) out vec2 outTexCoord;

Binary file not shown.

View File

@ -5,6 +5,9 @@ layout(location = 1) in vec4 inColor;
layout(push_constant) uniform PushConstants {
mat4 mvp;
vec4 clip_bounds;
vec4 clip_widths;
vec4 clip_heights;
} push;
layout(location = 0) out vec4 outColor;

Binary file not shown.