xf86-video-intel: 4 commits - src/sna/sna_accel.c src/sna/sna_glyphs.c src/sna/sna_render.c src/sna/sna_trapezoids_imprecise.c src/sna/sna_trapezoids_mono.c src/sna/sna_trapezoids_precise.c test/.gitignore test/Makefile.am test/render-glyphs.c test/render-triangle.c test/test.h test/test_image.c
Chris Wilson
ickle at kemper.freedesktop.org
Mon May 18 05:41:26 PDT 2015
src/sna/sna_accel.c | 9
src/sna/sna_glyphs.c | 91 ++++---
src/sna/sna_render.c | 2
src/sna/sna_trapezoids_imprecise.c | 3
src/sna/sna_trapezoids_mono.c | 50 +++-
src/sna/sna_trapezoids_precise.c | 3
test/.gitignore | 2
test/Makefile.am | 2
test/render-glyphs.c | 441 +++++++++++++++++++++++++++++++++++++
test/render-triangle.c | 180 +++++++++++++++
test/test.h | 9
test/test_image.c | 36 ---
12 files changed, 749 insertions(+), 79 deletions(-)
New commits:
commit 3852977f14a00db770df7efab79207116aaecbf0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon May 18 09:58:08 2015 +0100
test: Add a fidelity test for triangle edge rendering
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c
index 4e90f9c..8bc7c8a 100644
--- a/src/sna/sna_trapezoids_imprecise.c
+++ b/src/sna/sna_trapezoids_imprecise.c
@@ -1707,8 +1707,7 @@ static void span_thread_add_box(struct sna *sna, void *data,
{
struct span_thread_boxes *b = data;
- __DBG(("%s: adding %d boxes with alpha=%f\n",
- __FUNCTION__, count, alpha));
+ __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c
index 5b65fa4..07a7867 100644
--- a/src/sna/sna_trapezoids_mono.c
+++ b/src/sna/sna_trapezoids_mono.c
@@ -79,7 +79,7 @@ struct mono {
struct mono_polygon polygon;
};
-#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2)
+#define I(x) pixman_fixed_to_int((x) + pixman_fixed_1_minus_e/2)
static struct quorem
floored_muldivrem(int32_t x, int32_t a, int32_t b)
@@ -250,22 +250,22 @@ mono_add_line(struct mono *mono,
e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy);
- e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y,
+ e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1/2 - p1->y,
dx, dy);
e->x.quo += p1->x;
e->x.rem -= dy;
e->dy = dy;
-
- __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
- __FUNCTION__,
- I(e->x.quo), e->x.quo, e->x.rem, e->dy,
- e->dxdy.quo, e->dxdy.rem, e->dy));
}
e->x.quo += dst_x*pixman_fixed_1;
+ __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
+ __FUNCTION__,
+ I(e->x.quo), e->x.quo, e->x.rem, e->dy,
+ e->dxdy.quo, e->dxdy.rem, e->dy));
{
struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1];
+ assert(ytop - mono->clip.extents.y1 < mono->clip.extents.y2 - mono->clip.extents.y1);
if (*ptail)
(*ptail)->prev = e;
e->next = *ptail;
@@ -369,6 +369,10 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
e->x.rem == n->x.rem &&
e->dxdy.quo == n->dxdy.quo &&
e->dxdy.rem == n->dxdy.rem) {
+ assert(e->dy == n->dy);
+ __DBG(("%s: discarding cancellation pair (%d.%d) + (%d.%d)\n",
+ __FUNCTION__, e->x.quo, e->x.rem, e->dxdy.quo, e->dxdy.rem));
+
if (e->prev)
e->prev->next = n->next;
else
@@ -379,8 +383,11 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
break;
e = n->next;
- } else
+ } else {
+ __DBG(("%s: adding edge (%d.%d) + (%d.%d)/%d, height=%d\n",
+ __FUNCTION__, n->x.quo, n->x.rem, n->dxdy.quo, n->dxdy.rem, n->dy, n->height_left));
e = n;
+ }
}
return edges;
@@ -571,6 +578,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
int winding = 0;
BoxRec box;
+ __DBG(("%s: y=%d, h=%d\n", __FUNCTION__, y, h));
+
DBG_MONO_EDGES(edge);
VALIDATE_MONO_EDGES(&c->head);
@@ -581,6 +590,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
struct mono_edge *next = edge->next;
int16_t xend = I(edge->x.quo);
+ __DBG(("%s: adding edge dir=%d [winding=%d], x=%d [%d]\n",
+ __FUNCTION__, edge->dir, winding + edge->dir, xend, edge->x.quo));
if (--edge->height_left) {
if (edge->dy) {
edge->x.quo += edge->dxdy.quo;
@@ -589,6 +600,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
++edge->x.quo;
edge->x.rem -= edge->dy;
}
+ __DBG(("%s: stepped edge (%d.%d) + (%d.%d)/%d, height=%d, prev_x=%d\n",
+ __FUNCTION__, edge->x.quo, edge->x.rem, edge->dxdy.quo, edge->dxdy.rem, edge->dy, edge->height_left, edge->x.quo));
}
if (edge->x.quo < prev_x) {
@@ -612,17 +625,22 @@ mono_row(struct mono *c, int16_t y, int16_t h)
winding += edge->dir;
if (winding == 0) {
assert(I(next->x.quo) >= xend);
- if (I(next->x.quo) > xend + 1) {
+ if (I(next->x.quo) > xend) {
+ __DBG(("%s: end span: %d\n", __FUNCTION__, xend));
if (xstart < c->clip.extents.x1)
xstart = c->clip.extents.x1;
if (xend > c->clip.extents.x2)
xend = c->clip.extents.x2;
- if (xend > xstart)
+ if (xend > xstart) {
+ __DBG(("%s: emit span [%d, %d]\n", __FUNCTION__, xstart, xend));
c->span(c, xstart, xend, &box);
+ }
xstart = INT16_MIN;
}
- } else if (xstart == INT16_MIN)
+ } else if (xstart == INT16_MIN) {
+ __DBG(("%s: starting new span: %d\n", __FUNCTION__, xend));
xstart = xend;
+ }
edge = next;
}
@@ -684,9 +702,14 @@ mono_render(struct mono *mono)
for (i = 0; i < h; i = j) {
j = i + 1;
+ __DBG(("%s: row=%d, new edges? %d\n", __FUNCTION__,
+ i, polygon->y_buckets[i] != NULL));
+
if (polygon->y_buckets[i])
mono_merge_edges(mono, polygon->y_buckets[i]);
+ __DBG(("%s: row=%d, vertical? %d\n", __FUNCTION__,
+ i, mono->is_vertical));
if (mono->is_vertical) {
struct mono_edge *e = mono->head.next;
int min_height = h - i;
@@ -701,6 +724,7 @@ mono_render(struct mono *mono)
j++;
if (j != i + 1)
mono_step_edges(mono, j - (i + 1));
+ __DBG(("%s: %d vertical rows\n", __FUNCTION__, j-i));
}
mono_row(mono, i, j-i);
@@ -1423,10 +1447,13 @@ mono_triangles_span_converter(struct sna *sna,
mono_render(&mono);
mono.op.done(mono.sna, &mono.op);
}
+ mono_fini(&mono);
if (!was_clear && !operator_is_bounded(op)) {
xPointFixed p1, p2;
+ DBG(("%s: performing unbounded clear\n", __FUNCTION__));
+
if (!mono_init(&mono, 2+3*count))
return false;
@@ -1472,7 +1499,6 @@ mono_triangles_span_converter(struct sna *sna,
mono_fini(&mono);
}
- mono_fini(&mono);
REGION_UNINIT(NULL, &mono.clip);
return true;
}
diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c
index c983852..242b4ac 100644
--- a/src/sna/sna_trapezoids_precise.c
+++ b/src/sna/sna_trapezoids_precise.c
@@ -1655,8 +1655,7 @@ static void span_thread_add_box(struct sna *sna, void *data,
{
struct span_thread_boxes *b = data;
- __DBG(("%s: adding %d boxes with alpha=%f\n",
- __FUNCTION__, count, alpha));
+ __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
diff --git a/test/.gitignore b/test/.gitignore
index 373ba15..2a68c3d 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -11,6 +11,7 @@ cursor-test
render-fill
render-trapezoid
render-trapezoid-image
+render-triangle
render-fill-copy
render-composite-solid
render-composite-solid-mask
diff --git a/test/Makefile.am b/test/Makefile.am
index aaa656a..50f2126 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,6 +15,7 @@ stress_TESTS = \
render-glyphs \
render-trapezoid \
render-trapezoid-image \
+ render-triangle \
render-fill-copy \
render-composite-solid \
render-composite-solid-mask \
diff --git a/test/render-triangle.c b/test/render-triangle.c
new file mode 100644
index 0000000..165834c
--- /dev/null
+++ b/test/render-triangle.c
@@ -0,0 +1,180 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "test.h"
+
+enum edge {
+ EDGE_SHARP = PolyEdgeSharp,
+ EDGE_SMOOTH,
+};
+
+static void set_edge(Display *dpy, Picture p, enum edge edge)
+{
+ XRenderPictureAttributes a;
+
+ a.poly_edge = edge;
+ XRenderChangePicture(dpy, p, CPPolyEdge, &a);
+}
+
+static XRenderPictFormat *mask_format(Display *dpy, enum mask mask)
+{
+ switch (mask) {
+ default:
+ case MASK_NONE: return NULL;
+ case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1);
+ case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8);
+ }
+}
+
+static const char *mask_name(enum mask mask)
+{
+ switch (mask) {
+ default:
+ case MASK_NONE: return "none";
+ case MASK_A1: return "a1";
+ case MASK_A8: return "a8";
+ }
+}
+
+static const char *edge_name(enum edge edge)
+{
+ switch (edge) {
+ default:
+ case EDGE_SHARP: return "sharp";
+ case EDGE_SMOOTH: return "smooth";
+ }
+}
+
+static void clear(struct test_display *dpy, struct test_target *tt)
+{
+ XRenderColor render_color = {0};
+ XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
+ 0, 0, tt->width, tt->height);
+}
+
+static void step_to_point(int step, int width, int height, XPointFixed *p)
+{
+ do {
+ p->x = (step - 64) << 16;
+ p->y = -64 << 16;
+
+ step -= width - 128;
+ if (step <= 0)
+ return;
+
+ p->x = (width + 64) << 16;
+ p->y = (step - 64) << 16;
+ step -= height - 128;
+
+ if (step <= 0)
+ return;
+
+ p->x = (width + 64 - step) << 16;
+ p->y = (height + 64) << 16;
+ step -= width - 128;
+
+ if (step <= 0)
+ return;
+
+ p->x = -64 << 16;
+ p->y = (height + 64 - step) << 16;
+ step -= height - 128;
+ } while (step > 0);
+}
+
+static void edge_test(struct test *t,
+ enum mask mask,
+ enum edge edge,
+ enum target target)
+{
+ struct test_target out, ref;
+ XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
+ Picture src_ref, src_out;
+ XTriangle tri;
+ unsigned step, max;
+
+ test_target_create_render(&t->out, target, &out);
+ set_edge(t->out.dpy, out.picture, edge);
+ src_out = XRenderCreateSolidFill(t->out.dpy, &white);
+
+ test_target_create_render(&t->ref, target, &ref);
+ set_edge(t->ref.dpy, ref.picture, edge);
+ src_ref = XRenderCreateSolidFill(t->ref.dpy, &white);
+
+ printf("Testing edges (with mask %s and %s edges) (%s): ",
+ mask_name(mask),
+ edge_name(edge),
+ test_target_name(target));
+ fflush(stdout);
+
+ max = 2*(out.width + 128 + out.height+128);
+ step = 0;
+ for (step = 0; step <= max; step++) {
+ char buf[80];
+
+ step_to_point(step, out.width, out.height, &tri.p1);
+ step_to_point(step + out.width + 128,
+ out.width, out.height,
+ &tri.p2);
+ step_to_point(step + out.height + 128 + 2*(out.width + 128),
+ out.width, out.height,
+ &tri.p3);
+
+ sprintf(buf,
+ "tri=((%d, %d), (%d, %d), (%d, %d))\n",
+ tri.p1.x >> 16, tri.p1.y >> 16,
+ tri.p2.x >> 16, tri.p2.y >> 16,
+ tri.p3.x >> 16, tri.p3.y >> 16);
+
+ clear(&t->out, &out);
+ XRenderCompositeTriangles(t->out.dpy,
+ PictOpSrc,
+ src_out,
+ out.picture,
+ mask_format(t->out.dpy, mask),
+ 0, 0,
+ &tri, 1);
+
+ clear(&t->ref, &ref);
+ XRenderCompositeTriangles(t->ref.dpy,
+ PictOpSrc,
+ src_ref,
+ ref.picture,
+ mask_format(t->ref.dpy, mask),
+ 0, 0,
+ &tri, 1);
+
+ test_compare(t,
+ out.draw, out.format,
+ ref.draw, ref.format,
+ 0, 0, out.width, out.height,
+ buf);
+ }
+
+ XRenderFreePicture(t->out.dpy, src_out);
+ test_target_destroy_render(&t->out, &out);
+
+ XRenderFreePicture(t->ref.dpy, src_ref);
+ test_target_destroy_render(&t->ref, &ref);
+
+ printf("pass\n");
+}
+
+int main(int argc, char **argv)
+{
+ struct test test;
+ enum target target;
+ enum mask mask;
+ enum edge edge;
+
+ test_init(&test, argc, argv);
+
+ for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
+ for (mask = MASK_NONE; mask <= MASK_A8; mask++)
+ for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++)
+ edge_test(&test, mask, edge, target);
+ }
+
+ return 0;
+}
commit fe64672c83e75ccb3f7a1bf37e05df05d0c05392
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon May 18 09:18:41 2015 +0100
sna: Wrap GetImage with sigtrap
Mostly for completeness, though it is still remotely possibly for the
dst pointer to raise a SIGBUS (just less likely since it is not a i915
bo).
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index c79af6a..9a5079f 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -17072,7 +17072,7 @@ sna_get_image__fast(PixmapPtr pixmap,
if (priv == NULL || priv->gpu_damage == NULL)
return false;
- if (priv->clear) {
+ if (priv->clear && sigtrap_get() == 0) {
int w = region->extents.x2 - region->extents.x1;
int h = region->extents.y2 - region->extents.y1;
int pitch = PixmapBytePad(w, pixmap->drawable.depth);
@@ -17098,6 +17098,7 @@ sna_get_image__fast(PixmapPtr pixmap,
priv->clear_color);
}
+ sigtrap_put();
return true;
}
commit d4c82a16bc3ad89a9684c82cd1dd4bcef117ed8c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon May 18 09:16:12 2015 +0100
test: Remove the blit through a temporary Pixmap
Originally this was inplace so that we wouldn't simply migrate the
target away from the GPU whenever we inspected results. That is no
longer a problem and so we can speed up the tests by skipping the
temporary.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/test/test_image.c b/test/test_image.c
index d15a8af..1c07699 100644
--- a/test/test_image.c
+++ b/test/test_image.c
@@ -197,13 +197,10 @@ void test_compare(struct test *t,
const char *info)
{
XImage out_image, ref_image;
- Pixmap tmp;
- char *out, *ref;
+ uint32_t *out, *ref;
char buf[600];
uint32_t mask;
int i, j;
- XGCValues gcv;
- GC gc;
if (w * h * 4 > t->out.max_shm_size)
return test_compare_fallback(t,
@@ -214,37 +211,24 @@ void test_compare(struct test *t,
test_init_image(&out_image, &t->out.shm, out_format, w, h);
test_init_image(&ref_image, &t->ref.shm, ref_format, w, h);
- gcv.graphics_exposures = 0;
-
die_unless(out_image.depth == ref_image.depth);
die_unless(out_image.bits_per_pixel == ref_image.bits_per_pixel);
die_unless(out_image.bits_per_pixel == 32);
- mask = depth_mask(out_image.depth);
+ XShmGetImage(t->out.dpy, out_draw, &out_image, x, y, AllPlanes);
+ out = (uint32_t *)out_image.data;
- tmp = XCreatePixmap(t->out.dpy, out_draw, w, h, out_image.depth);
- gc = XCreateGC(t->out.dpy, tmp, GCGraphicsExposures, &gcv);
- XCopyArea(t->out.dpy, out_draw, tmp, gc, x, y, w, h, 0, 0);
- XShmGetImage(t->out.dpy, tmp, &out_image, 0, 0, AllPlanes);
- XFreeGC(t->out.dpy, gc);
- XFreePixmap(t->out.dpy, tmp);
- out = out_image.data;
-
- tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth);
- gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv);
- XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0);
- XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes);
- XFreeGC(t->ref.dpy, gc);
- XFreePixmap(t->ref.dpy, tmp);
- ref = ref_image.data;
+ XShmGetImage(t->ref.dpy, ref_draw, &ref_image, x, y, AllPlanes);
+ ref = (uint32_t *)ref_image.data;
/* Start with an exact comparison. However, one quicky desires
* a fuzzy comparator to hide hardware inaccuracies...
*/
+ mask = depth_mask(out_image.depth);
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
- uint32_t a = ((uint32_t *)out)[i] & mask;
- uint32_t b = ((uint32_t *)ref)[i] & mask;
+ uint32_t a = out[i] & mask;
+ uint32_t b = ref[i] & mask;
if (a != b && pixel_difference(a, b) > MAX_DELTA) {
show_pixels(buf,
&out_image, &ref_image,
@@ -255,8 +239,8 @@ void test_compare(struct test *t,
x,i, y,j, a, b, pixel_difference(a, b), buf, info);
}
}
- out += out_image.bytes_per_line;
- ref += ref_image.bytes_per_line;
+ out = (uint32_t *)((char *)out + out_image.bytes_per_line);
+ ref = (uint32_t *)((char *)ref + ref_image.bytes_per_line);
}
}
commit b10ef9cf5c9cc844f432e9024deeb78fa1034a8e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun May 17 20:45:25 2015 +0100
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 at chris-wilson.co.uk>
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index af98301..c79af6a 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -817,8 +817,8 @@ create_pixmap(struct sna *sna, ScreenPtr screen,
datasize += adjust;
}
- DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n",
- __FUNCTION__, width, height, depth, (long)datasize));
+ DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n",
+ __FUNCTION__, width, height, depth, bpp, (long)datasize));
pixmap = AllocatePixmap(screen, datasize);
if (!pixmap)
return NullPixmap;
@@ -4091,7 +4091,7 @@ sna_pixmap_create_upload(ScreenPtr screen,
assert(width);
assert(height);
- if (depth == 1)
+ if (depth < 8)
return create_pixmap(sna, screen, width, height, depth,
CREATE_PIXMAP_USAGE_SCRATCH);
diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
index 6d57e8f..9e945f0 100644
--- a/src/sna/sna_glyphs.c
+++ b/src/sna/sna_glyphs.c
@@ -74,7 +74,7 @@
#define NO_GLYPHS_VIA_MASK 0
#define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */
#define NO_GLYPHS_SLOW 0
-#define NO_DISCARD_MASK 0
+#define DISCARD_MASK 0 /* -1 = never, 1 = always */
#define CACHE_PICTURE_SIZE 1024
#define GLYPH_MIN_SIZE 8
@@ -1094,6 +1094,9 @@ sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
static inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth)
{
+ if (depth < 8)
+ return true;
+
if (FORCE_SMALL_MASK)
return FORCE_SMALL_MASK > 0;
@@ -1156,12 +1159,6 @@ glyphs_via_mask(struct sna *sna,
src_x += box.x1 - list->xOff;
src_y += box.y1 - list->yOff;
- if (format->depth < 8) {
- format = PictureMatchFormat(screen, 8, PICT_a8);
- if (!format)
- return false;
- }
-
component_alpha = NeedsComponent(format->format);
if (use_small_mask(sna, width, height, format->depth)) {
pixman_image_t *mask_image;
@@ -1179,7 +1176,7 @@ use_small_mask:
return false;
mask_image =
- pixman_image_create_bits(format->depth << 24 | format->format,
+ pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
width, height,
pixmap->devPrivate.ptr,
pixmap->devKind);
@@ -1386,10 +1383,11 @@ next_image:
DBG(("%s: atlas format=%08x, mask format=%08x\n",
__FUNCTION__,
(int)p->atlas->format,
- (int)(format->depth << 24 | format->format)));
+ (int)mask->format));
memset(&tmp, 0, sizeof(tmp));
- if (p->atlas->format == (format->depth << 24 | format->format)) {
+ if (p->atlas->format == mask->format ||
+ alphaless(p->atlas->format) == mask->format) {
ok = sna->render.composite(sna, PictOpAdd,
p->atlas, NULL, mask,
0, 0, 0, 0, 0, 0,
@@ -1564,6 +1562,8 @@ skip_glyph:
out:
if (list_extents != stack_extents)
free(list_extents);
+ DBG(("%s: format=%08d, depth=%d\n",
+ __FUNCTION__, format->format, format->depth));
return format;
}
@@ -1573,24 +1573,34 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
PictFormatPtr g;
uint32_t color;
- if (NO_DISCARD_MASK)
- return false;
+ if (DISCARD_MASK)
+ return DISCARD_MASK > 0;
DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n",
__FUNCTION__, nlist,
mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0,
op, op_is_bounded(op)));
- if (nlist == 1 && list->len == 1)
- return true;
+ if (nlist == 1 && list->len == 1) {
+ if (mask == list->format)
+ return true;
+
+ g = list->format;
+ goto skip;
+ }
- if (!op_is_bounded(op))
+ if (!op_is_bounded(op)) {
+ DBG(("%s: unbounded op, not discarding\n", __FUNCTION__));
return false;
+ }
/* No glyphs overlap and we are not performing a mask conversion. */
g = glyphs_format(nlist, list, glyphs);
- if (mask == g)
+ if (mask == g) {
+ DBG(("%s: mask matches glyphs format, no conversion, so discard mask\n",
+ __FUNCTION__));
return true;
+ }
DBG(("%s: preferred mask format %08x, depth %d\n",
__FUNCTION__, g ? (unsigned)g->format : 0, g ? g->depth : 0));
@@ -1605,18 +1615,41 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
list++;
}
+
+ if (!sna_picture_is_solid(src, &color))
+ return false;
+
+ return color >> 24 == 0xff;
} else {
- if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format))
+skip:
+ if (mask->format == g->format)
return true;
- if (g->depth != 1)
- return false;
- }
+ if (mask->format == alphaless(g->format))
+ return true;
+
+ if (PICT_FORMAT_TYPE(g->format) == PICT_TYPE_A &&
+ PICT_FORMAT_TYPE(mask->format) != PICT_TYPE_A)
+ return true;
- if (!sna_picture_is_solid(src, &color))
return false;
+ }
+}
- return color >> 24 == 0xff;
+static uint32_t pixman_format(PictFormatPtr short_format)
+{
+ uint32_t bpp;
+
+ bpp = short_format->depth;
+ if (bpp <= 1)
+ bpp = 1;
+ else if (bpp <= 8)
+ bpp = 8;
+ else if (bpp <= 16)
+ bpp = 16;
+ else
+ bpp = 32;
+ return bpp << 24 | short_format->format;
}
static void
@@ -1756,7 +1789,7 @@ next:
if (sigtrap_get() == 0) {
if (mask_format) {
pixman_composite_glyphs(op, src_image, dst_image,
- mask_format->format | (mask_format->depth << 24),
+ pixman_format(mask_format),
src_x + src_dx + region.extents.x1 - dst_x,
src_y + src_dy + region.extents.y1 - dst_y,
region.extents.x1, region.extents.y1,
@@ -1815,10 +1848,10 @@ out:
x, y,
mask_format->depth,
(long)mask_format->format,
- (long)(mask_format->depth << 24 | mask_format->format),
+ (long)pixman_format(mask_format),
NeedsComponent(mask_format->format)));
mask_image =
- pixman_image_create_bits(mask_format->depth << 24 | mask_format->format,
+ pixman_image_create_bits(pixman_format(mask_format),
region.extents.x2 - region.extents.x1,
region.extents.y2 - region.extents.y1,
NULL, 0);
@@ -2086,12 +2119,6 @@ glyphs_via_image(struct sna *sna,
src_x += box.x1 - list->xOff;
src_y += box.y1 - list->yOff;
- if (format->depth < 8) {
- format = PictureMatchFormat(screen, 8, PICT_a8);
- if (!format)
- return false;
- }
-
DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
__FUNCTION__, (unsigned long)format->format,
format->depth, (uint32_t)width*height*format->depth));
@@ -2104,7 +2131,7 @@ glyphs_via_image(struct sna *sna,
return false;
mask_image =
- pixman_image_create_bits(format->depth << 24 | format->format,
+ pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
width, height,
pixmap->devPrivate.ptr,
pixmap->devKind);
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index 8a9c7f4..d95536e 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -54,7 +54,7 @@ sna_format_for_depth(int depth)
{
switch (depth) {
case 1: return PICT_a1;
- case 4: return PICT_a4;
+ case 4: return PICT_x4a4;
case 8: return PICT_a8;
case 15: return PICT_x1r5g5b5;
case 16: return PICT_r5g6b5;
diff --git a/test/.gitignore b/test/.gitignore
index da174be..373ba15 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 9b37222..aaa656a 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 0000000..8822e36
--- /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 a3ef979..9eec1cf 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);
More information about the xorg-commit
mailing list