1428d7b3dSmrg#include <stdint.h> 2428d7b3dSmrg#include <stdio.h> 3428d7b3dSmrg#include <stdlib.h> 4428d7b3dSmrg 5428d7b3dSmrg#include <X11/Xutil.h> /* for XDestroyImage */ 6428d7b3dSmrg#include <pixman.h> /* for pixman blt functions */ 7428d7b3dSmrg 8428d7b3dSmrg#include "test.h" 9428d7b3dSmrg 10428d7b3dSmrgenum trapezoid { 11428d7b3dSmrg RECT_ALIGN, 12428d7b3dSmrg RECT_UNALIGN, 13428d7b3dSmrg GENERAL 14428d7b3dSmrg}; 15428d7b3dSmrg 16428d7b3dSmrgstatic const uint8_t ops[] = { 17428d7b3dSmrg PictOpClear, 18428d7b3dSmrg PictOpSrc, 19428d7b3dSmrg PictOpDst, 20428d7b3dSmrg}; 21428d7b3dSmrg 22428d7b3dSmrgstatic XRenderPictFormat *mask_format(Display *dpy, enum mask mask) 23428d7b3dSmrg{ 24428d7b3dSmrg switch (mask) { 25428d7b3dSmrg default: 26428d7b3dSmrg case MASK_NONE: return NULL; 27428d7b3dSmrg case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1); 28428d7b3dSmrg case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8); 29428d7b3dSmrg } 30428d7b3dSmrg} 31428d7b3dSmrg 32428d7b3dSmrgstatic const char *mask_name(enum mask mask) 33428d7b3dSmrg{ 34428d7b3dSmrg switch (mask) { 35428d7b3dSmrg default: 36428d7b3dSmrg case MASK_NONE: return "none"; 37428d7b3dSmrg case MASK_A1: return "a1"; 38428d7b3dSmrg case MASK_A8: return "a8"; 39428d7b3dSmrg } 40428d7b3dSmrg} 41428d7b3dSmrg 42428d7b3dSmrgstatic const char *trapezoid_name(enum trapezoid trapezoid) 43428d7b3dSmrg{ 44428d7b3dSmrg switch (trapezoid) { 45428d7b3dSmrg default: 46428d7b3dSmrg case RECT_ALIGN: return "pixel-aligned"; 47428d7b3dSmrg case RECT_UNALIGN: return "rectilinear"; 48428d7b3dSmrg case GENERAL: return "general"; 49428d7b3dSmrg } 50428d7b3dSmrg} 51428d7b3dSmrg 52428d7b3dSmrgstatic void fill_rect(struct test_display *dpy, Picture p, uint8_t op, 53428d7b3dSmrg int x, int y, int w, int h, 54428d7b3dSmrg int dx, int dy, enum mask mask, 55428d7b3dSmrg uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) 56428d7b3dSmrg{ 57428d7b3dSmrg XRenderColor render_color; 58428d7b3dSmrg XTrapezoid trap; 59428d7b3dSmrg Picture src; 60428d7b3dSmrg 61428d7b3dSmrg render_color.red = red * alpha; 62428d7b3dSmrg render_color.green = green * alpha; 63428d7b3dSmrg render_color.blue = blue * alpha; 64428d7b3dSmrg render_color.alpha = alpha << 8; 65428d7b3dSmrg 66428d7b3dSmrg trap.left.p1.x = trap.left.p2.x = (x << 16) + dx; 67428d7b3dSmrg trap.top = trap.left.p1.y = trap.right.p1.y = (y << 16) + dy; 68428d7b3dSmrg trap.right.p1.x = trap.right.p2.x = ((x + w) << 16) + dx; 69428d7b3dSmrg trap.bottom = trap.left.p2.y = trap.right.p2.y = ((y + h) << 16) + dy; 70428d7b3dSmrg 71428d7b3dSmrg src = XRenderCreateSolidFill(dpy->dpy, &render_color); 72428d7b3dSmrg XRenderCompositeTrapezoids(dpy->dpy, 73428d7b3dSmrg op, src, p, mask_format(dpy->dpy, mask), 74428d7b3dSmrg 0, 0, &trap, 1); 75428d7b3dSmrg XRenderFreePicture(dpy->dpy, src); 76428d7b3dSmrg} 77428d7b3dSmrg 78428d7b3dSmrgstatic void pixel_tests(struct test *t, int reps, int sets, enum target target) 79428d7b3dSmrg{ 80428d7b3dSmrg struct test_target tt; 81428d7b3dSmrg XImage image; 82428d7b3dSmrg uint32_t *cells = malloc(t->out.width*t->out.height*4); 83428d7b3dSmrg struct { 84428d7b3dSmrg uint16_t x, y; 85428d7b3dSmrg } *pixels = malloc(reps*sizeof(*pixels)); 86428d7b3dSmrg int r, s; 87428d7b3dSmrg 88428d7b3dSmrg printf("Testing setting of single pixels (%s): ", test_target_name(target)); 89428d7b3dSmrg fflush(stdout); 90428d7b3dSmrg 91428d7b3dSmrg test_target_create_render(&t->out, target, &tt); 92428d7b3dSmrg 93428d7b3dSmrg for (s = 0; s < sets; s++) { 94428d7b3dSmrg for (r = 0; r < reps; r++) { 95428d7b3dSmrg int x = rand() % (tt.width - 1); 96428d7b3dSmrg int y = rand() % (tt.height - 1); 97428d7b3dSmrg int red = rand() % 0xff; 98428d7b3dSmrg int green = rand() % 0xff; 99428d7b3dSmrg int blue = rand() % 0xff; 100428d7b3dSmrg int alpha = rand() % 0xff; 101428d7b3dSmrg 102428d7b3dSmrg fill_rect(&t->out, tt.picture, PictOpSrc, 103428d7b3dSmrg x, y, 1, 1, 104428d7b3dSmrg 0, 0, MASK_NONE, 105428d7b3dSmrg red, green, blue, alpha); 106428d7b3dSmrg 107428d7b3dSmrg pixels[r].x = x; 108428d7b3dSmrg pixels[r].y = y; 109428d7b3dSmrg cells[y*t->out.width+x] = color(red, green, blue, alpha); 110428d7b3dSmrg } 111428d7b3dSmrg 112428d7b3dSmrg test_init_image(&image, &t->out.shm, tt.format, 1, 1); 113428d7b3dSmrg 114428d7b3dSmrg for (r = 0; r < reps; r++) { 115428d7b3dSmrg uint32_t result; 116428d7b3dSmrg uint32_t x = pixels[r].x; 117428d7b3dSmrg uint32_t y = pixels[r].y; 118428d7b3dSmrg 119428d7b3dSmrg XShmGetImage(t->out.dpy, tt.draw, &image, 120428d7b3dSmrg x, y, AllPlanes); 121428d7b3dSmrg 122428d7b3dSmrg result = *(uint32_t *)image.data; 123428d7b3dSmrg if (!pixel_equal(image.depth, result, 124428d7b3dSmrg cells[y*tt.width+x])) { 125428d7b3dSmrg uint32_t mask = depth_mask(image.depth); 126428d7b3dSmrg die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", 127428d7b3dSmrg x, y, 128428d7b3dSmrg cells[y*tt.width+x] & mask, 129428d7b3dSmrg cells[y*tt.width+x], 130428d7b3dSmrg result & mask, 131428d7b3dSmrg result); 132428d7b3dSmrg } 133428d7b3dSmrg } 134428d7b3dSmrg } 135428d7b3dSmrg printf("passed [%d iterations x %d]\n", reps, sets); 136428d7b3dSmrg 137428d7b3dSmrg test_target_destroy_render(&t->out, &tt); 138428d7b3dSmrg 139428d7b3dSmrg free(pixels); 140428d7b3dSmrg free(cells); 141428d7b3dSmrg} 142428d7b3dSmrg 143428d7b3dSmrgstatic void clear(struct test_display *dpy, struct test_target *tt) 144428d7b3dSmrg{ 145428d7b3dSmrg XRenderColor render_color = {0}; 146428d7b3dSmrg XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, 147428d7b3dSmrg 0, 0, tt->width, tt->height); 148428d7b3dSmrg} 149428d7b3dSmrg 150428d7b3dSmrgstatic void area_tests(struct test *t, int reps, int sets, enum target target) 151428d7b3dSmrg{ 152428d7b3dSmrg struct test_target tt; 153428d7b3dSmrg XImage image; 154428d7b3dSmrg uint32_t *cells = calloc(sizeof(uint32_t), t->out.width*t->out.height); 155428d7b3dSmrg int r, s, x, y; 156428d7b3dSmrg 157428d7b3dSmrg printf("Testing area sets (%s): ", test_target_name(target)); 158428d7b3dSmrg fflush(stdout); 159428d7b3dSmrg 160428d7b3dSmrg test_target_create_render(&t->out, target, &tt); 161428d7b3dSmrg clear(&t->out, &tt); 162428d7b3dSmrg 163428d7b3dSmrg test_init_image(&image, &t->out.shm, tt.format, tt.width, tt.height); 164428d7b3dSmrg 165428d7b3dSmrg for (s = 0; s < sets; s++) { 166428d7b3dSmrg for (r = 0; r < reps; r++) { 167428d7b3dSmrg int w = rand() % tt.width; 168428d7b3dSmrg int h = rand() % tt.height; 169428d7b3dSmrg int red = rand() % 0xff; 170428d7b3dSmrg int green = rand() % 0xff; 171428d7b3dSmrg int blue = rand() % 0xff; 172428d7b3dSmrg int alpha = rand() % 0xff; 173428d7b3dSmrg 174428d7b3dSmrg x = rand() % (2*tt.width) - tt.width; 175428d7b3dSmrg y = rand() % (2*tt.height) - tt.height; 176428d7b3dSmrg 177428d7b3dSmrg fill_rect(&t->out, tt.picture, PictOpSrc, 178428d7b3dSmrg x, y, w, h, 179428d7b3dSmrg 0, 0, MASK_NONE, 180428d7b3dSmrg red, green, blue, alpha); 181428d7b3dSmrg 182428d7b3dSmrg if (x < 0) 183428d7b3dSmrg w += x, x = 0; 184428d7b3dSmrg if (y < 0) 185428d7b3dSmrg h += y, y = 0; 186428d7b3dSmrg if (x >= tt.width || y >= tt.height) 187428d7b3dSmrg continue; 188428d7b3dSmrg 189428d7b3dSmrg if (x + w > tt.width) 190428d7b3dSmrg w = tt.width - x; 191428d7b3dSmrg if (y + h > tt.height) 192428d7b3dSmrg h = tt.height - y; 193428d7b3dSmrg if (w <= 0 || h <= 0) 194428d7b3dSmrg continue; 195428d7b3dSmrg 196428d7b3dSmrg pixman_fill(cells, tt.width, 32, x, y, w, h, 197428d7b3dSmrg color(red, green, blue, alpha)); 198428d7b3dSmrg } 199428d7b3dSmrg 200428d7b3dSmrg XShmGetImage(t->out.dpy, tt.draw, &image, 0, 0, AllPlanes); 201428d7b3dSmrg 202428d7b3dSmrg for (y = 0; y < tt.height; y++) { 203428d7b3dSmrg for (x = 0; x < tt.width; x++) { 204428d7b3dSmrg uint32_t result = 205428d7b3dSmrg *(uint32_t *)(image.data + 206428d7b3dSmrg y*image.bytes_per_line + 207428d7b3dSmrg image.bits_per_pixel*x/8); 208428d7b3dSmrg if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { 209428d7b3dSmrg uint32_t mask = depth_mask(image.depth); 210428d7b3dSmrg 211428d7b3dSmrg die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", 212428d7b3dSmrg x, y, 213428d7b3dSmrg cells[y*tt.width+x] & mask, 214428d7b3dSmrg cells[y*tt.width+x], 215428d7b3dSmrg result & mask, 216428d7b3dSmrg result); 217428d7b3dSmrg } 218428d7b3dSmrg } 219428d7b3dSmrg } 220428d7b3dSmrg } 221428d7b3dSmrg 222428d7b3dSmrg printf("passed [%d iterations x %d]\n", reps, sets); 223428d7b3dSmrg 224428d7b3dSmrg test_target_destroy_render(&t->out, &tt); 225428d7b3dSmrg free(cells); 226428d7b3dSmrg} 227428d7b3dSmrg 228428d7b3dSmrgstatic void rect_tests(struct test *t, 229428d7b3dSmrg int dx, int dy, 230428d7b3dSmrg enum mask mask, 231428d7b3dSmrg int reps, int sets, 232428d7b3dSmrg enum target target) 233428d7b3dSmrg{ 234428d7b3dSmrg struct test_target out, ref; 235428d7b3dSmrg int r, s; 236428d7b3dSmrg 237428d7b3dSmrg printf("Testing area fills (offset %dx%d, mask %s) (%s): ", 238428d7b3dSmrg dx, dy, mask_name(mask), test_target_name(target)); 239428d7b3dSmrg fflush(stdout); 240428d7b3dSmrg 241428d7b3dSmrg test_target_create_render(&t->out, target, &out); 242428d7b3dSmrg clear(&t->out, &out); 243428d7b3dSmrg 244428d7b3dSmrg test_target_create_render(&t->ref, target, &ref); 245428d7b3dSmrg clear(&t->ref, &ref); 246428d7b3dSmrg 247428d7b3dSmrg for (s = 0; s < sets; s++) { 248428d7b3dSmrg for (r = 0; r < reps; r++) { 249428d7b3dSmrg int x = rand() % (2*out.width) - out.width; 250428d7b3dSmrg int y = rand() % (2*out.height) - out.height; 251428d7b3dSmrg int w = rand() % out.width; 252428d7b3dSmrg int h = rand() % out.height; 253428d7b3dSmrg int op = ops[rand() % sizeof(ops)]; 254428d7b3dSmrg int red = rand() % 0xff; 255428d7b3dSmrg int green = rand() % 0xff; 256428d7b3dSmrg int blue = rand() % 0xff; 257428d7b3dSmrg int alpha = rand() % 0xff; 258428d7b3dSmrg 259428d7b3dSmrg fill_rect(&t->out, out.picture, op, 260428d7b3dSmrg x, y, w, h, dx, dy, mask, 261428d7b3dSmrg red, green, blue, alpha); 262428d7b3dSmrg fill_rect(&t->ref, ref.picture, op, 263428d7b3dSmrg x, y, w, h, dx, dy, mask, 264428d7b3dSmrg red, green, blue, alpha); 265428d7b3dSmrg } 266428d7b3dSmrg 267428d7b3dSmrg test_compare(t, 268428d7b3dSmrg out.draw, out.format, 269428d7b3dSmrg ref.draw, ref.format, 270428d7b3dSmrg 0, 0, out.width, out.height, 271428d7b3dSmrg ""); 272428d7b3dSmrg } 273428d7b3dSmrg 274428d7b3dSmrg printf("passed [%d iterations x %d]\n", reps, sets); 275428d7b3dSmrg 276428d7b3dSmrg test_target_destroy_render(&t->out, &out); 277428d7b3dSmrg test_target_destroy_render(&t->ref, &ref); 278428d7b3dSmrg} 279428d7b3dSmrg 280428d7b3dSmrgstatic void random_trapezoid(XTrapezoid *trap, enum trapezoid trapezoid, 281428d7b3dSmrg int x1, int y1, int x2, int y2) 282428d7b3dSmrg{ 283428d7b3dSmrg switch (trapezoid) { 284428d7b3dSmrg case RECT_ALIGN: 285428d7b3dSmrg x1 = x1 + rand() % (x2 - x1); 286428d7b3dSmrg x2 = x1 + rand() % (x2 - x1); 287428d7b3dSmrg y1 = y1 + rand() % (y2 - y1); 288428d7b3dSmrg y2 = y1 + rand() % (y2 - y1); 289428d7b3dSmrg 290428d7b3dSmrg trap->left.p1.x = trap->left.p2.x = x1 << 16; 291428d7b3dSmrg trap->top = trap->left.p1.y = trap->right.p1.y = y1 << 16; 292428d7b3dSmrg trap->right.p1.x = trap->right.p2.x = x2 << 16; 293428d7b3dSmrg trap->bottom = trap->left.p2.y = trap->right.p2.y = y2 << 16; 294428d7b3dSmrg break; 295428d7b3dSmrg 296428d7b3dSmrg case RECT_UNALIGN: 297428d7b3dSmrg x1 <<= 16; x2 <<= 16; 298428d7b3dSmrg y1 <<= 16; y2 <<= 16; 299428d7b3dSmrg 300428d7b3dSmrg x1 = x1 + rand() % (x2 - x1); 301428d7b3dSmrg x2 = x1 + rand() % (x2 - x1); 302428d7b3dSmrg y1 = y1 + rand() % (y2 - y1); 303428d7b3dSmrg y2 = y1 + rand() % (y2 - y1); 304428d7b3dSmrg 305428d7b3dSmrg trap->left.p1.x = trap->left.p2.x = x1; 306428d7b3dSmrg trap->top = trap->left.p1.y = trap->right.p1.y = y1; 307428d7b3dSmrg trap->right.p1.x = trap->right.p2.x = x2; 308428d7b3dSmrg trap->bottom = trap->left.p2.y = trap->right.p2.y = y2; 309428d7b3dSmrg break; 310428d7b3dSmrg 311428d7b3dSmrg case GENERAL: 312428d7b3dSmrg x1 <<= 16; x2 <<= 16; 313428d7b3dSmrg y1 <<= 16; y2 <<= 16; 314428d7b3dSmrg 315428d7b3dSmrg trap->top = y1 + rand() % (y2 - y1); 316428d7b3dSmrg trap->bottom = y1 + rand() % (y2 - y1); 317428d7b3dSmrg 318428d7b3dSmrg trap->left.p1.x = x1 + rand() % (x2 - x1); 319428d7b3dSmrg trap->left.p2.x = x1 + rand() % (x2 - x1); 320428d7b3dSmrg 321428d7b3dSmrg trap->right.p1.x = x1 + rand() % (x2 - x1); 322428d7b3dSmrg trap->right.p2.x = x1 + rand() % (x2 - x1); 323428d7b3dSmrg break; 324428d7b3dSmrg 325428d7b3dSmrg } 326428d7b3dSmrg} 327428d7b3dSmrg 328428d7b3dSmrgstatic void trap_tests(struct test *t, 329428d7b3dSmrg enum mask mask, 330428d7b3dSmrg enum trapezoid trapezoid, 331428d7b3dSmrg int reps, int sets, 332428d7b3dSmrg enum target target) 333428d7b3dSmrg{ 334428d7b3dSmrg struct test_target out, ref; 335428d7b3dSmrg XTrapezoid *traps; 336428d7b3dSmrg int max_traps = 65536; 337428d7b3dSmrg int r, s, n; 338428d7b3dSmrg 339428d7b3dSmrg traps = malloc(sizeof(*traps) * max_traps); 340428d7b3dSmrg if (traps == NULL) 341428d7b3dSmrg return; 342428d7b3dSmrg 343428d7b3dSmrg printf("Testing trapezoids (%s with mask %s) (%s): ", 344428d7b3dSmrg trapezoid_name(trapezoid), 345428d7b3dSmrg mask_name(mask), 346428d7b3dSmrg test_target_name(target)); 347428d7b3dSmrg fflush(stdout); 348428d7b3dSmrg 349428d7b3dSmrg test_target_create_render(&t->out, target, &out); 350428d7b3dSmrg clear(&t->out, &out); 351428d7b3dSmrg 352428d7b3dSmrg test_target_create_render(&t->ref, target, &ref); 353428d7b3dSmrg clear(&t->ref, &ref); 354428d7b3dSmrg 355428d7b3dSmrg for (s = 0; s < sets; s++) { 356428d7b3dSmrg for (r = 0; r < reps; r++) { 357428d7b3dSmrg XRenderColor render_color; 358428d7b3dSmrg int op = ops[rand() % sizeof(ops)]; 359428d7b3dSmrg int red = rand() % 0xff; 360428d7b3dSmrg int green = rand() % 0xff; 361428d7b3dSmrg int blue = rand() % 0xff; 362428d7b3dSmrg int alpha = rand() % 0xff; 363428d7b3dSmrg int num_traps = rand() % max_traps; 364428d7b3dSmrg Picture src; 365428d7b3dSmrg 366428d7b3dSmrg for (n = 0; n < num_traps; n++) 367428d7b3dSmrg random_trapezoid(&traps[n], 0, 368428d7b3dSmrg 0, 0, out.width, out.height); 369428d7b3dSmrg 370428d7b3dSmrg render_color.red = red * alpha; 371428d7b3dSmrg render_color.green = green * alpha; 372428d7b3dSmrg render_color.blue = blue * alpha; 373428d7b3dSmrg render_color.alpha = alpha << 8; 374428d7b3dSmrg 375428d7b3dSmrg src = XRenderCreateSolidFill(t->out.dpy, 376428d7b3dSmrg &render_color); 377428d7b3dSmrg XRenderCompositeTrapezoids(t->out.dpy, 378428d7b3dSmrg op, src, out.picture, 379428d7b3dSmrg mask_format(t->out.dpy, mask), 380428d7b3dSmrg 0, 0, traps, num_traps); 381428d7b3dSmrg XRenderFreePicture(t->out.dpy, src); 382428d7b3dSmrg 383428d7b3dSmrg src = XRenderCreateSolidFill(t->ref.dpy, 384428d7b3dSmrg &render_color); 385428d7b3dSmrg XRenderCompositeTrapezoids(t->ref.dpy, 386428d7b3dSmrg op, src, ref.picture, 387428d7b3dSmrg mask_format(t->ref.dpy, mask), 388428d7b3dSmrg 0, 0, traps, num_traps); 389428d7b3dSmrg XRenderFreePicture(t->ref.dpy, src); 390428d7b3dSmrg } 391428d7b3dSmrg 392428d7b3dSmrg test_compare(t, 393428d7b3dSmrg out.draw, out.format, 394428d7b3dSmrg ref.draw, ref.format, 395428d7b3dSmrg 0, 0, out.width, out.height, 396428d7b3dSmrg ""); 397428d7b3dSmrg } 398428d7b3dSmrg 399428d7b3dSmrg printf("passed [%d iterations x %d]\n", reps, sets); 400428d7b3dSmrg 401428d7b3dSmrg test_target_destroy_render(&t->out, &out); 402428d7b3dSmrg test_target_destroy_render(&t->ref, &ref); 403428d7b3dSmrg free(traps); 404428d7b3dSmrg} 405428d7b3dSmrg 406428d7b3dSmrgint main(int argc, char **argv) 407428d7b3dSmrg{ 408428d7b3dSmrg struct test test; 409428d7b3dSmrg int i, dx, dy; 410428d7b3dSmrg enum target target; 411428d7b3dSmrg enum mask mask; 412428d7b3dSmrg enum trapezoid trapezoid; 413428d7b3dSmrg 414428d7b3dSmrg test_init(&test, argc, argv); 415428d7b3dSmrg 416428d7b3dSmrg for (i = 0; i <= DEFAULT_ITERATIONS; i++) { 417428d7b3dSmrg int reps = REPS(i), sets = SETS(i); 418428d7b3dSmrg 419428d7b3dSmrg for (target = TARGET_FIRST; target <= TARGET_LAST; target++) { 420428d7b3dSmrg pixel_tests(&test, reps, sets, target); 421428d7b3dSmrg area_tests(&test, reps, sets, target); 422428d7b3dSmrg for (dy = 0; dy < 1 << 16; dy += 1 << 14) 423428d7b3dSmrg for (dx = 0; dx < 1 << 16; dx += 1 << 14) 424428d7b3dSmrg for (mask = MASK_NONE; mask <= MASK_A8; mask++) 425428d7b3dSmrg rect_tests(&test, dx, dy, mask, reps, sets, target); 426428d7b3dSmrg for (trapezoid = RECT_ALIGN; trapezoid <= GENERAL; trapezoid++) 427428d7b3dSmrg trap_tests(&test, mask, trapezoid, reps, sets, target); 428428d7b3dSmrg } 429428d7b3dSmrg } 430428d7b3dSmrg 431428d7b3dSmrg return 0; 432428d7b3dSmrg} 433