1/* 2 * Copyright © 2009 Nokia Corporation 3 * Copyright © 2010 Movial Creative Technologies Oy 4 * Copyright © 2013 Intel Corporation 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26#ifdef HAVE_CONFIG_H 27#include "config.h" 28#endif 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <stdint.h> 34#include <stdbool.h> 35 36#include <X11/X.h> 37#include <X11/Xutil.h> /* for XDestroyImage */ 38#include <X11/Xlibint.h> 39#include <X11/extensions/Xrender.h> 40#if HAVE_MIT_SHM 41#include <X11/extensions/XShm.h> 42#if HAVE_X11_EXTENSIONS_SHMPROTO_H 43#include <X11/extensions/shmproto.h> 44#elif HAVE_X11_EXTENSIONS_SHMSTR_H 45#include <X11/extensions/shmstr.h> 46#else 47#error Failed to find the right header for X11 MIT-SHM protocol definitions 48#endif 49#include <sys/ipc.h> 50#include <sys/shm.h> 51#endif 52#include <pixman.h> /* for pixman blt functions */ 53 54#include "test.h" 55 56static const struct format { 57 const char *name; 58 pixman_format_code_t pixman_format; 59} formats[] = { 60 { "a8r8g8b8", PIXMAN_a8r8g8b8 }, 61 { "x8r8g8b8", PIXMAN_x8r8g8b8 }, 62 { "a8", PIXMAN_a8 }, 63 { "a4", PIXMAN_a4 }, 64 { "a1", PIXMAN_a1 }, 65}; 66 67static const struct op { 68 int value; 69 const char *name; 70} ops[] = { 71 { PictOpClear, "Clear" }, 72 { PictOpSrc, "Src" }, 73 { PictOpDst, "Dst" }, 74 { PictOpOver, "Over" }, 75 { PictOpOverReverse, "OverReverse" }, 76 { PictOpIn, "In" }, 77 { PictOpInReverse, "InReverse" }, 78 { PictOpOut, "Out" }, 79 { PictOpOutReverse, "OutReverse" }, 80 { PictOpAtop, "Atop" }, 81 { PictOpAtopReverse, "AtopReverse" }, 82 { PictOpXor, "Xor" }, 83 { PictOpAdd, "Add" }, 84 { PictOpSaturate, "Saturate" }, 85 { PictOpMultiply, "Multiply" }, 86 { PictOpScreen, "Screen" }, 87 { PictOpOverlay, "Overlay" }, 88 { PictOpDarken, "Darken" }, 89 { PictOpLighten, "Lighten" }, 90 { PictOpColorDodge, "Dodge" }, 91 { PictOpColorBurn, "Burn" }, 92 { PictOpHardLight, "HardLight" }, 93 { PictOpSoftLight, "SoftLight" }, 94}; 95 96static Picture source_pixmap(struct test_display *t, struct test_target *target, int format) 97{ 98 XRenderColor render_color[2] = { 99 { 0x8000, 0x8000, 0x8000, 0x8000 }, 100 { 0xffff, 0xffff, 0xffff, 0xffff }, 101 }; 102 Pixmap pixmap; 103 Picture picture; 104 105 pixmap = XCreatePixmap(t->dpy, t->root, 106 target->width, target->height, 107 PIXMAN_FORMAT_DEPTH(formats[format].pixman_format)); 108 109 picture = XRenderCreatePicture(t->dpy, pixmap, 110 XRenderFindStandardFormat(t->dpy, format), 111 0, NULL); 112 XFreePixmap(t->dpy, pixmap); 113 114 XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color[0], 115 0, 0, target->width, target->height/2); 116 XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color[1], 117 0, target->height/2, target->width, target->height/2); 118 119 return picture; 120} 121 122static Picture source_a8r8g8b8(struct test_display *t, struct test_target *target) 123{ 124 return source_pixmap(t, target, 0); 125} 126 127static Picture source_x8r8g8b8(struct test_display *t, struct test_target *target) 128{ 129 return source_pixmap(t, target, 1); 130} 131 132static Picture source_a8(struct test_display *t, struct test_target *target) 133{ 134 return source_pixmap(t, target, 2); 135} 136 137static Picture source_a4(struct test_display *t, struct test_target *target) 138{ 139 return source_pixmap(t, target, 3); 140} 141 142static Picture source_a1(struct test_display *t, struct test_target *target) 143{ 144 return source_pixmap(t, target, 3); 145} 146 147static Picture source_1x1r(struct test_display *t, struct test_target *target) 148{ 149 XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; 150 XRenderPictureAttributes pa; 151 Pixmap pixmap; 152 Picture picture; 153 154 pa.repeat = RepeatNormal; 155 156 pixmap = XCreatePixmap(t->dpy, t->root, 1, 1, 32); 157 picture = XRenderCreatePicture(t->dpy, pixmap, 158 XRenderFindStandardFormat(t->dpy, 0), 159 CPRepeat, &pa); 160 XFreePixmap(t->dpy, pixmap); 161 162 XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color, 163 0, 0, 1, 1); 164 165 return picture; 166} 167 168static Picture source_solid(struct test_display *t, struct test_target *target) 169{ 170 XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; 171 return XRenderCreateSolidFill(t->dpy, &render_color); 172} 173 174static Picture source_linear_horizontal(struct test_display *t, struct test_target *target) 175{ 176 XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; 177 XFixed stops[2] = {0, 0xffff}; 178 XLinearGradient gradient = { {0, 0}, {target->width << 16, 0}}; 179 180 return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2); 181} 182 183static Picture source_linear_vertical(struct test_display *t, struct test_target *target) 184{ 185 XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; 186 XFixed stops[2] = {0, 0xffff}; 187 XLinearGradient gradient = { {0, 0}, {0, target->height << 16}}; 188 189 return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2); 190} 191 192static Picture source_linear_diagonal(struct test_display *t, struct test_target *target) 193{ 194 XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; 195 XFixed stops[2] = {0, 0xffff}; 196 XLinearGradient gradient = { {0, 0}, {target->width << 16, target->height << 16}}; 197 198 return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2); 199} 200 201static Picture source_radial_concentric(struct test_display *t, struct test_target *target) 202{ 203 XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; 204 XFixed stops[2] = {0, 0xffff}; 205 XRadialGradient gradient = { 206 { 207 ((target->width << 16) + 1) / 2, 208 ((target->height << 16) + 1) / 2, 209 0, 210 }, 211 { 212 ((target->width << 16) + 1) / 2, 213 ((target->height << 16) + 1) / 2, 214 target->width << 15, 215 } 216 }; 217 218 return XRenderCreateRadialGradient(t->dpy, &gradient, stops, colors, 2); 219} 220 221static Picture source_radial_generic(struct test_display *t, struct test_target *target) 222{ 223 XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; 224 XFixed stops[2] = {0, 0xffff}; 225 XRadialGradient gradient = { 226 { 0, 0, target->width << 14, }, 227 { target->width << 16, target->height << 16, target->width << 14, } 228 }; 229 230 return XRenderCreateRadialGradient(t->dpy, &gradient, stops, colors, 2); 231} 232 233#if HAVE_MIT_SHM 234static XShmSegmentInfo shmref, shmout; 235 236static void setup_shm(struct test *t) 237{ 238 XShmSegmentInfo shm; 239 int size; 240 241 shm.shmid = -1; 242 243 if (!(t->ref.has_shm_pixmaps && t->out.has_shm_pixmaps)) 244 return; 245 246 size = t->ref.width * t->ref.height * 4; 247 size = (size + 4095) & -4096; 248 249 shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0666); 250 if (shm.shmid == -1) 251 return; 252 253 shm.shmaddr = shmat(shm.shmid, 0, 0); 254 if (shm.shmaddr == (char *) -1) { 255 shmctl(shm.shmid, IPC_RMID, NULL); 256 shm.shmid = -1; 257 return; 258 } 259 260 shm.readOnly = False; 261 262 shmref = shm; 263 XShmAttach(t->ref.dpy, &shmref); 264 XSync(t->ref.dpy, True); 265 266 shmout = shm; 267 XShmAttach(t->out.dpy, &shmout); 268 XSync(t->out.dpy, True); 269} 270 271static Picture source_shm(struct test_display *t, struct test_target *target) 272{ 273 XShmSegmentInfo *shm = t->target == REF ? &shmref : &shmout; 274 Pixmap pixmap; 275 Picture picture; 276 int size; 277 278 if (shm->shmid == -1) 279 return 0; 280 281 pixmap = XShmCreatePixmap(t->dpy, t->root, 282 shm->shmaddr, shm, 283 target->width, target->height, 32); 284 285 picture = XRenderCreatePicture(t->dpy, pixmap, 286 XRenderFindStandardFormat(t->dpy, 0), 287 0, NULL); 288 XFreePixmap(t->dpy, pixmap); 289 290 size = target->width * target->height * 4; 291 memset(shm->shmaddr, 0x80, size/2); 292 memset(shm->shmaddr+size/2, 0xff, size/2); 293 294 return picture; 295} 296#else 297static void setup_shm(struct test *t) { } 298static Picture source_shm(struct test_display *t, struct test_target *target) { return 0; } 299#endif 300 301static const struct { 302 Picture (*create)(struct test_display *, struct test_target *); 303 const char *name; 304} source[] = { 305 { source_a8r8g8b8, "a8r8g8b8 pixmap" }, 306 { source_x8r8g8b8, "x8r8g8b8 pixmap" }, 307 { source_a8, "a8 pixmap" }, 308 { source_a4, "a4 pixmap" }, 309 { source_a1, "a1 pixmap" }, 310 { source_1x1r, "a8r8g8b8 1x1R pixmap" }, 311 { source_solid, "solid" }, 312 { source_shm, "a8r8g8b8 shm" }, 313 { source_linear_horizontal, "linear (horizontal gradient)" }, 314 { source_linear_vertical, "linear (vertical gradient)" }, 315 { source_linear_diagonal, "linear (diagonal gradient)" }, 316 { source_radial_concentric, "radial (concentric)" }, 317 { source_radial_generic, "radial (generic)" }, 318}; 319 320static double _bench_source(struct test_display *t, enum target target_type, 321 int op, int src, int loops) 322{ 323 XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; 324 struct test_target target; 325 Picture picture; 326 struct timespec tv; 327 double elapsed; 328 329 test_target_create_render(t, target_type, &target); 330 XRenderFillRectangle(t->dpy, PictOpClear, target.picture, &render_color, 331 0, 0, target.width, target.height); 332 333 picture = source[src].create(t, &target); 334 if (picture) { 335 test_timer_start(t, &tv); 336 while (loops--) 337 XRenderComposite(t->dpy, op, 338 picture, 0, target.picture, 339 0, 0, 340 0, 0, 341 0, 0, 342 target.width, target.height); 343 elapsed = test_timer_stop(t, &tv); 344 XRenderFreePicture(t->dpy, picture); 345 } else 346 elapsed = -1; 347 348 test_target_destroy_render(t, &target); 349 350 return elapsed; 351} 352 353static void bench_source(struct test *t, enum target target, int op, int src) 354{ 355 double out, ref; 356 357 fprintf(stdout, "%28s with %s: ", source[src].name, ops[op].name); 358 fflush(stdout); 359 360 op = ops[op].value; 361 362 ref = _bench_source(&t->ref, target, op, src, 1000); 363 if (ref < 0) { 364 fprintf(stdout, "SKIP\n"); 365 return; 366 } 367 fprintf(stdout, "ref=%f, ", ref); 368 fflush(stdout); 369 370 out = _bench_source(&t->out, target, op, src, 1000); 371 if (out < 0) { 372 fprintf(stdout, "SKIP\n"); 373 return; 374 } 375 376 fprintf(stdout, "out=%f\n", out); 377} 378 379static double _bench_mask(struct test_display *t, enum target target_type, 380 int op, int src, int mask, int loops) 381{ 382 XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; 383 struct test_target target; 384 Picture ps, pm; 385 struct timespec tv; 386 double elapsed; 387 388 test_target_create_render(t, target_type, &target); 389 XRenderFillRectangle(t->dpy, PictOpClear, target.picture, &render_color, 390 0, 0, target.width, target.height); 391 392 ps = source[src].create(t, &target); 393 pm = source[mask].create(t, &target); 394 if (ps && pm) { 395 test_timer_start(t, &tv); 396 while (loops--) 397 XRenderComposite(t->dpy, op, 398 ps, pm, target.picture, 399 0, 0, 400 0, 0, 401 0, 0, 402 target.width, target.height); 403 elapsed = test_timer_stop(t, &tv); 404 } else 405 elapsed = -1; 406 407 if (ps) 408 XRenderFreePicture(t->dpy, ps); 409 if (pm) 410 XRenderFreePicture(t->dpy, pm); 411 412 test_target_destroy_render(t, &target); 413 414 return elapsed; 415} 416 417static void bench_mask(struct test *t, enum target target, int op, int src, int mask) 418{ 419 double out, ref; 420 421 fprintf(stdout, "%28s In %28s with %s: ", 422 source[src].name, source[mask].name, ops[op].name); 423 fflush(stdout); 424 425 op = ops[op].value; 426 427 ref = _bench_mask(&t->ref, target, op, src, mask, 1000); 428 if (ref < 0) { 429 fprintf(stdout, "SKIP\n"); 430 return; 431 } 432 fprintf(stdout, "ref=%f, ", ref); 433 fflush(stdout); 434 435 out = _bench_mask(&t->out, target, op, src, mask, 1000); 436 if (out < 0) { 437 fprintf(stdout, "SKIP\n"); 438 return; 439 } 440 441 fprintf(stdout, "out=%f\n", out); 442} 443 444int main(int argc, char **argv) 445{ 446 struct test test; 447 unsigned op, src, mask; 448 449 test_init(&test, argc, argv); 450 451 setup_shm(&test); 452 453 for (op = 0; op < sizeof(ops)/sizeof(ops[0]); op++) { 454 for (src = 0; src < sizeof(source)/sizeof(source[0]); src++) 455 bench_source(&test, ROOT, op, src); 456 fprintf (stdout, "\n"); 457 458 for (src = 0; src < sizeof(source)/sizeof(source[0]); src++) 459 for (mask = 0; mask < sizeof(source)/sizeof(source[0]); mask++) 460 bench_mask(&test, ROOT, op, src, mask); 461 fprintf (stdout, "\n"); 462 } 463 464 return 0; 465} 466