summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2004-05-10 07:21:19 +0000
committerEric Anholt <anholt@freebsd.org>2004-05-10 07:21:19 +0000
commit258f238ae94782fa1c0e1d8b6280d8d61c9c0c40 (patch)
treea273cc3885629976bf82d35c20f071ac271550e6
Initial revision
-rw-r--r--AUTHORS1
-rw-r--r--COPYING19
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL229
-rw-r--r--Makefile.am12
-rw-r--r--NEWS2
-rw-r--r--README12
-rw-r--r--TODO5
-rwxr-xr-xautogen.sh3
-rw-r--r--configure.ac30
-rw-r--r--main.c163
-rw-r--r--ops.c243
-rw-r--r--rendercheck.h55
-rw-r--r--tests.c650
14 files changed, 1424 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..f43375f
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Written in 2004 by Eric Anholt. \ No newline at end of file
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..af1d06b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright 2004 Eric Anholt
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Eric Anholt not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission. Eric Anholt makes no
+representations about the suitability of this software for any purpose. It
+is provided "as is" without express or implied warranty.
+
+ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..54caf7c
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,229 @@
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+ This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..1d5db7c
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,12 @@
+bin_PROGRAMS = rendercheck
+
+rendercheck_SOURCES = \
+ main.c \
+ ops.c \
+ rendercheck.h \
+ tests.c
+
+rendercheck_CFLAGS = $(RC_CFLAGS)
+rendercheck_LDADD = $(RC_LIBS)
+
+EXTRA_DIST = autogen.sh
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..0c03412
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,2 @@
+9 May 2004:
+First release of renderext.
diff --git a/README b/README
new file mode 100644
index 0000000..9034754
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+rendercheck is a program to test a Render extension implementation against
+separate calculations of expected output.
+
+Tests currently include:
+- Destination coordinates correctness
+- Source coordinates correctness
+- Composite with and without mask (with/without component alpha), with 1x1
+ repeating Pictures and 10x10 Pictures.
+
+Unfortunately, there are currently no command-line arguments to control
+its execution. Options, such as verbosity or number of iterations to encourage
+pixmap migration, are controlled only in source.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..8434c8f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,5 @@
+- Fix dest coords check (get_pixel broken)
+- Get a useful number being produced for error values, and correct eval_diff's limit.
+- Check transforms
+- check source/mask pixels falling outside the drawable.
+- Command line args for verbosity, what tests, move iter, etc.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..b1376df
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..f1fd779
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,30 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.57)
+AC_INIT([rendercheck],
+ 1.0,
+ [anholt@FreeBSD.org],
+ rendercheck)
+
+AC_CONFIG_SRCDIR([Makefile.am])
+AM_INIT_AUTOMAKE([dist-bzip2])
+
+AC_CONFIG_AUX_DIR(.)
+
+AM_MAINTAINER_MODE
+
+# Checks for programs.
+AC_PROG_CC
+
+# Checks for pkg-config packages
+PKG_CHECK_MODULES(RC, xrender)
+AC_SUBST(RC_CFLAGS)
+AC_SUBST(RC_LIBS)
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_HEADER_STDC
+
+AC_OUTPUT([Makefile])
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..d98cf7e
--- /dev/null
+++ b/main.c
@@ -0,0 +1,163 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Eric Anholt not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Eric Anholt makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rendercheck.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+
+extern int num_ops;
+extern int num_colors;
+extern color4d colors[];
+
+int is_verbose = FALSE; /* XXX: Make me a command line arg */
+
+/* Number of times to repeat operations so that pixmaps will tend to get moved
+ * into offscreen memory and allow hardware acceleration.
+ */
+int pixmap_move_iter = 1;
+
+int win_width = 10;
+int win_height = 10;
+
+static int
+bit_count(int i)
+{
+ int count;
+
+ count = (i >> 1) & 033333333333;
+ count = i - count - ((count >> 1) & 033333333333);
+ count = (((count + (count >> 3)) & 030707070707) % 077);
+ /* HAKMEM 169 */
+ return count;
+}
+
+/* This is not complete, but decent enough for now.*/
+void
+describe_format(char *desc, int len, XRenderPictFormat *format)
+{
+ char ad[4] = "", rd[4] = "", gd[4] = "", bd[4] = "";
+ int ac, rc, gc, bc;
+ int ashift;
+
+ ac = bit_count(format->direct.alphaMask);
+ rc = bit_count(format->direct.redMask);
+ gc = bit_count(format->direct.greenMask);
+ bc = bit_count(format->direct.blueMask);
+
+ if (ac != 0) {
+ snprintf(ad, 4, "a%d", ac);
+ ashift = format->direct.alpha;
+ } else if (rc + bc + gc < format->depth) {
+ /* There are bits that are not part of A,R,G,B. Mark them with
+ * an x.
+ */
+ snprintf(ad, 4, "x%d", format->depth - (format->direct.red +
+ format->direct.green + format->direct.blue));
+ if (format->direct.red == 0 || format->direct.green == 0)
+ ashift = format->depth;
+ else
+ ashift = 0;
+ } else
+ ashift = 0;
+
+ if (rc != 0)
+ snprintf(rd, 4, "r%d", rc);
+ if (gc != 0)
+ snprintf(gd, 4, "g%d", gc);
+ if (bc != 0)
+ snprintf(bd, 4, "b%d", bc);
+
+ if (ashift > format->direct.red) {
+ if (format->direct.red > format->direct.blue)
+ snprintf(desc, len, "%s%s%s%s", ad, rd, gd, bd);
+ else
+ snprintf(desc, len, "%s%s%s%s", ad, bd, gd, rd);
+ } else {
+ if (format->direct.red > format->direct.blue)
+ snprintf(desc, len, "%s%s%s%s", rd, gd, bd, ad);
+ else
+ snprintf(desc, len, "%s%s%s%s", bd, gd, rd, ad);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ Display *dpy;
+ XEvent ev;
+ int i, maj, min;
+ XWindowAttributes a;
+ picture_info window;
+ char window_desc[20];
+
+ dpy = XOpenDisplay(0);
+
+ if (!XRenderQueryExtension(dpy, &i, &i))
+ errx(1, "Render extension missing.");
+
+ XRenderQueryVersion(dpy, &maj, &min);
+ if (maj != 0 || min < 1)
+ errx(1, "Render extension version too low (%d.%d).", maj, min);
+
+ printf("Render extension version %d.%d\n", maj, min);
+
+ /* Conjoint/Disjoint were added in version 0.2, so disable those ops if
+ * the server doesn't support them.
+ */
+ if (min < 2) {
+ printf("Server doesn't support conjoint/disjoint ops, disabling.\n");
+ num_ops = PictOpSaturate;
+ }
+
+ window.d = XCreateSimpleWindow(dpy, RootWindow(dpy, 0), 0, 0, win_width,
+ win_height, 0, 0, WhitePixel(dpy, 0));
+ XGetWindowAttributes(dpy, window.d, &a);
+ window.format = XRenderFindVisualFormat(dpy, a.visual);
+ window.pict = XRenderCreatePicture(dpy, window.d,
+ window.format, 0, 0);
+ XSelectInput(dpy, window.d, ExposureMask);
+ XMapWindow(dpy, window.d);
+
+ describe_format(window_desc, 20, window.format);
+ printf("Window format: %s\n", window_desc);
+
+ /* We have to premultiply the alpha into the r, g, b values of the
+ * sample colors. Render colors are premultiplied with alpha, so r,g,b
+ * can never be greater than alpha.
+ */
+ for (i = 0; i < num_colors; i++) {
+ colors[i].r *= colors[i].a;
+ colors[i].g *= colors[i].a;
+ colors[i].b *= colors[i].a;
+ }
+
+ while (XNextEvent(dpy, &ev) == 0) {
+ if (ev.type == Expose && !ev.xexpose.count) {
+ begin_test(dpy, &window);
+ exit(0);
+ }
+ }
+ return 0;
+}
diff --git a/ops.c b/ops.c
new file mode 100644
index 0000000..86494c4
--- /dev/null
+++ b/ops.c
@@ -0,0 +1,243 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Eric Anholt not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Eric Anholt makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rendercheck.h"
+
+#define mult_chan(src, dst, Fa, Fb) \
+ min((double)(src) * (double)(Fa) + (double)(dst) * (double)(Fb), 1.0)
+
+static double
+calc_op(int op, double src, double dst, double srca, double dsta)
+{
+ double Fa, Fb;
+
+ switch (op) {
+ case PictOpClear:
+ case PictOpDisjointClear:
+ case PictOpConjointClear:
+ return mult_chan(src, dst, 0.0, 0.0);
+ case PictOpSrc:
+ case PictOpDisjointSrc:
+ case PictOpConjointSrc:
+ return mult_chan(src, dst, 1.0, 0.0);
+ case PictOpDst:
+ case PictOpDisjointDst:
+ case PictOpConjointDst:
+ return mult_chan(src, dst, 0.0, 1.0);
+ case PictOpOver:
+ return mult_chan(src, dst, 1.0, 1.0 - srca);
+ case PictOpOverReverse:
+ return mult_chan(src, dst, 1.0 - dsta, 1.0);
+ case PictOpIn:
+ return mult_chan(src, dst, dsta, 0.0);
+ case PictOpInReverse:
+ return mult_chan(src, dst, 0.0, srca);
+ case PictOpOut:
+ return mult_chan(src, dst, 1.0 - dsta, 0.0);
+ case PictOpOutReverse:
+ return mult_chan(src, dst, 0.0, 1.0 - srca);
+ case PictOpAtop:
+ return mult_chan(src, dst, dsta, 1.0 - srca);
+ case PictOpAtopReverse:
+ return mult_chan(src, dst, 1.0 - dsta, srca);
+ case PictOpXor:
+ return mult_chan(src, dst, 1.0 - dsta, 1.0 - srca);
+ case PictOpAdd:
+ return mult_chan(src, dst, 1.0, 1.0);
+ break;
+ case PictOpSaturate:
+ case PictOpDisjointOverReverse:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = min(1.0, (1.0 - dsta) / srca);
+ return mult_chan(src, dst, Fa, 1.0);
+ case PictOpDisjointOver:
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = min(1.0, (1.0 - srca) / dsta);
+ return mult_chan(src, dst, 1.0, Fb);
+ case PictOpDisjointIn:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = max(0.0, 1.0 - (1.0 - dsta) / srca);
+ return mult_chan(src, dst, Fa, 0.0);
+ case PictOpDisjointInReverse:
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = max(0.0, 1.0 - (1.0 - srca) / dsta);
+ return mult_chan(src, dst, 0.0, Fb);
+ case PictOpDisjointOut:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = min(1.0, (1.0 - dsta) / srca);
+ return mult_chan(src, dst, Fa, 0.0);
+ case PictOpDisjointOutReverse:
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = min(1.0, (1.0 - srca) / dsta);
+ return mult_chan(src, dst, 0.0, Fb);
+ case PictOpDisjointAtop:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = max(0.0, 1.0 - (1.0 - dsta) / srca);
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = min(1.0, (1.0 - srca) / dsta);
+ return mult_chan(src, dst, Fa, Fb);
+ case PictOpDisjointAtopReverse:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = min(1.0, (1.0 - dsta) / srca);
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = max(0.0, 1.0 - (1.0 - srca) / dsta);
+ return mult_chan(src, dst, Fa, Fb);
+ case PictOpDisjointXor:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = min(1.0, (1.0 - dsta) / srca);
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = min(1.0, (1.0 - srca) / dsta);
+ return mult_chan(src, dst, Fa, Fb);
+ case PictOpConjointOver:
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = max(0.0, 1.0 - srca / dsta);
+ return mult_chan(src, dst, 1.0, Fb);
+ case PictOpConjointOverReverse:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = max(0.0, 1.0 - dsta / srca);
+ return mult_chan(src, dst, Fa, 1.0);
+ case PictOpConjointIn:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = min(1.0, dsta / srca);
+ return mult_chan(src, dst, Fa, 0.0);
+ case PictOpConjointInReverse:
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = min(1.0, srca / dsta);
+ return mult_chan(src, dst, 0.0, Fb);
+ case PictOpConjointOut:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = max(0.0, 1.0 - dsta / srca);
+ return mult_chan(src, dst, Fa, 0.0);
+ case PictOpConjointOutReverse:
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = max(0.0, 1.0 - srca / dsta);
+ return mult_chan(src, dst, 0.0, Fb);
+ case PictOpConjointAtop:
+ if (srca == 0.0)
+ Fa = 1.0;
+ else
+ Fa = min(1.0, dsta / srca);
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = max(0.0, 1.0 - srca / dsta);
+ return mult_chan(src, dst, Fa, Fb);
+ case PictOpConjointAtopReverse:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = max(0.0, 1.0 - dsta / srca);
+ if (dsta == 0.0)
+ Fb = 1.0;
+ else
+ Fb = min(1.0, srca / dsta);
+ return mult_chan(src, dst, Fa, Fb);
+ case PictOpConjointXor:
+ if (srca == 0.0)
+ Fa = 0.0;
+ else
+ Fa = max(0.0, 1.0 - dsta / srca);
+ if (dsta == 0.0)
+ Fb = 0.0;
+ else
+ Fb = max(0.0, 1.0 - srca / dsta);
+ return mult_chan(src, dst, Fa, Fb);
+ default:
+ abort();
+ }
+}
+
+void
+do_composite(int op, color4d *src, color4d *mask, color4d *dst, color4d *result,
+ Bool componentAlpha)
+{
+ color4d srcval, srcalpha;
+
+ if (mask != NULL && componentAlpha) {
+ srcval.r = src->r * mask->r;
+ srcval.g = src->g * mask->g;
+ srcval.b = src->b * mask->b;
+ srcval.a = src->a * mask->a;
+ srcalpha.r = src->a * mask->r;
+ srcalpha.g = src->a * mask->g;
+ srcalpha.b = src->a * mask->b;
+ srcalpha.a = src->a * mask->a;
+ } else if (mask != NULL) {
+ srcval.r = src->r * mask->a;
+ srcval.g = src->g * mask->a;
+ srcval.b = src->b * mask->a;
+ srcval.a = src->a * mask->a;
+ srcalpha.r = src->a * mask->a;
+ srcalpha.g = src->a * mask->a;
+ srcalpha.b = src->a * mask->a;
+ srcalpha.a = src->a * mask->a;
+ } else {
+ srcval = *src;
+ srcalpha.r = src->a;
+ srcalpha.g = src->a;
+ srcalpha.b = src->a;
+ srcalpha.a = src->a;
+ }
+
+ result->r = calc_op(op, srcval.r, dst->r, srcalpha.r, dst->a);
+ result->g = calc_op(op, srcval.g, dst->g, srcalpha.g, dst->a);
+ result->b = calc_op(op, srcval.b, dst->b, srcalpha.b, dst->a);
+ result->a = calc_op(op, srcval.a, dst->a, srcalpha.a, dst->a);
+}
diff --git a/rendercheck.h b/rendercheck.h
new file mode 100644
index 0000000..0686a9d
--- /dev/null
+++ b/rendercheck.h
@@ -0,0 +1,55 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Eric Anholt not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Eric Anholt makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <X11/extensions/Xrender.h>
+
+#define min(a, b) (a < b ? a : b)
+#define max(a, b) (a > b ? a : b)
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+typedef struct _color4d
+{
+ double r, g, b, a;
+} color4d;
+
+typedef struct _picture_info {
+ Drawable d;
+ Picture pict;
+ XRenderPictFormat *format;
+ char *name; /* Possibly, some descriptive name. */
+ color4d color; /* If a 1x1R pict, the (corrected) color.*/
+} picture_info;
+
+/* tests.c */
+void
+begin_test(Display *dpy, picture_info *win);
+
+/* ops.c */
+void
+do_composite(int op, color4d *src, color4d *mask, color4d *dst, color4d *result,
+ Bool componentAlpha);
diff --git a/tests.c b/tests.c
new file mode 100644
index 0000000..d999189
--- /dev/null
+++ b/tests.c
@@ -0,0 +1,650 @@
+/*
+ * $Id$
+ *
+ * Copyright © 2004 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Eric Anholt not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Eric Anholt makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rendercheck.h"
+
+extern int win_width, win_height;
+extern int pixmap_move_iter;
+extern Bool is_verbose;
+
+color4d colors[] = {
+ {1.0, 1.0, 1.0, 1.0},
+ {1.0, 0, 0, 1.0},
+ {0, 1.0, 0, 1.0},
+ {0, 0, 1.0, 1.0},
+ {0.5, 0, 0, 0.25},
+ {0.5, 0, 0, .5},
+ {0.0, .5, 1.0, .5},
+ {0.0, .5, 1.0, 0}
+};
+
+int num_colors = sizeof(colors) / sizeof(colors[0]);
+
+struct op_info {
+ int op;
+ char *name;
+} ops[] = {
+ {PictOpClear, "Clear"},
+ {PictOpSrc, "Src"},
+ {PictOpDst, "Dst"},
+ {PictOpOver, "Over"},
+ {PictOpOverReverse, "OverReverse"},
+ {PictOpIn, "In"},
+ {PictOpInReverse, "InReverse"},
+ {PictOpOut, "Out"},
+ {PictOpOutReverse, "OutReverse"},
+ {PictOpAtop, "Atop"},
+ {PictOpAtopReverse, "AtopReverse"},
+ {PictOpXor, "Xor"},
+ {PictOpAdd, "Add"},
+ {PictOpSaturate, "Saturate"},
+ {PictOpDisjointClear, "DisjointClear"},
+ {PictOpDisjointSrc, "DisjointSrc"},
+ {PictOpDisjointDst, "DisjointDst"},
+ {PictOpDisjointOver, "DisjointOver"},
+ {PictOpDisjointOverReverse, "DisjointOverReverse"},
+ {PictOpDisjointIn, "DisjointIn"},
+ {PictOpDisjointInReverse, "DisjointInReverse"},
+ {PictOpDisjointOut, "DisjointOut"},
+ {PictOpDisjointOutReverse, "DisjointOutReverse"},
+ {PictOpDisjointAtop, "DisjointAtop"},
+ {PictOpDisjointAtopReverse, "DisjointAtopReverse"},
+ {PictOpDisjointXor, "DisjointXor"},
+ {PictOpConjointClear, "ConjointClear"},
+ {PictOpConjointSrc, "ConjointSrc"},
+ {PictOpConjointDst, "ConjointDst"},
+ {PictOpConjointOver, "ConjointOver"},
+ {PictOpConjointOverReverse, "ConjointOverReverse"},
+ {PictOpConjointIn, "ConjointIn"},
+ {PictOpConjointInReverse, "ConjointInReverse"},
+ {PictOpConjointOut, "ConjointOut"},
+ {PictOpConjointOutReverse, "ConjointOutReverse"},
+ {PictOpConjointAtop, "ConjointAtop"},
+ {PictOpConjointAtopReverse, "ConjointAtopReverse"},
+ {PictOpConjointXor, "ConjointXor"},
+};
+
+int num_ops = sizeof(ops) / sizeof(ops[0]);
+
+/* Originally a bullseye, this pattern has been modified so that flipping
+ * will result in errors as well.
+ */
+int target_colors[5][5] = {
+ {1, 1, 1, 1, 1},
+ {1, 0, 0, 0, 1},
+ {1, 1, 1, 0, 1},
+ {1, 0, 0, 1, 1},
+ {1, 1, 1, 1, 1},
+};
+
+#define round_pix(pix, mask) \
+ ((double)((int)(pix * (mask ) + .5)) / (double)(mask))
+
+static void
+color_correct(picture_info *pi, color4d *color)
+{
+ if (!pi->format->direct.redMask) {
+ color->r = 0.0;
+ color->g = 0.0;
+ color->b = 0.0;
+ } else {
+ color->r = round_pix(color->r, pi->format->direct.redMask);
+ color->g = round_pix(color->g, pi->format->direct.greenMask);
+ color->b = round_pix(color->b, pi->format->direct.blueMask);
+ }
+ if (!pi->format->direct.alphaMask)
+ color->a = 1.0;
+ else
+ color->a = round_pix(color->a, pi->format->direct.alphaMask);
+}
+
+static void
+get_pixel(Display *dpy, picture_info *pi, int x, int y, color4d *color)
+{
+ XImage *image;
+ unsigned long val;
+ unsigned long rm, gm, bm, am;
+
+ /* XXX: I am xlib clueless, and this function appears to not work right.
+ * I think it just always gets the 0,0 pixel, but I'm not sure.
+ */
+ image = XGetImage(dpy, pi->d, x, y, 1, 1, 0xffffffff, ZPixmap);
+ /*val = image->f.get_pixel(image, x, y);*/
+
+ val = *(unsigned long *)image->data;
+
+ rm = pi->format->direct.redMask << pi->format->direct.red;
+ gm = pi->format->direct.greenMask << pi->format->direct.green;
+ bm = pi->format->direct.blueMask << pi->format->direct.blue;
+ am = pi->format->direct.alphaMask << pi->format->direct.alpha;
+ if (am != 0)
+ color->a = (double)(val & am) / (double)am;
+ else
+ color->a = 1.0;
+ if (rm != 0) {
+ color->r = (double)(val & rm) / (double)rm;
+ color->g = (double)(val & gm) / (double)gm;
+ color->b = (double)(val & bm) / (double)bm;
+ } else {
+ color->r = 0.0;
+ color->g = 0.0;
+ color->b = 0.0;
+ }
+}
+
+static int
+eval_diff(char *name, color4d *expected, color4d *test, int x, int y,
+ Bool verbose)
+{
+ double rscale, gscale, bscale, ascale;
+ double rdiff, gdiff, bdiff, adiff, diff;
+
+ /* XXX: Need to be provided mask shifts so we can produce useful error
+ * values.
+ */
+ rscale = 1.0 * (1 << 5);
+ gscale = 1.0 * (1 << 6);
+ bscale = 1.0 * (1 << 5);
+ ascale = 1.0;
+ rdiff = fabs(test->r - expected->r) * rscale;
+ bdiff = fabs(test->g - expected->g) * gscale;
+ gdiff = fabs(test->b - expected->b) * bscale;
+ adiff = fabs(test->a - expected->a) * ascale;
+ /*rdiff = log2(1.0 + rdiff);
+ gdiff = log2(1.0 + gdiff);
+ bdiff = log2(1.0 + bdiff);
+ adiff = log2(1.0 + adiff);*/
+ diff = max(max(max(rdiff, gdiff), bdiff), adiff);
+ if (diff > 3.0) {
+ printf("%s test error of %.4f at (%d, %d) --\n"
+ "got: %.2f %.2f %.2f %.2f\n"
+ "expected: %.2f %.2f %.2f %.2f\n", name, diff, x, y,
+ test->r, test->g, test->b, test->a,
+ expected->r, expected->g, expected->b, expected->a);
+ return FALSE;
+ } else if (verbose) {
+ printf("%s test succeeded at (%d, %d) with %.4f: "
+ "%.2f %.2f %.2f %.2f\n", name, x, y, diff,
+ expected->r, expected->g, expected->b, expected->a);
+ }
+ return TRUE;
+}
+
+static Bool
+fill_test(Display *dpy, picture_info *win, picture_info *src, picture_info *dst)
+{
+ color4d expected, tested;
+
+ XRenderComposite(dpy, PictOpSrc, src->pict, 0, dst->pict, 0, 0, 0, 0,
+ 0, 0, win_width, win_height);
+ get_pixel(dpy, dst, 0, 0, &tested);
+ /* Copy the output to the window, so the user sees something visual. */
+ XRenderComposite(dpy, PictOpSrc, dst->pict, 0, win->pict, 0, 0, 0, 0,
+ 0, 0, win_width, win_height);
+
+ expected = src->color;
+ color_correct(dst, &expected);
+ return eval_diff("fill", &expected, &tested, 0, 0, is_verbose);
+}
+
+static Bool
+destcoords_test(Display *dpy, picture_info *win, picture_info *dst,
+ picture_info *bg, picture_info *fg)
+{
+ color4d expected, tested;
+ int x, y;
+ Bool failed = FALSE;
+
+ XRenderComposite(dpy, PictOpSrc, bg->pict, 0, dst->pict, 0, 0, 0, 0,
+ 0, 0, win_width, win_height);
+ XRenderComposite(dpy, PictOpSrc, fg->pict, 0, dst->pict, 0, 0, 0, 0,
+ 1, 1, 1, 1);
+ /* Copy the output to the window, so the user sees something visual. */
+ XRenderComposite(dpy, PictOpSrc, dst->pict, 0, win->pict, 0, 0, 0, 0,
+ 0, 0, win_width, win_height);
+
+ for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++) {
+ get_pixel(dpy, dst, 0, 0, &tested);
+ if (x == 1 && y == 1)
+ expected = fg->color;
+ else
+ expected = bg->color;
+ color_correct(dst, &expected);
+ if (!eval_diff("dst coords", &expected, &tested, x, y,
+ is_verbose))
+ failed = TRUE;
+ }
+ }
+
+ return !failed;
+}
+
+static Bool
+srccoords_test(Display *dpy, picture_info *win, picture_info *src,
+ picture_info *white, Bool test_mask)
+{
+ color4d expected, tested;
+ int i;
+ XRenderPictureAttributes pa;
+ Bool failed = FALSE;
+ int tested_colors[5][5];
+
+ for (i = 0; i < 25; i++) {
+ char name[20];
+ int x = i % 5, y = i / 5;
+
+ if (!test_mask)
+ XRenderComposite(dpy, PictOpSrc, src->pict, 0,
+ win->pict, x, y, 0, 0, 0, 0, 1, 1);
+ else {
+ /* Using PictOpSrc, color 0 (white), and component
+ * alpha, the mask color should be written to the
+ * destination.
+ */
+ pa.component_alpha = TRUE;
+ XRenderChangePicture(dpy, src->pict, CPComponentAlpha,
+ &pa);
+ XRenderComposite(dpy, PictOpSrc, white->pict, src->pict,
+ win->pict, 0, 0, x, y, 0, 0, 1, 1);
+ pa.component_alpha = FALSE;
+ XRenderChangePicture(dpy, src->pict, CPComponentAlpha,
+ &pa);
+ }
+ get_pixel(dpy, win, 0, 0, &tested);
+
+ expected = colors[target_colors[x][y]];
+ color_correct(win, &expected);
+ if (tested.r == 1.0) {
+ if (tested.g == 1.0 && tested.b == 1.0)
+ tested_colors[x][y] = 0;
+ else if (tested.g == 0.0 && tested.b == 0.0)
+ tested_colors[x][y] = 1;
+ else tested_colors[x][y] = 9;
+ } else
+ tested_colors[x][y] = 9;
+
+ if (test_mask)
+ snprintf(name, 20, "mask coords");
+ else
+ snprintf(name, 20, "src coords");
+ if (!eval_diff(name, &expected, &tested, x, y,
+ is_verbose))
+ failed = TRUE;
+ }
+ if (failed) {
+ int j;
+
+ printf("expected vs tested:\n");
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 5; j++)
+ printf("%d", target_colors[j][i]);
+ printf(" ");
+ for (j = 0; j < 5; j++)
+ printf("%d", tested_colors[j][i]);
+ printf("\n");
+ }
+ }
+
+ return !failed;
+}
+
+static Bool
+blend_test(Display *dpy, picture_info *win, picture_info *dst, int op,
+ picture_info *src_color, picture_info *dst_color)
+{
+ color4d expected, tested, tdst;
+ char testname[20];
+ int i;
+
+ for (i = 0; i < pixmap_move_iter; i++) {
+ XRenderComposite(dpy, PictOpSrc, dst_color->pict, 0, dst->pict, 0, 0,
+ 0, 0, 0, 0, win_width, win_height);
+ XRenderComposite(dpy, ops[op].op, src_color->pict, 0, dst->pict, 0, 0,
+ 0, 0, 0, 0, win_width, win_height);
+ }
+ get_pixel(dpy, dst, 0, 0, &tested);
+ /* Copy the output to the window, so the user sees something visual. */
+ XRenderComposite(dpy, PictOpSrc, dst->pict, 0, win->pict, 0, 0, 0, 0,
+ 0, 0, win_width, win_height);
+
+ tdst = dst_color->color;
+ color_correct(dst, &tdst);
+ do_composite(ops[op].op, &src_color->color, NULL, &tdst, &expected,
+ FALSE);
+ color_correct(dst, &expected);
+
+ snprintf(testname, 20, "%s blend", ops[op].name);
+ if (!eval_diff(testname, &expected, &tested, 0, 0, is_verbose)) {
+ printf("src color: %.2f %.2f %.2f %.2f\n"
+ "dst color: %.2f %.2f %.2f %.2f\n",
+ src_color->color.r, src_color->color.g,
+ src_color->color.b, src_color->color.a,
+ dst_color->color.r, dst_color->color.g,
+ dst_color->color.b, dst_color->color.a);
+ printf("src: %s, dst: %s\n", src_color->name, dst->name);
+ return FALSE;
+ } else if (is_verbose) {
+ printf("src: %s, dst: %s\n", src_color->name, dst->name);
+ }
+ return TRUE;
+}
+
+static Bool
+composite_test(Display *dpy, picture_info *win, picture_info *dst, int op,
+ picture_info *src_color, picture_info *mask_color, picture_info *dst_color,
+ Bool componentAlpha, Bool print_errors)
+{
+ color4d expected, tested, tdst, tmsk;
+ char testname[40];
+ XRenderPictureAttributes pa;
+ Bool success = TRUE;
+
+ if (componentAlpha) {
+ pa.component_alpha = TRUE;
+ XRenderChangePicture(dpy, mask_color->pict, CPComponentAlpha,
+ &pa);
+ }
+ XRenderComposite(dpy, PictOpSrc, dst_color->pict, 0, dst->pict, 0, 0,
+ 0, 0, 0, 0, win_width, win_height);
+ XRenderComposite(dpy, ops[op].op, src_color->pict, mask_color->pict,
+ dst->pict, 0, 0, 0, 0, 0, 0, win_width, win_height);
+ get_pixel(dpy, dst, 0, 0, &tested);
+ /* Copy the output to the window, so the user sees something visual. */
+ XRenderComposite(dpy, PictOpSrc, dst->pict, 0, win->pict, 0, 0, 0, 0,
+ 0, 0, win_width, win_height);
+ if (componentAlpha) {
+ pa.component_alpha = FALSE;
+ XRenderChangePicture(dpy, mask_color->pict, CPComponentAlpha,
+ &pa);
+ }
+
+ if (componentAlpha && mask_color->format->direct.redMask == 0) {
+ /* Ax component-alpha masks expand alpha into all color
+ * channels. XXX: This should be located somewhere generic.
+ */
+ tmsk.a = mask_color->color.a;
+ tmsk.r = mask_color->color.a;
+ tmsk.g = mask_color->color.a;
+ tmsk.b = mask_color->color.a;
+ } else
+ tmsk = mask_color->color;
+
+ tdst = dst_color->color;
+ color_correct(dst, &tdst);
+ do_composite(ops[op].op, &src_color->color, &tmsk, &tdst,
+ &expected, componentAlpha);
+ color_correct(dst, &expected);
+
+ snprintf(testname, 40, "%s %scomposite", ops[op].name,
+ componentAlpha ? "CA " : "");
+ if (!eval_diff(testname, &expected, &tested, 0, 0, is_verbose &&
+ print_errors)) {
+ if (print_errors)
+ printf("src color: %.2f %.2f %.2f %.2f\n"
+ "msk color: %.2f %.2f %.2f %.2f\n"
+ "dst color: %.2f %.2f %.2f %.2f\n",
+ src_color->color.r, src_color->color.g,
+ src_color->color.b, src_color->color.a,
+ mask_color->color.r, mask_color->color.g,
+ mask_color->color.b, mask_color->color.a,
+ dst_color->color.r, dst_color->color.g,
+ dst_color->color.b, dst_color->color.a);
+ printf("src: %s, mask: %s, dst: %s\n", src_color->name,
+ mask_color->name, dst->name);
+ success = FALSE;
+ } else if (is_verbose) {
+ printf("src: %s, mask: %s, dst: %s\n", src_color->name,
+ mask_color->name, dst->name);
+ }
+ return success;
+}
+
+
+void
+begin_test(Display *dpy, picture_info *win)
+{
+ int i, j, src, dst, mask;
+ int num_dests, num_formats;
+ picture_info *dests, *pictures_1x1, *pictures_10x10, picture_3x3;
+ picture_info picture_target;
+
+ num_dests = 3;
+ dests = (picture_info *)malloc(num_dests * sizeof(dests[0]));
+ if (dests == NULL)
+ errx(1, "malloc error");
+
+ dests[0].format = XRenderFindStandardFormat(dpy, PictStandardARGB32);
+ dests[1].format = XRenderFindStandardFormat(dpy, PictStandardRGB24);
+ dests[2].format = XRenderFindStandardFormat(dpy, PictStandardA8);
+ /*
+ dests[3].format = XRenderFindStandardFormat(dpy, PictStandardA4);
+ dests[4].format = XRenderFindStandardFormat(dpy, PictStandardA1);
+ */
+
+ for (i = 0; i < num_dests; i++) {
+ dests[i].d = XCreatePixmap(dpy, RootWindow(dpy, 0),
+ win_width, win_height, dests[i].format->depth);
+ dests[i].pict = XRenderCreatePicture(dpy, dests[i].d,
+ dests[i].format, 0, NULL);
+
+ dests[i].name = (char *)malloc(20);
+ if (dests[i].name == NULL)
+ errx(1, "malloc error");
+ describe_format(dests[i].name, 20, dests[i].format);
+ }
+
+ num_formats = 3;
+
+ pictures_1x1 = (picture_info *)malloc(num_colors * num_formats *
+ sizeof(picture_info));
+ if (pictures_1x1 == NULL)
+ errx(1, "malloc error");
+
+ for (i = 0; i < num_colors * num_formats; i++) {
+ XRenderPictureAttributes pa;
+ XRenderColor rendercolor;
+
+ /* The standard PictFormat numbers go from 0 to 4 */
+ pictures_1x1[i].format = XRenderFindStandardFormat(dpy,
+ i % num_formats);
+ pictures_1x1[i].d = XCreatePixmap(dpy, RootWindow(dpy, 0), 1,
+ 1, pictures_1x1[i].format->depth);
+ pa.repeat = TRUE;
+ pictures_1x1[i].pict = XRenderCreatePicture(dpy,
+ pictures_1x1[i].d, pictures_1x1[i].format, CPRepeat, &pa);
+
+ pictures_1x1[i].name = (char *)malloc(20);
+ if (pictures_1x1[i].name == NULL)
+ errx(1, "malloc error");
+ sprintf(pictures_1x1[i].name, "1x1R ");
+ describe_format(pictures_1x1[i].name +
+ strlen(pictures_1x1[i].name), 20 -
+ strlen(pictures_1x1[i].name), pictures_1x1[i].format);
+
+ rendercolor.red = colors[i / num_formats].r * 65535;
+ rendercolor.green = colors[i / num_formats].g * 65535;
+ rendercolor.blue = colors[i / num_formats].b * 65535;
+ rendercolor.alpha = colors[i / num_formats].a * 65535;
+ XRenderFillRectangle(dpy, PictOpSrc, pictures_1x1[i].pict,
+ &rendercolor, 0, 0, 1, 1);
+
+ pictures_1x1[i].color.r = colors[i / num_formats].r;
+ pictures_1x1[i].color.g = colors[i / num_formats].g;
+ pictures_1x1[i].color.b = colors[i / num_formats].b;
+ pictures_1x1[i].color.a = colors[i / num_formats].a;
+ color_correct(&pictures_1x1[i], &pictures_1x1[i].color);
+ }
+
+ pictures_10x10 = (picture_info *)malloc(num_colors * num_formats *
+ sizeof(picture_info));
+ if (pictures_10x10 == NULL)
+ errx(1, "malloc error");
+
+ for (i = 0; i < num_colors * num_formats; i++) {
+ XRenderPictureAttributes pa;
+ XRenderColor rendercolor;
+
+ /* The standard PictFormat numbers go from 0 to 4 */
+ pictures_10x10[i].format = XRenderFindStandardFormat(dpy,
+ i % num_formats);
+ pictures_10x10[i].d = XCreatePixmap(dpy, RootWindow(dpy, 0), 10,
+ 10, pictures_10x10[i].format->depth);
+ pa.repeat = TRUE;
+ pictures_10x10[i].pict = XRenderCreatePicture(dpy,
+ pictures_10x10[i].d, pictures_10x10[i].format, 0, NULL);
+
+ pictures_10x10[i].name = (char *)malloc(20);
+ if (pictures_10x10[i].name == NULL)
+ errx(1, "malloc error");
+ sprintf(pictures_10x10[i].name, "10x10 ");
+ describe_format(pictures_10x10[i].name +
+ strlen(pictures_10x10[i].name), 20 -
+ strlen(pictures_10x10[i].name), pictures_10x10[i].format);
+
+ rendercolor.red = colors[i / num_formats].r * 65535;
+ rendercolor.green = colors[i / num_formats].g * 65535;
+ rendercolor.blue = colors[i / num_formats].b * 65535;
+ rendercolor.alpha = colors[i / num_formats].a * 65535;
+ XRenderFillRectangle(dpy, PictOpSrc, pictures_10x10[i].pict,
+ &rendercolor, 0, 0, 10, 10);
+
+ pictures_10x10[i].color.r = colors[i / num_formats].r;
+ pictures_10x10[i].color.g = colors[i / num_formats].g;
+ pictures_10x10[i].color.b = colors[i / num_formats].b;
+ pictures_10x10[i].color.a = colors[i / num_formats].a;
+ color_correct(&pictures_10x10[i], &pictures_10x10[i].color);
+ }
+
+ picture_3x3.d = XCreatePixmap(dpy, RootWindow(dpy, 0), 3, 3, 32);
+ picture_3x3.format = XRenderFindStandardFormat(dpy, PictStandardARGB32);
+ picture_3x3.pict = XRenderCreatePicture(dpy, picture_3x3.d,
+ picture_3x3.format, 0, NULL);
+ picture_3x3.name = "3x3 sample picture";
+ for (i = 0; i < 9; i++) {
+ XRenderColor color;
+
+ color.red = colors[i % num_colors].r * 65535;
+ color.green = colors[i % num_colors].g * 65535;
+ color.blue = colors[i % num_colors].b * 65535;
+ color.alpha = colors[i % num_colors].a * 65535;
+ XRenderFillRectangle(dpy, PictOpSrc, picture_3x3.pict, &color,
+ i % 3, i / 3, 1, 1);
+ }
+ picture_target.d = XCreatePixmap(dpy, RootWindow(dpy, 0), 5, 5, 32);
+ picture_target.format = XRenderFindStandardFormat(dpy,
+ PictStandardARGB32);
+ picture_target.pict = XRenderCreatePicture(dpy, picture_target.d,
+ picture_target.format, 0, NULL);
+ picture_target.name = "target picture";
+ for (i = 0; i < 25; i++) {
+ int x = i % 5;
+ int y = i / 5;
+ XRenderColor color;
+ int tc;
+
+ tc = target_colors[x][y];
+
+ color.red = colors[tc].r * 65535;
+ color.green = colors[tc].g * 65535;
+ color.blue = colors[tc].b * 65535;
+ color.alpha = colors[tc].a * 65535;
+ XRenderFillRectangle(dpy, PictOpSrc, picture_target.pict,
+ &color, x, y, 1, 1);
+ }
+
+ printf("Beginning fill test\n");
+ for (i = 0; i < num_dests; i++) {
+ for (j = 0; j < num_colors * num_formats; j++) {
+ fill_test(dpy, win, &pictures_1x1[j], &dests[i]);
+ }
+ }
+
+ printf("Beginning dest coords test\n");
+ /* 0 and num_formats should result in ARGB8888 red on ARGB8888 white. */
+ destcoords_test(dpy, win, &dests[0], &pictures_1x1[0],
+ &pictures_1x1[num_formats]);
+
+ printf("Beginning src coords test\n");
+ srccoords_test(dpy, win, &picture_target, &pictures_1x1[0], FALSE);
+
+ printf("Beginning mask coords test\n");
+ srccoords_test(dpy, win, &picture_target, &pictures_1x1[0], TRUE);
+
+ for (i = 0; i < num_ops; i++) {
+ for (j = 0; j < num_dests; j++) {
+ printf("Beginning %s blend test on %s\n", ops[i].name,
+ dests[j].name);
+ for (src = 0; src < num_colors * num_formats; src++) {
+ for (dst = 0; dst < num_colors; dst++) {
+ blend_test(dpy, win, &dests[j], i,
+ &pictures_1x1[src], &pictures_1x1[dst]);
+ blend_test(dpy, win, &dests[j], i,
+ &pictures_10x10[src], &pictures_1x1[dst]);
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < num_ops; i++) {
+ for (j = 0; j < num_dests; j++) {
+ printf("Beginning %s composite mask test on %s\n", ops[i].name,
+ dests[j].name);
+ for (src = 0; src < num_colors; src++) {
+ for (mask = 0; mask < num_colors; mask++) {
+ for (dst = 0; dst < num_colors; dst++) {
+ composite_test(dpy, win, &dests[j], i,
+ &pictures_10x10[src], &pictures_10x10[mask],
+ &pictures_1x1[dst], FALSE, TRUE);
+ composite_test(dpy, win, &dests[j], i,
+ &pictures_1x1[src], &pictures_10x10[mask],
+ &pictures_1x1[dst], FALSE, TRUE);
+ composite_test(dpy, win, &dests[j], i,
+ &pictures_10x10[src], &pictures_1x1[mask],
+ &pictures_1x1[dst], FALSE, TRUE);
+ composite_test(dpy, win, &dests[j], i,
+ &pictures_1x1[src], &pictures_1x1[mask],
+ &pictures_1x1[dst], FALSE, TRUE);
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < num_ops; i++) {
+ for (j = 0; j < num_dests; j++) {
+ printf("Beginning %s composite CA mask test on %s\n",
+ ops[i].name, dests[j].name);
+ for (src = 0; src < num_colors; src++) {
+ for (mask = 0; mask < num_colors; mask++) {
+ for (dst = 0; dst < num_colors; dst++) {
+ composite_test(dpy, win, &dests[j], i,
+ &pictures_1x1[src], &pictures_1x1[mask],
+ &pictures_1x1[dst], TRUE, TRUE);
+ }
+ }
+ }
+ }
+ }
+}