Introduce ClutterBlitNode
It is not possible to express a blit operation using paint nodes as of now. This is a requirement for GNOME Shell, e.g., to implement its blur effect. Add a new ClutterBlitNode node that takes two framebuffers as input, and blits source into dest according to added rectangles. Because this paint node uses the rectangles in a different way compared to all the other nodes, add an auxiliary method to ensure all blit operations are valid. https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1340
This commit is contained in:
parent
bc81f17d5f
commit
4a69e70000
@ -1625,3 +1625,194 @@ clutter_layer_node_new_with_framebuffer (CoglFramebuffer *framebuffer,
|
||||
|
||||
return (ClutterPaintNode *) res;
|
||||
}
|
||||
|
||||
/*
|
||||
* ClutterBlitNode
|
||||
*/
|
||||
|
||||
struct _ClutterBlitNode
|
||||
{
|
||||
ClutterPaintNode parent_instance;
|
||||
|
||||
CoglFramebuffer *src;
|
||||
CoglFramebuffer *dst;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ClutterBlitNode, clutter_blit_node, CLUTTER_TYPE_PAINT_NODE)
|
||||
|
||||
static gboolean
|
||||
clutter_blit_node_pre_draw (ClutterPaintNode *node,
|
||||
ClutterPaintContext *paint_context)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_blit_node_draw (ClutterPaintNode *node,
|
||||
ClutterPaintContext *paint_context)
|
||||
{
|
||||
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
|
||||
g_autoptr (GError) error = NULL;
|
||||
guint i;
|
||||
|
||||
if (node->operations == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < node->operations->len; i++)
|
||||
{
|
||||
const ClutterPaintOperation *op;
|
||||
float op_width, op_height;
|
||||
|
||||
op = &g_array_index (node->operations, ClutterPaintOperation, i);
|
||||
|
||||
switch (op->opcode)
|
||||
{
|
||||
case PAINT_OP_INVALID:
|
||||
break;
|
||||
|
||||
case PAINT_OP_TEX_RECT:
|
||||
op_width = op->op.texrect[6] - op->op.texrect[4];
|
||||
op_height = op->op.texrect[7] - op->op.texrect[5];
|
||||
|
||||
cogl_blit_framebuffer (blit_node->src,
|
||||
blit_node->dst,
|
||||
op->op.texrect[0],
|
||||
op->op.texrect[1],
|
||||
op->op.texrect[4],
|
||||
op->op.texrect[5],
|
||||
op_width,
|
||||
op_height,
|
||||
&error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Error blitting framebuffers: %s", error->message);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case PAINT_OP_MULTITEX_RECT:
|
||||
case PAINT_OP_PRIMITIVE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_blit_node_finalize (ClutterPaintNode *node)
|
||||
{
|
||||
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
|
||||
|
||||
cogl_clear_object (&blit_node->src);
|
||||
cogl_clear_object (&blit_node->dst);
|
||||
|
||||
CLUTTER_PAINT_NODE_CLASS (clutter_blit_node_parent_class)->finalize (node);
|
||||
}
|
||||
|
||||
static JsonNode *
|
||||
clutter_blit_node_serialize (ClutterPaintNode *node)
|
||||
{
|
||||
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
|
||||
g_autoptr (JsonBuilder) builder = NULL;
|
||||
g_autofree char *src_ptr = NULL;
|
||||
g_autofree char *dst_ptr = NULL;
|
||||
|
||||
builder = json_builder_new ();
|
||||
|
||||
src_ptr = g_strdup_printf ("%p", blit_node->src);
|
||||
dst_ptr = g_strdup_printf ("%p", blit_node->dst);
|
||||
|
||||
json_builder_begin_object (builder);
|
||||
json_builder_set_member_name (builder, "source");
|
||||
json_builder_add_string_value (builder, src_ptr);
|
||||
json_builder_end_object (builder);
|
||||
|
||||
json_builder_begin_object (builder);
|
||||
json_builder_set_member_name (builder, "dst");
|
||||
json_builder_add_string_value (builder, dst_ptr);
|
||||
json_builder_end_object (builder);
|
||||
|
||||
return json_builder_get_root (builder);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_blit_node_class_init (ClutterTransformNodeClass *klass)
|
||||
{
|
||||
ClutterPaintNodeClass *node_class;
|
||||
|
||||
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
|
||||
node_class->pre_draw = clutter_blit_node_pre_draw;
|
||||
node_class->draw = clutter_blit_node_draw;
|
||||
node_class->finalize = clutter_blit_node_finalize;
|
||||
node_class->serialize = clutter_blit_node_serialize;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_blit_node_init (ClutterBlitNode *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_blit_node_new:
|
||||
* @src: the source #CoglFramebuffer
|
||||
* @dst: the destination #CoglFramebuffer
|
||||
*
|
||||
* Creates a new #ClutterBlitNode that blits @src into @dst.
|
||||
*
|
||||
* You must only add rectangles using clutter_blit_node_add_blit_rectangle().
|
||||
*
|
||||
* Return value: (transfer full): the newly created #ClutterBlitNode.
|
||||
* Use clutter_paint_node_unref() when done.
|
||||
*/
|
||||
ClutterPaintNode *
|
||||
clutter_blit_node_new (CoglFramebuffer *src,
|
||||
CoglFramebuffer *dst)
|
||||
{
|
||||
ClutterBlitNode *res;
|
||||
|
||||
g_return_val_if_fail (cogl_is_framebuffer (src), NULL);
|
||||
g_return_val_if_fail (cogl_is_framebuffer (dst), NULL);
|
||||
|
||||
res = _clutter_paint_node_create (CLUTTER_TYPE_BLIT_NODE);
|
||||
res->src = cogl_object_ref (src);
|
||||
res->dst = cogl_object_ref (dst);
|
||||
|
||||
return (ClutterPaintNode *) res;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_blit_node_add_blit_rectangle:
|
||||
* @blit_node: a #ClutterBlitNode
|
||||
* @src_x: Source x position
|
||||
* @src_y: Source y position
|
||||
* @dst_x: Destination x position
|
||||
* @dst_y: Destination y position
|
||||
* @width: Width of region to copy
|
||||
* @height: Height of region to copy
|
||||
*
|
||||
* Adds a new blit rectangle to the stack of rectangles. All the
|
||||
* constraints of cogl_blit_framebuffer() apply here.
|
||||
*/
|
||||
void
|
||||
clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_BLIT_NODE (blit_node));
|
||||
|
||||
clutter_paint_node_add_texture_rectangle (CLUTTER_PAINT_NODE (blit_node),
|
||||
&(ClutterActorBox) {
|
||||
.x1 = src_x,
|
||||
.y1 = src_y,
|
||||
.x2 = src_x + width,
|
||||
.y2 = src_y + height,
|
||||
},
|
||||
dst_x,
|
||||
dst_y,
|
||||
dst_x + width,
|
||||
dst_y + height);
|
||||
}
|
||||
|
@ -236,6 +236,36 @@ GType clutter_transform_node_get_type (void) G_GNUC_CONST;
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintNode * clutter_transform_node_new (const CoglMatrix *projection);
|
||||
|
||||
#define CLUTTER_TYPE_BLIT_NODE (clutter_blit_node_get_type ())
|
||||
#define CLUTTER_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BLIT_NODE, ClutterBlitNode))
|
||||
#define CLUTTER_IS_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BLIT_NODE))
|
||||
|
||||
/*
|
||||
* ClutterBlitNode:
|
||||
*
|
||||
* The #ClutterLayerNode structure is an opaque
|
||||
* type whose members cannot be directly accessed.
|
||||
*/
|
||||
typedef struct _ClutterBlitNode ClutterBlitNode;
|
||||
typedef struct _ClutterPaintNodeClass ClutterBlitNodeClass;
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GType clutter_blit_node_get_type (void) G_GNUC_CONST;
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintNode * clutter_blit_node_new (CoglFramebuffer *src,
|
||||
CoglFramebuffer *dst);
|
||||
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_PAINT_NODES_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user