clutter: Introduce geometric picking
Currently, Clutter does picking by drawing with Cogl and reading the pixel that's beneath the given point. Since Cogl has a journal that records drawing operations, and has optimizations to read a single pixel from a list of rectangle, it would be expected that we would hit this fast path and not flush the journal while picking. However, that's not the case: dithering, clipping with scissors, etc, can all flush the journal, issuing commands to the GPU and making picking slow. On NVidia-based systems, this glReadPixels() call is extremely costly. Introduce geometric picking, and avoid using the Cogl journal entirely. Do this by introducing a stack of actors in ClutterStage. This stack is cached, but for now, don't use the cache as much as possible. The picking routines are still tied to painting. When projecting the actor vertexes, do it manually and take the modelview matrix of the framebuffer into account as well. CPU usage on an Intel i7-7700, tested with two different GPUs/drivers: | | Intel | Nvidia | | ------: | --------: | -----: | | Moving the mouse: | | Before | 10% | 10% | | After | 6% | 6% | | Moving a window: | | Before | 23% | 81% | | After | 19% | 40% | Closes: https://gitlab.gnome.org/GNOME/mutter/issues/154, https://gitlab.gnome.org/GNOME/mutter/issues/691 Helps significantly with: https://gitlab.gnome.org/GNOME/mutter/issues/283, https://gitlab.gnome.org/GNOME/mutter/issues/590, https://gitlab.gnome.org/GNOME/mutter/issues/700 v2: Fix code style issues Simplify quadrilateral checks Remove the 0.5f hack Differentiate axis-aligned rectangles https://gitlab.gnome.org/GNOME/mutter/merge_requests/189
This commit is contained in:

committed by
Jonas Ådahl

parent
a70823dd1c
commit
14c706e51b
@ -7,7 +7,6 @@
|
||||
#define STAGE_HEIGHT 480
|
||||
#define ACTORS_X 12
|
||||
#define ACTORS_Y 16
|
||||
#define SHIFT_STEP STAGE_WIDTH / ACTORS_X
|
||||
|
||||
typedef struct _State State;
|
||||
|
||||
@ -22,84 +21,11 @@ struct _State
|
||||
gboolean pass;
|
||||
};
|
||||
|
||||
struct _ShiftEffect
|
||||
{
|
||||
ClutterShaderEffect parent_instance;
|
||||
};
|
||||
|
||||
struct _ShiftEffectClass
|
||||
{
|
||||
ClutterShaderEffectClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct _ShiftEffect ShiftEffect;
|
||||
typedef struct _ShiftEffectClass ShiftEffectClass;
|
||||
|
||||
#define TYPE_SHIFT_EFFECT (shift_effect_get_type ())
|
||||
|
||||
GType shift_effect_get_type (void);
|
||||
|
||||
G_DEFINE_TYPE (ShiftEffect,
|
||||
shift_effect,
|
||||
CLUTTER_TYPE_SHADER_EFFECT);
|
||||
|
||||
static void
|
||||
shader_paint (ClutterEffect *effect,
|
||||
ClutterEffectPaintFlags flags)
|
||||
{
|
||||
ClutterShaderEffect *shader = CLUTTER_SHADER_EFFECT (effect);
|
||||
float tex_width;
|
||||
ClutterActor *actor =
|
||||
clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
|
||||
|
||||
if (g_test_verbose ())
|
||||
g_debug ("shader_paint");
|
||||
|
||||
clutter_shader_effect_set_shader_source (shader,
|
||||
"uniform sampler2D tex;\n"
|
||||
"uniform float step;\n"
|
||||
"void main (void)\n"
|
||||
"{\n"
|
||||
" cogl_color_out = texture2D(tex, vec2 (cogl_tex_coord_in[0].s + step,\n"
|
||||
" cogl_tex_coord_in[0].t));\n"
|
||||
"}\n");
|
||||
|
||||
tex_width = clutter_actor_get_width (actor);
|
||||
|
||||
clutter_shader_effect_set_uniform (shader, "tex", G_TYPE_INT, 1, 0);
|
||||
clutter_shader_effect_set_uniform (shader, "step", G_TYPE_FLOAT, 1,
|
||||
SHIFT_STEP / tex_width);
|
||||
|
||||
CLUTTER_EFFECT_CLASS (shift_effect_parent_class)->paint (effect, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
shader_pick (ClutterEffect *effect,
|
||||
ClutterEffectPaintFlags flags)
|
||||
{
|
||||
shader_paint (effect, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
shift_effect_class_init (ShiftEffectClass *klass)
|
||||
{
|
||||
ClutterEffectClass *shader_class = CLUTTER_EFFECT_CLASS (klass);
|
||||
|
||||
shader_class->paint = shader_paint;
|
||||
shader_class->pick = shader_pick;
|
||||
}
|
||||
|
||||
static void
|
||||
shift_effect_init (ShiftEffect *self)
|
||||
{
|
||||
}
|
||||
|
||||
static const char *test_passes[] = {
|
||||
"No covering actor",
|
||||
"Invisible covering actor",
|
||||
"Clipped covering actor",
|
||||
"Blur effect",
|
||||
"Shift effect",
|
||||
};
|
||||
|
||||
static gboolean
|
||||
@ -167,30 +93,10 @@ on_timeout (gpointer data)
|
||||
if (g_test_verbose ())
|
||||
g_print ("With blur effect:\n");
|
||||
}
|
||||
else if (test_num == 4)
|
||||
{
|
||||
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
|
||||
continue;
|
||||
|
||||
clutter_actor_hide (over_actor);
|
||||
clutter_actor_remove_effect_by_name (CLUTTER_ACTOR (state->stage),
|
||||
"blur");
|
||||
|
||||
clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage),
|
||||
"shift",
|
||||
g_object_new (TYPE_SHIFT_EFFECT,
|
||||
NULL));
|
||||
|
||||
if (g_test_verbose ())
|
||||
g_print ("With shift effect:\n");
|
||||
}
|
||||
|
||||
for (y = 0; y < ACTORS_Y; y++)
|
||||
{
|
||||
if (test_num == 4)
|
||||
x = 1;
|
||||
else
|
||||
x = 0;
|
||||
x = 0;
|
||||
|
||||
for (; x < ACTORS_X; x++)
|
||||
{
|
||||
@ -200,9 +106,6 @@ on_timeout (gpointer data)
|
||||
|
||||
pick_x = x * state->actor_width + state->actor_width / 2;
|
||||
|
||||
if (test_num == 4)
|
||||
pick_x -= SHIFT_STEP;
|
||||
|
||||
actor =
|
||||
clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
|
||||
CLUTTER_PICK_ALL,
|
||||
|
@ -40,7 +40,6 @@ clutter_conform_tests_deprecated_tests = [
|
||||
'behaviours',
|
||||
'group',
|
||||
'rectangle',
|
||||
'texture',
|
||||
]
|
||||
|
||||
clutter_conform_tests = []
|
||||
|
@ -1,86 +0,0 @@
|
||||
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
|
||||
#include <clutter/clutter.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
static CoglHandle
|
||||
make_texture (void)
|
||||
{
|
||||
guint32 *data = g_malloc (100 * 100 * 4);
|
||||
int x;
|
||||
int y;
|
||||
|
||||
for (y = 0; y < 100; y ++)
|
||||
for (x = 0; x < 100; x++)
|
||||
{
|
||||
if (x < 50 && y < 50)
|
||||
data[y * 100 + x] = 0xff00ff00;
|
||||
else
|
||||
data[y * 100 + x] = 0xff00ffff;
|
||||
}
|
||||
return cogl_texture_new_from_data (100,
|
||||
100,
|
||||
COGL_TEXTURE_NONE,
|
||||
COGL_PIXEL_FORMAT_ARGB_8888,
|
||||
COGL_PIXEL_FORMAT_ARGB_8888,
|
||||
400,
|
||||
(guchar *)data);
|
||||
}
|
||||
|
||||
static void
|
||||
texture_pick_with_alpha (void)
|
||||
{
|
||||
ClutterTexture *tex = CLUTTER_TEXTURE (clutter_texture_new ());
|
||||
ClutterStage *stage = CLUTTER_STAGE (clutter_test_get_stage ());
|
||||
ClutterActor *actor;
|
||||
|
||||
clutter_texture_set_cogl_texture (tex, make_texture ());
|
||||
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (stage), CLUTTER_ACTOR (tex));
|
||||
|
||||
clutter_actor_show (CLUTTER_ACTOR (stage));
|
||||
|
||||
if (g_test_verbose ())
|
||||
{
|
||||
g_print ("\nstage = %p\n", stage);
|
||||
g_print ("texture = %p\n\n", tex);
|
||||
}
|
||||
|
||||
clutter_texture_set_pick_with_alpha (tex, TRUE);
|
||||
if (g_test_verbose ())
|
||||
g_print ("Testing with pick-with-alpha enabled:\n");
|
||||
|
||||
/* This should fall through and hit the stage: */
|
||||
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10);
|
||||
if (g_test_verbose ())
|
||||
g_print ("actor @ (10, 10) = %p\n", actor);
|
||||
g_assert (actor == CLUTTER_ACTOR (stage));
|
||||
|
||||
/* The rest should hit the texture */
|
||||
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 10);
|
||||
if (g_test_verbose ())
|
||||
g_print ("actor @ (90, 10) = %p\n", actor);
|
||||
g_assert (actor == CLUTTER_ACTOR (tex));
|
||||
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 90);
|
||||
if (g_test_verbose ())
|
||||
g_print ("actor @ (90, 90) = %p\n", actor);
|
||||
g_assert (actor == CLUTTER_ACTOR (tex));
|
||||
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 90);
|
||||
if (g_test_verbose ())
|
||||
g_print ("actor @ (10, 90) = %p\n", actor);
|
||||
g_assert (actor == CLUTTER_ACTOR (tex));
|
||||
|
||||
clutter_texture_set_pick_with_alpha (tex, FALSE);
|
||||
if (g_test_verbose ())
|
||||
g_print ("Testing with pick-with-alpha disabled:\n");
|
||||
|
||||
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10);
|
||||
if (g_test_verbose ())
|
||||
g_print ("actor @ (10, 10) = %p\n", actor);
|
||||
g_assert (actor == CLUTTER_ACTOR (tex));
|
||||
}
|
||||
|
||||
CLUTTER_TEST_SUITE (
|
||||
CLUTTER_TEST_UNIT ("/texture/pick-with-alpha", texture_pick_with_alpha)
|
||||
)
|
Reference in New Issue
Block a user