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 <e...@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

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to