xf86-video-intel/test/render-glyphs.c

442 lines
9.2 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <X11/Xutil.h> /* for XDestroyImage */
#include <pixman.h> /* for pixman blt functions */
#include "test.h"
static const XRenderColor colors[] = {
/* red, green, blue, alpha */
{ 0 },
{ 0, 0, 0, 0xffff },
{ 0xffff, 0, 0, 0xffff },
{ 0, 0xffff, 0, 0xffff },
{ 0, 0, 0xffff, 0xffff },
{ 0xffff, 0xffff, 0xffff, 0xffff },
};
static struct clip {
void *func;
} clips[] = {
{ NULL },
};
static int _x_error_occurred;
static int
_check_error_handler(Display *display,
XErrorEvent *event)
{
_x_error_occurred = 1;
return False; /* ignored */
}
static void clear(struct test_display *dpy,
struct test_target *tt,
const XRenderColor *c)
{
XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, c,
0, 0, tt->width, tt->height);
}
static bool check_op(struct test_display *dpy, int op, struct test_target *tt)
{
XRenderColor render_color = {0};
XSync(dpy->dpy, True);
_x_error_occurred = 0;
XRenderFillRectangle(dpy->dpy, op,
tt->picture, &render_color,
0, 0, 0, 0);
XSync(dpy->dpy, True);
return _x_error_occurred == 0;
}
struct glyph_iter {
enum {
GLYPHS, OP, DST, SRC, MASK, CLIP,
} stage;
int glyph_format;
int op;
int dst_color;
int src_color;
int mask_format;
int clip;
struct {
struct test_display *dpy;
struct test_target tt;
GlyphSet glyphset;
Picture src;
XRenderPictFormat *mask_format;
} ref, out;
};
static void glyph_iter_init(struct glyph_iter *gi,
struct test *t, enum target target)
{
memset(gi, 0, sizeof(*gi));
gi->out.dpy = &t->out;
test_target_create_render(&t->out, target, &gi->out.tt);
gi->ref.dpy = &t->ref;
test_target_create_render(&t->ref, target, &gi->ref.tt);
gi->stage = GLYPHS;
gi->glyph_format = -1;
gi->op = -1;
gi->dst_color = -1;
gi->src_color = -1;
gi->mask_format = -1;
gi->clip = -1;
}
static void render_clear(char *image, int image_size, int bpp)
{
memset(image, 0, image_size);
}
static void render_black(char *image, int image_size, int bpp)
{
if (bpp == 4) {
uint32_t *p = (uint32_t *)image;
image_size /= 4;
while (image_size--)
*p++ = 0x000000ff;
} else
memset(image, 0x55, image_size);
}
static void render_green(char *image, int image_size, int bpp)
{
if (bpp == 4) {
uint32_t *p = (uint32_t *)image;
image_size /= 4;
while (image_size--)
*p++ = 0xffff0000;
} else
memset(image, 0xaa, image_size);
}
static void render_white(char *image, int image_size, int bpp)
{
memset(image, 0xff, image_size);
}
static GlyphSet create_glyphs(Display *dpy, int format_id)
{
#define N_GLYPHS 4
XRenderPictFormat *format;
XGlyphInfo glyph = { 8, 8, 0, 0, 8, 0 };
char image[4*8*8];
GlyphSet glyphset;
Glyph gid;
int image_size;
int bpp;
int n;
format = XRenderFindStandardFormat(dpy, format_id);
if (format == NULL)
return 0;
switch (format_id) {
case PictStandardARGB32:
case PictStandardRGB24:
image_size = 4 * 8 * 8;
bpp = 4;
break;
case PictStandardA8:
case PictStandardA4:
image_size = 8 * 8;
bpp = 1;
break;
case PictStandardA1:
image_size = 8;
bpp = 0;
break;
default:
return 0;
}
glyphset = XRenderCreateGlyphSet(dpy, format);
for (n = 0; n < N_GLYPHS; n++) {
gid = n;
switch (n) {
case 0: render_clear(image, image_size, bpp); break;
case 1: render_black(image, image_size, bpp); break;
case 2: render_green(image, image_size, bpp); break;
case 3: render_white(image, image_size, bpp); break;
}
XRenderAddGlyphs(dpy, glyphset,
&gid, &glyph, 1, image, image_size);
}
return glyphset;
}
static const char *glyph_name(int n)
{
switch (n) {
case 0: return "clear";
case 1: return "black";
case 2: return "green";
case 3: return "white";
default: return "unknown";
}
}
static bool glyph_iter_next(struct glyph_iter *gi)
{
restart:
if (gi->stage == GLYPHS) {
if (++gi->glyph_format == PictStandardNUM)
return false;
if (gi->out.glyphset)
XRenderFreeGlyphSet(gi->out.dpy->dpy,
gi->out.glyphset);
gi->out.glyphset = create_glyphs(gi->out.dpy->dpy,
gi->glyph_format);
if (gi->ref.glyphset)
XRenderFreeGlyphSet(gi->ref.dpy->dpy,
gi->ref.glyphset);
gi->ref.glyphset = create_glyphs(gi->ref.dpy->dpy,
gi->glyph_format);
gi->stage++;
}
if (gi->stage == OP) {
do {
if (++gi->op == 255)
goto reset_op;
} while (!check_op(gi->out.dpy, gi->op, &gi->out.tt) ||
!check_op(gi->ref.dpy, gi->op, &gi->ref.tt));
gi->stage++;
}
if (gi->stage == DST) {
if (++gi->dst_color == ARRAY_SIZE(colors))
goto reset_dst;
gi->stage++;
}
if (gi->stage == SRC) {
if (++gi->src_color == ARRAY_SIZE(colors))
goto reset_src;
if (gi->ref.src)
XRenderFreePicture(gi->ref.dpy->dpy, gi->ref.src);
gi->ref.src = XRenderCreateSolidFill(gi->ref.dpy->dpy,
&colors[gi->src_color]);
if (gi->out.src)
XRenderFreePicture(gi->out.dpy->dpy, gi->out.src);
gi->out.src = XRenderCreateSolidFill(gi->out.dpy->dpy,
&colors[gi->src_color]);
gi->stage++;
}
if (gi->stage == MASK) {
if (++gi->mask_format > PictStandardNUM)
goto reset_mask;
if (gi->mask_format == PictStandardRGB24)
gi->mask_format++;
if (gi->mask_format < PictStandardNUM) {
gi->out.mask_format = XRenderFindStandardFormat(gi->out.dpy->dpy,
gi->mask_format);
gi->ref.mask_format = XRenderFindStandardFormat(gi->ref.dpy->dpy,
gi->mask_format);
} else {
gi->out.mask_format = NULL;
gi->ref.mask_format = NULL;
}
gi->stage++;
}
if (gi->stage == CLIP) {
if (++gi->clip == ARRAY_SIZE(clips))
goto reset_clip;
gi->stage++;
}
gi->stage--;
return true;
reset_op:
gi->op = -1;
reset_dst:
gi->dst_color = -1;
reset_src:
gi->src_color = -1;
reset_mask:
gi->mask_format = -1;
reset_clip:
gi->clip = -1;
gi->stage--;
goto restart;
}
static void glyph_iter_fini(struct glyph_iter *gi)
{
if (gi->out.glyphset)
XRenderFreeGlyphSet (gi->out.dpy->dpy, gi->out.glyphset);
if (gi->ref.glyphset)
XRenderFreeGlyphSet (gi->ref.dpy->dpy, gi->ref.glyphset);
test_target_destroy_render(gi->out.dpy, &gi->out.tt);
test_target_destroy_render(gi->ref.dpy, &gi->ref.tt);
}
static const char *stdformat_to_str(int id)
{
switch (id) {
case PictStandardARGB32: return "ARGB32";
case PictStandardRGB24: return "RGB24";
case PictStandardA8: return "A8";
case PictStandardA4: return "A4";
case PictStandardA1: return "A1";
default: return "none";
}
}
static char *glyph_iter_to_string(struct glyph_iter *gi,
const char *format,
...)
{
static char buf[100];
va_list ap;
int len;
len = sprintf(buf, "glyphs=%s, op=%d, dst=%08x, src=%08x, mask=%s",
stdformat_to_str(gi->glyph_format), gi->op,
xrender_color(&colors[gi->dst_color]),
xrender_color(&colors[gi->src_color]),
stdformat_to_str(gi->mask_format));
if (format) {
buf[len++] = ' ';
va_start(ap, format);
vsprintf(buf+len, format, ap);
va_end(ap);
}
return buf;
}
static void single(struct test *t, enum target target)
{
struct glyph_iter gi;
int n;
printf("Testing single glyph (%s): ", test_target_name(target));
fflush(stdout);
glyph_iter_init(&gi, t, target);
while (glyph_iter_next(&gi)) {
XGlyphElt8 elt;
char id[N_GLYPHS];
for (n = 0; n < N_GLYPHS; n++) {
id[n] = n;
elt.chars = &id[n];
elt.nchars = 1;
elt.xOff = 0;
elt.yOff = 0;
clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
elt.glyphset = gi.out.glyphset;
XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
gi.out.src,
gi.out.tt.picture,
gi.out.mask_format,
0, 0,
0, 8,
&elt, 1);
clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
elt.glyphset = gi.ref.glyphset;
XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
gi.ref.src,
gi.ref.tt.picture,
gi.ref.mask_format,
0, 0,
0, 8,
&elt, 1);
test_compare(t,
gi.out.tt.draw, gi.out.tt.format,
gi.ref.tt.draw, gi.ref.tt.format,
0, 0, gi.out.tt.width, gi.out.tt.height,
glyph_iter_to_string(&gi,
"glyph=%s",
glyph_name(n)));
}
elt.chars = &id[0];
elt.nchars = n;
clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
elt.glyphset = gi.out.glyphset;
XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
gi.out.src,
gi.out.tt.picture,
gi.out.mask_format,
0, 0,
0, 8,
&elt, 1);
clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
elt.glyphset = gi.ref.glyphset;
XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
gi.ref.src,
gi.ref.tt.picture,
gi.ref.mask_format,
0, 0,
0, 8,
&elt, 1);
test_compare(t,
gi.out.tt.draw, gi.out.tt.format,
gi.ref.tt.draw, gi.ref.tt.format,
0, 0, gi.out.tt.width, gi.out.tt.height,
glyph_iter_to_string(&gi, "all"));
}
glyph_iter_fini(&gi);
}
int main(int argc, char **argv)
{
struct test test;
int t;
test_init(&test, argc, argv);
XSetErrorHandler(_check_error_handler);
for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
single(&test, t);
//overlapping(&test, t);
//gap(&test, t);
//mixed(&test, t);
}
return 0;
}