1 | #include <gtk/gtk.h> |
2 | |
3 | #include "gsk/gl/gskglrenderer.h" |
4 | |
5 | #define N 20 |
6 | |
7 | static GskRenderer *gl_renderer = NULL; |
8 | |
9 | typedef struct _TextureBuilder TextureBuilder; |
10 | |
11 | typedef enum { |
12 | TEXTURE_METHOD_LOCAL, |
13 | TEXTURE_METHOD_GL, |
14 | TEXTURE_METHOD_GL_RELEASED, |
15 | TEXTURE_METHOD_PNG, |
16 | TEXTURE_METHOD_PNG_PIXBUF, |
17 | TEXTURE_METHOD_TIFF, |
18 | TEXTURE_METHOD_TIFF_PIXBUF, |
19 | |
20 | N_TEXTURE_METHODS |
21 | } TextureMethod; |
22 | |
23 | struct _TextureBuilder |
24 | { |
25 | GdkMemoryFormat format; |
26 | int width; |
27 | int height; |
28 | |
29 | guchar *pixels; |
30 | gsize stride; |
31 | gsize offset; |
32 | }; |
33 | |
34 | static gsize |
35 | gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) |
36 | { |
37 | switch (format) |
38 | { |
39 | case GDK_MEMORY_R8G8B8: |
40 | case GDK_MEMORY_B8G8R8: |
41 | return 3; |
42 | |
43 | case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: |
44 | case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: |
45 | case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: |
46 | case GDK_MEMORY_B8G8R8A8: |
47 | case GDK_MEMORY_A8R8G8B8: |
48 | case GDK_MEMORY_R8G8B8A8: |
49 | case GDK_MEMORY_A8B8G8R8: |
50 | return 4; |
51 | |
52 | case GDK_MEMORY_R16G16B16: |
53 | case GDK_MEMORY_R16G16B16_FLOAT: |
54 | return 6; |
55 | |
56 | case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: |
57 | case GDK_MEMORY_R16G16B16A16: |
58 | case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: |
59 | case GDK_MEMORY_R16G16B16A16_FLOAT: |
60 | return 8; |
61 | |
62 | case GDK_MEMORY_R32G32B32_FLOAT: |
63 | return 12; |
64 | |
65 | case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: |
66 | case GDK_MEMORY_R32G32B32A32_FLOAT: |
67 | return 16; |
68 | |
69 | case GDK_MEMORY_N_FORMATS: |
70 | default: |
71 | g_assert_not_reached (); |
72 | return 4; |
73 | } |
74 | } |
75 | |
76 | static gboolean |
77 | gdk_memory_format_has_alpha (GdkMemoryFormat format) |
78 | { |
79 | switch (format) |
80 | { |
81 | case GDK_MEMORY_R8G8B8: |
82 | case GDK_MEMORY_B8G8R8: |
83 | case GDK_MEMORY_R16G16B16: |
84 | case GDK_MEMORY_R16G16B16_FLOAT: |
85 | case GDK_MEMORY_R32G32B32_FLOAT: |
86 | return FALSE; |
87 | |
88 | case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: |
89 | case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: |
90 | case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: |
91 | case GDK_MEMORY_B8G8R8A8: |
92 | case GDK_MEMORY_A8R8G8B8: |
93 | case GDK_MEMORY_R8G8B8A8: |
94 | case GDK_MEMORY_A8B8G8R8: |
95 | case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: |
96 | case GDK_MEMORY_R16G16B16A16: |
97 | case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: |
98 | case GDK_MEMORY_R16G16B16A16_FLOAT: |
99 | case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: |
100 | case GDK_MEMORY_R32G32B32A32_FLOAT: |
101 | return TRUE; |
102 | |
103 | case GDK_MEMORY_N_FORMATS: |
104 | default: |
105 | g_assert_not_reached (); |
106 | return TRUE; |
107 | } |
108 | } |
109 | |
110 | static gpointer |
111 | encode (GdkMemoryFormat format, |
112 | TextureMethod method) |
113 | { |
114 | return GSIZE_TO_POINTER (method * GDK_MEMORY_N_FORMATS + format); |
115 | } |
116 | |
117 | static void |
118 | decode (gconstpointer data, |
119 | GdkMemoryFormat *format, |
120 | TextureMethod *method) |
121 | { |
122 | gsize value = GPOINTER_TO_SIZE (data); |
123 | |
124 | *format = value % GDK_MEMORY_N_FORMATS; |
125 | value /= GDK_MEMORY_N_FORMATS; |
126 | |
127 | *method = value; |
128 | } |
129 | |
130 | static void |
131 | texture_builder_init (TextureBuilder *builder, |
132 | GdkMemoryFormat format, |
133 | int width, |
134 | int height) |
135 | { |
136 | gsize ; |
137 | |
138 | builder->format = format; |
139 | builder->width = width; |
140 | builder->height = height; |
141 | |
142 | extra_stride = g_test_rand_bit() ? g_test_rand_int_range (begin: 0, end: 16) : 0; |
143 | builder->offset = g_test_rand_bit() ? g_test_rand_int_range (begin: 0, end: 128) : 0; |
144 | builder->stride = width * gdk_memory_format_bytes_per_pixel (format) + extra_stride; |
145 | builder->pixels = g_malloc0 (n_bytes: builder->offset + builder->stride * height); |
146 | } |
147 | |
148 | static GdkTexture * |
149 | texture_builder_finish (TextureBuilder *builder) |
150 | { |
151 | GBytes *bytes; |
152 | GdkTexture *texture; |
153 | |
154 | bytes = g_bytes_new_with_free_func (data: builder->pixels + builder->offset, |
155 | size: builder->height * builder->stride, |
156 | free_func: g_free, |
157 | user_data: builder->pixels); |
158 | texture = gdk_memory_texture_new (width: builder->width, |
159 | height: builder->height, |
160 | format: builder->format, |
161 | bytes, |
162 | stride: builder->stride); |
163 | g_bytes_unref (bytes); |
164 | |
165 | return texture; |
166 | } |
167 | |
168 | static inline void |
169 | set_pixel_u8 (guchar *data, |
170 | int r, |
171 | int g, |
172 | int b, |
173 | int a, |
174 | gboolean premultiply, |
175 | const GdkRGBA *color) |
176 | { |
177 | if (a >= 0) |
178 | data[a] = CLAMP (color->alpha * 256.f, 0.f, 255.f); |
179 | if (premultiply) |
180 | { |
181 | data[r] = CLAMP (color->red * color->alpha * 256.f, 0.f, 255.f); |
182 | data[g] = CLAMP (color->green * color->alpha * 256.f, 0.f, 255.f); |
183 | data[b] = CLAMP (color->blue * color->alpha * 256.f, 0.f, 255.f); |
184 | } |
185 | else |
186 | { |
187 | data[r] = CLAMP (color->red * 256.f, 0.f, 255.f); |
188 | data[g] = CLAMP (color->green * 256.f, 0.f, 255.f); |
189 | data[b] = CLAMP (color->blue * 256.f, 0.f, 255.f); |
190 | } |
191 | } |
192 | |
193 | static inline guint16 |
194 | float_to_half (const float x) |
195 | { |
196 | const guint b = *(guint*)&x+0x00001000; // round-to-nearest-even |
197 | const guint e = (b&0x7F800000)>>23; // exponent |
198 | const guint m = b&0x007FFFFF; // mantissa |
199 | return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : saturate |
200 | } |
201 | |
202 | static void |
203 | texture_builder_set_pixel (TextureBuilder *builder, |
204 | int x, |
205 | int y, |
206 | const GdkRGBA *color) |
207 | { |
208 | guchar *data; |
209 | |
210 | g_assert_cmpint (x, >=, 0); |
211 | g_assert_cmpint (x, <, builder->width); |
212 | g_assert_cmpint (y, >=, 0); |
213 | g_assert_cmpint (y, <, builder->height); |
214 | |
215 | data = builder->pixels |
216 | + builder->offset |
217 | + y * builder->stride |
218 | + x * gdk_memory_format_bytes_per_pixel (format: builder->format); |
219 | |
220 | switch (builder->format) |
221 | { |
222 | case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: |
223 | set_pixel_u8 (data, r: 2, g: 1, b: 0, a: 3, TRUE, color); |
224 | break; |
225 | case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: |
226 | set_pixel_u8 (data, r: 1, g: 2, b: 3, a: 0, TRUE, color); |
227 | break; |
228 | case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: |
229 | set_pixel_u8 (data, r: 0, g: 1, b: 2, a: 3, TRUE, color); |
230 | break; |
231 | case GDK_MEMORY_B8G8R8A8: |
232 | set_pixel_u8 (data, r: 2, g: 1, b: 0, a: 3, FALSE, color); |
233 | break; |
234 | case GDK_MEMORY_A8R8G8B8: |
235 | set_pixel_u8 (data, r: 1, g: 2, b: 3, a: 0, FALSE, color); |
236 | break; |
237 | case GDK_MEMORY_R8G8B8A8: |
238 | set_pixel_u8 (data, r: 0, g: 1, b: 2, a: 3, FALSE, color); |
239 | break; |
240 | case GDK_MEMORY_A8B8G8R8: |
241 | set_pixel_u8 (data, r: 3, g: 2, b: 1, a: 0, FALSE, color); |
242 | break; |
243 | case GDK_MEMORY_R8G8B8: |
244 | set_pixel_u8 (data, r: 0, g: 1, b: 2, a: -1, TRUE, color); |
245 | break; |
246 | case GDK_MEMORY_B8G8R8: |
247 | set_pixel_u8 (data, r: 2, g: 1, b: 0, a: -1, TRUE, color); |
248 | break; |
249 | case GDK_MEMORY_R16G16B16: |
250 | { |
251 | guint16 pixels[3] = { |
252 | CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f), |
253 | CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f), |
254 | CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f), |
255 | }; |
256 | memcpy (dest: data, src: pixels, n: 3 * sizeof (guint16)); |
257 | } |
258 | break; |
259 | case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: |
260 | { |
261 | guint16 pixels[4] = { |
262 | CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f), |
263 | CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f), |
264 | CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f), |
265 | CLAMP (color->alpha * 65536.f, 0, 65535.f), |
266 | }; |
267 | memcpy (dest: data, src: pixels, n: 4 * sizeof (guint16)); |
268 | } |
269 | break; |
270 | case GDK_MEMORY_R16G16B16A16: |
271 | { |
272 | guint16 pixels[4] = { |
273 | CLAMP (color->red * 65536.f, 0, 65535.f), |
274 | CLAMP (color->green * 65536.f, 0, 65535.f), |
275 | CLAMP (color->blue * 65536.f, 0, 65535.f), |
276 | CLAMP (color->alpha * 65536.f, 0, 65535.f), |
277 | }; |
278 | memcpy (dest: data, src: pixels, n: 4 * sizeof (guint16)); |
279 | } |
280 | break; |
281 | case GDK_MEMORY_R16G16B16_FLOAT: |
282 | { |
283 | guint16 pixels[3] = { |
284 | float_to_half (x: color->red * color->alpha), |
285 | float_to_half (x: color->green * color->alpha), |
286 | float_to_half (x: color->blue * color->alpha) |
287 | }; |
288 | memcpy (dest: data, src: pixels, n: 3 * sizeof (guint16)); |
289 | } |
290 | break; |
291 | case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: |
292 | { |
293 | guint16 pixels[4] = { |
294 | float_to_half (x: color->red * color->alpha), |
295 | float_to_half (x: color->green * color->alpha), |
296 | float_to_half (x: color->blue * color->alpha), |
297 | float_to_half (x: color->alpha) |
298 | }; |
299 | memcpy (dest: data, src: pixels, n: 4 * sizeof (guint16)); |
300 | } |
301 | break; |
302 | case GDK_MEMORY_R16G16B16A16_FLOAT: |
303 | { |
304 | guint16 pixels[4] = { |
305 | float_to_half (x: color->red), |
306 | float_to_half (x: color->green), |
307 | float_to_half (x: color->blue), |
308 | float_to_half (x: color->alpha) |
309 | }; |
310 | memcpy (dest: data, src: pixels, n: 4 * sizeof (guint16)); |
311 | } |
312 | break; |
313 | case GDK_MEMORY_R32G32B32_FLOAT: |
314 | { |
315 | float pixels[3] = { |
316 | color->red * color->alpha, |
317 | color->green * color->alpha, |
318 | color->blue * color->alpha |
319 | }; |
320 | memcpy (dest: data, src: pixels, n: 3 * sizeof (float)); |
321 | } |
322 | break; |
323 | case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: |
324 | { |
325 | float pixels[4] = { |
326 | color->red * color->alpha, |
327 | color->green * color->alpha, |
328 | color->blue * color->alpha, |
329 | color->alpha |
330 | }; |
331 | memcpy (dest: data, src: pixels, n: 4 * sizeof (float)); |
332 | } |
333 | break; |
334 | case GDK_MEMORY_R32G32B32A32_FLOAT: |
335 | { |
336 | float pixels[4] = { |
337 | color->red, |
338 | color->green, |
339 | color->blue, |
340 | color->alpha |
341 | }; |
342 | memcpy (dest: data, src: pixels, n: 4 * sizeof (float)); |
343 | } |
344 | break; |
345 | case GDK_MEMORY_N_FORMATS: |
346 | default: |
347 | g_assert_not_reached (); |
348 | break; |
349 | } |
350 | } |
351 | |
352 | static void |
353 | texture_builder_fill (TextureBuilder *builder, |
354 | const GdkRGBA *color) |
355 | { |
356 | int x, y; |
357 | |
358 | for (y = 0; y < builder->height; y++) |
359 | for (x = 0; x < builder->width; x++) |
360 | texture_builder_set_pixel (builder, x, y, color); |
361 | } |
362 | |
363 | static void |
364 | compare_textures (GdkTexture *expected, |
365 | GdkTexture *test, |
366 | gboolean has_alpha) |
367 | { |
368 | guint32 *expected_data, *test_data; |
369 | int width, height; |
370 | int x, y; |
371 | |
372 | g_assert_cmpint (gdk_texture_get_width (expected), ==, gdk_texture_get_width (test)); |
373 | g_assert_cmpint (gdk_texture_get_height (expected), ==, gdk_texture_get_height (test)); |
374 | |
375 | width = gdk_texture_get_width (texture: expected); |
376 | height = gdk_texture_get_height (texture: expected); |
377 | |
378 | expected_data = g_new (guint32, width * height); |
379 | gdk_texture_download (texture: expected, data: (guchar *) expected_data, stride: width * 4); |
380 | |
381 | test_data = g_new (guint32, width * height); |
382 | gdk_texture_download (texture: test, data: (guchar *) test_data, stride: width * 4); |
383 | |
384 | for (y = 0; y < height; y++) |
385 | { |
386 | for (x = 0; x < width; x++) |
387 | { |
388 | if (has_alpha) |
389 | g_assert_cmphex (expected_data[y * width + x], ==, test_data[y * width + x]); |
390 | else |
391 | g_assert_cmphex (expected_data[y * width + x] | 0xFF000000, ==, test_data[y * width + x]); |
392 | } |
393 | } |
394 | |
395 | g_free (mem: expected_data); |
396 | g_free (mem: test_data); |
397 | } |
398 | |
399 | static GdkTexture * |
400 | upload_to_gl (GdkTexture *texture) |
401 | { |
402 | GskRenderNode *node; |
403 | GdkTexture *result; |
404 | |
405 | if (gl_renderer == NULL) |
406 | return texture; |
407 | |
408 | node = gsk_texture_node_new (texture, |
409 | bounds: &GRAPHENE_RECT_INIT( |
410 | 0, 0, |
411 | gdk_texture_get_width (texture), |
412 | gdk_texture_get_height (texture) |
413 | )); |
414 | result = gsk_renderer_render_texture (renderer: gl_renderer, root: node, NULL); |
415 | gsk_render_node_unref (node); |
416 | g_object_unref (object: texture); |
417 | |
418 | return result; |
419 | } |
420 | |
421 | static GdkTexture * |
422 | create_texture (GdkMemoryFormat format, |
423 | TextureMethod method, |
424 | int width, |
425 | int height, |
426 | const GdkRGBA *color) |
427 | { |
428 | TextureBuilder builder; |
429 | GdkTexture *texture; |
430 | |
431 | texture_builder_init (builder: &builder, format, width, height); |
432 | texture_builder_fill (builder: &builder, color); |
433 | |
434 | texture = texture_builder_finish (builder: &builder); |
435 | |
436 | switch (method) |
437 | { |
438 | case TEXTURE_METHOD_LOCAL: |
439 | break; |
440 | |
441 | case TEXTURE_METHOD_GL: |
442 | texture = upload_to_gl (texture); |
443 | break; |
444 | |
445 | case TEXTURE_METHOD_GL_RELEASED: |
446 | texture = upload_to_gl (texture); |
447 | if (GDK_IS_GL_TEXTURE (texture)) |
448 | gdk_gl_texture_release (GDK_GL_TEXTURE (texture)); |
449 | break; |
450 | |
451 | case TEXTURE_METHOD_PNG: |
452 | { |
453 | GBytes *bytes = gdk_texture_save_to_png_bytes (texture); |
454 | g_assert (bytes); |
455 | g_object_unref (object: texture); |
456 | texture = gdk_texture_new_from_bytes (bytes, NULL); |
457 | g_assert (texture); |
458 | g_bytes_unref (bytes); |
459 | } |
460 | break; |
461 | |
462 | case TEXTURE_METHOD_PNG_PIXBUF: |
463 | { |
464 | GInputStream *stream; |
465 | GdkPixbuf *pixbuf; |
466 | GBytes *bytes; |
467 | |
468 | bytes = gdk_texture_save_to_png_bytes (texture); |
469 | g_assert (bytes); |
470 | g_object_unref (object: texture); |
471 | stream = g_memory_input_stream_new_from_bytes (bytes); |
472 | pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL); |
473 | g_object_unref (object: stream); |
474 | g_assert (pixbuf); |
475 | texture = gdk_texture_new_for_pixbuf (pixbuf); |
476 | g_assert (texture); |
477 | g_object_unref (object: pixbuf); |
478 | g_bytes_unref (bytes); |
479 | } |
480 | break; |
481 | |
482 | case TEXTURE_METHOD_TIFF: |
483 | { |
484 | GBytes *bytes = gdk_texture_save_to_tiff_bytes (texture); |
485 | g_assert (bytes); |
486 | g_object_unref (object: texture); |
487 | texture = gdk_texture_new_from_bytes (bytes, NULL); |
488 | g_assert (texture); |
489 | g_bytes_unref (bytes); |
490 | } |
491 | break; |
492 | |
493 | case TEXTURE_METHOD_TIFF_PIXBUF: |
494 | { |
495 | GInputStream *stream; |
496 | GdkPixbuf *pixbuf; |
497 | GBytes *bytes; |
498 | |
499 | bytes = gdk_texture_save_to_png_bytes (texture); |
500 | g_assert (bytes); |
501 | g_object_unref (object: texture); |
502 | stream = g_memory_input_stream_new_from_bytes (bytes); |
503 | pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL); |
504 | g_object_unref (object: stream); |
505 | g_assert (pixbuf); |
506 | texture = gdk_texture_new_for_pixbuf (pixbuf); |
507 | g_assert (texture); |
508 | g_object_unref (object: pixbuf); |
509 | g_bytes_unref (bytes); |
510 | } |
511 | break; |
512 | |
513 | case N_TEXTURE_METHODS: |
514 | default: |
515 | g_assert_not_reached (); |
516 | break; |
517 | } |
518 | |
519 | return texture; |
520 | } |
521 | |
522 | static void |
523 | create_random_color (GdkRGBA *color) |
524 | { |
525 | /* Generate colors so that premultiplying will result in values in steps of 1/15th */ |
526 | color->red = g_test_rand_int_range (begin: 0, end: 6) / 5.f; |
527 | color->green = g_test_rand_int_range (begin: 0, end: 6) / 5.f; |
528 | color->blue = g_test_rand_int_range (begin: 0, end: 6) / 5.f; |
529 | color->alpha = g_test_rand_int_range (begin: 0, end: 4) / 3.f; |
530 | } |
531 | |
532 | static void |
533 | test_download_1x1 (gconstpointer data) |
534 | { |
535 | GdkMemoryFormat format; |
536 | TextureMethod method; |
537 | GdkTexture *expected, *test; |
538 | gsize i; |
539 | |
540 | decode (data, format: &format, method: &method); |
541 | |
542 | for (i = 0; i < N; i++) |
543 | { |
544 | GdkRGBA color; |
545 | |
546 | create_random_color (color: &color); |
547 | expected = create_texture (GDK_MEMORY_DEFAULT, method: TEXTURE_METHOD_LOCAL, width: 1, height: 1, color: &color); |
548 | test = create_texture (format, method, width: 1, height: 1, color: &color); |
549 | |
550 | compare_textures (expected, test, has_alpha: gdk_memory_format_has_alpha (format)); |
551 | |
552 | g_object_unref (object: expected); |
553 | g_object_unref (object: test); |
554 | } |
555 | } |
556 | |
557 | static void |
558 | test_download_4x4 (gconstpointer data) |
559 | { |
560 | GdkMemoryFormat format; |
561 | TextureMethod method; |
562 | GdkTexture *expected, *test; |
563 | gsize i; |
564 | |
565 | decode (data, format: &format, method: &method); |
566 | |
567 | for (i = 0; i < N; i++) |
568 | { |
569 | GdkRGBA color; |
570 | |
571 | create_random_color (color: &color); |
572 | expected = create_texture (GDK_MEMORY_DEFAULT, method: TEXTURE_METHOD_LOCAL, width: 4, height: 4, color: &color); |
573 | test = create_texture (format, method, width: 4, height: 4, color: &color); |
574 | |
575 | compare_textures (expected, test, has_alpha: gdk_memory_format_has_alpha (format)); |
576 | |
577 | g_object_unref (object: expected); |
578 | g_object_unref (object: test); |
579 | } |
580 | } |
581 | |
582 | /* larger than what NGL puts into the icon cache */ |
583 | static void |
584 | test_download_192x192 (gconstpointer data) |
585 | { |
586 | GdkMemoryFormat format; |
587 | TextureMethod method; |
588 | GdkTexture *expected, *test; |
589 | GdkRGBA color; |
590 | |
591 | decode (data, format: &format, method: &method); |
592 | |
593 | create_random_color (color: &color); |
594 | expected = create_texture (GDK_MEMORY_DEFAULT, method: TEXTURE_METHOD_LOCAL, width: 192, height: 192, color: &color); |
595 | test = create_texture (format, method, width: 192, height: 192, color: &color); |
596 | |
597 | compare_textures (expected, test, has_alpha: gdk_memory_format_has_alpha (format)); |
598 | |
599 | g_object_unref (object: expected); |
600 | g_object_unref (object: test); |
601 | } |
602 | |
603 | static void |
604 | add_test (const char *name, |
605 | GTestDataFunc func) |
606 | { |
607 | GdkMemoryFormat format; |
608 | TextureMethod method; |
609 | GEnumClass *enum_class; |
610 | |
611 | enum_class = g_type_class_ref (type: GDK_TYPE_MEMORY_FORMAT); |
612 | |
613 | for (format = 0; format < GDK_MEMORY_N_FORMATS; format++) |
614 | { |
615 | for (method = 0; method < N_TEXTURE_METHODS; method++) |
616 | { |
617 | const char *method_names[N_TEXTURE_METHODS] = { "local" , "gl" , "gl-released" , "png" , "png-pixbuf" , "tiff" , "tiff-pixbuf" }; |
618 | char *test_name = g_strdup_printf (format: "%s/%s/%s" , |
619 | name, |
620 | g_enum_get_value (enum_class, value: format)->value_nick, |
621 | method_names[method]); |
622 | g_test_add_data_func_full (testpath: test_name, test_data: encode (format, method), test_func: func, NULL); |
623 | g_free (mem: test_name); |
624 | } |
625 | } |
626 | } |
627 | |
628 | int |
629 | main (int argc, char *argv[]) |
630 | { |
631 | int result; |
632 | |
633 | gtk_test_init (argcp: &argc, argvp: &argv, NULL); |
634 | |
635 | add_test (name: "/memorytexture/download_1x1" , func: test_download_1x1); |
636 | add_test (name: "/memorytexture/download_4x4" , func: test_download_4x4); |
637 | add_test (name: "/memorytexture/download_192x192" , func: test_download_192x192); |
638 | |
639 | gl_renderer = gsk_gl_renderer_new (); |
640 | if (!gsk_renderer_realize (renderer: gl_renderer, NULL, NULL)) |
641 | { |
642 | g_clear_object (&gl_renderer); |
643 | } |
644 | |
645 | result = g_test_run (); |
646 | |
647 | if (gl_renderer) |
648 | { |
649 | gsk_renderer_unrealize (renderer: gl_renderer); |
650 | g_clear_object (&gl_renderer); |
651 | } |
652 | gdk_gl_context_clear_current (); |
653 | |
654 | return result; |
655 | } |
656 | |