mutter/cogl/tests/conform/test-texture-mipmaps.c
Jonas Ådahl 49c8d42317 clutter: Introduce paint contexts
When painting, actors rely on semi global state tracked by the state to
get various things needed for painting, such as the current draw
framebuffer. Having state hidden in such ways can be very deceiving as
it's hard to follow changes spread out, and adding more and more state
that should be tracked during a paint gets annoying as they will not
change in isolation but one by one in their own places. To do this
better, introduce a paint context that is passed along in paint calls
that contains the necessary state needed during painting.

The paint context implements a framebuffer stack just as Cogl works,
which is currently needed for offscreen rendering used by clutter.

The same context is passed around for paint nodes, contents and effects
as well.

In this commit, the context is only introduced, but not used. It aims to
replace the Cogl framebuffer stack, and will allow actors to know what
view it is currently painted on.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/935
2019-12-03 19:02:14 +00:00

139 lines
4.0 KiB
C

#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <string.h>
#include "test-conform-common.h"
static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
#define TEX_SIZE 64
typedef struct _TestState
{
unsigned int padding;
} TestState;
/* Creates a texture where the pixels are evenly divided between
selecting just one of the R,G and B components */
static CoglHandle
make_texture (void)
{
guchar *tex_data = g_malloc (TEX_SIZE * TEX_SIZE * 3), *p = tex_data;
CoglHandle tex;
int x, y;
for (y = 0; y < TEX_SIZE; y++)
for (x = 0; x < TEX_SIZE; x++)
{
memset (p, 0, 3);
/* Set one of the components to full. The components should be
evenly represented so that each gets a third of the
texture */
p[(p - tex_data) / (TEX_SIZE * TEX_SIZE * 3 / 3)] = 255;
p += 3;
}
tex = test_utils_texture_new_from_data (TEX_SIZE, TEX_SIZE, TEST_UTILS_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGB_888,
COGL_PIXEL_FORMAT_ANY,
TEX_SIZE * 3,
tex_data);
g_free (tex_data);
return tex;
}
static void
on_paint (ClutterActor *actor,
ClutterPaintContext *paint_context,
TestState *state)
{
CoglHandle tex;
CoglHandle material;
uint8_t pixels[8];
tex = make_texture ();
material = cogl_material_new ();
cogl_material_set_layer (material, 0, tex);
cogl_object_unref (tex);
/* Render a 1x1 pixel quad without mipmaps */
cogl_set_source (material);
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_rectangle (0, 0, 1, 1);
/* Then with mipmaps */
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST,
COGL_MATERIAL_FILTER_NEAREST);
cogl_rectangle (1, 0, 2, 1);
cogl_object_unref (material);
/* Read back the two pixels we rendered */
cogl_read_pixels (0, 0, 2, 1,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
pixels);
/* The first pixel should be just one of the colors from the
texture. It doesn't matter which one */
g_assert ((pixels[0] == 255 && pixels[1] == 0 && pixels[2] == 0) ||
(pixels[0] == 0 && pixels[1] == 255 && pixels[2] == 0) ||
(pixels[0] == 0 && pixels[1] == 0 && pixels[2] == 255));
/* The second pixel should be more or less the average of all of the
pixels in the texture. Each component gets a third of the image
so each component should be approximately 255/3 */
g_assert (ABS (pixels[4] - 255 / 3) <= 3 &&
ABS (pixels[5] - 255 / 3) <= 3 &&
ABS (pixels[6] - 255 / 3) <= 3);
/* Comment this out if you want visual feedback for what this test paints */
#if 1
clutter_main_quit ();
#endif
}
static gboolean
queue_redraw (void *stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return TRUE;
}
void
test_texture_mipmaps (TestUtilsGTestFixture *fixture,
void *data)
{
TestState state;
ClutterActor *stage;
ClutterActor *group;
unsigned int idle_source;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
group = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, stage);
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (stage);
clutter_main ();
g_clear_handle_id (&idle_source, g_source_remove);
if (cogl_test_verbose ())
g_print ("OK\n");
}