summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2015-05-17 20:45:25 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2015-05-18 09:05:30 +0100
commitb10ef9cf5c9cc844f432e9024deeb78fa1034a8e (patch)
treede92d6fe730f1514f3396f69e55d0a948c1f94cb /test
parent6d64063750535f1c2b94e075d1d525ed289821aa (diff)
sna/glyphs: Improve handling of low bitdepth mask format conversions
We shouldn't just discard the mask if the user requests that we render the glyphs through a low bitdepth mask - and in doing so we should also be careful not to improve the bitdepth of that mask (since we don't take into account the extra quantisation desired). Testcase: render-glyphs Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'test')
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile.am1
-rw-r--r--test/render-glyphs.c441
-rw-r--r--test/test.h9
4 files changed, 452 insertions, 0 deletions
diff --git a/test/.gitignore b/test/.gitignore
index da174be8..373ba15e 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -18,6 +18,7 @@ render-copyarea
render-copyarea-mask
render-copyarea-size
render-copy-alphaless
+render-glyphs
mixed-stress
lowlevel-blt-bench
vsync.avi
diff --git a/test/Makefile.am b/test/Makefile.am
index 9b372228..aaa656af 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -12,6 +12,7 @@ stress_TESTS = \
DrawSegments \
cursor-test \
render-fill \
+ render-glyphs \
render-trapezoid \
render-trapezoid-image \
render-fill-copy \
diff --git a/test/render-glyphs.c b/test/render-glyphs.c
new file mode 100644
index 00000000..8822e36a
--- /dev/null
+++ b/test/render-glyphs.c
@@ -0,0 +1,441 @@
+#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;
+}
diff --git a/test/test.h b/test/test.h
index a3ef979d..9eec1cf9 100644
--- a/test/test.h
+++ b/test/test.h
@@ -107,6 +107,15 @@ static inline uint32_t color(uint8_t red, uint8_t green, uint8_t blue, uint8_t a
return alpha << 24 | ra >> 8 << 16 | ga >> 8 << 8 | ba >> 8;
}
+static inline uint32_t xrender_color(const XRenderColor *c)
+{
+ uint32_t ra = c->red * c->alpha;
+ uint32_t ga = c->green * c->alpha;
+ uint32_t ba = c->blue * c->alpha;
+
+ return c->alpha >> 8 << 24 | ra >> 24 << 16 | ga >> 24 << 8 | ba >> 24;
+}
+
void test_timer_start(struct test_display *t, struct timespec *tv);
double test_timer_stop(struct test_display *t, struct timespec *tv);