1 #include <clutter/clutter.h>
2 #include <cogl/cogl.h>
3 #include <string.h>
4 
5 #include "test-conform-common.h"
6 
7 static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
8 
9 #define TEX_SIZE 64
10 
11 typedef struct _TestState
12 {
13   unsigned int padding;
14 } TestState;
15 
16 /* Creates a texture where the pixels are evenly divided between
17    selecting just one of the R,G and B components */
18 static CoglHandle
make_texture(void)19 make_texture (void)
20 {
21   guchar *tex_data = g_malloc (TEX_SIZE * TEX_SIZE * 3), *p = tex_data;
22   CoglHandle tex;
23   int x, y;
24 
25   for (y = 0; y < TEX_SIZE; y++)
26     for (x = 0; x < TEX_SIZE; x++)
27       {
28         memset (p, 0, 3);
29         /* Set one of the components to full. The components should be
30            evenly represented so that each gets a third of the
31            texture */
32         p[(p - tex_data) / (TEX_SIZE * TEX_SIZE * 3 / 3)] = 255;
33         p += 3;
34       }
35 
36   tex = test_utils_texture_new_from_data (TEX_SIZE, TEX_SIZE, TEST_UTILS_TEXTURE_NONE,
37                                     COGL_PIXEL_FORMAT_RGB_888,
38                                     COGL_PIXEL_FORMAT_ANY,
39                                     TEX_SIZE * 3,
40                                     tex_data);
41 
42   g_free (tex_data);
43 
44   return tex;
45 }
46 
47 static void
on_paint(ClutterActor * actor,ClutterPaintContext * paint_context,TestState * state)48 on_paint (ClutterActor        *actor,
49           ClutterPaintContext *paint_context,
50           TestState           *state)
51 {
52   CoglHandle tex;
53   CoglHandle material;
54   uint8_t pixels[8];
55 
56   tex = make_texture ();
57   material = cogl_material_new ();
58   cogl_material_set_layer (material, 0, tex);
59   cogl_object_unref (tex);
60 
61   /* Render a 1x1 pixel quad without mipmaps */
62   cogl_set_source (material);
63   cogl_material_set_layer_filters (material, 0,
64                                    COGL_MATERIAL_FILTER_NEAREST,
65                                    COGL_MATERIAL_FILTER_NEAREST);
66   cogl_rectangle (0, 0, 1, 1);
67   /* Then with mipmaps */
68   cogl_material_set_layer_filters (material, 0,
69                                    COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST,
70                                    COGL_MATERIAL_FILTER_NEAREST);
71   cogl_rectangle (1, 0, 2, 1);
72 
73   cogl_object_unref (material);
74 
75   /* Read back the two pixels we rendered */
76   cogl_read_pixels (0, 0, 2, 1,
77                     COGL_READ_PIXELS_COLOR_BUFFER,
78                     COGL_PIXEL_FORMAT_RGBA_8888_PRE,
79                     pixels);
80 
81   /* The first pixel should be just one of the colors from the
82      texture. It doesn't matter which one */
83   g_assert ((pixels[0] == 255 && pixels[1] == 0 && pixels[2] == 0) ||
84             (pixels[0] == 0 && pixels[1] == 255 && pixels[2] == 0) ||
85             (pixels[0] == 0 && pixels[1] == 0 && pixels[2] == 255));
86   /* The second pixel should be more or less the average of all of the
87      pixels in the texture. Each component gets a third of the image
88      so each component should be approximately 255/3 */
89   g_assert (ABS (pixels[4] - 255 / 3) <= 3 &&
90             ABS (pixels[5] - 255 / 3) <= 3 &&
91             ABS (pixels[6] - 255 / 3) <= 3);
92 
93   /* Comment this out if you want visual feedback for what this test paints */
94 #if 1
95   clutter_test_quit ();
96 #endif
97 }
98 
99 static gboolean
queue_redraw(void * stage)100 queue_redraw (void *stage)
101 {
102   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
103 
104   return TRUE;
105 }
106 
107 void
test_texture_mipmaps(TestUtilsGTestFixture * fixture,void * data)108 test_texture_mipmaps (TestUtilsGTestFixture *fixture,
109                            void *data)
110 {
111   TestState state;
112   ClutterActor *stage;
113   ClutterActor *group;
114   unsigned int idle_source;
115 
116   stage = clutter_stage_get_default ();
117 
118   clutter_actor_set_background_color (CLUTTER_ACTOR (stage), &stage_color);
119 
120   group = clutter_actor_new ();
121   clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
122 
123   /* We force continuous redrawing of the stage, since we need to skip
124    * the first few frames, and we won't be doing anything else that
125    * will trigger redrawing. */
126   idle_source = g_idle_add (queue_redraw, stage);
127 
128   g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
129 
130   clutter_actor_show (stage);
131 
132   clutter_test_main ();
133 
134   g_clear_handle_id (&idle_source, g_source_remove);
135 
136   if (cogl_test_verbose ())
137     g_print ("OK\n");
138 }
139