/* * Copyright © 2009 Nokia Corporation * Copyright © 2010 Movial Creative Technologies Oy * Copyright © 2013 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include /* for XDestroyImage */ #include #include #if HAVE_MIT_SHM #include #if HAVE_X11_EXTENSIONS_SHMPROTO_H #include #elif HAVE_X11_EXTENSIONS_SHMSTR_H #include #else #error Failed to find the right header for X11 MIT-SHM protocol definitions #endif #include #include #endif #include /* for pixman blt functions */ #include "test.h" static const struct format { const char *name; pixman_format_code_t pixman_format; } formats[] = { { "a8r8g8b8", PIXMAN_a8r8g8b8 }, { "x8r8g8b8", PIXMAN_x8r8g8b8 }, { "a8", PIXMAN_a8 }, { "a4", PIXMAN_a4 }, { "a1", PIXMAN_a1 }, }; static const struct op { int value; const char *name; } ops[] = { { PictOpClear, "Clear" }, { PictOpSrc, "Src" }, { PictOpDst, "Dst" }, { PictOpOver, "Over" }, { PictOpOverReverse, "OverReverse" }, { PictOpIn, "In" }, { PictOpInReverse, "InReverse" }, { PictOpOut, "Out" }, { PictOpOutReverse, "OutReverse" }, { PictOpAtop, "Atop" }, { PictOpAtopReverse, "AtopReverse" }, { PictOpXor, "Xor" }, { PictOpAdd, "Add" }, { PictOpSaturate, "Saturate" }, { PictOpMultiply, "Multiply" }, { PictOpScreen, "Screen" }, { PictOpOverlay, "Overlay" }, { PictOpDarken, "Darken" }, { PictOpLighten, "Lighten" }, { PictOpColorDodge, "Dodge" }, { PictOpColorBurn, "Burn" }, { PictOpHardLight, "HardLight" }, { PictOpSoftLight, "SoftLight" }, }; static Picture source_pixmap(struct test_display *t, struct test_target *target, int format) { XRenderColor render_color[2] = { { 0x8000, 0x8000, 0x8000, 0x8000 }, { 0xffff, 0xffff, 0xffff, 0xffff }, }; Pixmap pixmap; Picture picture; pixmap = XCreatePixmap(t->dpy, t->root, target->width, target->height, PIXMAN_FORMAT_DEPTH(formats[format].pixman_format)); picture = XRenderCreatePicture(t->dpy, pixmap, XRenderFindStandardFormat(t->dpy, format), 0, NULL); XFreePixmap(t->dpy, pixmap); XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color[0], 0, 0, target->width, target->height/2); XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color[1], 0, target->height/2, target->width, target->height/2); return picture; } static Picture source_a8r8g8b8(struct test_display *t, struct test_target *target) { return source_pixmap(t, target, 0); } static Picture source_x8r8g8b8(struct test_display *t, struct test_target *target) { return source_pixmap(t, target, 1); } static Picture source_a8(struct test_display *t, struct test_target *target) { return source_pixmap(t, target, 2); } static Picture source_a4(struct test_display *t, struct test_target *target) { return source_pixmap(t, target, 3); } static Picture source_a1(struct test_display *t, struct test_target *target) { return source_pixmap(t, target, 3); } static Picture source_1x1r(struct test_display *t, struct test_target *target) { XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; XRenderPictureAttributes pa; Pixmap pixmap; Picture picture; pa.repeat = RepeatNormal; pixmap = XCreatePixmap(t->dpy, t->root, 1, 1, 32); picture = XRenderCreatePicture(t->dpy, pixmap, XRenderFindStandardFormat(t->dpy, 0), CPRepeat, &pa); XFreePixmap(t->dpy, pixmap); XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color, 0, 0, 1, 1); return picture; } static Picture source_solid(struct test_display *t, struct test_target *target) { XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; return XRenderCreateSolidFill(t->dpy, &render_color); } static Picture source_linear_horizontal(struct test_display *t, struct test_target *target) { XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; XFixed stops[2] = {0, 0xffff}; XLinearGradient gradient = { {0, 0}, {target->width << 16, 0}}; return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2); } static Picture source_linear_vertical(struct test_display *t, struct test_target *target) { XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; XFixed stops[2] = {0, 0xffff}; XLinearGradient gradient = { {0, 0}, {0, target->height << 16}}; return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2); } static Picture source_linear_diagonal(struct test_display *t, struct test_target *target) { XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; XFixed stops[2] = {0, 0xffff}; XLinearGradient gradient = { {0, 0}, {target->width << 16, target->height << 16}}; return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2); } static Picture source_radial_concentric(struct test_display *t, struct test_target *target) { XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; XFixed stops[2] = {0, 0xffff}; XRadialGradient gradient = { { ((target->width << 16) + 1) / 2, ((target->height << 16) + 1) / 2, 0, }, { ((target->width << 16) + 1) / 2, ((target->height << 16) + 1) / 2, target->width << 15, } }; return XRenderCreateRadialGradient(t->dpy, &gradient, stops, colors, 2); } static Picture source_radial_generic(struct test_display *t, struct test_target *target) { XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}}; XFixed stops[2] = {0, 0xffff}; XRadialGradient gradient = { { 0, 0, target->width << 14, }, { target->width << 16, target->height << 16, target->width << 14, } }; return XRenderCreateRadialGradient(t->dpy, &gradient, stops, colors, 2); } #if HAVE_MIT_SHM static XShmSegmentInfo shmref, shmout; static void setup_shm(struct test *t) { XShmSegmentInfo shm; int size; shm.shmid = -1; if (!(t->ref.has_shm_pixmaps && t->out.has_shm_pixmaps)) return; size = t->ref.width * t->ref.height * 4; size = (size + 4095) & -4096; shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0666); if (shm.shmid == -1) return; shm.shmaddr = shmat(shm.shmid, 0, 0); if (shm.shmaddr == (char *) -1) { shmctl(shm.shmid, IPC_RMID, NULL); shm.shmid = -1; return; } shm.readOnly = False; shmref = shm; XShmAttach(t->ref.dpy, &shmref); XSync(t->ref.dpy, True); shmout = shm; XShmAttach(t->out.dpy, &shmout); XSync(t->out.dpy, True); } static Picture source_shm(struct test_display *t, struct test_target *target) { XShmSegmentInfo *shm = t->target == REF ? &shmref : &shmout; Pixmap pixmap; Picture picture; int size; if (shm->shmid == -1) return 0; pixmap = XShmCreatePixmap(t->dpy, t->root, shm->shmaddr, shm, target->width, target->height, 32); picture = XRenderCreatePicture(t->dpy, pixmap, XRenderFindStandardFormat(t->dpy, 0), 0, NULL); XFreePixmap(t->dpy, pixmap); size = target->width * target->height * 4; memset(shm->shmaddr, 0x80, size/2); memset(shm->shmaddr+size/2, 0xff, size/2); return picture; } #else static void setup_shm(struct test *t) { } static Picture source_shm(struct test_display *t, struct test_target *target) { return 0; } #endif static const struct { Picture (*create)(struct test_display *, struct test_target *); const char *name; } source[] = { { source_a8r8g8b8, "a8r8g8b8 pixmap" }, { source_x8r8g8b8, "x8r8g8b8 pixmap" }, { source_a8, "a8 pixmap" }, { source_a4, "a4 pixmap" }, { source_a1, "a1 pixmap" }, { source_1x1r, "a8r8g8b8 1x1R pixmap" }, { source_solid, "solid" }, { source_shm, "a8r8g8b8 shm" }, { source_linear_horizontal, "linear (horizontal gradient)" }, { source_linear_vertical, "linear (vertical gradient)" }, { source_linear_diagonal, "linear (diagonal gradient)" }, { source_radial_concentric, "radial (concentric)" }, { source_radial_generic, "radial (generic)" }, }; static double _bench_source(struct test_display *t, enum target target_type, int op, int src, int loops) { XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; struct test_target target; Picture picture; struct timespec tv; double elapsed; test_target_create_render(t, target_type, &target); XRenderFillRectangle(t->dpy, PictOpClear, target.picture, &render_color, 0, 0, target.width, target.height); picture = source[src].create(t, &target); if (picture) { test_timer_start(t, &tv); while (loops--) XRenderComposite(t->dpy, op, picture, 0, target.picture, 0, 0, 0, 0, 0, 0, target.width, target.height); elapsed = test_timer_stop(t, &tv); XRenderFreePicture(t->dpy, picture); } else elapsed = -1; test_target_destroy_render(t, &target); return elapsed; } static void bench_source(struct test *t, enum target target, int op, int src) { double out, ref; fprintf(stdout, "%28s with %s: ", source[src].name, ops[op].name); fflush(stdout); op = ops[op].value; ref = _bench_source(&t->ref, target, op, src, 1000); if (ref < 0) { fprintf(stdout, "SKIP\n"); return; } fprintf(stdout, "ref=%f, ", ref); fflush(stdout); out = _bench_source(&t->out, target, op, src, 1000); if (out < 0) { fprintf(stdout, "SKIP\n"); return; } fprintf(stdout, "out=%f\n", out); } static double _bench_mask(struct test_display *t, enum target target_type, int op, int src, int mask, int loops) { XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 }; struct test_target target; Picture ps, pm; struct timespec tv; double elapsed; test_target_create_render(t, target_type, &target); XRenderFillRectangle(t->dpy, PictOpClear, target.picture, &render_color, 0, 0, target.width, target.height); ps = source[src].create(t, &target); pm = source[mask].create(t, &target); if (ps && pm) { test_timer_start(t, &tv); while (loops--) XRenderComposite(t->dpy, op, ps, pm, target.picture, 0, 0, 0, 0, 0, 0, target.width, target.height); elapsed = test_timer_stop(t, &tv); } else elapsed = -1; if (ps) XRenderFreePicture(t->dpy, ps); if (pm) XRenderFreePicture(t->dpy, pm); test_target_destroy_render(t, &target); return elapsed; } static void bench_mask(struct test *t, enum target target, int op, int src, int mask) { double out, ref; fprintf(stdout, "%28s In %28s with %s: ", source[src].name, source[mask].name, ops[op].name); fflush(stdout); op = ops[op].value; ref = _bench_mask(&t->ref, target, op, src, mask, 1000); if (ref < 0) { fprintf(stdout, "SKIP\n"); return; } fprintf(stdout, "ref=%f, ", ref); fflush(stdout); out = _bench_mask(&t->out, target, op, src, mask, 1000); if (out < 0) { fprintf(stdout, "SKIP\n"); return; } fprintf(stdout, "out=%f\n", out); } int main(int argc, char **argv) { struct test test; unsigned op, src, mask; test_init(&test, argc, argv); setup_shm(&test); for (op = 0; op < sizeof(ops)/sizeof(ops[0]); op++) { for (src = 0; src < sizeof(source)/sizeof(source[0]); src++) bench_source(&test, ROOT, op, src); fprintf (stdout, "\n"); for (src = 0; src < sizeof(source)/sizeof(source[0]); src++) for (mask = 0; mask < sizeof(source)/sizeof(source[0]); mask++) bench_mask(&test, ROOT, op, src, mask); fprintf (stdout, "\n"); } return 0; }