st: Use blur node to render shadow pipeline
It is generally faster than downloading the texture, blurring with the CPU, and uploading the blurred texture. Notice that 'n_values' is calculated differently from the blur_pixels() function; that's because it needs to match Clutter's blur shader interpretation of sigma [1]. [1] https://gitlab.gnome.org/GNOME/mutter/-/blob/master/clutter/clutter/clutter-blur.c#L89 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1539>
This commit is contained in:
parent
80a5b55a7a
commit
e59069c012
@ -382,46 +382,74 @@ _st_create_shadow_pipeline (StShadow *shadow_spec,
|
|||||||
{
|
{
|
||||||
ClutterBackend *backend = clutter_get_default_backend ();
|
ClutterBackend *backend = clutter_get_default_backend ();
|
||||||
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
||||||
GError *error = NULL;
|
g_autoptr (ClutterPaintNode) texture_node = NULL;
|
||||||
|
g_autoptr (ClutterPaintNode) blur_node = NULL;
|
||||||
static CoglPipeline *shadow_pipeline_template = NULL;
|
g_autoptr (CoglOffscreen) offscreen = NULL;
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
ClutterPaintContext *paint_context;
|
||||||
|
CoglFramebuffer *fb;
|
||||||
CoglPipeline *pipeline;
|
CoglPipeline *pipeline;
|
||||||
CoglTexture *texture;
|
CoglTexture *texture;
|
||||||
guchar *pixels_in, *pixels_out;
|
double sigma;
|
||||||
gint width_in, height_in, rowstride_in;
|
int src_height, dst_height;
|
||||||
gint width_out, height_out, rowstride_out;
|
int src_width, dst_width;
|
||||||
|
int n_values;
|
||||||
|
int half;
|
||||||
|
|
||||||
|
static CoglPipeline *shadow_pipeline_template = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (shadow_spec != NULL, NULL);
|
g_return_val_if_fail (shadow_spec != NULL, NULL);
|
||||||
g_return_val_if_fail (src_texture != NULL, NULL);
|
g_return_val_if_fail (src_texture != NULL, NULL);
|
||||||
|
|
||||||
width_in = cogl_texture_get_width (src_texture);
|
sigma = shadow_spec->blur / 2.f;
|
||||||
height_in = cogl_texture_get_height (src_texture);
|
n_values = ceil (3 * sigma);
|
||||||
rowstride_in = (width_in + 3) & ~3;
|
half = n_values / 2;
|
||||||
|
|
||||||
pixels_in = g_malloc0 (rowstride_in * height_in);
|
src_width = cogl_texture_get_width (src_texture);
|
||||||
|
src_height = cogl_texture_get_height (src_texture);
|
||||||
|
dst_width = src_width + 2 * half;
|
||||||
|
dst_height = src_height + 2 * half;
|
||||||
|
|
||||||
cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8,
|
texture = cogl_texture_2d_new_with_size (ctx, dst_width, dst_height);
|
||||||
rowstride_in, pixels_in);
|
if (!texture)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
|
offscreen = cogl_offscreen_new_with_texture (texture);
|
||||||
shadow_spec->blur * resource_scale,
|
fb = COGL_FRAMEBUFFER (offscreen);
|
||||||
&width_out, &height_out, &rowstride_out);
|
if (!cogl_framebuffer_allocate (fb, &error))
|
||||||
g_free (pixels_in);
|
|
||||||
|
|
||||||
texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, width_out, height_out,
|
|
||||||
COGL_PIXEL_FORMAT_A_8,
|
|
||||||
rowstride_out,
|
|
||||||
pixels_out,
|
|
||||||
&error));
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
{
|
||||||
g_warning ("Failed to allocate texture: %s", error->message);
|
cogl_clear_object (&texture);
|
||||||
g_error_free (error);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (pixels_out);
|
cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0.f, 0.f, 0.f, 0.f);
|
||||||
|
cogl_framebuffer_orthographic (fb, 0, 0, dst_width, dst_height, 0, 1.0);
|
||||||
|
cogl_framebuffer_scale (fb, resource_scale, resource_scale, 1);
|
||||||
|
|
||||||
|
/* Blur */
|
||||||
|
blur_node = clutter_blur_node_new (dst_width, dst_height, sigma);
|
||||||
|
clutter_paint_node_add_rectangle (blur_node,
|
||||||
|
&(ClutterActorBox) {
|
||||||
|
0.f, 0.f,
|
||||||
|
dst_width, dst_height,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Texture */
|
||||||
|
texture_node = clutter_texture_node_new (src_texture,
|
||||||
|
0,
|
||||||
|
CLUTTER_SCALING_FILTER_NEAREST,
|
||||||
|
CLUTTER_SCALING_FILTER_NEAREST);
|
||||||
|
clutter_paint_node_add_child (blur_node, texture_node);
|
||||||
|
clutter_paint_node_add_rectangle (texture_node,
|
||||||
|
&(ClutterActorBox) {
|
||||||
|
half, half,
|
||||||
|
src_width, src_height,
|
||||||
|
});
|
||||||
|
|
||||||
|
paint_context =
|
||||||
|
clutter_paint_context_new_for_framebuffer (fb, NULL, CLUTTER_PAINT_FLAG_NONE);
|
||||||
|
clutter_paint_node_paint (blur_node, paint_context);
|
||||||
|
clutter_paint_context_destroy (paint_context);
|
||||||
|
|
||||||
if (G_UNLIKELY (shadow_pipeline_template == NULL))
|
if (G_UNLIKELY (shadow_pipeline_template == NULL))
|
||||||
{
|
{
|
||||||
@ -438,8 +466,7 @@ _st_create_shadow_pipeline (StShadow *shadow_spec,
|
|||||||
pipeline = cogl_pipeline_copy (shadow_pipeline_template);
|
pipeline = cogl_pipeline_copy (shadow_pipeline_template);
|
||||||
cogl_pipeline_set_layer_texture (pipeline, 0, texture);
|
cogl_pipeline_set_layer_texture (pipeline, 0, texture);
|
||||||
|
|
||||||
if (texture)
|
cogl_clear_object (&texture);
|
||||||
cogl_object_unref (texture);
|
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user