mirror of
https://github.com/brl/mutter.git
synced 2024-11-24 00:50:42 -05:00
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
96e8074a4f
commit
5d7edde37d
@ -1625,3 +1625,206 @@ clutter_layer_node_new_with_framebuffer (CoglFramebuffer *framebuffer,
|
|||||||
|
|
||||||
return (ClutterPaintNode *) res;
|
return (ClutterPaintNode *) res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ClutterBlitNode
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct _ClutterBlitNode
|
||||||
|
{
|
||||||
|
ClutterPaintNode parent_instance;
|
||||||
|
|
||||||
|
CoglFramebuffer *source;
|
||||||
|
CoglFramebuffer *dest;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _ClutterBlitNodeClass
|
||||||
|
{
|
||||||
|
ClutterPaintNodeClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
CoglFramebuffer *source;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (node->operations == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
source = blit_node->source;
|
||||||
|
if (!source)
|
||||||
|
source = clutter_paint_context_get_framebuffer (paint_context);
|
||||||
|
|
||||||
|
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 (source,
|
||||||
|
blit_node->dest,
|
||||||
|
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->source);
|
||||||
|
cogl_clear_object (&blit_node->dest);
|
||||||
|
|
||||||
|
CLUTTER_PAINT_NODE_CLASS (clutter_layer_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 *source_ptr = NULL;
|
||||||
|
g_autofree char *dest_ptr = NULL;
|
||||||
|
|
||||||
|
builder = json_builder_new ();
|
||||||
|
|
||||||
|
source_ptr = g_strdup_printf ("%p", blit_node->source);
|
||||||
|
dest_ptr = g_strdup_printf ("%p", blit_node->dest);
|
||||||
|
|
||||||
|
json_builder_begin_object (builder);
|
||||||
|
json_builder_set_member_name (builder, "source");
|
||||||
|
json_builder_add_string_value (builder, source_ptr);
|
||||||
|
json_builder_end_object (builder);
|
||||||
|
|
||||||
|
json_builder_begin_object (builder);
|
||||||
|
json_builder_set_member_name (builder, "dest");
|
||||||
|
json_builder_add_string_value (builder, dest_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:
|
||||||
|
* @source: (nullable): the source #CoglFramebuffer
|
||||||
|
* @dest: the destination #CoglFramebuffer
|
||||||
|
*
|
||||||
|
* Creates a new #ClutterBlitNode that blits @source into @dest.
|
||||||
|
*
|
||||||
|
* If @source is %NULL, the most recent framebuffer stacked into a
|
||||||
|
* #ClutterPaintContext is used.
|
||||||
|
*
|
||||||
|
* 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 *source,
|
||||||
|
CoglFramebuffer *dest)
|
||||||
|
{
|
||||||
|
ClutterBlitNode *res;
|
||||||
|
|
||||||
|
g_return_val_if_fail (cogl_is_framebuffer (dest), NULL);
|
||||||
|
|
||||||
|
res = _clutter_paint_node_create (CLUTTER_TYPE_BLIT_NODE);
|
||||||
|
res->source = source ? cogl_object_ref (source) : NULL;
|
||||||
|
res->dest = cogl_object_ref (dest);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
src_x,
|
||||||
|
src_y,
|
||||||
|
src_x + width,
|
||||||
|
src_y + height,
|
||||||
|
},
|
||||||
|
dst_x,
|
||||||
|
dst_y,
|
||||||
|
dst_x + width,
|
||||||
|
dst_y + height);
|
||||||
|
}
|
||||||
|
@ -236,6 +236,38 @@ GType clutter_transform_node_get_type (void) G_GNUC_CONST;
|
|||||||
CLUTTER_EXPORT
|
CLUTTER_EXPORT
|
||||||
ClutterPaintNode * clutter_transform_node_new (const CoglMatrix *projection);
|
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.
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
*/
|
||||||
|
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 *source,
|
||||||
|
CoglFramebuffer *dest);
|
||||||
|
|
||||||
|
|
||||||
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __CLUTTER_PAINT_NODES_H__ */
|
#endif /* __CLUTTER_PAINT_NODES_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user