3
/* XXX: we currently include config.h above as a hack so we can
4
* determine if we are running with GLES2 or not but since Clutter
5
* uses the experimental Cogl api that will also define
6
* COGL_ENABLE_EXPERIMENTAL_2_0_API. The cogl_material_ api isn't
7
* exposed if COGL_ENABLE_EXPERIMENTAL_2_0_API is defined though so we
8
* undef it before cogl.h is included */
9
#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
11
#include <clutter/clutter.h>
12
#include <cogl/cogl.h>
15
#include "test-conform-common.h"
17
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
19
static TestConformGLFunctions gl_functions;
28
#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24)
29
#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
30
#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8)
31
#define MASK_ALPHA(COLOR) (COLOR & 0xff)
34
#define GL_VERSION 0x1F02
37
#ifndef GL_MAX_TEXTURE_IMAGE_UNITS
38
#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
40
#ifndef GL_MAX_VERTEX_ATTRIBS
41
#define GL_MAX_VERTEX_ATTRIBS 0x8869
43
#ifndef GL_MAX_TEXTURE_UNITS
44
#define GL_MAX_TEXTURE_UNITS 0x84E2
47
typedef struct _TestState
49
ClutterGeometry stage_geom;
54
check_pixel (TestState *state, int x, int y, guint32 color)
59
guint8 r = MASK_RED (color);
60
guint8 g = MASK_GREEN (color);
61
guint8 b = MASK_BLUE (color);
62
guint8 a = MASK_ALPHA (color);
64
/* See what we got... */
66
y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
67
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
69
cogl_read_pixels (x_off, y_off, 1, 1,
70
COGL_READ_PIXELS_COLOR_BUFFER,
71
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
73
if (g_test_verbose ())
74
g_print (" result = %02x, %02x, %02x, %02x\n",
75
pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]);
77
if (g_test_verbose ())
78
g_print (" expected = %x, %x, %x, %x\n",
80
/* FIXME - allow for hardware in-precision */
81
g_assert (pixel[RED] == r);
82
g_assert (pixel[GREEN] == g);
83
g_assert (pixel[BLUE] == b);
86
* We ignore the alpha, since we don't know if our render target is
88
/* g_assert (pixel[ALPHA] == a); */
92
test_material_with_primitives (TestState *state,
96
CoglTextureVertex verts[4];
103
verts[1].y = QUAD_WIDTH;
105
verts[2].x = QUAD_WIDTH;
106
verts[2].y = QUAD_WIDTH;
108
verts[3].x = QUAD_WIDTH;
114
cogl_translate (x * QUAD_WIDTH, y * QUAD_WIDTH, 0);
116
cogl_rectangle (0, 0, QUAD_WIDTH, QUAD_WIDTH);
118
cogl_translate (0, QUAD_WIDTH, 0);
119
cogl_polygon (verts, 4, FALSE);
121
cogl_translate (0, QUAD_WIDTH, 0);
122
vbo = cogl_vertex_buffer_new (4);
123
cogl_vertex_buffer_add (vbo,
125
2, /* n components */
126
COGL_ATTRIBUTE_TYPE_FLOAT,
127
FALSE, /* normalized */
128
sizeof (CoglTextureVertex), /* stride */
130
cogl_vertex_buffer_draw (vbo,
131
COGL_VERTICES_MODE_TRIANGLE_FAN,
134
cogl_handle_unref (vbo);
138
check_pixel (state, x, y, color);
139
check_pixel (state, x, y+1, color);
140
check_pixel (state, x, y+2, color);
144
test_invalid_texture_layers (TestState *state, int x, int y)
146
CoglHandle material = cogl_material_new ();
148
/* explicitly create a layer with an invalid handle. This may be desireable
149
* if the user also sets a texture combine string that e.g. refers to a
151
cogl_material_set_layer (material, 0, COGL_INVALID_HANDLE);
153
cogl_set_source (material);
155
cogl_handle_unref (material);
157
/* We expect a white fallback material to be used */
158
test_material_with_primitives (state, x, y, 0xffffffff);
161
#ifdef COGL_HAS_GLES2
163
using_gles2_driver (void)
165
/* FIXME: This should probably be replaced with some way to query
166
the driver from Cogl */
167
return g_str_has_prefix ((const char *) gl_functions.glGetString (GL_VERSION),
173
test_using_all_layers (TestState *state, int x, int y)
175
CoglHandle material = cogl_material_new ();
176
guint8 white_pixel[] = { 0xff, 0xff, 0xff, 0xff };
177
guint8 red_pixel[] = { 0xff, 0x00, 0x00, 0xff };
178
CoglHandle white_texture;
179
CoglHandle red_texture;
183
/* Create a material that uses the maximum number of layers. All but
184
the last layer will use a solid white texture. The last layer
185
will use a red texture. The layers will all be modulated together
186
so the final fragment should be red. */
188
white_texture = cogl_texture_new_from_data (1, 1, COGL_TEXTURE_NONE,
189
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
190
COGL_PIXEL_FORMAT_ANY,
192
red_texture = cogl_texture_new_from_data (1, 1, COGL_TEXTURE_NONE,
193
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
194
COGL_PIXEL_FORMAT_ANY,
197
/* FIXME: Cogl doesn't provide a way to query the maximum number of
198
texture layers so for now we'll just ask GL directly. */
199
#ifdef COGL_HAS_GLES2
200
if (using_gles2_driver ())
202
int n_image_units, n_attribs;
203
/* GLES 2 doesn't have GL_MAX_TEXTURE_UNITS and it uses
204
GL_MAX_TEXTURE_IMAGE_UNITS instead */
205
gl_functions.glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &n_image_units);
206
/* Cogl needs a vertex attrib for each layer to upload the texture
208
gl_functions.glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, &n_attribs);
209
/* We can't use two of the attribs because they are used by the
210
position and color */
212
n_layers = MIN (n_attribs, n_image_units);
217
#if defined(COGL_HAS_GLES1) || defined(COGL_HAS_GL)
218
gl_functions.glGetIntegerv (GL_MAX_TEXTURE_UNITS, &n_layers);
222
/* FIXME: is this still true? */
223
/* Cogl currently can't cope with more than 32 layers so we'll also
224
limit the maximum to that. */
228
for (i = 0; i < n_layers; i++)
230
cogl_material_set_layer_filters (material, i,
231
COGL_MATERIAL_FILTER_NEAREST,
232
COGL_MATERIAL_FILTER_NEAREST);
233
cogl_material_set_layer (material, i,
234
i == n_layers - 1 ? red_texture : white_texture);
237
cogl_set_source (material);
239
cogl_handle_unref (material);
240
cogl_handle_unref (white_texture);
241
cogl_handle_unref (red_texture);
243
/* We expect the final fragment to be red */
244
test_material_with_primitives (state, x, y, 0xff0000ff);
248
test_invalid_texture_layers_with_constant_colors (TestState *state,
251
CoglHandle material = cogl_material_new ();
252
CoglColor constant_color;
254
/* explicitly create a layer with an invalid handle */
255
cogl_material_set_layer (material, 0, COGL_INVALID_HANDLE);
257
/* ignore the fallback texture on the layer and use a constant color
259
cogl_color_init_from_4ub (&constant_color, 0, 0, 255, 255);
260
cogl_material_set_layer_combine (material, 0,
261
"RGBA=REPLACE(CONSTANT)",
263
cogl_material_set_layer_combine_constant (material, 0, &constant_color);
265
cogl_set_source (material);
267
cogl_handle_unref (material);
269
/* We expect the final fragments to be green */
270
test_material_with_primitives (state, x, y, 0x0000ffff);
274
basic_ref_counting_destroy_cb (void *user_data)
276
gboolean *destroyed_flag = user_data;
278
g_assert (*destroyed_flag == FALSE);
280
*destroyed_flag = TRUE;
284
test_basic_ref_counting (void)
286
CoglMaterial *material_parent;
287
gboolean parent_destroyed = FALSE;
288
CoglMaterial *material_child;
289
gboolean child_destroyed = FALSE;
290
static CoglUserDataKey user_data_key;
292
/* This creates a material with a copy and then just unrefs them
293
both without setting them as a source. They should immediately be
294
freed. We can test whether they were freed or not by registering
295
a destroy callback with some user data */
297
material_parent = cogl_material_new ();
298
/* Set some user data so we can detect when the material is
300
cogl_object_set_user_data (COGL_OBJECT (material_parent),
303
basic_ref_counting_destroy_cb);
305
material_child = cogl_material_copy (material_parent);
306
cogl_object_set_user_data (COGL_OBJECT (material_child),
309
basic_ref_counting_destroy_cb);
311
cogl_object_unref (material_child);
312
cogl_object_unref (material_parent);
314
g_assert (parent_destroyed);
315
g_assert (child_destroyed);
319
on_paint (ClutterActor *actor, TestState *state)
321
test_invalid_texture_layers (state,
324
test_invalid_texture_layers_with_constant_colors (state,
327
test_using_all_layers (state,
331
test_basic_ref_counting ();
333
/* Comment this out if you want visual feedback for what this test paints */
335
clutter_main_quit ();
340
queue_redraw (gpointer stage)
342
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
344
return G_SOURCE_CONTINUE;
348
test_cogl_materials (TestConformSimpleFixture *fixture,
356
test_conform_get_gl_functions (&gl_functions);
358
stage = clutter_stage_new ();
360
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
361
clutter_actor_get_geometry (stage, &state.stage_geom);
363
group = clutter_group_new ();
364
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
366
/* We force continuous redrawing of the stage, since we need to skip
367
* the first few frames, and we wont be doing anything else that
368
* will trigger redrawing. */
369
idle_source = clutter_threads_add_idle (queue_redraw, stage);
371
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
373
clutter_actor_show_all (stage);
377
g_source_remove (idle_source);
379
clutter_actor_destroy (stage);
381
if (g_test_verbose ())