[PATCH rendercheck 4/5] shmblend: New test for XRenderComposite() from a pixmap in SHM.

Eric Anholt eric at anholt.net
Mon Feb 1 13:48:46 PST 2016


There's a giant pile of code in glamor for uploading SHM pixmaps to
temporary GL memory for accelerating a Composite operation, and most of
its code is about how you convert formats.  Add a test that runs through
all the formats, to give us some coverage.

Signed-off-by: Eric Anholt <eric at anholt.net>
---
 Makefile.am   |   1 +
 configure.ac  |   2 +-
 rendercheck.h |   3 +
 t_shmblend.c  | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests.c       |   2 -
 5 files changed, 250 insertions(+), 3 deletions(-)
 create mode 100644 t_shmblend.c

diff --git a/Makefile.am b/Makefile.am
index 852d174..f77cb4f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,6 +16,7 @@ rendercheck_SOURCES = \
 	t_gtk_argb_xbgr.c \
 	t_libreoffice_xrgb.c \
 	t_repeat.c \
+	t_shmblend.c \
 	t_srccoords.c \
 	t_tsrccoords.c \
 	t_tsrccoords2.c \
diff --git a/configure.ac b/configure.ac
index 655a1b6..8ad0b3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@ XORG_TESTSET_CFLAG(CWARNFLAGS, [-Wno-shadow])
 AC_CHECK_HEADERS([err.h])
 
 # Checks for pkg-config packages
-PKG_CHECK_MODULES(RC, [xrender x11 xproto >= 7.0.17])
+PKG_CHECK_MODULES(RC, [xrender xext x11 xproto >= 7.0.17])
 
 AC_CONFIG_FILES([Makefile
                  man/Makefile])
diff --git a/rendercheck.h b/rendercheck.h
index f0fa7b7..1c392e8 100644
--- a/rendercheck.h
+++ b/rendercheck.h
@@ -24,6 +24,7 @@
 #include <X11/extensions/Xrender.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #if HAVE_ERR_H
 # include <err.h>
@@ -44,6 +45,7 @@ static inline void errx(int eval, const char *fmt, ...) {
 
 #define min(a, b) (a < b ? a : b)
 #define max(a, b) (a > b ? a : b)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
 typedef struct _color4d
 {
@@ -92,6 +94,7 @@ record_result(struct rendercheck_test_result *result, bool success)
 #define TEST_BUG7366		0x1000
 #define TEST_gtk_argb_xbgr	0x2000
 #define TEST_libreoffice_xrgb	0x4000
+#define TEST_shmblend		0x8000
 
 struct rendercheck_test {
 	int bit;
diff --git a/t_shmblend.c b/t_shmblend.c
new file mode 100644
index 0000000..752e17a
--- /dev/null
+++ b/t_shmblend.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright © 2016 Broadcom
+ *
+ * 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.
+ */
+
+#include <inttypes.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "rendercheck.h"
+#include <X11/extensions/XShm.h>
+
+bool had_x_error;
+static int (*orig_x_error_handler)(Display *, XErrorEvent *);
+
+static int
+shmerrorhandler(Display *d, XErrorEvent *e)
+{
+	had_x_error = true;
+	if (e->error_code == BadAccess) {
+		fprintf(stderr,"failed to attach shared memory\n");
+		return 0;
+	} else {
+		return (*orig_x_error_handler)(d,e);
+	}
+}
+
+static XShmSegmentInfo *
+get_x_shm_info(Display *dpy, size_t size)
+{
+	XShmSegmentInfo *shm_info = calloc(1, sizeof(*shm_info));
+
+	if (!XShmQueryExtension(dpy))
+		return NULL;
+
+	shm_info->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
+	if (shm_info->shmid < 0) {
+		free(shm_info);
+		return NULL;
+	}
+
+	shm_info->shmaddr = shmat(shm_info->shmid, NULL, 0);
+	if (shm_info->shmaddr == (void *)-1) {
+		free(shm_info);
+		return NULL;
+	}
+
+	shm_info->readOnly = false;
+
+	XSync(dpy, true);
+	had_x_error = false;
+	orig_x_error_handler = XSetErrorHandler(shmerrorhandler);
+	XShmAttach(dpy, shm_info);
+	XSync(dpy, true);
+	XSetErrorHandler(orig_x_error_handler);
+
+	return shm_info;
+}
+
+static void
+fill_shm_with_formatted_color(Display *dpy, XShmSegmentInfo *shm_info,
+			      XRenderPictFormat *format,
+			      int w, int h, color4d *color)
+{
+	XImage *image;
+	XRenderDirectFormat *layout = &format->direct;
+	unsigned long r = layout->redMask * color->r;
+	unsigned long g = layout->greenMask * color->g;
+	unsigned long b = layout->blueMask * color->b;
+	unsigned long a = layout->alphaMask * color->a;
+	unsigned long pix;
+
+	r <<= layout->red;
+	g <<= layout->green;
+	b <<= layout->blue;
+	a <<= layout->alpha;
+
+	pix = r | g | b | a;
+
+	image = XShmCreateImage(dpy, NULL, format->depth, ZPixmap,
+				shm_info->shmaddr, shm_info, w, h);
+	for (int y = 0; y < h; y++) {
+		for (int x = 0; x < w; x++) {
+			XPutPixel(image, x, y, pix);
+		}
+	}
+	XDestroyImage(image);
+}
+
+static bool
+test_format(Display *dpy, int op, int w, int h, struct render_format *format)
+{
+	XRenderPictFormat *argb32_format;
+	XShmSegmentInfo *shm_info;
+	Pixmap src_pix = 0, dst_pix;
+	bool pass = true;
+	size_t size = w * h * 4;
+	color4d dst_color = {.25, .25, .25, .25};
+	picture_info src, dst;
+
+	shm_info = get_x_shm_info(dpy, size);
+	if (!shm_info) {
+		pass = false;
+		goto fail;
+	}
+
+	/* Create the SHM pixmap for the source. */
+	src_pix = XShmCreatePixmap(dpy, DefaultRootWindow(dpy),
+				   shm_info->shmaddr, shm_info, w, h,
+				   format->format->depth);
+
+	src.pict = XRenderCreatePicture(dpy, src_pix, format->format, 0, NULL);
+	src.format = format->format;
+
+	/* Make a plain a8r8g8b8 picture for the dst. */
+	argb32_format = XRenderFindStandardFormat(dpy, PictStandardARGB32);
+	dst_pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), w, h,
+				argb32_format->depth);
+	dst.pict = XRenderCreatePicture(dpy, dst_pix, argb32_format, 0, NULL);
+	dst.format = XRenderFindStandardFormat(dpy, PictStandardARGB32);
+
+	for (int i = 0; i < num_colors; i++) {
+		color4d src_color = colors[i];
+		color4d expected;
+		XImage *image;
+		XRenderDirectFormat acc;
+
+		fill_shm_with_formatted_color(dpy, shm_info, format->format,
+					      w, h, &colors[i]);
+
+		argb_fill(dpy, &dst, 0, 0, w, h,
+			  dst_color.a, dst_color.r,
+			  dst_color.g, dst_color.b);
+
+		XRenderComposite(dpy, op,
+				 src.pict, 0, dst.pict,
+				 0, 0,
+				 0, 0,
+				 0, 0,
+				 w, h);
+
+		image = XGetImage(dpy, dst_pix,
+				  0, 0, w, h,
+				  0xffffffff, ZPixmap);
+
+		color_correct(&src, &src_color);
+
+		accuracy(&acc,
+			 &argb32_format->direct,
+			 &format->format->direct);
+
+		do_composite(op, &src_color, NULL, &dst_color, &expected, false);
+
+		for (int j = 0; j < w * h; j++) {
+			int x = j % w;
+			int y = j / h;
+			color4d tested;
+
+			get_pixel_from_image(image, &dst, x, y, &tested);
+
+			if (eval_diff(&acc, &expected, &tested) > 3.) {
+				char testname[30];
+
+				pass = false;
+
+				snprintf(testname, ARRAY_SIZE(testname),
+					 "%s %s SHM blend", ops[op].name,
+					format->name);
+
+				print_fail(testname, &expected, &tested, x, y,
+					   eval_diff(&acc, &expected, &tested));
+				printf("src color: %.2f %.2f %.2f %.2f\n",
+				       src_color.r,
+				       src_color.g,
+				       src_color.b,
+				       src_color.a);
+				printf("dst color: %.2f %.2f %.2f %.2f\n",
+				       dst_color.r,
+				       dst_color.g,
+				       dst_color.b,
+				       dst_color.a);
+
+				break;
+			}
+		}
+
+		XDestroyImage(image);
+	}
+
+	XRenderFreePicture(dpy, src.pict);
+	XRenderFreePicture(dpy, dst.pict);
+	XFreePixmap(dpy, dst_pix);
+fail:
+	if (shm_info) {
+		XFreePixmap(dpy, src_pix);
+		XShmDetach(dpy, shm_info);
+		/* Wait for server to fully detach before removing. */
+		XSync(dpy, False);
+		shmdt(shm_info->shmaddr);
+		shmctl(shm_info->shmid, IPC_RMID, NULL);
+		free(shm_info);
+	}
+
+	return pass;
+}
+
+static struct rendercheck_test_result
+test_shmblend(Display *dpy)
+{
+	struct rendercheck_test_result result = {};
+	int i;
+
+	for (i = 0; i < nformats; i++) {
+		struct render_format *format = &formats[i];
+
+		printf("Beginning SHM blend test from %s\n", format->name);
+
+		record_result(&result, test_format(dpy, PictOpSrc, 8, 8,
+						   format));
+		record_result(&result, test_format(dpy, PictOpOver, 8, 8,
+						   format));
+	}
+
+	return result;
+}
+
+DECLARE_RENDERCHECK_ARG_TEST(shmblend, "SHM Pixmap blending",
+			     test_shmblend);
diff --git a/tests.c b/tests.c
index 730acbf..ff2bbd8 100644
--- a/tests.c
+++ b/tests.c
@@ -229,8 +229,6 @@ argb_fill(Display *dpy, picture_info *p, int x, int y, int w, int h, float a,
 	XRenderFillRectangle(dpy, PictOpSrc, p->pict, &rendercolor, x, y, w, h);
 }
 
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
 /* Create a set of direct format XRenderPictFormats for later use.  This lets
  * us get more formats than just the standard required set, and lets us attach
  * names to them.
-- 
2.7.0



More information about the xorg-devel mailing list