"Initial commit to Gerrit"
[profile/ivi/cogl.git] / tests / conform / test-blend-strings.c
1 #include <cogl/cogl.h>
2
3 #include <string.h>
4
5 #include "test-utils.h"
6
7 #define QUAD_WIDTH 20
8
9 #define RED 0
10 #define GREEN 1
11 #define BLUE 2
12 #define ALPHA 3
13
14 #define MASK_RED(COLOR)   ((COLOR & 0xff000000) >> 24)
15 #define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16)
16 #define MASK_BLUE(COLOR)  ((COLOR & 0xff00) >> 8)
17 #define MASK_ALPHA(COLOR) (COLOR & 0xff)
18
19 #define BLEND_CONSTANT_UNUSED 0xDEADBEEF
20 #define TEX_CONSTANT_UNUSED   0xDEADBEEF
21
22 typedef struct _TestState
23 {
24   CoglContext *ctx;
25 } TestState;
26
27
28 static void
29 test_blend (TestState *state,
30             int x,
31             int y,
32             guint32 src_color,
33             guint32 dst_color,
34             const char *blend_string,
35             guint32 blend_constant,
36             guint32 expected_result)
37 {
38   /* src color */
39   guint8 Sr = MASK_RED (src_color);
40   guint8 Sg = MASK_GREEN (src_color);
41   guint8 Sb = MASK_BLUE (src_color);
42   guint8 Sa = MASK_ALPHA (src_color);
43   /* dest color */
44   guint8 Dr = MASK_RED (dst_color);
45   guint8 Dg = MASK_GREEN (dst_color);
46   guint8 Db = MASK_BLUE (dst_color);
47   guint8 Da = MASK_ALPHA (dst_color);
48   /* blend constant - when applicable */
49   guint8 Br = MASK_RED (blend_constant);
50   guint8 Bg = MASK_GREEN (blend_constant);
51   guint8 Bb = MASK_BLUE (blend_constant);
52   guint8 Ba = MASK_ALPHA (blend_constant);
53   CoglColor blend_const_color;
54
55   CoglHandle material;
56   CoglPipeline *pipeline;
57   gboolean status;
58   GError *error = NULL;
59   int y_off;
60   int x_off;
61
62   /* First write out the destination color without any blending... */
63   pipeline = cogl_pipeline_new (ctx);
64   cogl_pipeline_set_color4ub (pipeline, Dr, Dg, Db, Da);
65   cogl_pipeline_set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL);
66   cogl_set_source (pipeline);
67   cogl_rectangle (x * QUAD_WIDTH,
68                   y * QUAD_WIDTH,
69                   x * QUAD_WIDTH + QUAD_WIDTH,
70                   y * QUAD_WIDTH + QUAD_WIDTH);
71   cogl_object_unref (pipeline);
72
73   /*
74    * Now blend a rectangle over our well defined destination:
75    */
76
77   pipeline = cogl_pipeline_new (ctx);
78   cogl_pipeline_set_color4ub (pipeline, Sr, Sg, Sb, Sa);
79
80   status = cogl_pipeline_set_blend (pipeline, blend_string, &error);
81   if (!status)
82     {
83       /* It's not strictly a test failure; you need a more capable GPU or
84        * driver to test this blend string. */
85       if (cogl_test_verbose ())
86         {
87           g_debug ("Failed to test blend string %s: %s",
88                    blend_string, error->message);
89           g_print ("Skipping\n");
90         }
91       return;
92     }
93
94   cogl_color_init_from_4ub (&blend_const_color, Br, Bg, Bb, Ba);
95   cogl_pipeline_set_blend_constant (pipeline, &blend_const_color);
96
97   cogl_set_source (pipeline);
98   cogl_rectangle (x * QUAD_WIDTH,
99                   y * QUAD_WIDTH,
100                   x * QUAD_WIDTH + QUAD_WIDTH,
101                   y * QUAD_WIDTH + QUAD_WIDTH);
102   cogl_object_unref (pipeline);
103
104   /* See what we got... */
105
106   y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
107   x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
108
109   if (cogl_test_verbose ())
110     {
111       g_print ("test_blend (%d, %d):\n%s\n", x, y, blend_string);
112       g_print ("  src color = %02x, %02x, %02x, %02x\n", Sr, Sg, Sb, Sa);
113       g_print ("  dst color = %02x, %02x, %02x, %02x\n", Dr, Dg, Db, Da);
114       if (blend_constant != BLEND_CONSTANT_UNUSED)
115         g_print ("  blend constant = %02x, %02x, %02x, %02x\n",
116                  Br, Bg, Bb, Ba);
117       else
118         g_print ("  blend constant = UNUSED\n");
119     }
120
121   test_utils_check_pixel (fb, x_off, y_off, expected_result);
122
123
124   /*
125    * Test with legacy API
126    */
127
128   /* Clear previous work */
129   cogl_set_source_color4ub (0, 0, 0, 0xff);
130   cogl_rectangle (x * QUAD_WIDTH,
131                   y * QUAD_WIDTH,
132                   x * QUAD_WIDTH + QUAD_WIDTH,
133                   y * QUAD_WIDTH + QUAD_WIDTH);
134
135   /* First write out the destination color without any blending... */
136   material = cogl_material_new ();
137   cogl_material_set_color4ub (material, Dr, Dg, Db, Da);
138   cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
139   cogl_set_source (material);
140   cogl_rectangle (x * QUAD_WIDTH,
141                   y * QUAD_WIDTH,
142                   x * QUAD_WIDTH + QUAD_WIDTH,
143                   y * QUAD_WIDTH + QUAD_WIDTH);
144   cogl_handle_unref (material);
145
146   /*
147    * Now blend a rectangle over our well defined destination:
148    */
149
150   material = cogl_material_new ();
151   cogl_material_set_color4ub (material, Sr, Sg, Sb, Sa);
152
153   status = cogl_material_set_blend (material, blend_string, &error);
154   if (!status)
155     {
156       /* This is a failure as it must be equivalent to the new API */
157       g_warning ("Error setting blend string %s: %s",
158                  blend_string, error->message);
159       g_assert_not_reached ();
160     }
161
162   cogl_color_init_from_4ub (&blend_const_color, Br, Bg, Bb, Ba);
163   cogl_material_set_blend_constant (material, &blend_const_color);
164
165   cogl_set_source (material);
166   cogl_rectangle (x * QUAD_WIDTH,
167                   y * QUAD_WIDTH,
168                   x * QUAD_WIDTH + QUAD_WIDTH,
169                   y * QUAD_WIDTH + QUAD_WIDTH);
170   cogl_handle_unref (material);
171
172   /* See what we got... */
173
174   test_utils_check_pixel (fb, x_off, y_off, expected_result);
175 }
176
177 static CoglTexture *
178 make_texture (guint32 color)
179 {
180   guchar *tex_data, *p;
181   guint8 r = MASK_RED (color);
182   guint8 g = MASK_GREEN (color);
183   guint8 b = MASK_BLUE (color);
184   guint8 a = MASK_ALPHA (color);
185   CoglTexture *tex;
186
187   tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 4);
188
189   for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;)
190     {
191       *(--p) = a;
192       *(--p) = b;
193       *(--p) = g;
194       *(--p) = r;
195     }
196
197   /* Note: we don't use COGL_PIXEL_FORMAT_ANY for the internal format here
198    * since we don't want to allow Cogl to premultiply our data. */
199   tex = cogl_texture_new_from_data (QUAD_WIDTH,
200                                     QUAD_WIDTH,
201                                     COGL_TEXTURE_NONE,
202                                     COGL_PIXEL_FORMAT_RGBA_8888,
203                                     COGL_PIXEL_FORMAT_RGBA_8888,
204                                     QUAD_WIDTH * 4,
205                                     tex_data);
206
207   g_free (tex_data);
208
209   return tex;
210 }
211
212 static void
213 test_tex_combine (TestState *state,
214                   int x,
215                   int y,
216                   guint32 tex0_color,
217                   guint32 tex1_color,
218                   guint32 combine_constant,
219                   const char *combine_string,
220                   guint32 expected_result)
221 {
222   CoglTexture *tex0, *tex1;
223
224   /* combine constant - when applicable */
225   guint8 Cr = MASK_RED (combine_constant);
226   guint8 Cg = MASK_GREEN (combine_constant);
227   guint8 Cb = MASK_BLUE (combine_constant);
228   guint8 Ca = MASK_ALPHA (combine_constant);
229   CoglColor combine_const_color;
230
231   CoglHandle material;
232   gboolean status;
233   GError *error = NULL;
234   int y_off;
235   int x_off;
236
237
238   tex0 = make_texture (tex0_color);
239   tex1 = make_texture (tex1_color);
240
241   material = cogl_material_new ();
242
243   cogl_material_set_color4ub (material, 0x80, 0x80, 0x80, 0x80);
244   cogl_material_set_blend (material, "RGBA = ADD (SRC_COLOR, 0)", NULL);
245
246   cogl_material_set_layer (material, 0, tex0);
247   cogl_material_set_layer_combine (material, 0,
248                                    "RGBA = REPLACE (TEXTURE)", NULL);
249
250   cogl_material_set_layer (material, 1, tex1);
251   status = cogl_material_set_layer_combine (material, 1,
252                                             combine_string, &error);
253   if (!status)
254     {
255       /* It's not strictly a test failure; you need a more capable GPU or
256        * driver to test this texture combine string. */
257       g_debug ("Failed to test texture combine string %s: %s",
258                combine_string, error->message);
259     }
260
261   cogl_color_init_from_4ub (&combine_const_color, Cr, Cg, Cb, Ca);
262   cogl_material_set_layer_combine_constant (material, 1, &combine_const_color);
263
264   cogl_set_source (material);
265   cogl_rectangle (x * QUAD_WIDTH,
266                   y * QUAD_WIDTH,
267                   x * QUAD_WIDTH + QUAD_WIDTH,
268                   y * QUAD_WIDTH + QUAD_WIDTH);
269
270   cogl_handle_unref (material);
271   cogl_object_unref (tex0);
272   cogl_object_unref (tex1);
273
274   /* See what we got... */
275
276   y_off = y * QUAD_WIDTH + (QUAD_WIDTH / 2);
277   x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
278
279   if (cogl_test_verbose ())
280     {
281       g_print ("test_tex_combine (%d, %d):\n%s\n", x, y, combine_string);
282       g_print ("  texture 0 color = 0x%08lX\n", (unsigned long)tex0_color);
283       g_print ("  texture 1 color = 0x%08lX\n", (unsigned long)tex1_color);
284       if (combine_constant != TEX_CONSTANT_UNUSED)
285         g_print ("  combine constant = %02x, %02x, %02x, %02x\n",
286                  Cr, Cg, Cb, Ca);
287       else
288         g_print ("  combine constant = UNUSED\n");
289     }
290
291   test_utils_check_pixel (fb, x_off, y_off, expected_result);
292 }
293
294 static void
295 paint (TestState *state)
296 {
297   test_blend (state, 0, 0, /* position */
298               0xff0000ff, /* src */
299               0xffffffff, /* dst */
300               "RGBA = ADD (SRC_COLOR, 0)",
301               BLEND_CONSTANT_UNUSED,
302               0xff0000ff); /* expected */
303
304   test_blend (state, 1, 0, /* position */
305               0x11223344, /* src */
306               0x11223344, /* dst */
307               "RGBA = ADD (SRC_COLOR, DST_COLOR)",
308               BLEND_CONSTANT_UNUSED,
309               0x22446688); /* expected */
310
311   test_blend (state, 2, 0, /* position */
312               0x80808080, /* src */
313               0xffffffff, /* dst */
314               "RGBA = ADD (SRC_COLOR * (CONSTANT), 0)",
315               0x80808080, /* constant (RGBA all = 0.5 when normalized) */
316               0x40404040); /* expected */
317
318   test_blend (state, 3, 0, /* position */
319               0x80000080, /* src (alpha = 0.5 when normalized) */
320               0x40000000, /* dst */
321               "RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]),"
322               "            DST_COLOR * (1-SRC_COLOR[A]))",
323               BLEND_CONSTANT_UNUSED,
324               0x60000040); /* expected */
325
326   /* XXX:
327    * For all texture combine tests tex0 will use a combine mode of
328    * "RGBA = REPLACE (TEXTURE)"
329    */
330
331   test_tex_combine (state, 4, 0, /* position */
332                     0x11111111, /* texture 0 color */
333                     0x22222222, /* texture 1 color */
334                     TEX_CONSTANT_UNUSED,
335                     "RGBA = ADD (PREVIOUS, TEXTURE)", /* tex combine */
336                     0x33333333); /* expected */
337
338   test_tex_combine (state, 5, 0, /* position */
339                     0x40404040, /* texture 0 color */
340                     0x80808080, /* texture 1 color (RGBA all = 0.5) */
341                     TEX_CONSTANT_UNUSED,
342                     "RGBA = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */
343                     0x20202020); /* expected */
344
345   test_tex_combine (state, 6, 0, /* position */
346                     0xffffff80, /* texture 0 color (alpha = 0.5) */
347                     0xDEADBE40, /* texture 1 color */
348                     TEX_CONSTANT_UNUSED,
349                     "RGB = REPLACE (PREVIOUS)"
350                     "A = MODULATE (PREVIOUS, TEXTURE)", /* tex combine */
351                     0xffffff20); /* expected */
352
353   /* XXX: we are assuming test_tex_combine creates a material with
354    * a color of 0x80808080 (i.e. the "PRIMARY" color) */
355   test_tex_combine (state, 7, 0, /* position */
356                     0xffffff80, /* texture 0 color (alpha = 0.5) */
357                     0xDEADBE20, /* texture 1 color */
358                     TEX_CONSTANT_UNUSED,
359                     "RGB = REPLACE (PREVIOUS)"
360                     "A = MODULATE (PRIMARY, TEXTURE)", /* tex combine */
361                     0xffffff10); /* expected */
362
363   test_tex_combine (state, 8, 0, /* position */
364                     0x11111111, /* texture 0 color */
365                     0x22222222, /* texture 1 color */
366                     TEX_CONSTANT_UNUSED,
367                     "RGBA = ADD (PREVIOUS, 1-TEXTURE)", /* tex combine */
368                     0xeeeeeeee); /* expected */
369
370   /* this is again assuming a primary color of 0x80808080 */
371   test_tex_combine (state, 9, 0, /* position */
372                     0x10101010, /* texture 0 color */
373                     0x20202020, /* texture 1 color */
374                     TEX_CONSTANT_UNUSED,
375                     "RGBA = INTERPOLATE (PREVIOUS, TEXTURE, PRIMARY)",
376                     0x18181818); /* expected */
377
378 #if 0 /* using TEXTURE_N appears to be broken in cogl-blend-string.c */
379   test_tex_combine (state, 0, 1, /* position */
380                     0xDEADBEEF, /* texture 0 color (not used) */
381                     0x11223344, /* texture 1 color */
382                     TEX_CONSTANT_UNUSED,
383                     "RGBA = ADD (TEXTURE_1, TEXTURE)", /* tex combine */
384                     0x22446688); /* expected */
385 #endif
386
387   test_tex_combine (state, 1, 1, /* position */
388                     0x21314151, /* texture 0 color */
389                     0x99999999, /* texture 1 color */
390                     TEX_CONSTANT_UNUSED,
391                     "RGBA = ADD_SIGNED (PREVIOUS, TEXTURE)", /* tex combine */
392                     0x3a4a5a6a); /* expected */
393
394   test_tex_combine (state, 2, 1, /* position */
395                     0xfedcba98, /* texture 0 color */
396                     0x11111111, /* texture 1 color */
397                     TEX_CONSTANT_UNUSED,
398                     "RGBA = SUBTRACT (PREVIOUS, TEXTURE)", /* tex combine */
399                     0xedcba987); /* expected */
400
401   test_tex_combine (state, 3, 1, /* position */
402                     0x8899aabb, /* texture 0 color */
403                     0xbbaa9988, /* texture 1 color */
404                     TEX_CONSTANT_UNUSED,
405                     "RGB = DOT3_RGBA (PREVIOUS, TEXTURE)"
406                     "A = REPLACE (PREVIOUS)",
407                     0x2a2a2abb); /* expected */
408 }
409
410 void
411 test_blend_strings (void)
412 {
413   TestState state;
414
415   cogl_framebuffer_orthographic (fb, 0, 0,
416                                  cogl_framebuffer_get_width (fb),
417                                  cogl_framebuffer_get_height (fb),
418                                  -1,
419                                  100);
420
421   /* XXX: we have to push/pop a framebuffer since this test currently
422    * uses the legacy cogl_rectangle() api. */
423   cogl_push_framebuffer (fb);
424   paint (&state);
425   cogl_pop_framebuffer ();
426
427   if (cogl_test_verbose ())
428     g_print ("OK\n");
429 }
430