d031df2719
Fixes a display bug seenby ajacoutot@, ok jsg@ and kettenis@. newer X.Org (2.99.917 or master) version cause corruption on older machines (X40, i965), probably caused by a bug in our kernel, under investigation by kettenis@.
466 lines
12 KiB
C
466 lines
12 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <X11/X.h>
|
|
#include <X11/Xutil.h> /* for XDestroyImage */
|
|
#include <X11/Xlibint.h>
|
|
#include <X11/extensions/Xrender.h>
|
|
#if HAVE_MIT_SHM
|
|
#include <X11/extensions/XShm.h>
|
|
#if HAVE_X11_EXTENSIONS_SHMPROTO_H
|
|
#include <X11/extensions/shmproto.h>
|
|
#elif HAVE_X11_EXTENSIONS_SHMSTR_H
|
|
#include <X11/extensions/shmstr.h>
|
|
#else
|
|
#error Failed to find the right header for X11 MIT-SHM protocol definitions
|
|
#endif
|
|
#include <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#endif
|
|
#include <pixman.h> /* 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;
|
|
}
|