From 60ed3f88ae40a9cb00d559f92608300f9287cc5e Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 1 Feb 2016 13:48:46 -0800 Subject: shmblend: New test for XRenderComposite() from a pixmap in SHM. 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 --- 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 #include #include +#include #if HAVE_ERR_H # include @@ -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 +#include +#include +#include "rendercheck.h" +#include + +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. -- cgit v1.2.3