1 #define COGL_VERSION_MIN_REQUIRED COGL_VERSION_1_0
2 
3 #include <cogl/cogl.h>
4 #include <string.h>
5 
6 #include "test-utils.h"
7 
8 #define TEX_SIZE 4
9 
10 typedef struct _TestState
11 {
12   int width;
13   int height;
14   CoglTexture *texture;
15 } TestState;
16 
17 static CoglTexture *
create_texture(TestUtilsTextureFlags flags)18 create_texture (TestUtilsTextureFlags flags)
19 {
20   uint8_t *data = g_malloc (TEX_SIZE * TEX_SIZE * 4), *p = data;
21   CoglTexture *tex;
22   int x, y;
23 
24   for (y = 0; y < TEX_SIZE; y++)
25     for (x = 0; x < TEX_SIZE; x++)
26       {
27         *(p++) = 0;
28         *(p++) = (x & 1) * 255;
29         *(p++) = (y & 1) * 255;
30         *(p++) = 255;
31       }
32 
33   tex = test_utils_texture_new_from_data (test_ctx,
34                                           TEX_SIZE, TEX_SIZE, flags,
35                                           COGL_PIXEL_FORMAT_RGBA_8888_PRE,
36                                           TEX_SIZE * 4,
37                                           data);
38   g_free (data);
39 
40   return tex;
41 }
42 
43 static CoglPipeline *
create_pipeline(TestState * state,CoglPipelineWrapMode wrap_mode_s,CoglPipelineWrapMode wrap_mode_t)44 create_pipeline (TestState *state,
45                  CoglPipelineWrapMode wrap_mode_s,
46                  CoglPipelineWrapMode wrap_mode_t)
47 {
48   CoglPipeline *pipeline;
49 
50   pipeline = cogl_pipeline_new (test_ctx);
51   cogl_pipeline_set_layer_texture (pipeline, 0, state->texture);
52   cogl_pipeline_set_layer_filters (pipeline, 0,
53                                    COGL_PIPELINE_FILTER_NEAREST,
54                                    COGL_PIPELINE_FILTER_NEAREST);
55   cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0, wrap_mode_s);
56   cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0, wrap_mode_t);
57 
58   return pipeline;
59 }
60 
61 static CoglPipelineWrapMode
62 wrap_modes[] =
63   {
64     COGL_PIPELINE_WRAP_MODE_REPEAT,
65     COGL_PIPELINE_WRAP_MODE_REPEAT,
66 
67     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
68     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
69 
70     COGL_PIPELINE_WRAP_MODE_REPEAT,
71     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
72 
73     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
74     COGL_PIPELINE_WRAP_MODE_REPEAT,
75 
76     COGL_PIPELINE_WRAP_MODE_AUTOMATIC,
77     COGL_PIPELINE_WRAP_MODE_AUTOMATIC,
78 
79     COGL_PIPELINE_WRAP_MODE_AUTOMATIC,
80     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE
81   };
82 
83 static void
draw_tests(TestState * state)84 draw_tests (TestState *state)
85 {
86   int i;
87 
88   for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
89     {
90       CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
91       CoglPipeline *pipeline;
92 
93       /* Create a separate pipeline for each pair of wrap modes so
94          that we can verify whether the batch splitting works */
95       wrap_mode_s = wrap_modes[i];
96       wrap_mode_t = wrap_modes[i + 1];
97       pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t);
98       /* Render the pipeline at four times the size of the texture */
99       cogl_framebuffer_draw_textured_rectangle (test_fb,
100                                                 pipeline,
101                                                 i * TEX_SIZE,
102                                                 0,
103                                                 (i + 2) * TEX_SIZE,
104                                                 TEX_SIZE * 2,
105                                                 0, 0, 2, 2);
106       cogl_object_unref (pipeline);
107     }
108 }
109 
110 static const CoglTextureVertex vertices[4] =
111   {
112     { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
113     { 0.0f, TEX_SIZE * 2, 0.0f, 0.0f, 2.0f },
114     { TEX_SIZE * 2, TEX_SIZE * 2, 0.0f, 2.0f, 2.0f },
115     { TEX_SIZE * 2, 0.0f, 0.0f, 2.0f, 0.0f }
116   };
117 
118 static void
draw_tests_polygon(TestState * state)119 draw_tests_polygon (TestState *state)
120 {
121   int i;
122 
123   for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
124     {
125       CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
126       CoglPipeline *pipeline;
127 
128       wrap_mode_s = wrap_modes[i];
129       wrap_mode_t = wrap_modes[i + 1];
130       pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t);
131       cogl_set_source (pipeline);
132       cogl_object_unref (pipeline);
133       cogl_push_matrix ();
134       cogl_translate (TEX_SIZE * i, 0.0f, 0.0f);
135       /* Render the pipeline at four times the size of the texture */
136       cogl_polygon (vertices, G_N_ELEMENTS (vertices), FALSE);
137       cogl_pop_matrix ();
138     }
139 }
140 
141 static void
draw_tests_vbo(TestState * state)142 draw_tests_vbo (TestState *state)
143 {
144   CoglHandle vbo;
145   int i;
146 
147   vbo = cogl_vertex_buffer_new (4);
148   cogl_vertex_buffer_add (vbo, "gl_Vertex", 3,
149                           COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
150                           sizeof (vertices[0]),
151                           &vertices[0].x);
152   cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0", 2,
153                           COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
154                           sizeof (vertices[0]),
155                           &vertices[0].tx);
156   cogl_vertex_buffer_submit (vbo);
157 
158   for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
159     {
160       CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
161       CoglPipeline *pipeline;
162 
163       wrap_mode_s = wrap_modes[i];
164       wrap_mode_t = wrap_modes[i + 1];
165       pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t);
166       cogl_set_source (pipeline);
167       cogl_object_unref (pipeline);
168       cogl_push_matrix ();
169       cogl_translate (TEX_SIZE * i, 0.0f, 0.0f);
170       /* Render the pipeline at four times the size of the texture */
171       cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, 4);
172       cogl_pop_matrix ();
173     }
174 
175   cogl_handle_unref (vbo);
176 }
177 
178 static void
validate_set(TestState * state,int offset)179 validate_set (TestState *state, int offset)
180 {
181   uint8_t data[TEX_SIZE * 2 * TEX_SIZE * 2 * 4], *p;
182   int x, y, i;
183 
184   for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2)
185     {
186       CoglPipelineWrapMode wrap_mode_s, wrap_mode_t;
187 
188       wrap_mode_s = wrap_modes[i];
189       wrap_mode_t = wrap_modes[i + 1];
190 
191       cogl_framebuffer_read_pixels (test_fb, i * TEX_SIZE, offset * TEX_SIZE * 2,
192                                     TEX_SIZE * 2, TEX_SIZE * 2,
193                                     COGL_PIXEL_FORMAT_RGBA_8888,
194                                     data);
195 
196       p = data;
197 
198       for (y = 0; y < TEX_SIZE * 2; y++)
199         for (x = 0; x < TEX_SIZE * 2; x++)
200           {
201             uint8_t green, blue;
202 
203             if (x < TEX_SIZE ||
204                 wrap_mode_s == COGL_PIPELINE_WRAP_MODE_REPEAT ||
205                 wrap_mode_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
206               green = (x & 1) * 255;
207             else
208               green = ((TEX_SIZE - 1) & 1) * 255;
209 
210             if (y < TEX_SIZE ||
211                 wrap_mode_t == COGL_PIPELINE_WRAP_MODE_REPEAT ||
212                 wrap_mode_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
213               blue = (y & 1) * 255;
214             else
215               blue = ((TEX_SIZE - 1) & 1) * 255;
216 
217             g_assert_cmpint (p[0], ==, 0);
218             g_assert_cmpint (p[1], ==, green);
219             g_assert_cmpint (p[2], ==, blue);
220 
221             p += 4;
222           }
223     }
224 }
225 
226 static void
validate_result(TestState * state)227 validate_result (TestState *state)
228 {
229   validate_set (state, 0); /* non-atlased rectangle */
230 #if 0 /* this doesn't currently work */
231   validate_set (state, 1); /* atlased rectangle */
232 #endif
233   validate_set (state, 2); /* cogl_polygon */
234   validate_set (state, 3); /* vertex buffer */
235 }
236 
237 static void
paint(TestState * state)238 paint (TestState *state)
239 {
240   /* Draw the tests first with a non atlased texture */
241   state->texture = create_texture (TEST_UTILS_TEXTURE_NO_ATLAS);
242   draw_tests (state);
243   cogl_object_unref (state->texture);
244 
245   /* Draw the tests again with a possible atlased texture. This should
246      end up testing software repeats */
247   state->texture = create_texture (TEST_UTILS_TEXTURE_NONE);
248   cogl_framebuffer_push_matrix (test_fb);
249   cogl_framebuffer_translate (test_fb, 0.0f, TEX_SIZE * 2.0f, 0.0f);
250   draw_tests (state);
251   cogl_pop_matrix ();
252   cogl_object_unref (state->texture);
253 
254   /* Draw the tests using cogl_polygon */
255   state->texture = create_texture (COGL_TEXTURE_NO_ATLAS);
256   cogl_push_matrix ();
257   cogl_translate (0.0f, TEX_SIZE * 4.0f, 0.0f);
258   draw_tests_polygon (state);
259   cogl_pop_matrix ();
260   cogl_object_unref (state->texture);
261 
262   /* Draw the tests using a vertex buffer */
263   state->texture = create_texture (COGL_TEXTURE_NO_ATLAS);
264   cogl_push_matrix ();
265   cogl_translate (0.0f, TEX_SIZE * 6.0f, 0.0f);
266   draw_tests_vbo (state);
267   cogl_pop_matrix ();
268   cogl_object_unref (state->texture);
269 
270   validate_result (state);
271 }
272 
273 void
test_wrap_modes(void)274 test_wrap_modes (void)
275 {
276   TestState state;
277 
278   state.width = cogl_framebuffer_get_width (test_fb);
279   state.height = cogl_framebuffer_get_height (test_fb);
280 
281   cogl_framebuffer_orthographic (test_fb,
282                                  0, 0,
283                                  state.width,
284                                  state.height,
285                                  -1,
286                                  100);
287 
288   /* XXX: we have to push/pop a framebuffer since this test currently
289    * uses the legacy cogl_vertex_buffer_draw() api. */
290   cogl_push_framebuffer (test_fb);
291   paint (&state);
292   cogl_pop_framebuffer ();
293 
294   if (cogl_test_verbose ())
295     g_print ("OK\n");
296 }
297