wok-next rev 20905

Update packages from ISO and LFS backages (all but toolchain)
author Aleksej Bobylev <al.bobylev@gmail.com>
date Tue Aug 07 00:30:45 2018 +0300 (2018-08-07)
parents ab33f7358585
children a3c581bf52b8
files LibreOffice/receipt automake/receipt bison/receipt coreutils/stuff/patches/coreutils-8.29-i18n-1.patch coreutils/stuff/patches/coreutils-8.30-i18n-1.patch coreutils/stuff/patches/series expect/receipt file/receipt fribidi/receipt gdbm/receipt gzip/receipt harfbuzz/receipt hicolor-icon-theme/receipt imlib2/receipt intel-microcode/.icon.png intel-microcode/receipt intel-microcode/stuff/intel-microcode2ucode.c iproute2/receipt ipxe/receipt ipxe/stuff/patches/gcc7.patch itstool/receipt iucode-tool/receipt jansson/receipt keybinder/receipt keybinder3/receipt libblockdev/receipt libbluray/description.txt libbluray/receipt libbsd/receipt libbytesize/receipt libconfig/receipt libdrm/receipt libevdev/receipt libgpg-error/receipt libgphoto2/receipt libidn2/receipt libjpeg-turbo/.icon.png libjpeg-turbo/description.txt libjpeg-turbo/receipt libkeybinder/receipt libmtp/receipt libnfs/receipt libogg/receipt libpipeline/receipt libpng16/receipt libpng16/stuff/patches/libpng-1.6.34-apng.patch libpng16/stuff/patches/libpng-1.6.35-apng.patch libpng16/stuff/patches/series libsoup/receipt libtirpc/receipt libunistring/receipt libusb/receipt libvorbis/receipt libwnck2/receipt libxml2/receipt lvm2/receipt lxpanel/receipt lzma/receipt man-db/receipt mate-notification-daemon-gtk2/receipt mc/receipt mc/stuff/patches/mc-slitaz.patch mpc-library/receipt mpfr/receipt mpfr4/receipt nano/receipt nano/stuff/patches/nanorc.patch nano/stuff/patches/receipt-as-sh.patch nano/stuff/patches/series ncurses/receipt ndctl/receipt nettle/receipt npth/receipt nspr/receipt nss/receipt openldap/receipt opusfile/receipt pango/receipt patch/receipt pcre/receipt polkit105/receipt polkit105/stuff/10-udisks2.rules polkit105/stuff/patches/0001-Bug-50145-make-netgroup-support-optional.patch polkit105/stuff/patches/CVE-2013-4288.patch polkit105/stuff/patches/CVE-2015-3218.patch polkit105/stuff/patches/CVE-2015-3255.patch polkit105/stuff/patches/CVE-2015-4625.patch polkit105/stuff/patches/automake.patch polkit105/stuff/patches/disable-ck-test.patch polkit105/stuff/patches/fix-consolekit-db-stat.patch polkit105/stuff/patches/fix-parallel-make.patch polkit105/stuff/patches/fix-test-fgetpwent.patch polkit105/stuff/patches/series shadow/receipt shared-mime-info/receipt shared-mime-info/stuff/patches/series shared-mime-info/stuff/patches/slitaz-locales.patch slim/receipt slim/stuff/patches/libslim-underlinking.patch slim/stuff/patches/no-slimlock.patch slim/stuff/patches/series slim/stuff/patches/slim-1.3.6-slitaz.patch slim/stuff/patches/slim-freetype-dirs.patch slim/stuff/patches/snprintf.patch sudoku/receipt sudoku/stuff/sudoku sudoku/stuff/sudoku.desktop sudoku/stuff/sudoku48.png texinfo/receipt texinfo/stuff/patches/series texinfo/stuff/patches/texinfo-escape.patch udisks2/receipt unbound/receipt util-linux/receipt vim/.icon.png vim/receipt volume_key/receipt xarchiver/.icon.png xarchiver/receipt xarchiver/stuff/patches/series xarchiver/stuff/patches/xarchiver-0.5.3-icons.patch xarchiver/stuff/patches/xarchiver-0.5.4.13-icons.patch xfce4-mixer/receipt xfce4-volumed/receipt xorg-libXScrnSaver/receipt xorg-libXcomposite/receipt xorg-libXcursor/receipt xorg-libXfont2/receipt xorg-libXinerama/receipt xorg-libXxf86misc/receipt xorg-libdmx/receipt xorg-libpciaccess/receipt xorg-libxcb/receipt xorg-xcb-proto/receipt xorg-xcb-proto/stuff/patches/series xorg-xcb-proto/stuff/patches/xcb-proto-1.12-schema-1.patch xorg-xcompmgr/receipt xorg-xf86-input-evdev/receipt xorg-xf86-input-mouse/receipt xorg-xf86-input-synaptics/receipt xorg-xf86-video-fbdev/receipt xorg-xf86-video-intel/receipt xorg-xf86-video-intel/stuff/patches/git.patch xorg-xf86-video-intel/stuff/patches/series xorg-xf86-video-vesa/receipt xorg-xkbcomp/receipt xorg-xkeyboard-config/receipt xorg-xprop/receipt xorg-xset/receipt xorg-xwininfo/receipt yad/receipt
line diff
     1.1 --- a/LibreOffice/receipt	Mon Jul 30 23:44:42 2018 +0300
     1.2 +++ b/LibreOffice/receipt	Tue Aug 07 00:30:45 2018 +0300
     1.3 @@ -83,9 +83,13 @@
     1.4  			;;
     1.5  		LibreOffice)
     1.6  			copy @std *.inc @rm
     1.7 -			DEPENDS="gtk+ dbus-glib libcomerr libkrb5 xorg-libSM \
     1.8 -			xorg-libXinerama xorg-libXrandr"
     1.9 -			SUGGESTED="gst1-plugins-base mesa"
    1.10 +			DEPENDS="atk cairo dbus dbus-glib fontconfig freetype gdk-pixbuf \
    1.11 +			glib gpgme gst1-plugins-base gstreamer1 gtk+ icu lcms2 libassuan \
    1.12 +			libcomerr libcups libcurl libepoxy libgpg-error libicu libkrb5 \
    1.13 +			libsqlite3 libxml2 libxslt neon nspr nss pango perl python \
    1.14 +			xorg-libICE xorg-libSM xorg-libX11 xorg-libXext xorg-libXinerama \
    1.15 +			xorg-libXrandr xorg-libXrender zlib"
    1.16 +			SUGGESTED="mesa"
    1.17  
    1.18  			action 'Info: current size is...'; sizes
    1.19  
    1.20 @@ -152,6 +156,9 @@
    1.21  			# all the rest...
    1.22  			copy @std *.inc @rm
    1.23  			CAT="office|extra files"
    1.24 +			DEPENDS="glib gst0-plugins-base gstreamer0 libepoxy libicu libxml2 \
    1.25 +			xorg-libICE xorg-libSM xorg-libX11 xorg-libXext"
    1.26 +			SUGGESTED="libQtCore libQtGui libQtNetwork"
    1.27  			;;
    1.28  	esac
    1.29  }
     2.1 --- a/automake/receipt	Mon Jul 30 23:44:42 2018 +0300
     2.2 +++ b/automake/receipt	Tue Aug 07 00:30:45 2018 +0300
     2.3 @@ -1,13 +1,13 @@
     2.4  # SliTaz package receipt v2.
     2.5  
     2.6  PACKAGE="automake"
     2.7 -VERSION="1.15.1"
     2.8 +VERSION="1.16.1"
     2.9  CATEGORY="development"
    2.10  SHORT_DESC="A GNU tool for automatically creating Makefiles"
    2.11  MAINTAINER="pankso@slitaz.org"
    2.12  LICENSE="GPL2"
    2.13  WEB_SITE="https://www.gnu.org/software/automake/"
    2.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/automake.html"
    2.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/automake.html"
    2.16  HOST_ARCH="i486 x86_64"
    2.17  
    2.18  TARBALL="$PACKAGE-$VERSION.tar.xz"
     3.1 --- a/bison/receipt	Mon Jul 30 23:44:42 2018 +0300
     3.2 +++ b/bison/receipt	Tue Aug 07 00:30:45 2018 +0300
     3.3 @@ -1,7 +1,7 @@
     3.4  # SliTaz package receipt v2.
     3.5  
     3.6  PACKAGE="bison"
     3.7 -VERSION="3.0.4"
     3.8 +VERSION="3.0.5"
     3.9  CATEGORY="development"
    3.10  SHORT_DESC="GNU parser generator"
    3.11  MAINTAINER="pankso@slitaz.org"
     4.1 --- a/coreutils/stuff/patches/coreutils-8.29-i18n-1.patch	Mon Jul 30 23:44:42 2018 +0300
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,5521 +0,0 @@
     4.4 -Submitted by:            DJ Lucas (dj_AT_linuxfromscratch_DOT_org)
     4.5 -Date:                    2017-03-12
     4.6 -Initial Package Version: 8.27
     4.7 -Upstream Status:         Rejected
     4.8 -Origin:                  Based on Fedora's i18n patches at
     4.9 -                         http://pkgs.fedoraproject.org/cgit/rpms/coreutils.git/tree/
    4.10 -Description:             Fixes i18n issues with various Coreutils programs
    4.11 -
    4.12 -diff -Naurp coreutils-8.27-orig/bootstrap.conf coreutils-8.27/bootstrap.conf
    4.13 ---- coreutils-8.27-orig/bootstrap.conf	2017-03-07 23:34:06.000000000 -0600
    4.14 -+++ coreutils-8.27/bootstrap.conf	2017-03-11 23:47:38.068058445 -0600
    4.15 -@@ -152,6 +152,7 @@ gnulib_modules="
    4.16 -   maintainer-makefile
    4.17 -   malloc-gnu
    4.18 -   manywarnings
    4.19 -+  mbfile
    4.20 -   mbrlen
    4.21 -   mbrtowc
    4.22 -   mbsalign
    4.23 -diff -Naurp coreutils-8.27-orig/configure.ac coreutils-8.27/configure.ac
    4.24 ---- coreutils-8.27-orig/configure.ac	2017-02-26 08:52:29.000000000 -0600
    4.25 -+++ coreutils-8.27/configure.ac	2017-03-11 23:47:38.068058445 -0600
    4.26 -@@ -429,6 +429,8 @@ fi
    4.27 - # I'm leaving it here for now.  This whole thing needs to be modernized...
    4.28 - gl_WINSIZE_IN_PTEM
    4.29 - 
    4.30 -+gl_MBFILE
    4.31 -+
    4.32 - gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H
    4.33 - 
    4.34 - if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \
    4.35 -diff -Naurp coreutils-8.27-orig/lib/linebuffer.h coreutils-8.27/lib/linebuffer.h
    4.36 ---- coreutils-8.27-orig/lib/linebuffer.h	2017-01-01 16:35:38.000000000 -0600
    4.37 -+++ coreutils-8.27/lib/linebuffer.h	2017-03-11 23:47:13.089286391 -0600
    4.38 -@@ -21,6 +21,11 @@
    4.39 - 
    4.40 - # include <stdio.h>
    4.41 - 
    4.42 -+/* Get mbstate_t.  */
    4.43 -+# if HAVE_WCHAR_H
    4.44 -+#  include <wchar.h>
    4.45 -+# endif
    4.46 -+
    4.47 - /* A 'struct linebuffer' holds a line of text. */
    4.48 - 
    4.49 - struct linebuffer
    4.50 -@@ -28,6 +33,9 @@ struct linebuffer
    4.51 -   size_t size;                  /* Allocated. */
    4.52 -   size_t length;                /* Used. */
    4.53 -   char *buffer;
    4.54 -+# if HAVE_WCHAR_H
    4.55 -+  mbstate_t state;
    4.56 -+# endif
    4.57 - };
    4.58 - 
    4.59 - /* Initialize linebuffer LINEBUFFER for use. */
    4.60 -diff -Naurp coreutils-8.27-orig/lib/mbfile.c coreutils-8.27/lib/mbfile.c
    4.61 ---- coreutils-8.27-orig/lib/mbfile.c	1969-12-31 18:00:00.000000000 -0600
    4.62 -+++ coreutils-8.27/lib/mbfile.c	2017-03-11 23:47:38.069058397 -0600
    4.63 -@@ -0,0 +1,3 @@
    4.64 -+#include <config.h>
    4.65 -+#define MBFILE_INLINE _GL_EXTERN_INLINE
    4.66 -+#include "mbfile.h"
    4.67 -diff -Naurp coreutils-8.27-orig/lib/mbfile.h coreutils-8.27/lib/mbfile.h
    4.68 ---- coreutils-8.27-orig/lib/mbfile.h	1969-12-31 18:00:00.000000000 -0600
    4.69 -+++ coreutils-8.27/lib/mbfile.h	2017-03-11 23:47:38.069058397 -0600
    4.70 -@@ -0,0 +1,255 @@
    4.71 -+/* Multibyte character I/O: macros for multi-byte encodings.
    4.72 -+   Copyright (C) 2001, 2005, 2009-2017 Free Software Foundation, Inc.
    4.73 -+
    4.74 -+   This program is free software: you can redistribute it and/or modify
    4.75 -+   it under the terms of the GNU General Public License as published by
    4.76 -+   the Free Software Foundation; either version 3 of the License, or
    4.77 -+   (at your option) any later version.
    4.78 -+
    4.79 -+   This program is distributed in the hope that it will be useful,
    4.80 -+   but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.81 -+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.82 -+   GNU General Public License for more details.
    4.83 -+
    4.84 -+   You should have received a copy of the GNU General Public License
    4.85 -+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
    4.86 -+
    4.87 -+/* Written by Mitsuru Chinen <mchinen@yamato.ibm.com>
    4.88 -+   and Bruno Haible <bruno@clisp.org>.  */
    4.89 -+
    4.90 -+/* The macros in this file implement multi-byte character input from a
    4.91 -+   stream.
    4.92 -+
    4.93 -+   mb_file_t
    4.94 -+     is the type for multibyte character input stream, usable for variable
    4.95 -+     declarations.
    4.96 -+
    4.97 -+   mbf_char_t
    4.98 -+     is the type for multibyte character or EOF, usable for variable
    4.99 -+     declarations.
   4.100 -+
   4.101 -+   mbf_init (mbf, stream)
   4.102 -+     initializes the MB_FILE for reading from stream.
   4.103 -+
   4.104 -+   mbf_getc (mbc, mbf)
   4.105 -+     reads the next multibyte character from mbf and stores it in mbc.
   4.106 -+
   4.107 -+   mb_iseof (mbc)
   4.108 -+     returns true if mbc represents the EOF value.
   4.109 -+
   4.110 -+   Here are the function prototypes of the macros.
   4.111 -+
   4.112 -+   extern void          mbf_init (mb_file_t mbf, FILE *stream);
   4.113 -+   extern void          mbf_getc (mbf_char_t mbc, mb_file_t mbf);
   4.114 -+   extern bool          mb_iseof (const mbf_char_t mbc);
   4.115 -+ */
   4.116 -+
   4.117 -+#ifndef _MBFILE_H
   4.118 -+#define _MBFILE_H 1
   4.119 -+
   4.120 -+#include <assert.h>
   4.121 -+#include <stdbool.h>
   4.122 -+#include <stdio.h>
   4.123 -+#include <string.h>
   4.124 -+
   4.125 -+/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
   4.126 -+   <wchar.h>.
   4.127 -+   BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
   4.128 -+   <wchar.h>.  */
   4.129 -+#include <stdio.h>
   4.130 -+#include <time.h>
   4.131 -+#include <wchar.h>
   4.132 -+
   4.133 -+#include "mbchar.h"
   4.134 -+
   4.135 -+#ifndef _GL_INLINE_HEADER_BEGIN
   4.136 -+ #error "Please include config.h first."
   4.137 -+#endif
   4.138 -+_GL_INLINE_HEADER_BEGIN
   4.139 -+#ifndef MBFILE_INLINE
   4.140 -+# define MBFILE_INLINE _GL_INLINE
   4.141 -+#endif
   4.142 -+
   4.143 -+struct mbfile_multi {
   4.144 -+  FILE *fp;
   4.145 -+  bool eof_seen;
   4.146 -+  bool have_pushback;
   4.147 -+  mbstate_t state;
   4.148 -+  unsigned int bufcount;
   4.149 -+  char buf[MBCHAR_BUF_SIZE];
   4.150 -+  struct mbchar pushback;
   4.151 -+};
   4.152 -+
   4.153 -+MBFILE_INLINE void
   4.154 -+mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf)
   4.155 -+{
   4.156 -+  size_t bytes;
   4.157 -+
   4.158 -+  /* If EOF has already been seen, don't use getc.  This matters if
   4.159 -+     mbf->fp is connected to an interactive tty.  */
   4.160 -+  if (mbf->eof_seen)
   4.161 -+    goto eof;
   4.162 -+
   4.163 -+  /* Return character pushed back, if there is one.  */
   4.164 -+  if (mbf->have_pushback)
   4.165 -+    {
   4.166 -+      mb_copy (mbc, &mbf->pushback);
   4.167 -+      mbf->have_pushback = false;
   4.168 -+      return;
   4.169 -+    }
   4.170 -+
   4.171 -+  /* Before using mbrtowc, we need at least one byte.  */
   4.172 -+  if (mbf->bufcount == 0)
   4.173 -+    {
   4.174 -+      int c = getc (mbf->fp);
   4.175 -+      if (c == EOF)
   4.176 -+        {
   4.177 -+          mbf->eof_seen = true;
   4.178 -+          goto eof;
   4.179 -+        }
   4.180 -+      mbf->buf[0] = (unsigned char) c;
   4.181 -+      mbf->bufcount++;
   4.182 -+    }
   4.183 -+
   4.184 -+  /* Handle most ASCII characters quickly, without calling mbrtowc().  */
   4.185 -+  if (mbf->bufcount == 1 && mbsinit (&mbf->state) && is_basic (mbf->buf[0]))
   4.186 -+    {
   4.187 -+      /* These characters are part of the basic character set.  ISO C 99
   4.188 -+         guarantees that their wide character code is identical to their
   4.189 -+         char code.  */
   4.190 -+      mbc->wc = mbc->buf[0] = mbf->buf[0];
   4.191 -+      mbc->wc_valid = true;
   4.192 -+      mbc->ptr = &mbc->buf[0];
   4.193 -+      mbc->bytes = 1;
   4.194 -+      mbf->bufcount = 0;
   4.195 -+      return;
   4.196 -+    }
   4.197 -+
   4.198 -+  /* Use mbrtowc on an increasing number of bytes.  Read only as many bytes
   4.199 -+     from mbf->fp as needed.  This is needed to give reasonable interactive
   4.200 -+     behaviour when mbf->fp is connected to an interactive tty.  */
   4.201 -+  for (;;)
   4.202 -+    {
   4.203 -+      /* We don't know whether the 'mbrtowc' function updates the state when
   4.204 -+         it returns -2, - this is the ISO C 99 and glibc-2.2 behaviour - or
   4.205 -+         not - amended ANSI C, glibc-2.1 and Solaris 2.7 behaviour.  We
   4.206 -+         don't have an autoconf test for this, yet.
   4.207 -+         The new behaviour would allow us to feed the bytes one by one into
   4.208 -+         mbrtowc.  But the old behaviour forces us to feed all bytes since
   4.209 -+         the end of the last character into mbrtowc.  Since we want to retry
   4.210 -+         with more bytes when mbrtowc returns -2, we must backup the state
   4.211 -+         before calling mbrtowc, because implementations with the new
   4.212 -+         behaviour will clobber it.  */
   4.213 -+      mbstate_t backup_state = mbf->state;
   4.214 -+
   4.215 -+      bytes = mbrtowc (&mbc->wc, &mbf->buf[0], mbf->bufcount, &mbf->state);
   4.216 -+
   4.217 -+      if (bytes == (size_t) -1)
   4.218 -+        {
   4.219 -+          /* An invalid multibyte sequence was encountered.  */
   4.220 -+          /* Return a single byte.  */
   4.221 -+          bytes = 1;
   4.222 -+          mbc->wc_valid = false;
   4.223 -+          break;
   4.224 -+        }
   4.225 -+      else if (bytes == (size_t) -2)
   4.226 -+        {
   4.227 -+          /* An incomplete multibyte character.  */
   4.228 -+          mbf->state = backup_state;
   4.229 -+          if (mbf->bufcount == MBCHAR_BUF_SIZE)
   4.230 -+            {
   4.231 -+              /* An overlong incomplete multibyte sequence was encountered.  */
   4.232 -+              /* Return a single byte.  */
   4.233 -+              bytes = 1;
   4.234 -+              mbc->wc_valid = false;
   4.235 -+              break;
   4.236 -+            }
   4.237 -+          else
   4.238 -+            {
   4.239 -+              /* Read one more byte and retry mbrtowc.  */
   4.240 -+              int c = getc (mbf->fp);
   4.241 -+              if (c == EOF)
   4.242 -+                {
   4.243 -+                  /* An incomplete multibyte character at the end.  */
   4.244 -+                  mbf->eof_seen = true;
   4.245 -+                  bytes = mbf->bufcount;
   4.246 -+                  mbc->wc_valid = false;
   4.247 -+                  break;
   4.248 -+                }
   4.249 -+              mbf->buf[mbf->bufcount] = (unsigned char) c;
   4.250 -+              mbf->bufcount++;
   4.251 -+            }
   4.252 -+        }
   4.253 -+      else
   4.254 -+        {
   4.255 -+          if (bytes == 0)
   4.256 -+            {
   4.257 -+              /* A null wide character was encountered.  */
   4.258 -+              bytes = 1;
   4.259 -+              assert (mbf->buf[0] == '\0');
   4.260 -+              assert (mbc->wc == 0);
   4.261 -+            }
   4.262 -+          mbc->wc_valid = true;
   4.263 -+          break;
   4.264 -+        }
   4.265 -+    }
   4.266 -+
   4.267 -+  /* Return the multibyte sequence mbf->buf[0..bytes-1].  */
   4.268 -+  mbc->ptr = &mbc->buf[0];
   4.269 -+  memcpy (&mbc->buf[0], &mbf->buf[0], bytes);
   4.270 -+  mbc->bytes = bytes;
   4.271 -+
   4.272 -+  mbf->bufcount -= bytes;
   4.273 -+  if (mbf->bufcount > 0)
   4.274 -+    {
   4.275 -+      /* It's not worth calling memmove() for so few bytes.  */
   4.276 -+      unsigned int count = mbf->bufcount;
   4.277 -+      char *p = &mbf->buf[0];
   4.278 -+
   4.279 -+      do
   4.280 -+        {
   4.281 -+          *p = *(p + bytes);
   4.282 -+          p++;
   4.283 -+        }
   4.284 -+      while (--count > 0);
   4.285 -+    }
   4.286 -+  return;
   4.287 -+
   4.288 -+eof:
   4.289 -+  /* An mbchar_t with bytes == 0 is used to indicate EOF.  */
   4.290 -+  mbc->ptr = NULL;
   4.291 -+  mbc->bytes = 0;
   4.292 -+  mbc->wc_valid = false;
   4.293 -+  return;
   4.294 -+}
   4.295 -+
   4.296 -+MBFILE_INLINE void
   4.297 -+mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf)
   4.298 -+{
   4.299 -+  mb_copy (&mbf->pushback, mbc);
   4.300 -+  mbf->have_pushback = true;
   4.301 -+}
   4.302 -+
   4.303 -+typedef struct mbfile_multi mb_file_t;
   4.304 -+
   4.305 -+typedef mbchar_t mbf_char_t;
   4.306 -+
   4.307 -+#define mbf_init(mbf, stream)                                           \
   4.308 -+  ((mbf).fp = (stream),                                                 \
   4.309 -+   (mbf).eof_seen = false,                                              \
   4.310 -+   (mbf).have_pushback = false,                                         \
   4.311 -+   memset (&(mbf).state, '\0', sizeof (mbstate_t)),                     \
   4.312 -+   (mbf).bufcount = 0)
   4.313 -+
   4.314 -+#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf))
   4.315 -+
   4.316 -+#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf))
   4.317 -+
   4.318 -+#define mb_iseof(mbc) ((mbc).bytes == 0)
   4.319 -+
   4.320 -+#ifndef _GL_INLINE_HEADER_BEGIN
   4.321 -+ #error "Please include config.h first."
   4.322 -+#endif
   4.323 -+_GL_INLINE_HEADER_BEGIN
   4.324 -+
   4.325 -+#endif /* _MBFILE_H */
   4.326 -diff -Naurp coreutils-8.27-orig/m4/mbfile.m4 coreutils-8.27/m4/mbfile.m4
   4.327 ---- coreutils-8.27-orig/m4/mbfile.m4	1969-12-31 18:00:00.000000000 -0600
   4.328 -+++ coreutils-8.27/m4/mbfile.m4	2017-03-11 23:47:38.070058349 -0600
   4.329 -@@ -0,0 +1,14 @@
   4.330 -+# mbfile.m4 serial 7
   4.331 -+dnl Copyright (C) 2005, 2008-2017 Free Software Foundation, Inc.
   4.332 -+dnl This file is free software; the Free Software Foundation
   4.333 -+dnl gives unlimited permission to copy and/or distribute it,
   4.334 -+dnl with or without modifications, as long as this notice is preserved.
   4.335 -+
   4.336 -+dnl autoconf tests required for use of mbfile.h
   4.337 -+dnl From Bruno Haible.
   4.338 -+
   4.339 -+AC_DEFUN([gl_MBFILE],
   4.340 -+[
   4.341 -+  AC_REQUIRE([AC_TYPE_MBSTATE_T])
   4.342 -+  :
   4.343 -+])
   4.344 -diff -Naurp coreutils-8.27-orig/src/cut.c coreutils-8.27/src/cut.c
   4.345 ---- coreutils-8.27-orig/src/cut.c	2017-01-01 16:34:24.000000000 -0600
   4.346 -+++ coreutils-8.27/src/cut.c	2017-03-11 23:47:59.526048471 -0600
   4.347 -@@ -28,6 +28,11 @@
   4.348 - #include <assert.h>
   4.349 - #include <getopt.h>
   4.350 - #include <sys/types.h>
   4.351 -+
   4.352 -+/* Get mbstate_t, mbrtowc().  */
   4.353 -+#if HAVE_WCHAR_H
   4.354 -+# include <wchar.h>
   4.355 -+#endif
   4.356 - #include "system.h"
   4.357 - 
   4.358 - #include "error.h"
   4.359 -@@ -38,6 +43,18 @@
   4.360 - 
   4.361 - #include "set-fields.h"
   4.362 - 
   4.363 -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
   4.364 -+   installation; work around this configuration error.        */
   4.365 -+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
   4.366 -+# undef MB_LEN_MAX
   4.367 -+# define MB_LEN_MAX 16
   4.368 -+#endif
   4.369 -+
   4.370 -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
   4.371 -+#if HAVE_MBRTOWC && defined mbstate_t
   4.372 -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
   4.373 -+#endif
   4.374 -+
   4.375 - /* The official name of this program (e.g., no 'g' prefix).  */
   4.376 - #define PROGRAM_NAME "cut"
   4.377 - 
   4.378 -@@ -54,6 +71,52 @@
   4.379 -     }									\
   4.380 -   while (0)
   4.381 - 
   4.382 -+/* Refill the buffer BUF to get a multibyte character. */
   4.383 -+#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM)                        \
   4.384 -+  do                                                                        \
   4.385 -+    {                                                                        \
   4.386 -+      if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM))        \
   4.387 -+        {                                                                \
   4.388 -+          memmove (BUF, BUFPOS, BUFLEN);                                \
   4.389 -+          BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
   4.390 -+          BUFPOS = BUF;                                                        \
   4.391 -+        }                                                                \
   4.392 -+    }                                                                        \
   4.393 -+  while (0)
   4.394 -+
   4.395 -+/* Get wide character on BUFPOS. BUFPOS is not included after that.
   4.396 -+   If byte sequence is not valid as a character, CONVFAIL is true. Otherwise false. */
   4.397 -+#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \
   4.398 -+  do                                                                        \
   4.399 -+    {                                                                        \
   4.400 -+      mbstate_t state_bak;                                                \
   4.401 -+                                                                        \
   4.402 -+      if (BUFLEN < 1)                                                        \
   4.403 -+        {                                                                \
   4.404 -+          WC = WEOF;                                                        \
   4.405 -+          break;                                                        \
   4.406 -+        }                                                                \
   4.407 -+                                                                        \
   4.408 -+      /* Get a wide character. */                                        \
   4.409 -+      CONVFAIL = false;                                                        \
   4.410 -+      state_bak = STATE;                                                \
   4.411 -+      MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE);        \
   4.412 -+                                                                        \
   4.413 -+      switch (MBLENGTH)                                                        \
   4.414 -+        {                                                                \
   4.415 -+        case (size_t)-1:                                                \
   4.416 -+        case (size_t)-2:                                                \
   4.417 -+          CONVFAIL = true;                                                        \
   4.418 -+          STATE = state_bak;                                                \
   4.419 -+          /* Fall througn. */                                                \
   4.420 -+                                                                        \
   4.421 -+        case 0:                                                                \
   4.422 -+          MBLENGTH = 1;                                                        \
   4.423 -+          break;                                                        \
   4.424 -+        }                                                                \
   4.425 -+    }                                                                        \
   4.426 -+  while (0)
   4.427 -+
   4.428 - 
   4.429 - /* Pointer inside RP.  When checking if a byte or field is selected
   4.430 -    by a finite range, we check if it is between CURRENT_RP.LO
   4.431 -@@ -61,6 +124,9 @@
   4.432 -    CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */
   4.433 - static struct field_range_pair *current_rp;
   4.434 - 
   4.435 -+/* Length of the delimiter given as argument to -d.  */
   4.436 -+size_t delimlen;
   4.437 -+
   4.438 - /* This buffer is used to support the semantics of the -s option
   4.439 -    (or lack of same) when the specified field list includes (does
   4.440 -    not include) the first field.  In both of those cases, the entire
   4.441 -@@ -77,15 +143,25 @@ enum operating_mode
   4.442 -   {
   4.443 -     undefined_mode,
   4.444 - 
   4.445 --    /* Output characters that are in the given bytes. */
   4.446 -+    /* Output bytes that are at the given positions. */
   4.447 -     byte_mode,
   4.448 - 
   4.449 -+    /* Output characters that are at the given positions. */
   4.450 -+    character_mode,
   4.451 -+
   4.452 -     /* Output the given delimiter-separated fields. */
   4.453 -     field_mode
   4.454 -   };
   4.455 - 
   4.456 - static enum operating_mode operating_mode;
   4.457 - 
   4.458 -+/* If nonzero, when in byte mode, don't split multibyte characters.  */
   4.459 -+static int byte_mode_character_aware;
   4.460 -+
   4.461 -+/* If nonzero, the function for single byte locale is work
   4.462 -+   if this program runs on multibyte locale. */
   4.463 -+static int force_singlebyte_mode;
   4.464 -+
   4.465 - /* If true do not output lines containing no delimiter characters.
   4.466 -    Otherwise, all such lines are printed.  This option is valid only
   4.467 -    with field mode.  */
   4.468 -@@ -97,6 +173,9 @@ static bool complement;
   4.469 - 
   4.470 - /* The delimiter character for field mode. */
   4.471 - static unsigned char delim;
   4.472 -+#if HAVE_WCHAR_H
   4.473 -+static wchar_t wcdelim;
   4.474 -+#endif
   4.475 - 
   4.476 - /* The delimiter for each line/record. */
   4.477 - static unsigned char line_delim = '\n';
   4.478 -@@ -164,7 +243,7 @@ Print selected parts of lines from each
   4.479 -   -f, --fields=LIST       select only these fields;  also print any line\n\
   4.480 -                             that contains no delimiter character, unless\n\
   4.481 -                             the -s option is specified\n\
   4.482 --  -n                      (ignored)\n\
   4.483 -+  -n                      with -b: don't split multibyte characters\n\
   4.484 - "), stdout);
   4.485 -       fputs (_("\
   4.486 -       --complement        complement the set of selected bytes, characters\n\
   4.487 -@@ -280,6 +359,82 @@ cut_bytes (FILE *stream)
   4.488 -     }
   4.489 - }
   4.490 - 
   4.491 -+#if HAVE_MBRTOWC
   4.492 -+/* This function is in use for the following case.
   4.493 -+
   4.494 -+   1. Read from the stream STREAM, printing to standard output any selected
   4.495 -+   characters.
   4.496 -+
   4.497 -+   2. Read from stream STREAM, printing to standard output any selected bytes,
   4.498 -+   without splitting multibyte characters.  */
   4.499 -+
   4.500 -+static void
   4.501 -+cut_characters_or_cut_bytes_no_split (FILE *stream)
   4.502 -+{
   4.503 -+  size_t idx;                /* number of bytes or characters in the line so far. */
   4.504 -+  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
   4.505 -+  char *bufpos;                /* Next read position of BUF. */
   4.506 -+  size_t buflen;        /* The length of the byte sequence in buf. */
   4.507 -+  wint_t wc;                /* A gotten wide character. */
   4.508 -+  size_t mblength;        /* The byte size of a multibyte character which shows
   4.509 -+                           as same character as WC. */
   4.510 -+  mbstate_t state;        /* State of the stream. */
   4.511 -+  bool convfail = false;  /* true, when conversion failed. Otherwise false. */
   4.512 -+  /* Whether to begin printing delimiters between ranges for the current line.
   4.513 -+     Set after we've begun printing data corresponding to the first range.  */
   4.514 -+  bool print_delimiter = false;
   4.515 -+
   4.516 -+  idx = 0;
   4.517 -+  buflen = 0;
   4.518 -+  bufpos = buf;
   4.519 -+  memset (&state, '\0', sizeof(mbstate_t));
   4.520 -+
   4.521 -+  current_rp = frp;
   4.522 -+
   4.523 -+  while (1)
   4.524 -+    {
   4.525 -+      REFILL_BUFFER (buf, bufpos, buflen, stream);
   4.526 -+
   4.527 -+      GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail);
   4.528 -+      (void) convfail;  /* ignore unused */
   4.529 -+
   4.530 -+      if (wc == WEOF)
   4.531 -+        {
   4.532 -+          if (idx > 0)
   4.533 -+            putchar (line_delim);
   4.534 -+          break;
   4.535 -+        }
   4.536 -+      else if (wc == line_delim)
   4.537 -+        {
   4.538 -+          putchar (line_delim);
   4.539 -+          idx = 0;
   4.540 -+          print_delimiter = false;
   4.541 -+          current_rp = frp;
   4.542 -+        }
   4.543 -+      else
   4.544 -+        {
   4.545 -+          next_item (&idx);
   4.546 -+          if (print_kth (idx))
   4.547 -+            {
   4.548 -+              if (output_delimiter_specified)
   4.549 -+                {
   4.550 -+                  if (print_delimiter && is_range_start_index (idx))
   4.551 -+                    {
   4.552 -+                      fwrite (output_delimiter_string, sizeof (char),
   4.553 -+                              output_delimiter_length, stdout);
   4.554 -+                    }
   4.555 -+                  print_delimiter = true;
   4.556 -+                }
   4.557 -+              fwrite (bufpos, mblength, sizeof(char), stdout);
   4.558 -+            }
   4.559 -+        }
   4.560 -+
   4.561 -+      buflen -= mblength;
   4.562 -+      bufpos += mblength;
   4.563 -+    }
   4.564 -+}
   4.565 -+#endif
   4.566 -+
   4.567 - /* Read from stream STREAM, printing to standard output any selected fields.  */
   4.568 - 
   4.569 - static void
   4.570 -@@ -425,13 +580,211 @@ cut_fields (FILE *stream)
   4.571 -     }
   4.572 - }
   4.573 - 
   4.574 -+#if HAVE_MBRTOWC
   4.575 -+static void
   4.576 -+cut_fields_mb (FILE *stream)
   4.577 -+{
   4.578 -+  int c;
   4.579 -+  size_t field_idx;
   4.580 -+  int found_any_selected_field;
   4.581 -+  int buffer_first_field;
   4.582 -+  int empty_input;
   4.583 -+  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
   4.584 -+  char *bufpos;                /* Next read position of BUF. */
   4.585 -+  size_t buflen;        /* The length of the byte sequence in buf. */
   4.586 -+  wint_t wc = 0;        /* A gotten wide character. */
   4.587 -+  size_t mblength;        /* The byte size of a multibyte character which shows
   4.588 -+                           as same character as WC. */
   4.589 -+  mbstate_t state;        /* State of the stream. */
   4.590 -+  bool convfail = false;  /* true, when conversion failed. Otherwise false. */
   4.591 -+
   4.592 -+  current_rp = frp;
   4.593 -+
   4.594 -+  found_any_selected_field = 0;
   4.595 -+  field_idx = 1;
   4.596 -+  bufpos = buf;
   4.597 -+  buflen = 0;
   4.598 -+  memset (&state, '\0', sizeof(mbstate_t));
   4.599 -+
   4.600 -+  c = getc (stream);
   4.601 -+  empty_input = (c == EOF);
   4.602 -+  if (c != EOF)
   4.603 -+  {
   4.604 -+    ungetc (c, stream);
   4.605 -+    wc = 0;
   4.606 -+  }
   4.607 -+  else
   4.608 -+    wc = WEOF;
   4.609 -+
   4.610 -+  /* To support the semantics of the -s flag, we may have to buffer
   4.611 -+     all of the first field to determine whether it is `delimited.'
   4.612 -+     But that is unnecessary if all non-delimited lines must be printed
   4.613 -+     and the first field has been selected, or if non-delimited lines
   4.614 -+     must be suppressed and the first field has *not* been selected.
   4.615 -+     That is because a non-delimited line has exactly one field.  */
   4.616 -+  buffer_first_field = (suppress_non_delimited ^ !print_kth (1));
   4.617 -+
   4.618 -+  while (1)
   4.619 -+    {
   4.620 -+      if (field_idx == 1 && buffer_first_field)
   4.621 -+        {
   4.622 -+          int len = 0;
   4.623 -+
   4.624 -+          while (1)
   4.625 -+            {
   4.626 -+              REFILL_BUFFER (buf, bufpos, buflen, stream);
   4.627 -+
   4.628 -+              GET_NEXT_WC_FROM_BUFFER
   4.629 -+                (wc, bufpos, buflen, mblength, state, convfail);
   4.630 -+
   4.631 -+              if (wc == WEOF)
   4.632 -+                break;
   4.633 -+
   4.634 -+              field_1_buffer = xrealloc (field_1_buffer, len + mblength);
   4.635 -+              memcpy (field_1_buffer + len, bufpos, mblength);
   4.636 -+              len += mblength;
   4.637 -+              buflen -= mblength;
   4.638 -+              bufpos += mblength;
   4.639 -+
   4.640 -+              if (!convfail && (wc == line_delim || wc == wcdelim))
   4.641 -+                break;
   4.642 -+            }
   4.643 -+
   4.644 -+          if (len <= 0 && wc == WEOF)
   4.645 -+            break;
   4.646 -+
   4.647 -+          /* If the first field extends to the end of line (it is not
   4.648 -+             delimited) and we are printing all non-delimited lines,
   4.649 -+             print this one.  */
   4.650 -+          if (convfail || (!convfail && wc != wcdelim))
   4.651 -+            {
   4.652 -+              if (suppress_non_delimited)
   4.653 -+                {
   4.654 -+                  /* Empty.        */
   4.655 -+                }
   4.656 -+              else
   4.657 -+                {
   4.658 -+                  fwrite (field_1_buffer, sizeof (char), len, stdout);
   4.659 -+                  /* Make sure the output line is newline terminated.  */
   4.660 -+                  if (convfail || (!convfail && wc != line_delim))
   4.661 -+                    putchar (line_delim);
   4.662 -+                }
   4.663 -+              continue;
   4.664 -+            }
   4.665 -+
   4.666 -+          if (print_kth (1))
   4.667 -+            {
   4.668 -+              /* Print the field, but not the trailing delimiter.  */
   4.669 -+              fwrite (field_1_buffer, sizeof (char), len - 1, stdout);
   4.670 -+              found_any_selected_field = 1;
   4.671 -+            }
   4.672 -+          next_item (&field_idx);
   4.673 -+        }
   4.674 -+
   4.675 -+      if (wc != WEOF)
   4.676 -+        {
   4.677 -+          if (print_kth (field_idx))
   4.678 -+            {
   4.679 -+              if (found_any_selected_field)
   4.680 -+                {
   4.681 -+                  fwrite (output_delimiter_string, sizeof (char),
   4.682 -+                          output_delimiter_length, stdout);
   4.683 -+                }
   4.684 -+              found_any_selected_field = 1;
   4.685 -+            }
   4.686 -+
   4.687 -+          while (1)
   4.688 -+            {
   4.689 -+              REFILL_BUFFER (buf, bufpos, buflen, stream);
   4.690 -+
   4.691 -+              GET_NEXT_WC_FROM_BUFFER
   4.692 -+                (wc, bufpos, buflen, mblength, state, convfail);
   4.693 -+
   4.694 -+              if (wc == WEOF)
   4.695 -+                break;
   4.696 -+              else if (!convfail && (wc == wcdelim || wc == line_delim))
   4.697 -+                {
   4.698 -+                  buflen -= mblength;
   4.699 -+                  bufpos += mblength;
   4.700 -+                  break;
   4.701 -+                }
   4.702 -+
   4.703 -+              if (print_kth (field_idx))
   4.704 -+                fwrite (bufpos, mblength, sizeof(char), stdout);
   4.705 -+
   4.706 -+              buflen -= mblength;
   4.707 -+              bufpos += mblength;
   4.708 -+            }
   4.709 -+        }
   4.710 -+
   4.711 -+      if ((!convfail || wc == line_delim) && buflen < 1)
   4.712 -+        wc = WEOF;
   4.713 -+
   4.714 -+      if (!convfail && wc == wcdelim)
   4.715 -+        next_item (&field_idx);
   4.716 -+      else if (wc == WEOF || (!convfail && wc == line_delim))
   4.717 -+        {
   4.718 -+          if (found_any_selected_field
   4.719 -+              || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
   4.720 -+            putchar (line_delim);
   4.721 -+          if (wc == WEOF)
   4.722 -+            break;
   4.723 -+          field_idx = 1;
   4.724 -+          current_rp = frp;
   4.725 -+          found_any_selected_field = 0;
   4.726 -+        }
   4.727 -+    }
   4.728 -+}
   4.729 -+#endif
   4.730 -+
   4.731 - static void
   4.732 - cut_stream (FILE *stream)
   4.733 - {
   4.734 --  if (operating_mode == byte_mode)
   4.735 --    cut_bytes (stream);
   4.736 -+#if HAVE_MBRTOWC
   4.737 -+  if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
   4.738 -+    {
   4.739 -+      switch (operating_mode)
   4.740 -+        {
   4.741 -+        case byte_mode:
   4.742 -+          if (byte_mode_character_aware)
   4.743 -+            cut_characters_or_cut_bytes_no_split (stream);
   4.744 -+          else
   4.745 -+            cut_bytes (stream);
   4.746 -+          break;
   4.747 -+
   4.748 -+        case character_mode:
   4.749 -+          cut_characters_or_cut_bytes_no_split (stream);
   4.750 -+          break;
   4.751 -+
   4.752 -+        case field_mode:
   4.753 -+          if (delimlen == 1)
   4.754 -+            {
   4.755 -+              /* Check if we have utf8 multibyte locale, so we can use this
   4.756 -+                 optimization because of uniqueness of characters, which is
   4.757 -+                 not true for e.g. SJIS */
   4.758 -+              char * loc = setlocale(LC_CTYPE, NULL);
   4.759 -+              if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") ||
   4.760 -+                  strstr (loc, "UTF8") || strstr (loc, "utf8")))
   4.761 -+                {
   4.762 -+                  cut_fields (stream);
   4.763 -+                  break;
   4.764 -+                }
   4.765 -+            }
   4.766 -+          cut_fields_mb (stream);
   4.767 -+          break;
   4.768 -+
   4.769 -+        default:
   4.770 -+          abort ();
   4.771 -+        }
   4.772 -+    }
   4.773 -   else
   4.774 --    cut_fields (stream);
   4.775 -+#endif
   4.776 -+    {
   4.777 -+      if (operating_mode == field_mode)
   4.778 -+        cut_fields (stream);
   4.779 -+      else
   4.780 -+        cut_bytes (stream);
   4.781 -+    }
   4.782 - }
   4.783 - 
   4.784 - /* Process file FILE to standard output.
   4.785 -@@ -483,6 +836,7 @@ main (int argc, char **argv)
   4.786 -   bool ok;
   4.787 -   bool delim_specified = false;
   4.788 -   char *spec_list_string IF_LINT ( = NULL);
   4.789 -+  char mbdelim[MB_LEN_MAX + 1];
   4.790 - 
   4.791 -   initialize_main (&argc, &argv);
   4.792 -   set_program_name (argv[0]);
   4.793 -@@ -505,7 +859,6 @@ main (int argc, char **argv)
   4.794 -       switch (optc)
   4.795 -         {
   4.796 -         case 'b':
   4.797 --        case 'c':
   4.798 -           /* Build the byte list. */
   4.799 -           if (operating_mode != undefined_mode)
   4.800 -             FATAL_ERROR (_("only one type of list may be specified"));
   4.801 -@@ -513,6 +866,14 @@ main (int argc, char **argv)
   4.802 -           spec_list_string = optarg;
   4.803 -           break;
   4.804 - 
   4.805 -+        case 'c':
   4.806 -+          /* Build the character list. */
   4.807 -+          if (operating_mode != undefined_mode)
   4.808 -+            FATAL_ERROR (_("only one type of list may be specified"));
   4.809 -+          operating_mode = character_mode;
   4.810 -+          spec_list_string = optarg;
   4.811 -+          break;
   4.812 -+
   4.813 -         case 'f':
   4.814 -           /* Build the field list. */
   4.815 -           if (operating_mode != undefined_mode)
   4.816 -@@ -524,10 +885,38 @@ main (int argc, char **argv)
   4.817 -         case 'd':
   4.818 -           /* New delimiter. */
   4.819 -           /* Interpret -d '' to mean 'use the NUL byte as the delimiter.'  */
   4.820 --          if (optarg[0] != '\0' && optarg[1] != '\0')
   4.821 --            FATAL_ERROR (_("the delimiter must be a single character"));
   4.822 --          delim = optarg[0];
   4.823 --          delim_specified = true;
   4.824 -+            {
   4.825 -+#if HAVE_MBRTOWC
   4.826 -+              if(MB_CUR_MAX > 1)
   4.827 -+                {
   4.828 -+                  mbstate_t state;
   4.829 -+
   4.830 -+                  memset (&state, '\0', sizeof(mbstate_t));
   4.831 -+                  delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
   4.832 -+
   4.833 -+                  if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
   4.834 -+                    ++force_singlebyte_mode;
   4.835 -+                  else
   4.836 -+                    {
   4.837 -+                      delimlen = (delimlen < 1) ? 1 : delimlen;
   4.838 -+                      if (wcdelim != L'\0' && *(optarg + delimlen) != '\0')
   4.839 -+                        FATAL_ERROR (_("the delimiter must be a single character"));
   4.840 -+                      memcpy (mbdelim, optarg, delimlen);
   4.841 -+                      mbdelim[delimlen] = '\0';
   4.842 -+                      if (delimlen == 1)
   4.843 -+                        delim = *optarg;
   4.844 -+                    }
   4.845 -+                }
   4.846 -+
   4.847 -+              if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
   4.848 -+#endif
   4.849 -+                {
   4.850 -+                  if (optarg[0] != '\0' && optarg[1] != '\0')
   4.851 -+                    FATAL_ERROR (_("the delimiter must be a single character"));
   4.852 -+                  delim = (unsigned char) optarg[0];
   4.853 -+                }
   4.854 -+            delim_specified = true;
   4.855 -+          }
   4.856 -           break;
   4.857 - 
   4.858 -         case OUTPUT_DELIMITER_OPTION:
   4.859 -@@ -540,6 +929,7 @@ main (int argc, char **argv)
   4.860 -           break;
   4.861 - 
   4.862 -         case 'n':
   4.863 -+          byte_mode_character_aware = 1;
   4.864 -           break;
   4.865 - 
   4.866 -         case 's':
   4.867 -@@ -579,15 +969,34 @@ main (int argc, char **argv)
   4.868 -               | (complement ? SETFLD_COMPLEMENT : 0) );
   4.869 - 
   4.870 -   if (!delim_specified)
   4.871 --    delim = '\t';
   4.872 -+    {
   4.873 -+      delim = '\t';
   4.874 -+#ifdef HAVE_MBRTOWC
   4.875 -+      wcdelim = L'\t';
   4.876 -+      mbdelim[0] = '\t';
   4.877 -+      mbdelim[1] = '\0';
   4.878 -+      delimlen = 1;
   4.879 -+#endif
   4.880 -+    }
   4.881 - 
   4.882 -   if (output_delimiter_string == NULL)
   4.883 -     {
   4.884 --      static char dummy[2];
   4.885 --      dummy[0] = delim;
   4.886 --      dummy[1] = '\0';
   4.887 --      output_delimiter_string = dummy;
   4.888 --      output_delimiter_length = 1;
   4.889 -+#ifdef HAVE_MBRTOWC
   4.890 -+      if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
   4.891 -+        {
   4.892 -+          output_delimiter_string = xstrdup(mbdelim);
   4.893 -+          output_delimiter_length = delimlen;
   4.894 -+        }
   4.895 -+
   4.896 -+      if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
   4.897 -+#endif
   4.898 -+        {
   4.899 -+          static char dummy[2];
   4.900 -+          dummy[0] = delim;
   4.901 -+          dummy[1] = '\0';
   4.902 -+          output_delimiter_string = dummy;
   4.903 -+          output_delimiter_length = 1;
   4.904 -+        }
   4.905 -     }
   4.906 - 
   4.907 -   if (optind == argc)
   4.908 -diff -Naurp coreutils-8.27-orig/src/expand.c coreutils-8.27/src/expand.c
   4.909 ---- coreutils-8.27-orig/src/expand.c	2017-02-26 15:42:25.000000000 -0600
   4.910 -+++ coreutils-8.27/src/expand.c	2017-03-11 23:49:06.758133530 -0600
   4.911 -@@ -37,6 +37,9 @@
   4.912 - #include <stdio.h>
   4.913 - #include <getopt.h>
   4.914 - #include <sys/types.h>
   4.915 -+
   4.916 -+#include <mbfile.h>
   4.917 -+
   4.918 - #include "system.h"
   4.919 - #include "die.h"
   4.920 - #include "xstrndup.h"
   4.921 -@@ -100,19 +103,41 @@ expand (void)
   4.922 - {
   4.923 -   /* Input stream.  */
   4.924 -   FILE *fp = next_file (NULL);
   4.925 -+  mb_file_t mbf;
   4.926 -+  mbf_char_t c;
   4.927 -+  /* True if the starting locale is utf8.  */
   4.928 -+  bool using_utf_locale;
   4.929 -+
   4.930 -+  /* True if the first file contains BOM header.  */
   4.931 -+  bool found_bom;
   4.932 -+  using_utf_locale=check_utf_locale();
   4.933 - 
   4.934 -   if (!fp)
   4.935 -     return;
   4.936 -+  mbf_init (mbf, fp);
   4.937 -+  found_bom=check_bom(fp,&mbf);
   4.938 - 
   4.939 --  while (true)
   4.940 -+  if (using_utf_locale == false && found_bom == true)
   4.941 -+  {
   4.942 -+    /*try using some predefined locale */
   4.943 -+
   4.944 -+    if (set_utf_locale () != 0)
   4.945 -     {
   4.946 --      /* Input character, or EOF.  */
   4.947 --      int c;
   4.948 -+      error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
   4.949 -+    }
   4.950 -+  }
   4.951 -+
   4.952 - 
   4.953 -+  if (found_bom == true)
   4.954 -+  {
   4.955 -+    print_bom();
   4.956 -+  }
   4.957 -+
   4.958 -+  while (true)
   4.959 -+    {
   4.960 -       /* If true, perform translations.  */
   4.961 -       bool convert = true;
   4.962 - 
   4.963 --
   4.964 -       /* The following variables have valid values only when CONVERT
   4.965 -          is true:  */
   4.966 - 
   4.967 -@@ -122,17 +147,48 @@ expand (void)
   4.968 -       /* Index in TAB_LIST of next tab stop to examine.  */
   4.969 -       size_t tab_index = 0;
   4.970 - 
   4.971 --
   4.972 -       /* Convert a line of text.  */
   4.973 - 
   4.974 -       do
   4.975 -         {
   4.976 --          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
   4.977 --            continue;
   4.978 -+          while (true) {
   4.979 -+            mbf_getc (c, mbf);
   4.980 -+            if ((mb_iseof (c)) && (fp = next_file (fp)))
   4.981 -+              {
   4.982 -+                mbf_init (mbf, fp);
   4.983 -+                if (fp!=NULL)
   4.984 -+                {
   4.985 -+                  if (check_bom(fp,&mbf)==true)
   4.986 -+                  {
   4.987 -+                    /*Not the first file - check BOM header*/
   4.988 -+                    if (using_utf_locale==false && found_bom==false)
   4.989 -+                    {
   4.990 -+                      /*BOM header in subsequent file but not in the first one. */
   4.991 -+                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
   4.992 -+                    }
   4.993 -+                  }
   4.994 -+                  else
   4.995 -+                  {
   4.996 -+                    if(using_utf_locale==false && found_bom==true)
   4.997 -+                    {
   4.998 -+                      /*First file conatined BOM header - locale was switched to UTF
   4.999 -+                      /*all subsequent files should contain BOM. */
  4.1000 -+                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
  4.1001 -+                    }
  4.1002 -+                  }
  4.1003 -+                }
  4.1004 -+                continue;
  4.1005 -+              }
  4.1006 -+            else
  4.1007 -+              {
  4.1008 -+                break;
  4.1009 -+              }
  4.1010 -+            }
  4.1011 -+
  4.1012 - 
  4.1013 -           if (convert)
  4.1014 -             {
  4.1015 --              if (c == '\t')
  4.1016 -+              if (mb_iseq (c, '\t'))
  4.1017 -                 {
  4.1018 -                   /* Column the next input tab stop is on.  */
  4.1019 -                   uintmax_t next_tab_column;
  4.1020 -@@ -151,32 +207,34 @@ expand (void)
  4.1021 -                     if (putchar (' ') < 0)
  4.1022 -                       die (EXIT_FAILURE, errno, _("write error"));
  4.1023 - 
  4.1024 --                  c = ' ';
  4.1025 -+                  mb_setascii (&c, ' ');
  4.1026 -                 }
  4.1027 --              else if (c == '\b')
  4.1028 -+              else if (mb_iseq (c, '\b'))
  4.1029 -                 {
  4.1030 -                   /* Go back one column, and force recalculation of the
  4.1031 -                      next tab stop.  */
  4.1032 -                   column -= !!column;
  4.1033 -                   tab_index -= !!tab_index;
  4.1034 -                 }
  4.1035 --              else
  4.1036 -+              /* A leading control character could make us trip over.  */
  4.1037 -+              else if (!mb_iscntrl (c))
  4.1038 -                 {
  4.1039 --                  column++;
  4.1040 -+                  column += mb_width (c);
  4.1041 -                   if (!column)
  4.1042 -                     die (EXIT_FAILURE, 0, _("input line is too long"));
  4.1043 -                 }
  4.1044 - 
  4.1045 --              convert &= convert_entire_line || !! isblank (c);
  4.1046 -+              convert &= convert_entire_line || mb_isblank (c);
  4.1047 -             }
  4.1048 - 
  4.1049 --          if (c < 0)
  4.1050 -+          if (mb_iseof (c))
  4.1051 -             return;
  4.1052 - 
  4.1053 --          if (putchar (c) < 0)
  4.1054 -+          mb_putc (c, stdout);
  4.1055 -+          if (ferror (stdout))
  4.1056 -             die (EXIT_FAILURE, errno, _("write error"));
  4.1057 -         }
  4.1058 --      while (c != '\n');
  4.1059 -+      while (!mb_iseq (c, '\n'));
  4.1060 -     }
  4.1061 - }
  4.1062 - 
  4.1063 -diff -Naurp coreutils-8.27-orig/src/expand-common.c coreutils-8.27/src/expand-common.c
  4.1064 ---- coreutils-8.27-orig/src/expand-common.c	2017-03-01 11:22:55.000000000 -0600
  4.1065 -+++ coreutils-8.27/src/expand-common.c	2017-03-11 23:49:06.757133570 -0600
  4.1066 -@@ -18,6 +18,7 @@
  4.1067 - 
  4.1068 - #include <stdio.h>
  4.1069 - #include <sys/types.h>
  4.1070 -+#include <mbfile.h>
  4.1071 - #include "system.h"
  4.1072 - #include "die.h"
  4.1073 - #include "error.h"
  4.1074 -@@ -105,6 +106,119 @@ set_extend_size (uintmax_t tabval)
  4.1075 -   return ok;
  4.1076 - }
  4.1077 - 
  4.1078 -+extern int
  4.1079 -+set_utf_locale (void)
  4.1080 -+{
  4.1081 -+      /*try using some predefined locale */
  4.1082 -+      const char* predef_locales[] = {"C.UTF8","en_US.UTF8","en_GB.UTF8"};
  4.1083 -+
  4.1084 -+      const int predef_locales_count=3;
  4.1085 -+      for (int i=0;i<predef_locales_count;i++)
  4.1086 -+        {
  4.1087 -+          if (setlocale(LC_ALL,predef_locales[i])!=NULL)
  4.1088 -+          {
  4.1089 -+            break;
  4.1090 -+          }
  4.1091 -+          else if (i==predef_locales_count-1)
  4.1092 -+          {
  4.1093 -+            return 1;
  4.1094 -+            error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
  4.1095 -+          }
  4.1096 -+        }
  4.1097 -+        return 0;
  4.1098 -+}
  4.1099 -+
  4.1100 -+extern bool
  4.1101 -+check_utf_locale(void)
  4.1102 -+{
  4.1103 -+  char* locale = setlocale (LC_CTYPE , NULL);
  4.1104 -+  if (locale == NULL)
  4.1105 -+  {
  4.1106 -+    return false;
  4.1107 -+  }
  4.1108 -+  else if (strcasestr(locale, "utf8") == NULL && strcasestr(locale, "utf-8") == NULL)
  4.1109 -+  {
  4.1110 -+    return false;
  4.1111 -+  }
  4.1112 -+  return true;
  4.1113 -+}
  4.1114 -+
  4.1115 -+extern bool
  4.1116 -+check_bom(FILE* fp, mb_file_t *mbf)
  4.1117 -+{
  4.1118 -+  int c;
  4.1119 -+
  4.1120 -+
  4.1121 -+  c=fgetc(fp);
  4.1122 -+
  4.1123 -+  /*test BOM header of the first file */
  4.1124 -+  mbf->bufcount=0;
  4.1125 -+  if (c == 0xEF)
  4.1126 -+  {
  4.1127 -+    c=fgetc(fp);
  4.1128 -+  }
  4.1129 -+  else
  4.1130 -+  {
  4.1131 -+    if (c != EOF)
  4.1132 -+    {
  4.1133 -+      ungetc(c,fp);
  4.1134 -+    }
  4.1135 -+    return false;
  4.1136 -+  }
  4.1137 -+
  4.1138 -+  if (c == 0xBB)
  4.1139 -+  {
  4.1140 -+    c=fgetc(fp);
  4.1141 -+  }
  4.1142 -+  else
  4.1143 -+  {
  4.1144 -+    if ( c!= EOF )
  4.1145 -+    {
  4.1146 -+      mbf->buf[0]=(unsigned char) 0xEF;
  4.1147 -+      mbf->bufcount=1;
  4.1148 -+      ungetc(c,fp);
  4.1149 -+      return false;
  4.1150 -+    }
  4.1151 -+    else
  4.1152 -+    {
  4.1153 -+      ungetc(0xEF,fp);
  4.1154 -+      return false;
  4.1155 -+    }
  4.1156 -+  }
  4.1157 -+  if (c == 0xBF)
  4.1158 -+  {
  4.1159 -+    mbf->bufcount=0;
  4.1160 -+    return true;
  4.1161 -+  }
  4.1162 -+  else
  4.1163 -+  {
  4.1164 -+    if (c != EOF)
  4.1165 -+    {
  4.1166 -+      mbf->buf[0]=(unsigned char) 0xEF;
  4.1167 -+      mbf->buf[1]=(unsigned char) 0xBB;
  4.1168 -+      mbf->bufcount=2;
  4.1169 -+      ungetc(c,fp);
  4.1170 -+      return false;
  4.1171 -+    }
  4.1172 -+    else
  4.1173 -+    {
  4.1174 -+      mbf->buf[0]=(unsigned char) 0xEF;
  4.1175 -+      mbf->bufcount=1;
  4.1176 -+      ungetc(0xBB,fp);
  4.1177 -+      return false;
  4.1178 -+    }
  4.1179 -+  }
  4.1180 -+  return false;
  4.1181 -+}
  4.1182 -+
  4.1183 -+extern void
  4.1184 -+print_bom(void)
  4.1185 -+{
  4.1186 -+  putc (0xEF, stdout);
  4.1187 -+  putc (0xBB, stdout);
  4.1188 -+  putc (0xBF, stdout);
  4.1189 -+}
  4.1190 -+
  4.1191 - /* Add the comma or blank separated list of tab stops STOPS
  4.1192 -    to the list of tab stops.  */
  4.1193 - extern void
  4.1194 -diff -Naurp coreutils-8.27-orig/src/expand-common.h coreutils-8.27/src/expand-common.h
  4.1195 ---- coreutils-8.27-orig/src/expand-common.h	2017-01-01 16:34:24.000000000 -0600
  4.1196 -+++ coreutils-8.27/src/expand-common.h	2017-03-11 23:49:06.758133530 -0600
  4.1197 -@@ -34,6 +34,18 @@ extern size_t max_column_width;
  4.1198 - /* The desired exit status.  */
  4.1199 - extern int exit_status;
  4.1200 - 
  4.1201 -+extern int
  4.1202 -+set_utf_locale (void);
  4.1203 -+
  4.1204 -+extern bool
  4.1205 -+check_utf_locale(void);
  4.1206 -+
  4.1207 -+extern bool
  4.1208 -+check_bom(FILE* fp, mb_file_t *mbf);
  4.1209 -+
  4.1210 -+extern void
  4.1211 -+print_bom(void);
  4.1212 -+
  4.1213 - /* Add tab stop TABVAL to the end of 'tab_list'.  */
  4.1214 - extern void
  4.1215 - add_tab_stop (uintmax_t tabval);
  4.1216 -diff -Naurp coreutils-8.27-orig/src/fold.c coreutils-8.27/src/fold.c
  4.1217 ---- coreutils-8.27-orig/src/fold.c	2017-01-01 16:34:24.000000000 -0600
  4.1218 -+++ coreutils-8.27/src/fold.c	2017-03-11 23:49:30.982169404 -0600
  4.1219 -@@ -22,12 +22,34 @@
  4.1220 - #include <getopt.h>
  4.1221 - #include <sys/types.h>
  4.1222 - 
  4.1223 -+/* Get mbstate_t, mbrtowc(), wcwidth().  */
  4.1224 -+#if HAVE_WCHAR_H
  4.1225 -+# include <wchar.h>
  4.1226 -+#endif
  4.1227 -+
  4.1228 -+/* Get iswprint(), iswblank(), wcwidth().  */
  4.1229 -+#if HAVE_WCTYPE_H
  4.1230 -+# include <wctype.h>
  4.1231 -+#endif
  4.1232 -+
  4.1233 - #include "system.h"
  4.1234 - #include "die.h"
  4.1235 - #include "error.h"
  4.1236 - #include "fadvise.h"
  4.1237 - #include "xdectoint.h"
  4.1238 - 
  4.1239 -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
  4.1240 -+      installation; work around this configuration error.  */
  4.1241 -+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
  4.1242 -+# undef MB_LEN_MAX
  4.1243 -+# define MB_LEN_MAX 16
  4.1244 -+#endif
  4.1245 -+
  4.1246 -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  4.1247 -+#if HAVE_MBRTOWC && defined mbstate_t
  4.1248 -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  4.1249 -+#endif
  4.1250 -+
  4.1251 - #define TAB_WIDTH 8
  4.1252 - 
  4.1253 - /* The official name of this program (e.g., no 'g' prefix).  */
  4.1254 -@@ -35,20 +57,41 @@
  4.1255 - 
  4.1256 - #define AUTHORS proper_name ("David MacKenzie")
  4.1257 - 
  4.1258 -+#define FATAL_ERROR(Message)                                            \
  4.1259 -+  do                                                                    \
  4.1260 -+    {                                                                   \
  4.1261 -+      error (0, 0, (Message));                                          \
  4.1262 -+      usage (2);                                                        \
  4.1263 -+    }                                                                   \
  4.1264 -+  while (0)
  4.1265 -+
  4.1266 -+enum operating_mode
  4.1267 -+{
  4.1268 -+  /* Fold texts by columns that are at the given positions. */
  4.1269 -+  column_mode,
  4.1270 -+
  4.1271 -+  /* Fold texts by bytes that are at the given positions. */
  4.1272 -+  byte_mode,
  4.1273 -+
  4.1274 -+  /* Fold texts by characters that are at the given positions. */
  4.1275 -+  character_mode,
  4.1276 -+};
  4.1277 -+
  4.1278 -+/* The argument shows current mode. (Default: column_mode) */
  4.1279 -+static enum operating_mode operating_mode;
  4.1280 -+
  4.1281 - /* If nonzero, try to break on whitespace. */
  4.1282 - static bool break_spaces;
  4.1283 - 
  4.1284 --/* If nonzero, count bytes, not column positions. */
  4.1285 --static bool count_bytes;
  4.1286 --
  4.1287 - /* If nonzero, at least one of the files we read was standard input. */
  4.1288 - static bool have_read_stdin;
  4.1289 - 
  4.1290 --static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::";
  4.1291 -+static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::";
  4.1292 - 
  4.1293 - static struct option const longopts[] =
  4.1294 - {
  4.1295 -   {"bytes", no_argument, NULL, 'b'},
  4.1296 -+  {"characters", no_argument, NULL, 'c'},
  4.1297 -   {"spaces", no_argument, NULL, 's'},
  4.1298 -   {"width", required_argument, NULL, 'w'},
  4.1299 -   {GETOPT_HELP_OPTION_DECL},
  4.1300 -@@ -76,6 +119,7 @@ Wrap input lines in each FILE, writing t
  4.1301 - 
  4.1302 -       fputs (_("\
  4.1303 -   -b, --bytes         count bytes rather than columns\n\
  4.1304 -+  -c, --characters    count characters rather than columns\n\
  4.1305 -   -s, --spaces        break at spaces\n\
  4.1306 -   -w, --width=WIDTH   use WIDTH columns instead of 80\n\
  4.1307 - "), stdout);
  4.1308 -@@ -93,7 +137,7 @@ Wrap input lines in each FILE, writing t
  4.1309 - static size_t
  4.1310 - adjust_column (size_t column, char c)
  4.1311 - {
  4.1312 --  if (!count_bytes)
  4.1313 -+  if (operating_mode != byte_mode)
  4.1314 -     {
  4.1315 -       if (c == '\b')
  4.1316 -         {
  4.1317 -@@ -116,30 +160,14 @@ adjust_column (size_t column, char c)
  4.1318 -    to stdout, with maximum line length WIDTH.
  4.1319 -    Return true if successful.  */
  4.1320 - 
  4.1321 --static bool
  4.1322 --fold_file (char const *filename, size_t width)
  4.1323 -+static void
  4.1324 -+fold_text (FILE *istream, size_t width, int *saved_errno)
  4.1325 - {
  4.1326 --  FILE *istream;
  4.1327 -   int c;
  4.1328 -   size_t column = 0;		/* Screen column where next char will go. */
  4.1329 -   size_t offset_out = 0;	/* Index in 'line_out' for next char. */
  4.1330 -   static char *line_out = NULL;
  4.1331 -   static size_t allocated_out = 0;
  4.1332 --  int saved_errno;
  4.1333 --
  4.1334 --  if (STREQ (filename, "-"))
  4.1335 --    {
  4.1336 --      istream = stdin;
  4.1337 --      have_read_stdin = true;
  4.1338 --    }
  4.1339 --  else
  4.1340 --    istream = fopen (filename, "r");
  4.1341 --
  4.1342 --  if (istream == NULL)
  4.1343 --    {
  4.1344 --      error (0, errno, "%s", quotef (filename));
  4.1345 --      return false;
  4.1346 --    }
  4.1347 - 
  4.1348 -   fadvise (istream, FADVISE_SEQUENTIAL);
  4.1349 - 
  4.1350 -@@ -169,6 +197,15 @@ fold_file (char const *filename, size_t
  4.1351 -               bool found_blank = false;
  4.1352 -               size_t logical_end = offset_out;
  4.1353 - 
  4.1354 -+              /* If LINE_OUT has no wide character,
  4.1355 -+                 put a new wide character in LINE_OUT
  4.1356 -+                 if column is bigger than width. */
  4.1357 -+              if (offset_out == 0)
  4.1358 -+                {
  4.1359 -+                  line_out[offset_out++] = c;
  4.1360 -+                  continue;
  4.1361 -+                }
  4.1362 -+
  4.1363 -               /* Look for the last blank. */
  4.1364 -               while (logical_end)
  4.1365 -                 {
  4.1366 -@@ -215,11 +252,220 @@ fold_file (char const *filename, size_t
  4.1367 -       line_out[offset_out++] = c;
  4.1368 -     }
  4.1369 - 
  4.1370 --  saved_errno = errno;
  4.1371 -+  *saved_errno = errno;
  4.1372 -+
  4.1373 -+  if (offset_out)
  4.1374 -+    fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
  4.1375 -+
  4.1376 -+}
  4.1377 -+
  4.1378 -+#if HAVE_MBRTOWC
  4.1379 -+static void
  4.1380 -+fold_multibyte_text (FILE *istream, size_t width, int *saved_errno)
  4.1381 -+{
  4.1382 -+  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
  4.1383 -+  size_t buflen = 0;        /* The length of the byte sequence in buf. */
  4.1384 -+  char *bufpos = buf;         /* Next read position of BUF. */
  4.1385 -+  wint_t wc;                /* A gotten wide character. */
  4.1386 -+  size_t mblength;        /* The byte size of a multibyte character which shows
  4.1387 -+                           as same character as WC. */
  4.1388 -+  mbstate_t state, state_bak;        /* State of the stream. */
  4.1389 -+  int convfail = 0;                /* 1, when conversion is failed. Otherwise 0. */
  4.1390 -+
  4.1391 -+  static char *line_out = NULL;
  4.1392 -+  size_t offset_out = 0;        /* Index in `line_out' for next char. */
  4.1393 -+  static size_t allocated_out = 0;
  4.1394 -+
  4.1395 -+  int increment;
  4.1396 -+  size_t column = 0;
  4.1397 -+
  4.1398 -+  size_t last_blank_pos;
  4.1399 -+  size_t last_blank_column;
  4.1400 -+  int is_blank_seen;
  4.1401 -+  int last_blank_increment = 0;
  4.1402 -+  int is_bs_following_last_blank;
  4.1403 -+  size_t bs_following_last_blank_num;
  4.1404 -+  int is_cr_after_last_blank;
  4.1405 -+
  4.1406 -+#define CLEAR_FLAGS                                \
  4.1407 -+   do                                                \
  4.1408 -+     {                                                \
  4.1409 -+        last_blank_pos = 0;                        \
  4.1410 -+        last_blank_column = 0;                        \
  4.1411 -+        is_blank_seen = 0;                        \
  4.1412 -+        is_bs_following_last_blank = 0;                \
  4.1413 -+        bs_following_last_blank_num = 0;        \
  4.1414 -+        is_cr_after_last_blank = 0;                \
  4.1415 -+     }                                                \
  4.1416 -+   while (0)
  4.1417 -+
  4.1418 -+#define START_NEW_LINE                        \
  4.1419 -+   do                                        \
  4.1420 -+     {                                        \
  4.1421 -+      putchar ('\n');                        \
  4.1422 -+      column = 0;                        \
  4.1423 -+      offset_out = 0;                        \
  4.1424 -+      CLEAR_FLAGS;                        \
  4.1425 -+    }                                        \
  4.1426 -+   while (0)
  4.1427 -+
  4.1428 -+  CLEAR_FLAGS;
  4.1429 -+  memset (&state, '\0', sizeof(mbstate_t));
  4.1430 -+
  4.1431 -+  for (;; bufpos += mblength, buflen -= mblength)
  4.1432 -+    {
  4.1433 -+      if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream))
  4.1434 -+        {
  4.1435 -+          memmove (buf, bufpos, buflen);
  4.1436 -+          buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream);
  4.1437 -+          bufpos = buf;
  4.1438 -+        }
  4.1439 -+
  4.1440 -+      if (buflen < 1)
  4.1441 -+        break;
  4.1442 -+
  4.1443 -+      /* Get a wide character. */
  4.1444 -+      state_bak = state;
  4.1445 -+      mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state);
  4.1446 -+
  4.1447 -+      switch (mblength)
  4.1448 -+        {
  4.1449 -+        case (size_t)-1:
  4.1450 -+        case (size_t)-2:
  4.1451 -+          convfail++;
  4.1452 -+          state = state_bak;
  4.1453 -+          /* Fall through. */
  4.1454 -+
  4.1455 -+        case 0:
  4.1456 -+          mblength = 1;
  4.1457 -+          break;
  4.1458 -+        }
  4.1459 -+
  4.1460 -+rescan:
  4.1461 -+      if (convfail)
  4.1462 -+        increment = 1;
  4.1463 -+      else if (wc == L'\n')
  4.1464 -+        {
  4.1465 -+          /* preserve newline */
  4.1466 -+          fwrite (line_out, sizeof(char), offset_out, stdout);
  4.1467 -+          START_NEW_LINE;
  4.1468 -+          continue;
  4.1469 -+        }
  4.1470 -+      else if (operating_mode == byte_mode)                  /* byte mode */
  4.1471 -+        increment = mblength;
  4.1472 -+      else if (operating_mode == character_mode)        /* character mode */
  4.1473 -+        increment = 1;
  4.1474 -+      else                                                 /* column mode */
  4.1475 -+        {
  4.1476 -+          switch (wc)
  4.1477 -+            {
  4.1478 -+            case L'\b':
  4.1479 -+              increment = (column > 0) ? -1 : 0;
  4.1480 -+              break;
  4.1481 -+
  4.1482 -+            case L'\r':
  4.1483 -+              increment = -1 * column;
  4.1484 -+              break;
  4.1485 -+
  4.1486 -+            case L'\t':
  4.1487 -+              increment = 8 - column % 8;
  4.1488 -+              break;
  4.1489 -+
  4.1490 -+            default:
  4.1491 -+              increment = wcwidth (wc);
  4.1492 -+              increment = (increment < 0) ? 0 : increment;
  4.1493 -+            }
  4.1494 -+        }
  4.1495 -+
  4.1496 -+      if (column + increment > width && break_spaces && last_blank_pos)
  4.1497 -+        {
  4.1498 -+          fwrite (line_out, sizeof(char), last_blank_pos, stdout);
  4.1499 -+          putchar ('\n');
  4.1500 -+
  4.1501 -+          offset_out = offset_out - last_blank_pos;
  4.1502 -+          column = column - last_blank_column + ((is_cr_after_last_blank)
  4.1503 -+              ? last_blank_increment : bs_following_last_blank_num);
  4.1504 -+          memmove (line_out, line_out + last_blank_pos, offset_out);
  4.1505 -+          CLEAR_FLAGS;
  4.1506 -+          goto rescan;
  4.1507 -+        }
  4.1508 -+
  4.1509 -+      if (column + increment > width && column != 0)
  4.1510 -+        {
  4.1511 -+          fwrite (line_out, sizeof(char), offset_out, stdout);
  4.1512 -+          START_NEW_LINE;
  4.1513 -+          goto rescan;
  4.1514 -+        }
  4.1515 -+
  4.1516 -+      if (allocated_out < offset_out + mblength)
  4.1517 -+        {
  4.1518 -+          line_out = X2REALLOC (line_out, &allocated_out);
  4.1519 -+        }
  4.1520 -+
  4.1521 -+      memcpy (line_out + offset_out, bufpos, mblength);
  4.1522 -+      offset_out += mblength;
  4.1523 -+      column += increment;
  4.1524 -+
  4.1525 -+      if (is_blank_seen && !convfail && wc == L'\r')
  4.1526 -+        is_cr_after_last_blank = 1;
  4.1527 -+
  4.1528 -+      if (is_bs_following_last_blank && !convfail && wc == L'\b')
  4.1529 -+        ++bs_following_last_blank_num;
  4.1530 -+      else
  4.1531 -+        is_bs_following_last_blank = 0;
  4.1532 -+
  4.1533 -+      if (break_spaces && !convfail && iswblank (wc))
  4.1534 -+        {
  4.1535 -+          last_blank_pos = offset_out;
  4.1536 -+          last_blank_column = column;
  4.1537 -+          is_blank_seen = 1;
  4.1538 -+          last_blank_increment = increment;
  4.1539 -+          is_bs_following_last_blank = 1;
  4.1540 -+          bs_following_last_blank_num = 0;
  4.1541 -+          is_cr_after_last_blank = 0;
  4.1542 -+        }
  4.1543 -+    }
  4.1544 -+
  4.1545 -+  *saved_errno = errno;
  4.1546 - 
  4.1547 -   if (offset_out)
  4.1548 -     fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
  4.1549 - 
  4.1550 -+}
  4.1551 -+#endif
  4.1552 -+
  4.1553 -+/* Fold file FILENAME, or standard input if FILENAME is "-",
  4.1554 -+   to stdout, with maximum line length WIDTH.
  4.1555 -+   Return 0 if successful, 1 if an error occurs. */
  4.1556 -+
  4.1557 -+static bool
  4.1558 -+fold_file (char const *filename, size_t width)
  4.1559 -+{
  4.1560 -+  FILE *istream;
  4.1561 -+  int saved_errno;
  4.1562 -+
  4.1563 -+  if (STREQ (filename, "-"))
  4.1564 -+    {
  4.1565 -+      istream = stdin;
  4.1566 -+      have_read_stdin = 1;
  4.1567 -+    }
  4.1568 -+  else
  4.1569 -+    istream = fopen (filename, "r");
  4.1570 -+
  4.1571 -+  if (istream == NULL)
  4.1572 -+    {
  4.1573 -+      error (0, errno, "%s", filename);
  4.1574 -+      return 1;
  4.1575 -+    }
  4.1576 -+
  4.1577 -+  /* Define how ISTREAM is being folded. */
  4.1578 -+#if HAVE_MBRTOWC
  4.1579 -+  if (MB_CUR_MAX > 1)
  4.1580 -+    fold_multibyte_text (istream, width, &saved_errno);
  4.1581 -+  else
  4.1582 -+#endif
  4.1583 -+    fold_text (istream, width, &saved_errno);
  4.1584 -+
  4.1585 -   if (ferror (istream))
  4.1586 -     {
  4.1587 -       error (0, saved_errno, "%s", quotef (filename));
  4.1588 -@@ -252,7 +498,8 @@ main (int argc, char **argv)
  4.1589 - 
  4.1590 -   atexit (close_stdout);
  4.1591 - 
  4.1592 --  break_spaces = count_bytes = have_read_stdin = false;
  4.1593 -+  operating_mode = column_mode;
  4.1594 -+  break_spaces = have_read_stdin = false;
  4.1595 - 
  4.1596 -   while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
  4.1597 -     {
  4.1598 -@@ -261,7 +508,15 @@ main (int argc, char **argv)
  4.1599 -       switch (optc)
  4.1600 -         {
  4.1601 -         case 'b':		/* Count bytes rather than columns. */
  4.1602 --          count_bytes = true;
  4.1603 -+          if (operating_mode != column_mode)
  4.1604 -+            FATAL_ERROR (_("only one way of folding may be specified"));
  4.1605 -+          operating_mode = byte_mode;
  4.1606 -+          break;
  4.1607 -+
  4.1608 -+        case 'c':
  4.1609 -+          if (operating_mode != column_mode)
  4.1610 -+            FATAL_ERROR (_("only one way of folding may be specified"));
  4.1611 -+          operating_mode = character_mode;
  4.1612 -           break;
  4.1613 - 
  4.1614 -         case 's':		/* Break at word boundaries. */
  4.1615 -diff -Naurp coreutils-8.27-orig/src/join.c coreutils-8.27/src/join.c
  4.1616 ---- coreutils-8.27-orig/src/join.c	2017-01-01 16:34:24.000000000 -0600
  4.1617 -+++ coreutils-8.27/src/join.c	2017-03-11 23:47:13.091286290 -0600
  4.1618 -@@ -22,19 +22,33 @@
  4.1619 - #include <sys/types.h>
  4.1620 - #include <getopt.h>
  4.1621 - 
  4.1622 -+/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth().  */
  4.1623 -+#if HAVE_WCHAR_H
  4.1624 -+# include <wchar.h>
  4.1625 -+#endif
  4.1626 -+
  4.1627 -+/* Get iswblank(), towupper.  */
  4.1628 -+#if HAVE_WCTYPE_H
  4.1629 -+# include <wctype.h>
  4.1630 -+#endif
  4.1631 -+
  4.1632 - #include "system.h"
  4.1633 - #include "die.h"
  4.1634 - #include "error.h"
  4.1635 - #include "fadvise.h"
  4.1636 - #include "hard-locale.h"
  4.1637 - #include "linebuffer.h"
  4.1638 --#include "memcasecmp.h"
  4.1639 - #include "quote.h"
  4.1640 - #include "stdio--.h"
  4.1641 - #include "xmemcoll.h"
  4.1642 - #include "xstrtol.h"
  4.1643 - #include "argmatch.h"
  4.1644 - 
  4.1645 -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  4.1646 -+#if HAVE_MBRTOWC && defined mbstate_t
  4.1647 -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  4.1648 -+#endif
  4.1649 -+
  4.1650 - /* The official name of this program (e.g., no 'g' prefix).  */
  4.1651 - #define PROGRAM_NAME "join"
  4.1652 - 
  4.1653 -@@ -136,10 +150,12 @@ static struct outlist outlist_head;
  4.1654 - /* Last element in 'outlist', where a new element can be added.  */
  4.1655 - static struct outlist *outlist_end = &outlist_head;
  4.1656 - 
  4.1657 --/* Tab character separating fields.  If negative, fields are separated
  4.1658 --   by any nonempty string of blanks, otherwise by exactly one
  4.1659 --   tab character whose value (when cast to unsigned char) equals TAB.  */
  4.1660 --static int tab = -1;
  4.1661 -+/* Tab character separating fields.  If NULL, fields are separated
  4.1662 -+   by any nonempty string of blanks.  */
  4.1663 -+static char *tab = NULL;
  4.1664 -+
  4.1665 -+/* The number of bytes used for tab. */
  4.1666 -+static size_t tablen = 0;
  4.1667 - 
  4.1668 - /* If nonzero, check that the input is correctly ordered. */
  4.1669 - static enum
  4.1670 -@@ -276,13 +292,14 @@ xfields (struct line *line)
  4.1671 -   if (ptr == lim)
  4.1672 -     return;
  4.1673 - 
  4.1674 --  if (0 <= tab && tab != '\n')
  4.1675 -+  if (tab != NULL)
  4.1676 -     {
  4.1677 -+      unsigned char t = tab[0];
  4.1678 -       char *sep;
  4.1679 --      for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
  4.1680 -+      for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1)
  4.1681 -         extract_field (line, ptr, sep - ptr);
  4.1682 -     }
  4.1683 --  else if (tab < 0)
  4.1684 -+   else
  4.1685 -     {
  4.1686 -       /* Skip leading blanks before the first field.  */
  4.1687 -       while (field_sep (*ptr))
  4.1688 -@@ -306,6 +323,147 @@ xfields (struct line *line)
  4.1689 -   extract_field (line, ptr, lim - ptr);
  4.1690 - }
  4.1691 - 
  4.1692 -+#if HAVE_MBRTOWC
  4.1693 -+static void
  4.1694 -+xfields_multibyte (struct line *line)
  4.1695 -+{
  4.1696 -+  char *ptr = line->buf.buffer;
  4.1697 -+  char const *lim = ptr + line->buf.length - 1;
  4.1698 -+  wchar_t wc = 0;
  4.1699 -+  size_t mblength = 1;
  4.1700 -+  mbstate_t state, state_bak;
  4.1701 -+
  4.1702 -+  memset (&state, 0, sizeof (mbstate_t));
  4.1703 -+
  4.1704 -+  if (ptr >= lim)
  4.1705 -+    return;
  4.1706 -+
  4.1707 -+  if (tab != NULL)
  4.1708 -+    {
  4.1709 -+      char *sep = ptr;
  4.1710 -+      for (; ptr < lim; ptr = sep + mblength)
  4.1711 -+	{
  4.1712 -+	  sep = ptr;
  4.1713 -+	  while (sep < lim)
  4.1714 -+	    {
  4.1715 -+	      state_bak = state;
  4.1716 -+	      mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
  4.1717 -+
  4.1718 -+	      if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.1719 -+		{
  4.1720 -+		  mblength = 1;
  4.1721 -+		  state = state_bak;
  4.1722 -+		}
  4.1723 -+	      mblength = (mblength < 1) ? 1 : mblength;
  4.1724 -+
  4.1725 -+	      if (mblength == tablen && !memcmp (sep, tab, mblength))
  4.1726 -+		break;
  4.1727 -+	      else
  4.1728 -+		{
  4.1729 -+		  sep += mblength;
  4.1730 -+		  continue;
  4.1731 -+		}
  4.1732 -+	    }
  4.1733 -+
  4.1734 -+	  if (sep >= lim)
  4.1735 -+	    break;
  4.1736 -+
  4.1737 -+	  extract_field (line, ptr, sep - ptr);
  4.1738 -+	}
  4.1739 -+    }
  4.1740 -+  else
  4.1741 -+    {
  4.1742 -+      /* Skip leading blanks before the first field.  */
  4.1743 -+      while(ptr < lim)
  4.1744 -+      {
  4.1745 -+        state_bak = state;
  4.1746 -+        mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
  4.1747 -+
  4.1748 -+        if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.1749 -+          {
  4.1750 -+            mblength = 1;
  4.1751 -+            state = state_bak;
  4.1752 -+            break;
  4.1753 -+          }
  4.1754 -+        mblength = (mblength < 1) ? 1 : mblength;
  4.1755 -+
  4.1756 -+        if (!iswblank(wc) && wc != '\n')
  4.1757 -+          break;
  4.1758 -+        ptr += mblength;
  4.1759 -+      }
  4.1760 -+
  4.1761 -+      do
  4.1762 -+	{
  4.1763 -+	  char *sep;
  4.1764 -+	  state_bak = state;
  4.1765 -+	  mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
  4.1766 -+	  if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.1767 -+	    {
  4.1768 -+	      mblength = 1;
  4.1769 -+	      state = state_bak;
  4.1770 -+	      break;
  4.1771 -+	    }
  4.1772 -+	  mblength = (mblength < 1) ? 1 : mblength;
  4.1773 -+
  4.1774 -+	  sep = ptr + mblength;
  4.1775 -+	  while (sep < lim)
  4.1776 -+	    {
  4.1777 -+	      state_bak = state;
  4.1778 -+	      mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
  4.1779 -+	      if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.1780 -+		{
  4.1781 -+		  mblength = 1;
  4.1782 -+		  state = state_bak;
  4.1783 -+		  break;
  4.1784 -+		}
  4.1785 -+	      mblength = (mblength < 1) ? 1 : mblength;
  4.1786 -+
  4.1787 -+	      if (iswblank (wc) || wc == '\n')
  4.1788 -+		break;
  4.1789 -+
  4.1790 -+	      sep += mblength;
  4.1791 -+	    }
  4.1792 -+
  4.1793 -+	  extract_field (line, ptr, sep - ptr);
  4.1794 -+	  if (sep >= lim)
  4.1795 -+	    return;
  4.1796 -+
  4.1797 -+	  state_bak = state;
  4.1798 -+	  mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
  4.1799 -+	  if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.1800 -+	    {
  4.1801 -+	      mblength = 1;
  4.1802 -+	      state = state_bak;
  4.1803 -+	      break;
  4.1804 -+	    }
  4.1805 -+	  mblength = (mblength < 1) ? 1 : mblength;
  4.1806 -+
  4.1807 -+	  ptr = sep + mblength;
  4.1808 -+	  while (ptr < lim)
  4.1809 -+	    {
  4.1810 -+	      state_bak = state;
  4.1811 -+	      mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
  4.1812 -+	      if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.1813 -+		{
  4.1814 -+		  mblength = 1;
  4.1815 -+		  state = state_bak;
  4.1816 -+		  break;
  4.1817 -+		}
  4.1818 -+	      mblength = (mblength < 1) ? 1 : mblength;
  4.1819 -+
  4.1820 -+	      if (!iswblank (wc) && wc != '\n')
  4.1821 -+		break;
  4.1822 -+
  4.1823 -+	      ptr += mblength;
  4.1824 -+	    }
  4.1825 -+	}
  4.1826 -+      while (ptr < lim);
  4.1827 -+    }
  4.1828 -+
  4.1829 -+  extract_field (line, ptr, lim - ptr);
  4.1830 -+}
  4.1831 -+#endif
  4.1832 -+
  4.1833 - static void
  4.1834 - freeline (struct line *line)
  4.1835 - {
  4.1836 -@@ -327,56 +485,133 @@ keycmp (struct line const *line1, struct
  4.1837 -         size_t jf_1, size_t jf_2)
  4.1838 - {
  4.1839 -   /* Start of field to compare in each file.  */
  4.1840 --  char *beg1;
  4.1841 --  char *beg2;
  4.1842 --
  4.1843 --  size_t len1;
  4.1844 --  size_t len2;		/* Length of fields to compare.  */
  4.1845 -+  char *beg[2];
  4.1846 -+  char *copy[2];
  4.1847 -+  size_t len[2]; 	/* Length of fields to compare.  */
  4.1848 -   int diff;
  4.1849 -+  int i, j;
  4.1850 -+  int mallocd = 0;
  4.1851 - 
  4.1852 -   if (jf_1 < line1->nfields)
  4.1853 -     {
  4.1854 --      beg1 = line1->fields[jf_1].beg;
  4.1855 --      len1 = line1->fields[jf_1].len;
  4.1856 -+      beg[0] = line1->fields[jf_1].beg;
  4.1857 -+      len[0] = line1->fields[jf_1].len;
  4.1858 -     }
  4.1859 -   else
  4.1860 -     {
  4.1861 --      beg1 = NULL;
  4.1862 --      len1 = 0;
  4.1863 -+      beg[0] = NULL;
  4.1864 -+      len[0] = 0;
  4.1865 -     }
  4.1866 - 
  4.1867 -   if (jf_2 < line2->nfields)
  4.1868 -     {
  4.1869 --      beg2 = line2->fields[jf_2].beg;
  4.1870 --      len2 = line2->fields[jf_2].len;
  4.1871 -+      beg[1] = line2->fields[jf_2].beg;
  4.1872 -+      len[1] = line2->fields[jf_2].len;
  4.1873 -     }
  4.1874 -   else
  4.1875 -     {
  4.1876 --      beg2 = NULL;
  4.1877 --      len2 = 0;
  4.1878 -+      beg[1] = NULL;
  4.1879 -+      len[1] = 0;
  4.1880 -     }
  4.1881 - 
  4.1882 --  if (len1 == 0)
  4.1883 --    return len2 == 0 ? 0 : -1;
  4.1884 --  if (len2 == 0)
  4.1885 -+  if (len[0] == 0)
  4.1886 -+    return len[1] == 0 ? 0 : -1;
  4.1887 -+  if (len[1] == 0)
  4.1888 -     return 1;
  4.1889 - 
  4.1890 -   if (ignore_case)
  4.1891 -     {
  4.1892 --      /* FIXME: ignore_case does not work with NLS (in particular,
  4.1893 --         with multibyte chars).  */
  4.1894 --      diff = memcasecmp (beg1, beg2, MIN (len1, len2));
  4.1895 -+#ifdef HAVE_MBRTOWC
  4.1896 -+      if (MB_CUR_MAX > 1)
  4.1897 -+      {
  4.1898 -+        size_t mblength;
  4.1899 -+        wchar_t wc, uwc;
  4.1900 -+        mbstate_t state, state_bak;
  4.1901 -+
  4.1902 -+        memset (&state, '\0', sizeof (mbstate_t));
  4.1903 -+
  4.1904 -+        for (i = 0; i < 2; i++)
  4.1905 -+          {
  4.1906 -+            mallocd = 1;
  4.1907 -+            copy[i] = xmalloc (len[i] + 1);
  4.1908 -+            memset (copy[i], '\0',len[i] + 1);
  4.1909 -+
  4.1910 -+            for (j = 0; j < MIN (len[0], len[1]);)
  4.1911 -+              {
  4.1912 -+                state_bak = state;
  4.1913 -+                mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state);
  4.1914 -+
  4.1915 -+                switch (mblength)
  4.1916 -+                  {
  4.1917 -+                  case (size_t) -1:
  4.1918 -+                  case (size_t) -2:
  4.1919 -+                    state = state_bak;
  4.1920 -+                    /* Fall through */
  4.1921 -+                  case 0:
  4.1922 -+                    mblength = 1;
  4.1923 -+                    break;
  4.1924 -+
  4.1925 -+                  default:
  4.1926 -+                    uwc = towupper (wc);
  4.1927 -+
  4.1928 -+                    if (uwc != wc)
  4.1929 -+                      {
  4.1930 -+                        mbstate_t state_wc;
  4.1931 -+                        size_t mblen;
  4.1932 -+
  4.1933 -+                        memset (&state_wc, '\0', sizeof (mbstate_t));
  4.1934 -+                        mblen = wcrtomb (copy[i] + j, uwc, &state_wc);
  4.1935 -+                        assert (mblen != (size_t)-1);
  4.1936 -+                      }
  4.1937 -+                    else
  4.1938 -+                      memcpy (copy[i] + j, beg[i] + j, mblength);
  4.1939 -+                  }
  4.1940 -+                j += mblength;
  4.1941 -+              }
  4.1942 -+            copy[i][j] = '\0';
  4.1943 -+          }
  4.1944 -+      }
  4.1945 -+      else
  4.1946 -+#endif
  4.1947 -+      {
  4.1948 -+        for (i = 0; i < 2; i++)
  4.1949 -+          {
  4.1950 -+            mallocd = 1;
  4.1951 -+            copy[i] = xmalloc (len[i] + 1);
  4.1952 -+
  4.1953 -+            for (j = 0; j < MIN (len[0], len[1]); j++)
  4.1954 -+              copy[i][j] = toupper (beg[i][j]);
  4.1955 -+
  4.1956 -+            copy[i][j] = '\0';
  4.1957 -+          }
  4.1958 -+      }
  4.1959 -     }
  4.1960 -   else
  4.1961 -     {
  4.1962 --      if (hard_LC_COLLATE)
  4.1963 --        return xmemcoll (beg1, len1, beg2, len2);
  4.1964 --      diff = memcmp (beg1, beg2, MIN (len1, len2));
  4.1965 -+      copy[0] = beg[0];
  4.1966 -+      copy[1] = beg[1];
  4.1967 -     }
  4.1968 - 
  4.1969 -+  if (hard_LC_COLLATE)
  4.1970 -+    {
  4.1971 -+      diff = xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]);
  4.1972 -+
  4.1973 -+      if (mallocd)
  4.1974 -+        for (i = 0; i < 2; i++)
  4.1975 -+          free (copy[i]);
  4.1976 -+
  4.1977 -+      return diff;
  4.1978 -+    }
  4.1979 -+  diff = memcmp (copy[0], copy[1], MIN (len[0], len[1]));
  4.1980 -+
  4.1981 -+  if (mallocd)
  4.1982 -+    for (i = 0; i < 2; i++)
  4.1983 -+      free (copy[i]);
  4.1984 -+
  4.1985 -+
  4.1986 -   if (diff)
  4.1987 -     return diff;
  4.1988 --  return len1 < len2 ? -1 : len1 != len2;
  4.1989 -+  return len[0] - len[1];
  4.1990 - }
  4.1991 - 
  4.1992 - /* Check that successive input lines PREV and CURRENT from input file
  4.1993 -@@ -468,6 +703,11 @@ get_line (FILE *fp, struct line **linep,
  4.1994 -     }
  4.1995 -   ++line_no[which - 1];
  4.1996 - 
  4.1997 -+#if HAVE_MBRTOWC
  4.1998 -+  if (MB_CUR_MAX > 1)
  4.1999 -+    xfields_multibyte (line);
  4.2000 -+  else
  4.2001 -+#endif
  4.2002 -   xfields (line);
  4.2003 - 
  4.2004 -   if (prevline[which - 1])
  4.2005 -@@ -567,21 +807,28 @@ prfield (size_t n, struct line const *li
  4.2006 - 
  4.2007 - /* Output all the fields in line, other than the join field.  */
  4.2008 - 
  4.2009 -+#define PUT_TAB_CHAR							\
  4.2010 -+  do									\
  4.2011 -+    {									\
  4.2012 -+      (tab != NULL) ?							\
  4.2013 -+	fwrite(tab, sizeof(char), tablen, stdout) : putchar (' ');	\
  4.2014 -+    }									\
  4.2015 -+  while (0)
  4.2016 -+
  4.2017 - static void
  4.2018 - prfields (struct line const *line, size_t join_field, size_t autocount)
  4.2019 - {
  4.2020 -   size_t i;
  4.2021 -   size_t nfields = autoformat ? autocount : line->nfields;
  4.2022 --  char output_separator = tab < 0 ? ' ' : tab;
  4.2023 - 
  4.2024 -   for (i = 0; i < join_field && i < nfields; ++i)
  4.2025 -     {
  4.2026 --      putchar (output_separator);
  4.2027 -+      PUT_TAB_CHAR;
  4.2028 -       prfield (i, line);
  4.2029 -     }
  4.2030 -   for (i = join_field + 1; i < nfields; ++i)
  4.2031 -     {
  4.2032 --      putchar (output_separator);
  4.2033 -+      PUT_TAB_CHAR;
  4.2034 -       prfield (i, line);
  4.2035 -     }
  4.2036 - }
  4.2037 -@@ -592,7 +839,6 @@ static void
  4.2038 - prjoin (struct line const *line1, struct line const *line2)
  4.2039 - {
  4.2040 -   const struct outlist *outlist;
  4.2041 --  char output_separator = tab < 0 ? ' ' : tab;
  4.2042 -   size_t field;
  4.2043 -   struct line const *line;
  4.2044 - 
  4.2045 -@@ -626,7 +872,7 @@ prjoin (struct line const *line1, struct
  4.2046 -           o = o->next;
  4.2047 -           if (o == NULL)
  4.2048 -             break;
  4.2049 --          putchar (output_separator);
  4.2050 -+          PUT_TAB_CHAR;
  4.2051 -         }
  4.2052 -       putchar (eolchar);
  4.2053 -     }
  4.2054 -@@ -1104,20 +1350,43 @@ main (int argc, char **argv)
  4.2055 - 
  4.2056 -         case 't':
  4.2057 -           {
  4.2058 --            unsigned char newtab = optarg[0];
  4.2059 -+            char *newtab = NULL;
  4.2060 -+            size_t newtablen;
  4.2061 -+            newtab = xstrdup (optarg);
  4.2062 -+#if HAVE_MBRTOWC
  4.2063 -+            if (MB_CUR_MAX > 1)
  4.2064 -+              {
  4.2065 -+                mbstate_t state;
  4.2066 -+
  4.2067 -+                memset (&state, 0, sizeof (mbstate_t));
  4.2068 -+                newtablen = mbrtowc (NULL, newtab,
  4.2069 -+                                     strnlen (newtab, MB_LEN_MAX),
  4.2070 -+                                     &state);
  4.2071 -+                if (newtablen == (size_t) 0
  4.2072 -+                    || newtablen == (size_t) -1
  4.2073 -+                    || newtablen == (size_t) -2)
  4.2074 -+                  newtablen = 1;
  4.2075 -+              }
  4.2076 -+            else
  4.2077 -+#endif
  4.2078 -+              newtablen = 1;
  4.2079 -             if (! newtab)
  4.2080 --              newtab = '\n'; /* '' => process the whole line.  */
  4.2081 -+              newtab = (char*)"\n"; /* '' => process the whole line.  */
  4.2082 -             else if (optarg[1])
  4.2083 -               {
  4.2084 --                if (STREQ (optarg, "\\0"))
  4.2085 --                  newtab = '\0';
  4.2086 --                else
  4.2087 --                  die (EXIT_FAILURE, 0, _("multi-character tab %s"),
  4.2088 --                       quote (optarg));
  4.2089 -+                if (newtablen == 1 && newtab[1])
  4.2090 -+                {
  4.2091 -+                  if (STREQ (newtab, "\\0"))
  4.2092 -+                     newtab[0] = '\0';
  4.2093 -+                }
  4.2094 -+              }
  4.2095 -+            if (tab != NULL && strcmp (tab, newtab))
  4.2096 -+              {
  4.2097 -+                free (newtab);
  4.2098 -+                die (EXIT_FAILURE, 0, _("incompatible tabs"));
  4.2099 -               }
  4.2100 --            if (0 <= tab && tab != newtab)
  4.2101 --              die (EXIT_FAILURE, 0, _("incompatible tabs"));
  4.2102 -             tab = newtab;
  4.2103 -+            tablen = newtablen;
  4.2104 -           }
  4.2105 -           break;
  4.2106 - 
  4.2107 -diff -Naurp coreutils-8.27-orig/src/pr.c coreutils-8.27/src/pr.c
  4.2108 ---- coreutils-8.27-orig/src/pr.c	2017-01-01 16:34:24.000000000 -0600
  4.2109 -+++ coreutils-8.27/src/pr.c	2017-03-11 23:47:13.094286139 -0600
  4.2110 -@@ -311,6 +311,24 @@
  4.2111 - 
  4.2112 - #include <getopt.h>
  4.2113 - #include <sys/types.h>
  4.2114 -+
  4.2115 -+/* Get MB_LEN_MAX.  */
  4.2116 -+#include <limits.h>
  4.2117 -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
  4.2118 -+   installation; work around this configuration error.  */
  4.2119 -+#if !defined MB_LEN_MAX || MB_LEN_MAX == 1
  4.2120 -+# define MB_LEN_MAX 16
  4.2121 -+#endif
  4.2122 -+
  4.2123 -+/* Get MB_CUR_MAX.  */
  4.2124 -+#include <stdlib.h>
  4.2125 -+
  4.2126 -+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
  4.2127 -+/* Get mbstate_t, mbrtowc(), wcwidth().  */
  4.2128 -+#if HAVE_WCHAR_H
  4.2129 -+# include <wchar.h>
  4.2130 -+#endif
  4.2131 -+
  4.2132 - #include "system.h"
  4.2133 - #include "die.h"
  4.2134 - #include "error.h"
  4.2135 -@@ -324,6 +342,18 @@
  4.2136 - #include "xstrtol.h"
  4.2137 - #include "xdectoint.h"
  4.2138 - 
  4.2139 -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  4.2140 -+#if HAVE_MBRTOWC && defined mbstate_t
  4.2141 -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  4.2142 -+#endif
  4.2143 -+
  4.2144 -+#ifndef HAVE_DECL_WCWIDTH
  4.2145 -+"this configure-time declaration test was not run"
  4.2146 -+#endif
  4.2147 -+#if !HAVE_DECL_WCWIDTH
  4.2148 -+extern int wcwidth ();
  4.2149 -+#endif
  4.2150 -+
  4.2151 - /* The official name of this program (e.g., no 'g' prefix).  */
  4.2152 - #define PROGRAM_NAME "pr"
  4.2153 - 
  4.2154 -@@ -416,7 +446,20 @@ struct COLUMN
  4.2155 - 
  4.2156 - typedef struct COLUMN COLUMN;
  4.2157 - 
  4.2158 --static int char_to_clump (char c);
  4.2159 -+/* Funtion pointers to switch functions for single byte locale or for
  4.2160 -+   multibyte locale. If multibyte functions do not exist in your sysytem,
  4.2161 -+   these pointers always point the function for single byte locale. */
  4.2162 -+static void (*print_char) (char c);
  4.2163 -+static int (*char_to_clump) (char c);
  4.2164 -+
  4.2165 -+/* Functions for single byte locale. */
  4.2166 -+static void print_char_single (char c);
  4.2167 -+static int char_to_clump_single (char c);
  4.2168 -+
  4.2169 -+/* Functions for multibyte locale. */
  4.2170 -+static void print_char_multi (char c);
  4.2171 -+static int char_to_clump_multi (char c);
  4.2172 -+
  4.2173 - static bool read_line (COLUMN *p);
  4.2174 - static bool print_page (void);
  4.2175 - static bool print_stored (COLUMN *p);
  4.2176 -@@ -428,6 +471,7 @@ static void add_line_number (COLUMN *p);
  4.2177 - static void getoptnum (const char *n_str, int min, int *num,
  4.2178 -                        const char *errfmt);
  4.2179 - static void getoptarg (char *arg, char switch_char, char *character,
  4.2180 -+                       int *character_length, int *character_width,
  4.2181 -                        int *number);
  4.2182 - static void print_files (int number_of_files, char **av);
  4.2183 - static void init_parameters (int number_of_files);
  4.2184 -@@ -441,7 +485,6 @@ static void store_char (char c);
  4.2185 - static void pad_down (unsigned int lines);
  4.2186 - static void read_rest_of_line (COLUMN *p);
  4.2187 - static void skip_read (COLUMN *p, int column_number);
  4.2188 --static void print_char (char c);
  4.2189 - static void cleanup (void);
  4.2190 - static void print_sep_string (void);
  4.2191 - static void separator_string (const char *optarg_S);
  4.2192 -@@ -453,7 +496,7 @@ static COLUMN *column_vector;
  4.2193 -    we store the leftmost columns contiguously in buff.
  4.2194 -    To print a line from buff, get the index of the first character
  4.2195 -    from line_vector[i], and print up to line_vector[i + 1]. */
  4.2196 --static char *buff;
  4.2197 -+static unsigned char *buff;
  4.2198 - 
  4.2199 - /* Index of the position in buff where the next character
  4.2200 -    will be stored. */
  4.2201 -@@ -557,7 +600,7 @@ static int chars_per_column;
  4.2202 - static bool untabify_input = false;
  4.2203 - 
  4.2204 - /* (-e) The input tab character. */
  4.2205 --static char input_tab_char = '\t';
  4.2206 -+static char input_tab_char[MB_LEN_MAX] = "\t";
  4.2207 - 
  4.2208 - /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
  4.2209 -    where the leftmost column is 1. */
  4.2210 -@@ -567,7 +610,10 @@ static int chars_per_input_tab = 8;
  4.2211 - static bool tabify_output = false;
  4.2212 - 
  4.2213 - /* (-i) The output tab character. */
  4.2214 --static char output_tab_char = '\t';
  4.2215 -+static char output_tab_char[MB_LEN_MAX] = "\t";
  4.2216 -+
  4.2217 -+/* (-i) The byte length of output tab character. */
  4.2218 -+static int output_tab_char_length = 1;
  4.2219 - 
  4.2220 - /* (-i) The width of the output tab. */
  4.2221 - static int chars_per_output_tab = 8;
  4.2222 -@@ -637,7 +683,13 @@ static int line_number;
  4.2223 - static bool numbered_lines = false;
  4.2224 - 
  4.2225 - /* (-n) Character which follows each line number. */
  4.2226 --static char number_separator = '\t';
  4.2227 -+static char number_separator[MB_LEN_MAX] = "\t";
  4.2228 -+
  4.2229 -+/* (-n) The byte length of the character which follows each line number. */
  4.2230 -+static int number_separator_length = 1;
  4.2231 -+
  4.2232 -+/* (-n) The character width of the character which follows each line number. */
  4.2233 -+static int number_separator_width = 0;
  4.2234 - 
  4.2235 - /* (-n) line counting starts with 1st line of input file (not with 1st
  4.2236 -    line of 1st page printed). */
  4.2237 -@@ -690,6 +742,7 @@ static bool use_col_separator = false;
  4.2238 -    -a|COLUMN|-m is a 'space' and with the -J option a 'tab'. */
  4.2239 - static char const *col_sep_string = "";
  4.2240 - static int col_sep_length = 0;
  4.2241 -+static int col_sep_width = 0;
  4.2242 - static char *column_separator = (char *) " ";
  4.2243 - static char *line_separator = (char *) "\t";
  4.2244 - 
  4.2245 -@@ -851,6 +904,13 @@ separator_string (const char *optarg_S)
  4.2246 -     integer_overflow ();
  4.2247 -   col_sep_length = len;
  4.2248 -   col_sep_string = optarg_S;
  4.2249 -+
  4.2250 -+#if HAVE_MBRTOWC
  4.2251 -+  if (MB_CUR_MAX > 1)
  4.2252 -+    col_sep_width = mbswidth (col_sep_string, 0);
  4.2253 -+  else
  4.2254 -+#endif
  4.2255 -+    col_sep_width = col_sep_length;
  4.2256 - }
  4.2257 - 
  4.2258 - int
  4.2259 -@@ -875,6 +935,21 @@ main (int argc, char **argv)
  4.2260 - 
  4.2261 -   atexit (close_stdout);
  4.2262 - 
  4.2263 -+/* Define which functions are used, the ones for single byte locale or the ones
  4.2264 -+   for multibyte locale. */
  4.2265 -+#if HAVE_MBRTOWC
  4.2266 -+  if (MB_CUR_MAX > 1)
  4.2267 -+    {
  4.2268 -+      print_char = print_char_multi;
  4.2269 -+      char_to_clump = char_to_clump_multi;
  4.2270 -+    }
  4.2271 -+  else
  4.2272 -+#endif
  4.2273 -+    {
  4.2274 -+      print_char = print_char_single;
  4.2275 -+      char_to_clump = char_to_clump_single;
  4.2276 -+    }
  4.2277 -+
  4.2278 -   n_files = 0;
  4.2279 -   file_names = (argc > 1
  4.2280 -                 ? xnmalloc (argc - 1, sizeof (char *))
  4.2281 -@@ -951,8 +1026,12 @@ main (int argc, char **argv)
  4.2282 -           break;
  4.2283 -         case 'e':
  4.2284 -           if (optarg)
  4.2285 --            getoptarg (optarg, 'e', &input_tab_char,
  4.2286 --                       &chars_per_input_tab);
  4.2287 -+            {
  4.2288 -+              int dummy_length, dummy_width;
  4.2289 -+
  4.2290 -+              getoptarg (optarg, 'e', input_tab_char, &dummy_length,
  4.2291 -+                         &dummy_width, &chars_per_input_tab);
  4.2292 -+            }
  4.2293 -           /* Could check tab width > 0. */
  4.2294 -           untabify_input = true;
  4.2295 -           break;
  4.2296 -@@ -965,8 +1044,12 @@ main (int argc, char **argv)
  4.2297 -           break;
  4.2298 -         case 'i':
  4.2299 -           if (optarg)
  4.2300 --            getoptarg (optarg, 'i', &output_tab_char,
  4.2301 --                       &chars_per_output_tab);
  4.2302 -+            {
  4.2303 -+              int dummy_width;
  4.2304 -+
  4.2305 -+              getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length,
  4.2306 -+                         &dummy_width, &chars_per_output_tab);
  4.2307 -+            }
  4.2308 -           /* Could check tab width > 0. */
  4.2309 -           tabify_output = true;
  4.2310 -           break;
  4.2311 -@@ -984,8 +1067,8 @@ main (int argc, char **argv)
  4.2312 -         case 'n':
  4.2313 -           numbered_lines = true;
  4.2314 -           if (optarg)
  4.2315 --            getoptarg (optarg, 'n', &number_separator,
  4.2316 --                       &chars_per_number);
  4.2317 -+            getoptarg (optarg, 'n', number_separator, &number_separator_length,
  4.2318 -+                       &number_separator_width, &chars_per_number);
  4.2319 -           break;
  4.2320 -         case 'N':
  4.2321 -           skip_count = false;
  4.2322 -@@ -1010,6 +1093,7 @@ main (int argc, char **argv)
  4.2323 -           /* Reset an additional input of -s, -S dominates -s */
  4.2324 -           col_sep_string = "";
  4.2325 -           col_sep_length = 0;
  4.2326 -+          col_sep_width = 0;
  4.2327 -           use_col_separator = true;
  4.2328 -           if (optarg)
  4.2329 -             separator_string (optarg);
  4.2330 -@@ -1166,10 +1250,45 @@ getoptnum (const char *n_str, int min, i
  4.2331 -    a number. */
  4.2332 - 
  4.2333 - static void
  4.2334 --getoptarg (char *arg, char switch_char, char *character, int *number)
  4.2335 -+getoptarg (char *arg, char switch_char, char *character, int *character_length,
  4.2336 -+           int *character_width, int *number)
  4.2337 - {
  4.2338 -   if (!ISDIGIT (*arg))
  4.2339 --    *character = *arg++;
  4.2340 -+    {
  4.2341 -+#ifdef HAVE_MBRTOWC
  4.2342 -+      if (MB_CUR_MAX > 1)        /* for multibyte locale. */
  4.2343 -+        {
  4.2344 -+          wchar_t wc;
  4.2345 -+          size_t mblength;
  4.2346 -+          int width;
  4.2347 -+          mbstate_t state = {'\0'};
  4.2348 -+
  4.2349 -+          mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state);
  4.2350 -+
  4.2351 -+          if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.2352 -+            {
  4.2353 -+              *character_length = 1;
  4.2354 -+              *character_width = 1;
  4.2355 -+            }
  4.2356 -+          else
  4.2357 -+            {
  4.2358 -+              *character_length = (mblength < 1) ? 1 : mblength;
  4.2359 -+              width = wcwidth (wc);
  4.2360 -+              *character_width = (width < 0) ? 0 : width;
  4.2361 -+            }
  4.2362 -+
  4.2363 -+          strncpy (character, arg, *character_length);
  4.2364 -+          arg += *character_length;
  4.2365 -+        }
  4.2366 -+      else                        /* for single byte locale. */
  4.2367 -+#endif
  4.2368 -+        {
  4.2369 -+          *character = *arg++;
  4.2370 -+          *character_length = 1;
  4.2371 -+          *character_width = 1;
  4.2372 -+        }
  4.2373 -+    }
  4.2374 -+
  4.2375 -   if (*arg)
  4.2376 -     {
  4.2377 -       long int tmp_long;
  4.2378 -@@ -1191,6 +1310,11 @@ static void
  4.2379 - init_parameters (int number_of_files)
  4.2380 - {
  4.2381 -   int chars_used_by_number = 0;
  4.2382 -+  int mb_len = 1;
  4.2383 -+#if HAVE_MBRTOWC
  4.2384 -+  if (MB_CUR_MAX > 1)
  4.2385 -+    mb_len = MB_LEN_MAX;
  4.2386 -+#endif
  4.2387 - 
  4.2388 -   lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
  4.2389 -   if (lines_per_body <= 0)
  4.2390 -@@ -1228,7 +1352,7 @@ init_parameters (int number_of_files)
  4.2391 -           else
  4.2392 -             col_sep_string = column_separator;
  4.2393 - 
  4.2394 --          col_sep_length = 1;
  4.2395 -+          col_sep_length = col_sep_width = 1;
  4.2396 -           use_col_separator = true;
  4.2397 -         }
  4.2398 -       /* It's rather pointless to define a TAB separator with column
  4.2399 -@@ -1258,11 +1382,11 @@ init_parameters (int number_of_files)
  4.2400 -              + TAB_WIDTH (chars_per_input_tab, chars_per_number);   */
  4.2401 - 
  4.2402 -       /* Estimate chars_per_text without any margin and keep it constant. */
  4.2403 --      if (number_separator == '\t')
  4.2404 -+      if (number_separator[0] == '\t')
  4.2405 -         number_width = (chars_per_number
  4.2406 -                         + TAB_WIDTH (chars_per_default_tab, chars_per_number));
  4.2407 -       else
  4.2408 --        number_width = chars_per_number + 1;
  4.2409 -+        number_width = chars_per_number + number_separator_width;
  4.2410 - 
  4.2411 -       /* The number is part of the column width unless we are
  4.2412 -          printing files in parallel. */
  4.2413 -@@ -1271,7 +1395,7 @@ init_parameters (int number_of_files)
  4.2414 -     }
  4.2415 - 
  4.2416 -   int sep_chars, useful_chars;
  4.2417 --  if (INT_MULTIPLY_WRAPV (columns - 1, col_sep_length, &sep_chars))
  4.2418 -+  if (INT_MULTIPLY_WRAPV (columns - 1, col_sep_width, &sep_chars))
  4.2419 -     sep_chars = INT_MAX;
  4.2420 -   if (INT_SUBTRACT_WRAPV (chars_per_line - chars_used_by_number, sep_chars,
  4.2421 -                           &useful_chars))
  4.2422 -@@ -1294,7 +1418,7 @@ init_parameters (int number_of_files)
  4.2423 -      We've to use 8 as the lower limit, if we use chars_per_default_tab = 8
  4.2424 -      to expand a tab which is not an input_tab-char. */
  4.2425 -   free (clump_buff);
  4.2426 --  clump_buff = xmalloc (MAX (8, chars_per_input_tab));
  4.2427 -+  clump_buff = xmalloc (mb_len * MAX (8, chars_per_input_tab));
  4.2428 - }
  4.2429 - 
  4.2430 - /* Open the necessary files,
  4.2431 -@@ -1402,7 +1526,7 @@ init_funcs (void)
  4.2432 - 
  4.2433 -   /* Enlarge p->start_position of first column to use the same form of
  4.2434 -      padding_not_printed with all columns. */
  4.2435 --  h = h + col_sep_length;
  4.2436 -+  h = h + col_sep_width;
  4.2437 - 
  4.2438 -   /* This loop takes care of all but the rightmost column. */
  4.2439 - 
  4.2440 -@@ -1436,7 +1560,7 @@ init_funcs (void)
  4.2441 -         }
  4.2442 -       else
  4.2443 -         {
  4.2444 --          h = h_next + col_sep_length;
  4.2445 -+          h = h_next + col_sep_width;
  4.2446 -           h_next = h + chars_per_column;
  4.2447 -         }
  4.2448 -     }
  4.2449 -@@ -1727,9 +1851,9 @@ static void
  4.2450 - align_column (COLUMN *p)
  4.2451 - {
  4.2452 -   padding_not_printed = p->start_position;
  4.2453 --  if (col_sep_length < padding_not_printed)
  4.2454 -+  if (col_sep_width < padding_not_printed)
  4.2455 -     {
  4.2456 --      pad_across_to (padding_not_printed - col_sep_length);
  4.2457 -+      pad_across_to (padding_not_printed - col_sep_width);
  4.2458 -       padding_not_printed = ANYWHERE;
  4.2459 -     }
  4.2460 - 
  4.2461 -@@ -2004,13 +2128,13 @@ store_char (char c)
  4.2462 -       /* May be too generous. */
  4.2463 -       buff = X2REALLOC (buff, &buff_allocated);
  4.2464 -     }
  4.2465 --  buff[buff_current++] = c;
  4.2466 -+  buff[buff_current++] = (unsigned char) c;
  4.2467 - }
  4.2468 - 
  4.2469 - static void
  4.2470 - add_line_number (COLUMN *p)
  4.2471 - {
  4.2472 --  int i;
  4.2473 -+  int i, j;
  4.2474 -   char *s;
  4.2475 -   int num_width;
  4.2476 - 
  4.2477 -@@ -2027,22 +2151,24 @@ add_line_number (COLUMN *p)
  4.2478 -       /* Tabification is assumed for multiple columns, also for n-separators,
  4.2479 -          but 'default n-separator = TAB' hasn't been given priority over
  4.2480 -          equal column_width also specified by POSIX. */
  4.2481 --      if (number_separator == '\t')
  4.2482 -+      if (number_separator[0] == '\t')
  4.2483 -         {
  4.2484 -           i = number_width - chars_per_number;
  4.2485 -           while (i-- > 0)
  4.2486 -             (p->char_func) (' ');
  4.2487 -         }
  4.2488 -       else
  4.2489 --        (p->char_func) (number_separator);
  4.2490 -+        for (j = 0; j < number_separator_length; j++)
  4.2491 -+          (p->char_func) (number_separator[j]);
  4.2492 -     }
  4.2493 -   else
  4.2494 -     /* To comply with POSIX, we avoid any expansion of default TAB
  4.2495 -        separator with a single column output. No column_width requirement
  4.2496 -        has to be considered. */
  4.2497 -     {
  4.2498 --      (p->char_func) (number_separator);
  4.2499 --      if (number_separator == '\t')
  4.2500 -+      for (j = 0; j < number_separator_length; j++)
  4.2501 -+        (p->char_func) (number_separator[j]);
  4.2502 -+      if (number_separator[0] == '\t')
  4.2503 -         output_position = POS_AFTER_TAB (chars_per_output_tab,
  4.2504 -                           output_position);
  4.2505 -     }
  4.2506 -@@ -2203,7 +2329,7 @@ print_white_space (void)
  4.2507 -   while (goal - h_old > 1
  4.2508 -          && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)
  4.2509 -     {
  4.2510 --      putchar (output_tab_char);
  4.2511 -+      fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout);
  4.2512 -       h_old = h_new;
  4.2513 -     }
  4.2514 -   while (++h_old <= goal)
  4.2515 -@@ -2223,6 +2349,7 @@ print_sep_string (void)
  4.2516 - {
  4.2517 -   char const *s = col_sep_string;
  4.2518 -   int l = col_sep_length;
  4.2519 -+  int not_space_flag;
  4.2520 - 
  4.2521 -   if (separators_not_printed <= 0)
  4.2522 -     {
  4.2523 -@@ -2234,6 +2361,7 @@ print_sep_string (void)
  4.2524 -     {
  4.2525 -       for (; separators_not_printed > 0; --separators_not_printed)
  4.2526 -         {
  4.2527 -+          not_space_flag = 0;
  4.2528 -           while (l-- > 0)
  4.2529 -             {
  4.2530 -               /* 3 types of sep_strings: spaces only, spaces and chars,
  4.2531 -@@ -2247,12 +2375,15 @@ print_sep_string (void)
  4.2532 -                 }
  4.2533 -               else
  4.2534 -                 {
  4.2535 -+                  not_space_flag = 1;
  4.2536 -                   if (spaces_not_printed > 0)
  4.2537 -                     print_white_space ();
  4.2538 -                   putchar (*s++);
  4.2539 --                  ++output_position;
  4.2540 -                 }
  4.2541 -             }
  4.2542 -+          if (not_space_flag)
  4.2543 -+            output_position += col_sep_width;
  4.2544 -+
  4.2545 -           /* sep_string ends with some spaces */
  4.2546 -           if (spaces_not_printed > 0)
  4.2547 -             print_white_space ();
  4.2548 -@@ -2280,7 +2411,7 @@ print_clump (COLUMN *p, int n, char *clu
  4.2549 -    required number of tabs and spaces. */
  4.2550 - 
  4.2551 - static void
  4.2552 --print_char (char c)
  4.2553 -+print_char_single (char c)
  4.2554 - {
  4.2555 -   if (tabify_output)
  4.2556 -     {
  4.2557 -@@ -2304,6 +2435,74 @@ print_char (char c)
  4.2558 -   putchar (c);
  4.2559 - }
  4.2560 - 
  4.2561 -+#ifdef HAVE_MBRTOWC
  4.2562 -+static void
  4.2563 -+print_char_multi (char c)
  4.2564 -+{
  4.2565 -+  static size_t mbc_pos = 0;
  4.2566 -+  static char mbc[MB_LEN_MAX] = {'\0'};
  4.2567 -+  static mbstate_t state = {'\0'};
  4.2568 -+  mbstate_t state_bak;
  4.2569 -+  wchar_t wc;
  4.2570 -+  size_t mblength;
  4.2571 -+  int width;
  4.2572 -+
  4.2573 -+  if (tabify_output)
  4.2574 -+    {
  4.2575 -+      state_bak = state;
  4.2576 -+      mbc[mbc_pos++] = c;
  4.2577 -+      mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
  4.2578 -+
  4.2579 -+      while (mbc_pos > 0)
  4.2580 -+        {
  4.2581 -+          switch (mblength)
  4.2582 -+            {
  4.2583 -+            case (size_t)-2:
  4.2584 -+              state = state_bak;
  4.2585 -+              return;
  4.2586 -+
  4.2587 -+            case (size_t)-1:
  4.2588 -+              state = state_bak;
  4.2589 -+              ++output_position;
  4.2590 -+              putchar (mbc[0]);
  4.2591 -+              memmove (mbc, mbc + 1, MB_CUR_MAX - 1);
  4.2592 -+              --mbc_pos;
  4.2593 -+              break;
  4.2594 -+
  4.2595 -+            case 0:
  4.2596 -+              mblength = 1;
  4.2597 -+
  4.2598 -+            default:
  4.2599 -+              if (wc == L' ')
  4.2600 -+                {
  4.2601 -+                  memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
  4.2602 -+                  --mbc_pos;
  4.2603 -+                  ++spaces_not_printed;
  4.2604 -+                  return;
  4.2605 -+                }
  4.2606 -+              else if (spaces_not_printed > 0)
  4.2607 -+                print_white_space ();
  4.2608 -+
  4.2609 -+              /* Nonprintables are assumed to have width 0, except L'\b'. */
  4.2610 -+              if ((width = wcwidth (wc)) < 1)
  4.2611 -+                {
  4.2612 -+                  if (wc == L'\b')
  4.2613 -+                    --output_position;
  4.2614 -+                }
  4.2615 -+              else
  4.2616 -+                output_position += width;
  4.2617 -+
  4.2618 -+              fwrite (mbc, sizeof(char), mblength, stdout);
  4.2619 -+              memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
  4.2620 -+              mbc_pos -= mblength;
  4.2621 -+            }
  4.2622 -+        }
  4.2623 -+      return;
  4.2624 -+    }
  4.2625 -+  putchar (c);
  4.2626 -+}
  4.2627 -+#endif
  4.2628 -+
  4.2629 - /* Skip to page PAGE before printing.
  4.2630 -    PAGE may be larger than total number of pages. */
  4.2631 - 
  4.2632 -@@ -2483,9 +2682,9 @@ read_line (COLUMN *p)
  4.2633 -           align_empty_cols = false;
  4.2634 -         }
  4.2635 - 
  4.2636 --      if (col_sep_length < padding_not_printed)
  4.2637 -+      if (col_sep_width < padding_not_printed)
  4.2638 -         {
  4.2639 --          pad_across_to (padding_not_printed - col_sep_length);
  4.2640 -+          pad_across_to (padding_not_printed - col_sep_width);
  4.2641 -           padding_not_printed = ANYWHERE;
  4.2642 -         }
  4.2643 - 
  4.2644 -@@ -2555,7 +2754,7 @@ print_stored (COLUMN *p)
  4.2645 -   int i;
  4.2646 - 
  4.2647 -   int line = p->current_line++;
  4.2648 --  char *first = &buff[line_vector[line]];
  4.2649 -+  unsigned char *first = &buff[line_vector[line]];
  4.2650 -   /* FIXME
  4.2651 -      UMR: Uninitialized memory read:
  4.2652 -      * This is occurring while in:
  4.2653 -@@ -2567,7 +2766,7 @@ print_stored (COLUMN *p)
  4.2654 -      xmalloc        [xmalloc.c:94]
  4.2655 -      init_store_cols [pr.c:1648]
  4.2656 -      */
  4.2657 --  char *last = &buff[line_vector[line + 1]];
  4.2658 -+  unsigned char *last = &buff[line_vector[line + 1]];
  4.2659 - 
  4.2660 -   pad_vertically = true;
  4.2661 - 
  4.2662 -@@ -2586,9 +2785,9 @@ print_stored (COLUMN *p)
  4.2663 -         }
  4.2664 -     }
  4.2665 - 
  4.2666 --  if (col_sep_length < padding_not_printed)
  4.2667 -+  if (col_sep_width < padding_not_printed)
  4.2668 -     {
  4.2669 --      pad_across_to (padding_not_printed - col_sep_length);
  4.2670 -+      pad_across_to (padding_not_printed - col_sep_width);
  4.2671 -       padding_not_printed = ANYWHERE;
  4.2672 -     }
  4.2673 - 
  4.2674 -@@ -2601,8 +2800,8 @@ print_stored (COLUMN *p)
  4.2675 -   if (spaces_not_printed == 0)
  4.2676 -     {
  4.2677 -       output_position = p->start_position + end_vector[line];
  4.2678 --      if (p->start_position - col_sep_length == chars_per_margin)
  4.2679 --        output_position -= col_sep_length;
  4.2680 -+      if (p->start_position - col_sep_width == chars_per_margin)
  4.2681 -+        output_position -= col_sep_width;
  4.2682 -     }
  4.2683 - 
  4.2684 -   return true;
  4.2685 -@@ -2621,7 +2820,7 @@ print_stored (COLUMN *p)
  4.2686 -    number of characters is 1.) */
  4.2687 - 
  4.2688 - static int
  4.2689 --char_to_clump (char c)
  4.2690 -+char_to_clump_single (char c)
  4.2691 - {
  4.2692 -   unsigned char uc = c;
  4.2693 -   char *s = clump_buff;
  4.2694 -@@ -2631,10 +2830,10 @@ char_to_clump (char c)
  4.2695 -   int chars;
  4.2696 -   int chars_per_c = 8;
  4.2697 - 
  4.2698 --  if (c == input_tab_char)
  4.2699 -+  if (c == input_tab_char[0])
  4.2700 -     chars_per_c = chars_per_input_tab;
  4.2701 - 
  4.2702 --  if (c == input_tab_char || c == '\t')
  4.2703 -+  if (c == input_tab_char[0] || c == '\t')
  4.2704 -     {
  4.2705 -       width = TAB_WIDTH (chars_per_c, input_position);
  4.2706 - 
  4.2707 -@@ -2715,6 +2914,164 @@ char_to_clump (char c)
  4.2708 -   return chars;
  4.2709 - }
  4.2710 - 
  4.2711 -+#ifdef HAVE_MBRTOWC
  4.2712 -+static int
  4.2713 -+char_to_clump_multi (char c)
  4.2714 -+{
  4.2715 -+  static size_t mbc_pos = 0;
  4.2716 -+  static char mbc[MB_LEN_MAX] = {'\0'};
  4.2717 -+  static mbstate_t state = {'\0'};
  4.2718 -+  mbstate_t state_bak;
  4.2719 -+  wchar_t wc;
  4.2720 -+  size_t mblength;
  4.2721 -+  int wc_width;
  4.2722 -+  register char *s = clump_buff;
  4.2723 -+  register int i, j;
  4.2724 -+  char esc_buff[4];
  4.2725 -+  int width;
  4.2726 -+  int chars;
  4.2727 -+  int chars_per_c = 8;
  4.2728 -+
  4.2729 -+  state_bak = state;
  4.2730 -+  mbc[mbc_pos++] = c;
  4.2731 -+  mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
  4.2732 -+
  4.2733 -+  width = 0;
  4.2734 -+  chars = 0;
  4.2735 -+  while (mbc_pos > 0)
  4.2736 -+    {
  4.2737 -+      switch (mblength)
  4.2738 -+        {
  4.2739 -+        case (size_t)-2:
  4.2740 -+          state = state_bak;
  4.2741 -+          return 0;
  4.2742 -+
  4.2743 -+        case (size_t)-1:
  4.2744 -+          state = state_bak;
  4.2745 -+          mblength = 1;
  4.2746 -+
  4.2747 -+          if (use_esc_sequence || use_cntrl_prefix)
  4.2748 -+            {
  4.2749 -+              width = +4;
  4.2750 -+              chars = +4;
  4.2751 -+              *s++ = '\\';
  4.2752 -+              sprintf (esc_buff, "%03o", (unsigned char) mbc[0]);
  4.2753 -+              for (i = 0; i <= 2; ++i)
  4.2754 -+                *s++ = (int) esc_buff[i];
  4.2755 -+            }
  4.2756 -+          else
  4.2757 -+            {
  4.2758 -+              width += 1;
  4.2759 -+              chars += 1;
  4.2760 -+              *s++ = mbc[0];
  4.2761 -+            }
  4.2762 -+          break;
  4.2763 -+
  4.2764 -+        case 0:
  4.2765 -+          mblength = 1;
  4.2766 -+                /* Fall through */
  4.2767 -+
  4.2768 -+        default:
  4.2769 -+          if (memcmp (mbc, input_tab_char, mblength) == 0)
  4.2770 -+            chars_per_c = chars_per_input_tab;
  4.2771 -+
  4.2772 -+          if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t')
  4.2773 -+            {
  4.2774 -+              int  width_inc;
  4.2775 -+
  4.2776 -+              width_inc = TAB_WIDTH (chars_per_c, input_position);
  4.2777 -+              width += width_inc;
  4.2778 -+
  4.2779 -+              if (untabify_input)
  4.2780 -+                {
  4.2781 -+                  for (i = width_inc; i; --i)
  4.2782 -+                    *s++ = ' ';
  4.2783 -+                  chars += width_inc;
  4.2784 -+                }
  4.2785 -+              else
  4.2786 -+                {
  4.2787 -+                  for (i = 0; i <  mblength; i++)
  4.2788 -+                    *s++ = mbc[i];
  4.2789 -+                  chars += mblength;
  4.2790 -+                }
  4.2791 -+            }
  4.2792 -+          else if ((wc_width = wcwidth (wc)) < 1)
  4.2793 -+            {
  4.2794 -+              if (use_esc_sequence)
  4.2795 -+                {
  4.2796 -+                  for (i = 0; i < mblength; i++)
  4.2797 -+                    {
  4.2798 -+                      width += 4;
  4.2799 -+                      chars += 4;
  4.2800 -+                      *s++ = '\\';
  4.2801 -+                      sprintf (esc_buff, "%03o", (unsigned char) mbc[i]);
  4.2802 -+                      for (j = 0; j <= 2; ++j)
  4.2803 -+                        *s++ = (int) esc_buff[j];
  4.2804 -+                    }
  4.2805 -+                }
  4.2806 -+              else if (use_cntrl_prefix)
  4.2807 -+                {
  4.2808 -+                  if (wc < 0200)
  4.2809 -+                    {
  4.2810 -+                      width += 2;
  4.2811 -+                      chars += 2;
  4.2812 -+                      *s++ = '^';
  4.2813 -+                      *s++ = wc ^ 0100;
  4.2814 -+                    }
  4.2815 -+                  else
  4.2816 -+                    {
  4.2817 -+                      for (i = 0; i < mblength; i++)
  4.2818 -+                        {
  4.2819 -+                          width += 4;
  4.2820 -+                          chars += 4;
  4.2821 -+                          *s++ = '\\';
  4.2822 -+                          sprintf (esc_buff, "%03o", (unsigned char) mbc[i]);
  4.2823 -+                          for (j = 0; j <= 2; ++j)
  4.2824 -+                            *s++ = (int) esc_buff[j];
  4.2825 -+                        }
  4.2826 -+                    }
  4.2827 -+                }
  4.2828 -+              else if (wc == L'\b')
  4.2829 -+                {
  4.2830 -+                  width += -1;
  4.2831 -+                  chars += 1;
  4.2832 -+                  *s++ = c;
  4.2833 -+                }
  4.2834 -+              else
  4.2835 -+                {
  4.2836 -+                  width += 0;
  4.2837 -+                  chars += mblength;
  4.2838 -+                  for (i = 0; i < mblength; i++)
  4.2839 -+                    *s++ = mbc[i];
  4.2840 -+                }
  4.2841 -+            }
  4.2842 -+          else
  4.2843 -+            {
  4.2844 -+              width += wc_width;
  4.2845 -+              chars += mblength;
  4.2846 -+              for (i = 0; i < mblength; i++)
  4.2847 -+                *s++ = mbc[i];
  4.2848 -+            }
  4.2849 -+        }
  4.2850 -+      memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
  4.2851 -+      mbc_pos -= mblength;
  4.2852 -+    }
  4.2853 -+
  4.2854 -+  /* Too many backspaces must put us in position 0 -- never negative. */
  4.2855 -+  if (width < 0 && input_position == 0)
  4.2856 -+    {
  4.2857 -+      chars = 0;
  4.2858 -+      input_position = 0;
  4.2859 -+    }
  4.2860 -+  else if (width < 0 && input_position <= -width)
  4.2861 -+    input_position = 0;
  4.2862 -+  else
  4.2863 -+   input_position += width;
  4.2864 -+
  4.2865 -+  return chars;
  4.2866 -+}
  4.2867 -+#endif
  4.2868 -+
  4.2869 - /* We've just printed some files and need to clean up things before
  4.2870 -    looking for more options and printing the next batch of files.
  4.2871 - 
  4.2872 -diff -Naurp coreutils-8.27-orig/src/sort.c coreutils-8.27/src/sort.c
  4.2873 ---- coreutils-8.27-orig/src/sort.c	2017-01-01 16:34:24.000000000 -0600
  4.2874 -+++ coreutils-8.27/src/sort.c	2017-03-11 23:49:22.416505389 -0600
  4.2875 -@@ -29,6 +29,14 @@
  4.2876 - #include <sys/wait.h>
  4.2877 - #include <signal.h>
  4.2878 - #include <assert.h>
  4.2879 -+#if HAVE_WCHAR_H
  4.2880 -+# include <wchar.h>
  4.2881 -+#endif
  4.2882 -+/* Get isw* functions. */
  4.2883 -+#if HAVE_WCTYPE_H
  4.2884 -+# include <wctype.h>
  4.2885 -+#endif
  4.2886 -+
  4.2887 - #include "system.h"
  4.2888 - #include "argmatch.h"
  4.2889 - #include "die.h"
  4.2890 -@@ -165,14 +173,39 @@ static int decimal_point;
  4.2891 - /* Thousands separator; if -1, then there isn't one.  */
  4.2892 - static int thousands_sep;
  4.2893 - 
  4.2894 -+/* True if -f is specified.  */
  4.2895 -+static bool folding;
  4.2896 -+
  4.2897 - /* Nonzero if the corresponding locales are hard.  */
  4.2898 - static bool hard_LC_COLLATE;
  4.2899 --#if HAVE_NL_LANGINFO
  4.2900 -+#if HAVE_LANGINFO_CODESET
  4.2901 - static bool hard_LC_TIME;
  4.2902 - #endif
  4.2903 - 
  4.2904 - #define NONZERO(x) ((x) != 0)
  4.2905 - 
  4.2906 -+/* get a multibyte character's byte length. */
  4.2907 -+#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE)                        \
  4.2908 -+  do                                                                        \
  4.2909 -+    {                                                                        \
  4.2910 -+      wchar_t wc;                                                        \
  4.2911 -+      mbstate_t state_bak;                                                \
  4.2912 -+                                                                        \
  4.2913 -+      state_bak = STATE;                                                \
  4.2914 -+      mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE);                        \
  4.2915 -+                                                                        \
  4.2916 -+      switch (MBLENGTH)                                                        \
  4.2917 -+        {                                                                \
  4.2918 -+        case (size_t)-1:                                                \
  4.2919 -+        case (size_t)-2:                                                \
  4.2920 -+          STATE = state_bak;                                                \
  4.2921 -+                /* Fall through. */                                        \
  4.2922 -+        case 0:                                                                \
  4.2923 -+          MBLENGTH = 1;                                                        \
  4.2924 -+      }                                                                        \
  4.2925 -+    }                                                                        \
  4.2926 -+  while (0)
  4.2927 -+
  4.2928 - /* The kind of blanks for '-b' to skip in various options. */
  4.2929 - enum blanktype { bl_start, bl_end, bl_both };
  4.2930 - 
  4.2931 -@@ -346,13 +379,11 @@ static bool reverse;
  4.2932 -    they were read if all keys compare equal.  */
  4.2933 - static bool stable;
  4.2934 - 
  4.2935 --/* If TAB has this value, blanks separate fields.  */
  4.2936 --enum { TAB_DEFAULT = CHAR_MAX + 1 };
  4.2937 --
  4.2938 --/* Tab character separating fields.  If TAB_DEFAULT, then fields are
  4.2939 -+/* Tab character separating fields.  If tab_length is 0, then fields are
  4.2940 -    separated by the empty string between a non-blank character and a blank
  4.2941 -    character. */
  4.2942 --static int tab = TAB_DEFAULT;
  4.2943 -+static char tab[MB_LEN_MAX + 1];
  4.2944 -+static size_t tab_length = 0;
  4.2945 - 
  4.2946 - /* Flag to remove consecutive duplicate lines from the output.
  4.2947 -    Only the last of a sequence of equal lines will be output. */
  4.2948 -@@ -811,6 +842,46 @@ reap_all (void)
  4.2949 -     reap (-1);
  4.2950 - }
  4.2951 - 
  4.2952 -+/* Function pointers. */
  4.2953 -+static void
  4.2954 -+(*inittables) (void);
  4.2955 -+static char *
  4.2956 -+(*begfield) (const struct line*, const struct keyfield *);
  4.2957 -+static char *
  4.2958 -+(*limfield) (const struct line*, const struct keyfield *);
  4.2959 -+static void
  4.2960 -+(*skipblanks) (char **ptr, char *lim);
  4.2961 -+static int
  4.2962 -+(*getmonth) (char const *, size_t, char **);
  4.2963 -+static int
  4.2964 -+(*keycompare) (const struct line *, const struct line *);
  4.2965 -+static int
  4.2966 -+(*numcompare) (const char *, const char *);
  4.2967 -+
  4.2968 -+/* Test for white space multibyte character.
  4.2969 -+   Set LENGTH the byte length of investigated multibyte character. */
  4.2970 -+#if HAVE_MBRTOWC
  4.2971 -+static int
  4.2972 -+ismbblank (const char *str, size_t len, size_t *length)
  4.2973 -+{
  4.2974 -+  size_t mblength;
  4.2975 -+  wchar_t wc;
  4.2976 -+  mbstate_t state;
  4.2977 -+
  4.2978 -+  memset (&state, '\0', sizeof(mbstate_t));
  4.2979 -+  mblength = mbrtowc (&wc, str, len, &state);
  4.2980 -+
  4.2981 -+  if (mblength == (size_t)-1 || mblength == (size_t)-2)
  4.2982 -+    {
  4.2983 -+      *length = 1;
  4.2984 -+      return 0;
  4.2985 -+    }
  4.2986 -+
  4.2987 -+  *length = (mblength < 1) ? 1 : mblength;
  4.2988 -+  return iswblank (wc) || wc == '\n';
  4.2989 -+}
  4.2990 -+#endif
  4.2991 -+
  4.2992 - /* Clean up any remaining temporary files.  */
  4.2993 - 
  4.2994 - static void
  4.2995 -@@ -1255,7 +1326,7 @@ zaptemp (char const *name)
  4.2996 -   free (node);
  4.2997 - }
  4.2998 - 
  4.2999 --#if HAVE_NL_LANGINFO
  4.3000 -+#if HAVE_LANGINFO_CODESET
  4.3001 - 
  4.3002 - static int
  4.3003 - struct_month_cmp (void const *m1, void const *m2)
  4.3004 -@@ -1270,7 +1341,7 @@ struct_month_cmp (void const *m1, void c
  4.3005 - /* Initialize the character class tables. */
  4.3006 - 
  4.3007 - static void
  4.3008 --inittables (void)
  4.3009 -+inittables_uni (void)
  4.3010 - {
  4.3011 -   size_t i;
  4.3012 - 
  4.3013 -@@ -1282,7 +1353,7 @@ inittables (void)
  4.3014 -       fold_toupper[i] = toupper (i);
  4.3015 -     }
  4.3016 - 
  4.3017 --#if HAVE_NL_LANGINFO
  4.3018 -+#if HAVE_LANGINFO_CODESET
  4.3019 -   /* If we're not in the "C" locale, read different names for months.  */
  4.3020 -   if (hard_LC_TIME)
  4.3021 -     {
  4.3022 -@@ -1364,6 +1435,84 @@ specify_nmerge (int oi, char c, char con
  4.3023 -     xstrtol_fatal (e, oi, c, long_options, s);
  4.3024 - }
  4.3025 - 
  4.3026 -+#if HAVE_MBRTOWC
  4.3027 -+static void
  4.3028 -+inittables_mb (void)
  4.3029 -+{
  4.3030 -+  int i, j, k, l;
  4.3031 -+  char *name, *s, *lc_time, *lc_ctype;
  4.3032 -+  size_t s_len, mblength;
  4.3033 -+  char mbc[MB_LEN_MAX];
  4.3034 -+  wchar_t wc, pwc;
  4.3035 -+  mbstate_t state_mb, state_wc;
  4.3036 -+
  4.3037 -+  lc_time = setlocale (LC_TIME, "");
  4.3038 -+  if (lc_time)
  4.3039 -+    lc_time = xstrdup (lc_time);
  4.3040 -+
  4.3041 -+  lc_ctype = setlocale (LC_CTYPE, "");
  4.3042 -+  if (lc_ctype)
  4.3043 -+    lc_ctype = xstrdup (lc_ctype);
  4.3044 -+
  4.3045 -+  if (lc_time && lc_ctype)
  4.3046 -+    /* temporarily set LC_CTYPE to match LC_TIME, so that we can convert
  4.3047 -+     * the names of months to upper case */
  4.3048 -+    setlocale (LC_CTYPE, lc_time);
  4.3049 -+
  4.3050 -+  for (i = 0; i < MONTHS_PER_YEAR; i++)
  4.3051 -+    {
  4.3052 -+      s = (char *) nl_langinfo (ABMON_1 + i);
  4.3053 -+      s_len = strlen (s);
  4.3054 -+      monthtab[i].name = name = (char *) xmalloc (s_len + 1);
  4.3055 -+      monthtab[i].val = i + 1;
  4.3056 -+
  4.3057 -+      memset (&state_mb, '\0', sizeof (mbstate_t));
  4.3058 -+      memset (&state_wc, '\0', sizeof (mbstate_t));
  4.3059 -+
  4.3060 -+      for (j = 0; j < s_len;)
  4.3061 -+        {
  4.3062 -+          if (!ismbblank (s + j, s_len - j, &mblength))
  4.3063 -+            break;
  4.3064 -+          j += mblength;
  4.3065 -+        }
  4.3066 -+
  4.3067 -+      for (k = 0; j < s_len;)
  4.3068 -+        {
  4.3069 -+          mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb);
  4.3070 -+          assert (mblength != (size_t)-1 && mblength != (size_t)-2);
  4.3071 -+          if (mblength == 0)
  4.3072 -+            break;
  4.3073 -+
  4.3074 -+          pwc = towupper (wc);
  4.3075 -+          if (pwc == wc)
  4.3076 -+            {
  4.3077 -+              memcpy (mbc, s + j, mblength);
  4.3078 -+              j += mblength;
  4.3079 -+            }
  4.3080 -+          else
  4.3081 -+            {
  4.3082 -+              j += mblength;
  4.3083 -+              mblength = wcrtomb (mbc, pwc, &state_wc);
  4.3084 -+              assert (mblength != (size_t)0 && mblength != (size_t)-1);
  4.3085 -+            }
  4.3086 -+
  4.3087 -+          for (l = 0; l < mblength; l++)
  4.3088 -+            name[k++] = mbc[l];
  4.3089 -+        }
  4.3090 -+      name[k] = '\0';
  4.3091 -+    }
  4.3092 -+  qsort ((void *) monthtab, MONTHS_PER_YEAR,
  4.3093 -+      sizeof (struct month), struct_month_cmp);
  4.3094 -+
  4.3095 -+  if (lc_time && lc_ctype)
  4.3096 -+    /* restore the original locales */
  4.3097 -+    setlocale (LC_CTYPE, lc_ctype);
  4.3098 -+
  4.3099 -+  free (lc_ctype);
  4.3100 -+  free (lc_time);
  4.3101 -+}
  4.3102 -+#endif
  4.3103 -+
  4.3104 - /* Specify the amount of main memory to use when sorting.  */
  4.3105 - static void
  4.3106 - specify_sort_size (int oi, char c, char const *s)
  4.3107 -@@ -1597,7 +1746,7 @@ buffer_linelim (struct buffer const *buf
  4.3108 -    by KEY in LINE. */
  4.3109 - 
  4.3110 - static char *
  4.3111 --begfield (struct line const *line, struct keyfield const *key)
  4.3112 -+begfield_uni (const struct line *line, const struct keyfield *key)
  4.3113 - {
  4.3114 -   char *ptr = line->text, *lim = ptr + line->length - 1;
  4.3115 -   size_t sword = key->sword;
  4.3116 -@@ -1606,10 +1755,10 @@ begfield (struct line const *line, struc
  4.3117 -   /* The leading field separator itself is included in a field when -t
  4.3118 -      is absent.  */
  4.3119 - 
  4.3120 --  if (tab != TAB_DEFAULT)
  4.3121 -+  if (tab_length)
  4.3122 -     while (ptr < lim && sword--)
  4.3123 -       {
  4.3124 --        while (ptr < lim && *ptr != tab)
  4.3125 -+        while (ptr < lim && *ptr != tab[0])
  4.3126 -           ++ptr;
  4.3127 -         if (ptr < lim)
  4.3128 -           ++ptr;
  4.3129 -@@ -1635,11 +1784,70 @@ begfield (struct line const *line, struc
  4.3130 -   return ptr;
  4.3131 - }
  4.3132 - 
  4.3133 -+#if HAVE_MBRTOWC
  4.3134 -+static char *
  4.3135 -+begfield_mb (const struct line *line, const struct keyfield *key)
  4.3136 -+{
  4.3137 -+  int i;
  4.3138 -+  char *ptr = line->text, *lim = ptr + line->length - 1;
  4.3139 -+  size_t sword = key->sword;
  4.3140 -+  size_t schar = key->schar;
  4.3141 -+  size_t mblength;
  4.3142 -+  mbstate_t state;
  4.3143 -+
  4.3144 -+  memset (&state, '\0', sizeof(mbstate_t));
  4.3145 -+
  4.3146 -+  if (tab_length)
  4.3147 -+    while (ptr < lim && sword--)
  4.3148 -+      {
  4.3149 -+        while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
  4.3150 -+          {
  4.3151 -+            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3152 -+            ptr += mblength;
  4.3153 -+          }
  4.3154 -+        if (ptr < lim)
  4.3155 -+          {
  4.3156 -+            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3157 -+            ptr += mblength;
  4.3158 -+          }
  4.3159 -+      }
  4.3160 -+  else
  4.3161 -+    while (ptr < lim && sword--)
  4.3162 -+      {
  4.3163 -+        while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  4.3164 -+          ptr += mblength;
  4.3165 -+        if (ptr < lim)
  4.3166 -+          {
  4.3167 -+            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3168 -+            ptr += mblength;
  4.3169 -+          }
  4.3170 -+        while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
  4.3171 -+          ptr += mblength;
  4.3172 -+      }
  4.3173 -+
  4.3174 -+  if (key->skipsblanks)
  4.3175 -+    while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  4.3176 -+      ptr += mblength;
  4.3177 -+
  4.3178 -+  for (i = 0; i < schar; i++)
  4.3179 -+    {
  4.3180 -+      GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3181 -+
  4.3182 -+      if (ptr + mblength > lim)
  4.3183 -+        break;
  4.3184 -+      else
  4.3185 -+        ptr += mblength;
  4.3186 -+    }
  4.3187 -+
  4.3188 -+  return ptr;
  4.3189 -+}
  4.3190 -+#endif
  4.3191 -+
  4.3192 - /* Return the limit of (a pointer to the first character after) the field
  4.3193 -    in LINE specified by KEY. */
  4.3194 - 
  4.3195 - static char *
  4.3196 --limfield (struct line const *line, struct keyfield const *key)
  4.3197 -+limfield_uni (const struct line *line, const struct keyfield *key)
  4.3198 - {
  4.3199 -   char *ptr = line->text, *lim = ptr + line->length - 1;
  4.3200 -   size_t eword = key->eword, echar = key->echar;
  4.3201 -@@ -1654,10 +1862,10 @@ limfield (struct line const *line, struc
  4.3202 -      'beginning' is the first character following the delimiting TAB.
  4.3203 -      Otherwise, leave PTR pointing at the first 'blank' character after
  4.3204 -      the preceding field.  */
  4.3205 --  if (tab != TAB_DEFAULT)
  4.3206 -+  if (tab_length)
  4.3207 -     while (ptr < lim && eword--)
  4.3208 -       {
  4.3209 --        while (ptr < lim && *ptr != tab)
  4.3210 -+        while (ptr < lim && *ptr != tab[0])
  4.3211 -           ++ptr;
  4.3212 -         if (ptr < lim && (eword || echar))
  4.3213 -           ++ptr;
  4.3214 -@@ -1703,10 +1911,10 @@ limfield (struct line const *line, struc
  4.3215 -      */
  4.3216 - 
  4.3217 -   /* Make LIM point to the end of (one byte past) the current field.  */
  4.3218 --  if (tab != TAB_DEFAULT)
  4.3219 -+  if (tab_length)
  4.3220 -     {
  4.3221 -       char *newlim;
  4.3222 --      newlim = memchr (ptr, tab, lim - ptr);
  4.3223 -+      newlim = memchr (ptr, tab[0], lim - ptr);
  4.3224 -       if (newlim)
  4.3225 -         lim = newlim;
  4.3226 -     }
  4.3227 -@@ -1737,6 +1945,130 @@ limfield (struct line const *line, struc
  4.3228 -   return ptr;
  4.3229 - }
  4.3230 - 
  4.3231 -+#if HAVE_MBRTOWC
  4.3232 -+static char *
  4.3233 -+limfield_mb (const struct line *line, const struct keyfield *key)
  4.3234 -+{
  4.3235 -+  char *ptr = line->text, *lim = ptr + line->length - 1;
  4.3236 -+  size_t eword = key->eword, echar = key->echar;
  4.3237 -+  int i;
  4.3238 -+  size_t mblength;
  4.3239 -+  mbstate_t state;
  4.3240 -+
  4.3241 -+  if (echar == 0)
  4.3242 -+    eword++; /* skip all of end field. */
  4.3243 -+
  4.3244 -+  memset (&state, '\0', sizeof(mbstate_t));
  4.3245 -+
  4.3246 -+  if (tab_length)
  4.3247 -+    while (ptr < lim && eword--)
  4.3248 -+      {
  4.3249 -+        while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
  4.3250 -+          {
  4.3251 -+            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3252 -+            ptr += mblength;
  4.3253 -+          }
  4.3254 -+        if (ptr < lim && (eword | echar))
  4.3255 -+          {
  4.3256 -+            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3257 -+            ptr += mblength;
  4.3258 -+          }
  4.3259 -+      }
  4.3260 -+  else
  4.3261 -+    while (ptr < lim && eword--)
  4.3262 -+      {
  4.3263 -+        while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  4.3264 -+          ptr += mblength;
  4.3265 -+        if (ptr < lim)
  4.3266 -+          {
  4.3267 -+            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3268 -+            ptr += mblength;
  4.3269 -+          }
  4.3270 -+        while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
  4.3271 -+          ptr += mblength;
  4.3272 -+      }
  4.3273 -+
  4.3274 -+
  4.3275 -+# ifdef POSIX_UNSPECIFIED
  4.3276 -+  /* Make LIM point to the end of (one byte past) the current field.  */
  4.3277 -+  if (tab_length)
  4.3278 -+    {
  4.3279 -+      char *newlim, *p;
  4.3280 -+
  4.3281 -+      newlim = NULL;
  4.3282 -+      for (p = ptr; p < lim;)
  4.3283 -+         {
  4.3284 -+          if (memcmp (p, tab, tab_length) == 0)
  4.3285 -+            {
  4.3286 -+              newlim = p;
  4.3287 -+              break;
  4.3288 -+            }
  4.3289 -+
  4.3290 -+          GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3291 -+          p += mblength;
  4.3292 -+        }
  4.3293 -+    }
  4.3294 -+  else
  4.3295 -+    {
  4.3296 -+      char *newlim;
  4.3297 -+      newlim = ptr;
  4.3298 -+
  4.3299 -+      while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength))
  4.3300 -+        newlim += mblength;
  4.3301 -+      if (ptr < lim)
  4.3302 -+        {
  4.3303 -+          GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3304 -+          ptr += mblength;
  4.3305 -+        }
  4.3306 -+      while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength))
  4.3307 -+        newlim += mblength;
  4.3308 -+      lim = newlim;
  4.3309 -+    }
  4.3310 -+# endif
  4.3311 -+
  4.3312 -+  if (echar != 0)
  4.3313 -+  {
  4.3314 -+    /* If we're skipping leading blanks, don't start counting characters
  4.3315 -+     *      until after skipping past any leading blanks.  */
  4.3316 -+    if (key->skipeblanks)
  4.3317 -+      while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  4.3318 -+        ptr += mblength;
  4.3319 -+
  4.3320 -+    memset (&state, '\0', sizeof(mbstate_t));
  4.3321 -+
  4.3322 -+    /* Advance PTR by ECHAR (if possible), but no further than LIM.  */
  4.3323 -+    for (i = 0; i < echar; i++)
  4.3324 -+     {
  4.3325 -+        GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  4.3326 -+
  4.3327 -+        if (ptr + mblength > lim)
  4.3328 -+          break;
  4.3329 -+        else
  4.3330 -+          ptr += mblength;
  4.3331 -+      }
  4.3332 -+  }
  4.3333 -+
  4.3334 -+  return ptr;
  4.3335 -+}
  4.3336 -+#endif
  4.3337 -+
  4.3338 -+static void
  4.3339 -+skipblanks_uni (char **ptr, char *lim)
  4.3340 -+{
  4.3341 -+  while (*ptr < lim && blanks[to_uchar (**ptr)])
  4.3342 -+    ++(*ptr);
  4.3343 -+}
  4.3344 -+
  4.3345 -+#if HAVE_MBRTOWC
  4.3346 -+static void
  4.3347 -+skipblanks_mb (char **ptr, char *lim)
  4.3348 -+{
  4.3349 -+  size_t mblength;
  4.3350 -+  while (*ptr < lim && ismbblank (*ptr, lim - *ptr, &mblength))
  4.3351 -+    (*ptr) += mblength;
  4.3352 -+}
  4.3353 -+#endif
  4.3354 -+
  4.3355 - /* Fill BUF reading from FP, moving buf->left bytes from the end
  4.3356 -    of buf->buf to the beginning first.  If EOF is reached and the
  4.3357 -    file wasn't terminated by a newline, supply one.  Set up BUF's line
  4.3358 -@@ -1823,8 +2155,22 @@ fillbuf (struct buffer *buf, FILE *fp, c
  4.3359 -                   else
  4.3360 -                     {
  4.3361 -                       if (key->skipsblanks)
  4.3362 --                        while (blanks[to_uchar (*line_start)])
  4.3363 --                          line_start++;
  4.3364 -+                        {
  4.3365 -+#if HAVE_MBRTOWC
  4.3366 -+                          if (MB_CUR_MAX > 1)
  4.3367 -+                            {
  4.3368 -+                              size_t mblength;
  4.3369 -+                              while (line_start < line->keylim &&
  4.3370 -+                                     ismbblank (line_start,
  4.3371 -+                                                line->keylim - line_start,
  4.3372 -+                                                &mblength))
  4.3373 -+                                line_start += mblength;
  4.3374 -+                            }
  4.3375 -+                          else
  4.3376 -+#endif
  4.3377 -+                          while (blanks[to_uchar (*line_start)])
  4.3378 -+                            line_start++;
  4.3379 -+                        }
  4.3380 -                       line->keybeg = line_start;
  4.3381 -                     }
  4.3382 -                 }
  4.3383 -@@ -1958,12 +2304,10 @@ find_unit_order (char const *number)
  4.3384 -        <none/unknown> < K/k < M < G < T < P < E < Z < Y  */
  4.3385 - 
  4.3386 - static int
  4.3387 --human_numcompare (char const *a, char const *b)
  4.3388 -+human_numcompare (char *a, char *b)
  4.3389 - {
  4.3390 --  while (blanks[to_uchar (*a)])
  4.3391 --    a++;
  4.3392 --  while (blanks[to_uchar (*b)])
  4.3393 --    b++;
  4.3394 -+  skipblanks(&a, a + strlen(a));
  4.3395 -+  skipblanks(&b, b + strlen(b));
  4.3396 - 
  4.3397 -   int diff = find_unit_order (a) - find_unit_order (b);
  4.3398 -   return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep));
  4.3399 -@@ -1974,7 +2318,7 @@ human_numcompare (char const *a, char co
  4.3400 -    hideously fast. */
  4.3401 - 
  4.3402 - static int
  4.3403 --numcompare (char const *a, char const *b)
  4.3404 -+numcompare_uni (const char *a, const char *b)
  4.3405 - {
  4.3406 -   while (blanks[to_uchar (*a)])
  4.3407 -     a++;
  4.3408 -@@ -1984,6 +2328,25 @@ numcompare (char const *a, char const *b
  4.3409 -   return strnumcmp (a, b, decimal_point, thousands_sep);
  4.3410 - }
  4.3411 - 
  4.3412 -+#if HAVE_MBRTOWC
  4.3413 -+static int
  4.3414 -+numcompare_mb (const char *a, const char *b)
  4.3415 -+{
  4.3416 -+  size_t mblength, len;
  4.3417 -+  len = strlen (a); /* okay for UTF-8 */
  4.3418 -+  while (*a && ismbblank (a, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
  4.3419 -+    {
  4.3420 -+      a += mblength;
  4.3421 -+      len -= mblength;
  4.3422 -+    }
  4.3423 -+  len = strlen (b); /* okay for UTF-8 */
  4.3424 -+  while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
  4.3425 -+    b += mblength;
  4.3426 -+
  4.3427 -+  return strnumcmp (a, b, decimal_point, thousands_sep);
  4.3428 -+}
  4.3429 -+#endif /* HAV_EMBRTOWC */
  4.3430 -+
  4.3431 - /* Work around a problem whereby the long double value returned by glibc's
  4.3432 -    strtold ("NaN", ...) contains uninitialized bits: clear all bytes of
  4.3433 -    A and B before calling strtold.  FIXME: remove this function once
  4.3434 -@@ -2034,7 +2397,7 @@ general_numcompare (char const *sa, char
  4.3435 -    Return 0 if the name in S is not recognized.  */
  4.3436 - 
  4.3437 - static int
  4.3438 --getmonth (char const *month, char **ea)
  4.3439 -+getmonth_uni (char const *month, size_t len, char **ea)
  4.3440 - {
  4.3441 -   size_t lo = 0;
  4.3442 -   size_t hi = MONTHS_PER_YEAR;
  4.3443 -@@ -2310,15 +2673,14 @@ debug_key (struct line const *line, stru
  4.3444 -           char saved = *lim;
  4.3445 -           *lim = '\0';
  4.3446 - 
  4.3447 --          while (blanks[to_uchar (*beg)])
  4.3448 --            beg++;
  4.3449 -+          skipblanks (&beg, lim);
  4.3450 - 
  4.3451 -           char *tighter_lim = beg;
  4.3452 - 
  4.3453 -           if (lim < beg)
  4.3454 -             tighter_lim = lim;
  4.3455 -           else if (key->month)
  4.3456 --            getmonth (beg, &tighter_lim);
  4.3457 -+            getmonth (beg, lim-beg, &tighter_lim);
  4.3458 -           else if (key->general_numeric)
  4.3459 -             ignore_value (strtold (beg, &tighter_lim));
  4.3460 -           else if (key->numeric || key->human_numeric)
  4.3461 -@@ -2452,7 +2814,7 @@ key_warnings (struct keyfield const *gke
  4.3462 -       /* Warn about significant leading blanks.  */
  4.3463 -       bool implicit_skip = key_numeric (key) || key->month;
  4.3464 -       bool line_offset = key->eword == 0 && key->echar != 0; /* -k1.x,1.y  */
  4.3465 --      if (!zero_width && !gkey_only && tab == TAB_DEFAULT && !line_offset
  4.3466 -+      if (!zero_width && !gkey_only && !tab_length && !line_offset
  4.3467 -           && ((!key->skipsblanks && !implicit_skip)
  4.3468 -               || (!key->skipsblanks && key->schar)
  4.3469 -               || (!key->skipeblanks && key->echar)))
  4.3470 -@@ -2510,11 +2872,87 @@ key_warnings (struct keyfield const *gke
  4.3471 -     error (0, 0, _("option '-r' only applies to last-resort comparison"));
  4.3472 - }
  4.3473 - 
  4.3474 -+#if HAVE_MBRTOWC
  4.3475 -+static int
  4.3476 -+getmonth_mb (const char *s, size_t len, char **ea)
  4.3477 -+{
  4.3478 -+  char *month;
  4.3479 -+  register size_t i;
  4.3480 -+  register int lo = 0, hi = MONTHS_PER_YEAR, result;
  4.3481 -+  char *tmp;
  4.3482 -+  size_t wclength, mblength;
  4.3483 -+  const char *pp;
  4.3484 -+  const wchar_t *wpp;
  4.3485 -+  wchar_t *month_wcs;
  4.3486 -+  mbstate_t state;
  4.3487 -+
  4.3488 -+  while (len > 0 && ismbblank (s, len, &mblength))
  4.3489 -+    {
  4.3490 -+      s += mblength;
  4.3491 -+      len -= mblength;
  4.3492 -+    }
  4.3493 -+
  4.3494 -+  if (len == 0)
  4.3495 -+    return 0;
  4.3496 -+
  4.3497 -+  if (SIZE_MAX - len < 1)
  4.3498 -+    xalloc_die ();
  4.3499 -+
  4.3500 -+  month = (char *) xnmalloc (len + 1, MB_CUR_MAX);
  4.3501 -+
  4.3502 -+  pp = tmp = (char *) xnmalloc (len + 1, MB_CUR_MAX);
  4.3503 -+  memcpy (tmp, s, len);
  4.3504 -+  tmp[len] = '\0';
  4.3505 -+  wpp = month_wcs = (wchar_t *) xnmalloc (len + 1, sizeof (wchar_t));
  4.3506 -+  memset (&state, '\0', sizeof (mbstate_t));
  4.3507 -+
  4.3508 -+  wclength = mbsrtowcs (month_wcs, &pp, len + 1, &state);
  4.3509 -+  if (wclength == (size_t)-1 || pp != NULL)
  4.3510 -+    error (SORT_FAILURE, 0, _("Invalid multibyte input %s."), quote(s));
  4.3511 -+
  4.3512 -+  for (i = 0; i < wclength; i++)
  4.3513 -+    {
  4.3514 -+      month_wcs[i] = towupper(month_wcs[i]);
  4.3515 -+      if (iswblank (month_wcs[i]))
  4.3516 -+        {
  4.3517 -+          month_wcs[i] = L'\0';
  4.3518 -+          break;
  4.3519 -+        }
  4.3520 -+    }
  4.3521 -+
  4.3522 -+  mblength = wcsrtombs (month, &wpp, (len + 1) * MB_CUR_MAX, &state);
  4.3523 -+  assert (mblength != (-1) && wpp == NULL);
  4.3524 -+
  4.3525 -+  do
  4.3526 -+    {
  4.3527 -+      int ix = (lo + hi) / 2;
  4.3528 -+
  4.3529 -+      if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0)
  4.3530 -+        hi = ix;
  4.3531 -+      else
  4.3532 -+        lo = ix;
  4.3533 -+    }
  4.3534 -+  while (hi - lo > 1);
  4.3535 -+
  4.3536 -+  result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name))
  4.3537 -+      ? monthtab[lo].val : 0);
  4.3538 -+
  4.3539 -+  if (ea && result)
  4.3540 -+     *ea = (char*) s + strlen (monthtab[lo].name);
  4.3541 -+
  4.3542 -+  free (month);
  4.3543 -+  free (tmp);
  4.3544 -+  free (month_wcs);
  4.3545 -+
  4.3546 -+  return result;
  4.3547 -+}
  4.3548 -+#endif
  4.3549 -+
  4.3550 - /* Compare two lines A and B trying every key in sequence until there
  4.3551 -    are no more keys or a difference is found. */
  4.3552 - 
  4.3553 - static int
  4.3554 --keycompare (struct line const *a, struct line const *b)
  4.3555 -+keycompare_uni (const struct line *a, const struct line *b)
  4.3556 - {
  4.3557 -   struct keyfield *key = keylist;
  4.3558 - 
  4.3559 -@@ -2599,7 +3037,7 @@ keycompare (struct line const *a, struct
  4.3560 -           else if (key->human_numeric)
  4.3561 -             diff = human_numcompare (ta, tb);
  4.3562 -           else if (key->month)
  4.3563 --            diff = getmonth (ta, NULL) - getmonth (tb, NULL);
  4.3564 -+            diff = getmonth (ta, tlena, NULL) - getmonth (tb, tlenb, NULL);
  4.3565 -           else if (key->random)
  4.3566 -             diff = compare_random (ta, tlena, tb, tlenb);
  4.3567 -           else if (key->version)
  4.3568 -@@ -2715,6 +3153,211 @@ keycompare (struct line const *a, struct
  4.3569 -   return key->reverse ? -diff : diff;
  4.3570 - }
  4.3571 - 
  4.3572 -+#if HAVE_MBRTOWC
  4.3573 -+static int
  4.3574 -+keycompare_mb (const struct line *a, const struct line *b)
  4.3575 -+{
  4.3576 -+  struct keyfield *key = keylist;
  4.3577 -+
  4.3578 -+  /* For the first iteration only, the key positions have been
  4.3579 -+     precomputed for us. */
  4.3580 -+  char *texta = a->keybeg;
  4.3581 -+  char *textb = b->keybeg;
  4.3582 -+  char *lima = a->keylim;
  4.3583 -+  char *limb = b->keylim;
  4.3584 -+
  4.3585 -+  size_t mblength_a, mblength_b;
  4.3586 -+  wchar_t wc_a, wc_b;
  4.3587 -+  mbstate_t state_a, state_b;
  4.3588 -+
  4.3589 -+  int diff = 0;
  4.3590 -+
  4.3591 -+  memset (&state_a, '\0', sizeof(mbstate_t));
  4.3592 -+  memset (&state_b, '\0', sizeof(mbstate_t));
  4.3593 -+  /* Ignore keys with start after end.  */
  4.3594 -+  if (a->keybeg - a->keylim > 0)
  4.3595 -+    return 0;
  4.3596 -+
  4.3597 -+
  4.3598 -+              /* Ignore and/or translate chars before comparing.  */
  4.3599 -+# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE)        \
  4.3600 -+  do                                                                        \
  4.3601 -+    {                                                                        \
  4.3602 -+      wchar_t uwc;                                                        \
  4.3603 -+      char mbc[MB_LEN_MAX];                                                \
  4.3604 -+      mbstate_t state_wc;                                                \
  4.3605 -+                                                                        \
  4.3606 -+      for (NEW_LEN = i = 0; i < LEN;)                                        \
  4.3607 -+        {                                                                \
  4.3608 -+          mbstate_t state_bak;                                                \
  4.3609 -+                                                                        \
  4.3610 -+          state_bak = STATE;                                                \
  4.3611 -+          MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE);                \
  4.3612 -+                                                                        \
  4.3613 -+          if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1                \
  4.3614 -+              || MBLENGTH == 0)                                                \
  4.3615 -+            {                                                                \
  4.3616 -+              if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1)        \
  4.3617 -+                STATE = state_bak;                                        \
  4.3618 -+              if (!ignore)                                                \
  4.3619 -+                COPY[NEW_LEN++] = TEXT[i];                                \
  4.3620 -+              i++;                                                         \
  4.3621 -+              continue;                                                        \
  4.3622 -+            }                                                                \
  4.3623 -+                                                                        \
  4.3624 -+          if (ignore)                                                        \
  4.3625 -+            {                                                                \
  4.3626 -+              if ((ignore == nonprinting && !iswprint (WC))                \
  4.3627 -+                   || (ignore == nondictionary                                \
  4.3628 -+                       && !iswalnum (WC) && !iswblank (WC)))                \
  4.3629 -+                {                                                        \
  4.3630 -+                  i += MBLENGTH;                                        \
  4.3631 -+                  continue;                                                \
  4.3632 -+                }                                                        \
  4.3633 -+            }                                                                \
  4.3634 -+                                                                        \
  4.3635 -+          if (translate)                                                \
  4.3636 -+            {                                                                \
  4.3637 -+                                                                        \
  4.3638 -+              uwc = towupper(WC);                                        \
  4.3639 -+              if (WC == uwc)                                                \
  4.3640 -+                {                                                        \
  4.3641 -+                  memcpy (mbc, TEXT + i, MBLENGTH);                        \
  4.3642 -+                  i += MBLENGTH;                                        \
  4.3643 -+                }                                                        \
  4.3644 -+              else                                                        \
  4.3645 -+                {                                                        \
  4.3646 -+                  i += MBLENGTH;                                        \
  4.3647 -+                  WC = uwc;                                                \
  4.3648 -+                  memset (&state_wc, '\0', sizeof (mbstate_t));                \
  4.3649 -+                                                                        \
  4.3650 -+                  MBLENGTH = wcrtomb (mbc, WC, &state_wc);                \
  4.3651 -+                  assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0);        \
  4.3652 -+                }                                                        \
  4.3653 -+                                                                        \
  4.3654 -+              for (j = 0; j < MBLENGTH; j++)                                \
  4.3655 -+                COPY[NEW_LEN++] = mbc[j];                                \
  4.3656 -+            }                                                                \
  4.3657 -+          else                                                                \
  4.3658 -+            for (j = 0; j < MBLENGTH; j++)                                \
  4.3659 -+              COPY[NEW_LEN++] = TEXT[i++];                                \
  4.3660 -+        }                                                                \
  4.3661 -+      COPY[NEW_LEN] = '\0';                                                \
  4.3662 -+    }                                                                        \
  4.3663 -+  while (0)
  4.3664 -+
  4.3665 -+      /* Actually compare the fields. */
  4.3666 -+
  4.3667 -+  for (;;)
  4.3668 -+    {
  4.3669 -+      /* Find the lengths. */
  4.3670 -+      size_t lena = lima <= texta ? 0 : lima - texta;
  4.3671 -+      size_t lenb = limb <= textb ? 0 : limb - textb;
  4.3672 -+
  4.3673 -+      char enda IF_LINT (= 0);
  4.3674 -+      char endb IF_LINT (= 0);
  4.3675 -+
  4.3676 -+      char const *translate = key->translate;
  4.3677 -+      bool const *ignore = key->ignore;
  4.3678 -+
  4.3679 -+      if (ignore || translate)
  4.3680 -+        {
  4.3681 -+          if (SIZE_MAX - lenb - 2 < lena)
  4.3682 -+            xalloc_die ();
  4.3683 -+          char *copy_a = (char *) xnmalloc (lena + lenb + 2, MB_CUR_MAX);
  4.3684 -+          char *copy_b = copy_a + lena * MB_CUR_MAX + 1;
  4.3685 -+          size_t new_len_a, new_len_b;
  4.3686 -+          size_t i, j;
  4.3687 -+
  4.3688 -+          IGNORE_CHARS (new_len_a, lena, texta, copy_a,
  4.3689 -+                        wc_a, mblength_a, state_a);
  4.3690 -+          IGNORE_CHARS (new_len_b, lenb, textb, copy_b,
  4.3691 -+                        wc_b, mblength_b, state_b);
  4.3692 -+          texta = copy_a; textb = copy_b;
  4.3693 -+          lena = new_len_a; lenb = new_len_b;
  4.3694 -+        }
  4.3695 -+      else
  4.3696 -+        {
  4.3697 -+          /* Use the keys in-place, temporarily null-terminated.  */
  4.3698 -+          enda = texta[lena]; texta[lena] = '\0';
  4.3699 -+          endb = textb[lenb]; textb[lenb] = '\0';
  4.3700 -+        }
  4.3701 -+
  4.3702 -+      if (key->random)
  4.3703 -+        diff = compare_random (texta, lena, textb, lenb);
  4.3704 -+      else if (key->numeric | key->general_numeric | key->human_numeric)
  4.3705 -+        {
  4.3706 -+          char savea = *lima, saveb = *limb;
  4.3707 -+
  4.3708 -+          *lima = *limb = '\0';
  4.3709 -+          diff = (key->numeric ? numcompare (texta, textb)
  4.3710 -+                  : key->general_numeric ? general_numcompare (texta, textb)
  4.3711 -+                  : human_numcompare (texta, textb));
  4.3712 -+          *lima = savea, *limb = saveb;
  4.3713 -+        }
  4.3714 -+      else if (key->version)
  4.3715 -+        diff = filevercmp (texta, textb);
  4.3716 -+      else if (key->month)
  4.3717 -+        diff = getmonth (texta, lena, NULL) - getmonth (textb, lenb, NULL);
  4.3718 -+      else if (lena == 0)
  4.3719 -+        diff = - NONZERO (lenb);
  4.3720 -+      else if (lenb == 0)
  4.3721 -+        diff = 1;
  4.3722 -+      else if (hard_LC_COLLATE && !folding)
  4.3723 -+        {
  4.3724 -+          diff = xmemcoll0 (texta, lena + 1, textb, lenb + 1);
  4.3725 -+        }
  4.3726 -+      else
  4.3727 -+        {
  4.3728 -+          diff = memcmp (texta, textb, MIN (lena, lenb));
  4.3729 -+          if (diff == 0)
  4.3730 -+            diff = lena < lenb ? -1 : lena != lenb;
  4.3731 -+        }
  4.3732 -+
  4.3733 -+      if (ignore || translate)
  4.3734 -+        free (texta);
  4.3735 -+      else
  4.3736 -+        {
  4.3737 -+          texta[lena] = enda;
  4.3738 -+          textb[lenb] = endb;
  4.3739 -+        }
  4.3740 -+
  4.3741 -+      if (diff)
  4.3742 -+        goto not_equal;
  4.3743 -+
  4.3744 -+      key = key->next;
  4.3745 -+      if (! key)
  4.3746 -+        break;
  4.3747 -+
  4.3748 -+      /* Find the beginning and limit of the next field.  */
  4.3749 -+      if (key->eword != -1)
  4.3750 -+        lima = limfield (a, key), limb = limfield (b, key);
  4.3751 -+      else
  4.3752 -+        lima = a->text + a->length - 1, limb = b->text + b->length - 1;
  4.3753 -+
  4.3754 -+      if (key->sword != -1)
  4.3755 -+        texta = begfield (a, key), textb = begfield (b, key);
  4.3756 -+      else
  4.3757 -+        {
  4.3758 -+          texta = a->text, textb = b->text;
  4.3759 -+          if (key->skipsblanks)
  4.3760 -+            {
  4.3761 -+              while (texta < lima && ismbblank (texta, lima - texta, &mblength_a))
  4.3762 -+                texta += mblength_a;
  4.3763 -+              while (textb < limb && ismbblank (textb, limb - textb, &mblength_b))
  4.3764 -+                textb += mblength_b;
  4.3765 -+            }
  4.3766 -+        }
  4.3767 -+    }
  4.3768 -+
  4.3769 -+not_equal:
  4.3770 -+  if (key && key->reverse)
  4.3771 -+    return -diff;
  4.3772 -+  else
  4.3773 -+    return diff;
  4.3774 -+}
  4.3775 -+#endif
  4.3776 -+
  4.3777 - /* Compare two lines A and B, returning negative, zero, or positive
  4.3778 -    depending on whether A compares less than, equal to, or greater than B. */
  4.3779 - 
  4.3780 -@@ -2742,7 +3385,7 @@ compare (struct line const *a, struct li
  4.3781 -     diff = - NONZERO (blen);
  4.3782 -   else if (blen == 0)
  4.3783 -     diff = 1;
  4.3784 --  else if (hard_LC_COLLATE)
  4.3785 -+  else if (hard_LC_COLLATE && !folding)
  4.3786 -     {
  4.3787 -       /* Note xmemcoll0 is a performance enhancement as
  4.3788 -          it will not unconditionally write '\0' after the
  4.3789 -@@ -4139,6 +4782,7 @@ set_ordering (char const *s, struct keyf
  4.3790 -           break;
  4.3791 -         case 'f':
  4.3792 -           key->translate = fold_toupper;
  4.3793 -+          folding = true;
  4.3794 -           break;
  4.3795 -         case 'g':
  4.3796 -           key->general_numeric = true;
  4.3797 -@@ -4218,7 +4862,7 @@ main (int argc, char **argv)
  4.3798 -   initialize_exit_failure (SORT_FAILURE);
  4.3799 - 
  4.3800 -   hard_LC_COLLATE = hard_locale (LC_COLLATE);
  4.3801 --#if HAVE_NL_LANGINFO
  4.3802 -+#if HAVE_LANGINFO_CODESET
  4.3803 -   hard_LC_TIME = hard_locale (LC_TIME);
  4.3804 - #endif
  4.3805 - 
  4.3806 -@@ -4239,6 +4883,29 @@ main (int argc, char **argv)
  4.3807 -       thousands_sep = -1;
  4.3808 -   }
  4.3809 - 
  4.3810 -+#if HAVE_MBRTOWC
  4.3811 -+  if (MB_CUR_MAX > 1)
  4.3812 -+    {
  4.3813 -+      inittables = inittables_mb;
  4.3814 -+      begfield = begfield_mb;
  4.3815 -+      limfield = limfield_mb;
  4.3816 -+      skipblanks = skipblanks_mb;
  4.3817 -+      getmonth = getmonth_mb;
  4.3818 -+      keycompare = keycompare_mb;
  4.3819 -+      numcompare = numcompare_mb;
  4.3820 -+    }
  4.3821 -+  else
  4.3822 -+#endif
  4.3823 -+    {
  4.3824 -+      inittables = inittables_uni;
  4.3825 -+      begfield = begfield_uni;
  4.3826 -+      limfield = limfield_uni;
  4.3827 -+      skipblanks = skipblanks_uni;
  4.3828 -+      getmonth = getmonth_uni;
  4.3829 -+      keycompare = keycompare_uni;
  4.3830 -+      numcompare = numcompare_uni;
  4.3831 -+    }
  4.3832 -+
  4.3833 -   have_read_stdin = false;
  4.3834 -   inittables ();
  4.3835 - 
  4.3836 -@@ -4513,13 +5180,34 @@ main (int argc, char **argv)
  4.3837 - 
  4.3838 -         case 't':
  4.3839 -           {
  4.3840 --            char newtab = optarg[0];
  4.3841 --            if (! newtab)
  4.3842 -+            char newtab[MB_LEN_MAX + 1];
  4.3843 -+            size_t newtab_length = 1;
  4.3844 -+            strncpy (newtab, optarg, MB_LEN_MAX);
  4.3845 -+            if (! newtab[0])
  4.3846 -               die (SORT_FAILURE, 0, _("empty tab"));
  4.3847 --            if (optarg[1])
  4.3848 -+#if HAVE_MBRTOWC
  4.3849 -+            if (MB_CUR_MAX > 1)
  4.3850 -+              {
  4.3851 -+                wchar_t wc;
  4.3852 -+                mbstate_t state;
  4.3853 -+
  4.3854 -+                memset (&state, '\0', sizeof (mbstate_t));
  4.3855 -+                newtab_length = mbrtowc (&wc, newtab, strnlen (newtab,
  4.3856 -+                                                               MB_LEN_MAX),
  4.3857 -+                                         &state);
  4.3858 -+                switch (newtab_length)
  4.3859 -+                  {
  4.3860 -+                  case (size_t) -1:
  4.3861 -+                  case (size_t) -2:
  4.3862 -+                  case 0:
  4.3863 -+                    newtab_length = 1;
  4.3864 -+                  }
  4.3865 -+              }
  4.3866 -+#endif
  4.3867 -+            if (newtab_length == 1 && optarg[1])
  4.3868 -               {
  4.3869 -                 if (STREQ (optarg, "\\0"))
  4.3870 --                  newtab = '\0';
  4.3871 -+                  newtab[0] = '\0';
  4.3872 -                 else
  4.3873 -                   {
  4.3874 -                     /* Provoke with 'sort -txx'.  Complain about
  4.3875 -@@ -4530,9 +5218,11 @@ main (int argc, char **argv)
  4.3876 -                          quote (optarg));
  4.3877 -                   }
  4.3878 -               }
  4.3879 --            if (tab != TAB_DEFAULT && tab != newtab)
  4.3880 -+            if (tab_length && (tab_length != newtab_length
  4.3881 -+                        || memcmp (tab, newtab, tab_length) != 0))
  4.3882 -               die (SORT_FAILURE, 0, _("incompatible tabs"));
  4.3883 --            tab = newtab;
  4.3884 -+            memcpy (tab, newtab, newtab_length);
  4.3885 -+            tab_length = newtab_length;
  4.3886 -           }
  4.3887 -           break;
  4.3888 - 
  4.3889 -@@ -4770,12 +5460,10 @@ main (int argc, char **argv)
  4.3890 -       sort (files, nfiles, outfile, nthreads);
  4.3891 -     }
  4.3892 - 
  4.3893 --#ifdef lint
  4.3894 -   if (files_from)
  4.3895 -     readtokens0_free (&tok);
  4.3896 -   else
  4.3897 -     free (files);
  4.3898 --#endif
  4.3899 - 
  4.3900 -   if (have_read_stdin && fclose (stdin) == EOF)
  4.3901 -     sort_die (_("close failed"), "-");
  4.3902 -diff -Naurp coreutils-8.27-orig/src/unexpand.c coreutils-8.27/src/unexpand.c
  4.3903 ---- coreutils-8.27-orig/src/unexpand.c	2017-01-01 16:34:24.000000000 -0600
  4.3904 -+++ coreutils-8.27/src/unexpand.c	2017-03-11 23:49:06.758133530 -0600
  4.3905 -@@ -38,6 +38,9 @@
  4.3906 - #include <stdio.h>
  4.3907 - #include <getopt.h>
  4.3908 - #include <sys/types.h>
  4.3909 -+
  4.3910 -+#include <mbfile.h>
  4.3911 -+
  4.3912 - #include "system.h"
  4.3913 - #include "die.h"
  4.3914 - #include "xstrndup.h"
  4.3915 -@@ -107,24 +110,47 @@ unexpand (void)
  4.3916 - {
  4.3917 -   /* Input stream.  */
  4.3918 -   FILE *fp = next_file (NULL);
  4.3919 -+  mb_file_t mbf;
  4.3920 - 
  4.3921 -   /* The array of pending blanks.  In non-POSIX locales, blanks can
  4.3922 -      include characters other than spaces, so the blanks must be
  4.3923 -      stored, not merely counted.  */
  4.3924 --  char *pending_blank;
  4.3925 -+  mbf_char_t *pending_blank;
  4.3926 -+  /* True if the starting locale is utf8.  */
  4.3927 -+  bool using_utf_locale;
  4.3928 -+
  4.3929 -+  /* True if the first file contains BOM header.  */
  4.3930 -+  bool found_bom;
  4.3931 -+  using_utf_locale=check_utf_locale();
  4.3932 - 
  4.3933 -   if (!fp)
  4.3934 -     return;
  4.3935 -+  mbf_init (mbf, fp);
  4.3936 -+  found_bom=check_bom(fp,&mbf);
  4.3937 - 
  4.3938 -+  if (using_utf_locale == false && found_bom == true)
  4.3939 -+  {
  4.3940 -+    /*try using some predefined locale */
  4.3941 -+
  4.3942 -+    if (set_utf_locale () != 0)
  4.3943 -+    {
  4.3944 -+      error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
  4.3945 -+    }
  4.3946 -+  }
  4.3947 -   /* The worst case is a non-blank character, then one blank, then a
  4.3948 -      tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so
  4.3949 -      allocate MAX_COLUMN_WIDTH bytes to store the blanks.  */
  4.3950 --  pending_blank = xmalloc (max_column_width);
  4.3951 -+  pending_blank = xmalloc (max_column_width * sizeof (mbf_char_t));
  4.3952 -+
  4.3953 -+  if (found_bom == true)
  4.3954 -+  {
  4.3955 -+    print_bom();
  4.3956 -+  }
  4.3957 - 
  4.3958 -   while (true)
  4.3959 -     {
  4.3960 -       /* Input character, or EOF.  */
  4.3961 --      int c;
  4.3962 -+      mbf_char_t c;
  4.3963 - 
  4.3964 -       /* If true, perform translations.  */
  4.3965 -       bool convert = true;
  4.3966 -@@ -158,12 +184,44 @@ unexpand (void)
  4.3967 - 
  4.3968 -       do
  4.3969 -         {
  4.3970 --          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
  4.3971 --            continue;
  4.3972 -+          while (true) {
  4.3973 -+            mbf_getc (c, mbf);
  4.3974 -+            if ((mb_iseof (c)) && (fp = next_file (fp)))
  4.3975 -+              {
  4.3976 -+                mbf_init (mbf, fp);
  4.3977 -+                if (fp!=NULL)
  4.3978 -+                {
  4.3979 -+                  if (check_bom(fp,&mbf)==true)
  4.3980 -+                  {
  4.3981 -+                    /*Not the first file - check BOM header*/
  4.3982 -+                    if (using_utf_locale==false && found_bom==false)
  4.3983 -+                    {
  4.3984 -+                      /*BOM header in subsequent file but not in the first one. */
  4.3985 -+                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
  4.3986 -+                    }
  4.3987 -+                  }
  4.3988 -+                  else
  4.3989 -+                  {
  4.3990 -+                    if(using_utf_locale==false && found_bom==true)
  4.3991 -+                    {
  4.3992 -+                      /*First file conatined BOM header - locale was switched to UTF
  4.3993 -+                      /*all subsequent files should contain BOM. */
  4.3994 -+                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
  4.3995 -+                    }
  4.3996 -+                  }
  4.3997 -+                }
  4.3998 -+                continue;
  4.3999 -+              }
  4.4000 -+            else
  4.4001 -+              {
  4.4002 -+                break;
  4.4003 -+              }
  4.4004 -+            }
  4.4005 -+
  4.4006 - 
  4.4007 -           if (convert)
  4.4008 -             {
  4.4009 --              bool blank = !! isblank (c);
  4.4010 -+              bool blank = mb_isblank (c);
  4.4011 - 
  4.4012 -               if (blank)
  4.4013 -                 {
  4.4014 -@@ -180,16 +238,16 @@ unexpand (void)
  4.4015 -                       if (next_tab_column < column)
  4.4016 -                         die (EXIT_FAILURE, 0, _("input line is too long"));
  4.4017 - 
  4.4018 --                      if (c == '\t')
  4.4019 -+                      if (mb_iseq (c, '\t'))
  4.4020 -                         {
  4.4021 -                           column = next_tab_column;
  4.4022 - 
  4.4023 -                           if (pending)
  4.4024 --                            pending_blank[0] = '\t';
  4.4025 -+                            mb_setascii (&pending_blank[0], '\t');
  4.4026 -                         }
  4.4027 -                       else
  4.4028 -                         {
  4.4029 --                          column++;
  4.4030 -+                          column += mb_width (c);
  4.4031 - 
  4.4032 -                           if (! (prev_blank && column == next_tab_column))
  4.4033 -                             {
  4.4034 -@@ -197,13 +255,14 @@ unexpand (void)
  4.4035 -                                  will be replaced by tabs.  */
  4.4036 -                               if (column == next_tab_column)
  4.4037 -                                 one_blank_before_tab_stop = true;
  4.4038 --                              pending_blank[pending++] = c;
  4.4039 -+                              mb_copy (&pending_blank[pending++], &c);
  4.4040 -                               prev_blank = true;
  4.4041 -                               continue;
  4.4042 -                             }
  4.4043 - 
  4.4044 -                           /* Replace the pending blanks by a tab or two.  */
  4.4045 --                          pending_blank[0] = c = '\t';
  4.4046 -+                          mb_setascii (&c, '\t');
  4.4047 -+                          mb_setascii (&pending_blank[0], '\t');
  4.4048 -                         }
  4.4049 - 
  4.4050 -                       /* Discard pending blanks, unless it was a single
  4.4051 -@@ -211,7 +270,7 @@ unexpand (void)
  4.4052 -                       pending = one_blank_before_tab_stop;
  4.4053 -                     }
  4.4054 -                 }
  4.4055 --              else if (c == '\b')
  4.4056 -+              else if (mb_iseq (c, '\b'))
  4.4057 -                 {
  4.4058 -                   /* Go back one column, and force recalculation of the
  4.4059 -                      next tab stop.  */
  4.4060 -@@ -219,9 +278,9 @@ unexpand (void)
  4.4061 -                   next_tab_column = column;
  4.4062 -                   tab_index -= !!tab_index;
  4.4063 -                 }
  4.4064 --              else
  4.4065 -+              else if (!mb_iseq (c, '\n'))
  4.4066 -                 {
  4.4067 --                  column++;
  4.4068 -+                  column += mb_width (c);
  4.4069 -                   if (!column)
  4.4070 -                     die (EXIT_FAILURE, 0, _("input line is too long"));
  4.4071 -                 }
  4.4072 -@@ -229,8 +288,11 @@ unexpand (void)
  4.4073 -               if (pending)
  4.4074 -                 {
  4.4075 -                   if (pending > 1 && one_blank_before_tab_stop)
  4.4076 --                    pending_blank[0] = '\t';
  4.4077 --                  if (fwrite (pending_blank, 1, pending, stdout) != pending)
  4.4078 -+                    mb_setascii (&pending_blank[0], '\t');
  4.4079 -+
  4.4080 -+                  for (int n = 0; n < pending; ++n)
  4.4081 -+                    mb_putc (pending_blank[n], stdout);
  4.4082 -+                  if (ferror (stdout))
  4.4083 -                     die (EXIT_FAILURE, errno, _("write error"));
  4.4084 -                   pending = 0;
  4.4085 -                   one_blank_before_tab_stop = false;
  4.4086 -@@ -240,16 +302,17 @@ unexpand (void)
  4.4087 -               convert &= convert_entire_line || blank;
  4.4088 -             }
  4.4089 - 
  4.4090 --          if (c < 0)
  4.4091 -+          if (mb_iseof (c))
  4.4092 -             {
  4.4093 -               free (pending_blank);
  4.4094 -               return;
  4.4095 -             }
  4.4096 - 
  4.4097 --          if (putchar (c) < 0)
  4.4098 -+          mb_putc (c, stdout);
  4.4099 -+          if (ferror (stdout))
  4.4100 -             die (EXIT_FAILURE, errno, _("write error"));
  4.4101 -         }
  4.4102 --      while (c != '\n');
  4.4103 -+      while (!mb_iseq (c, '\n'));
  4.4104 -     }
  4.4105 - }
  4.4106 - 
  4.4107 -diff -Naurp coreutils-8.27-orig/src/uniq.c coreutils-8.27/src/uniq.c
  4.4108 ---- coreutils-8.27-orig/src/uniq.c	2017-01-01 16:34:24.000000000 -0600
  4.4109 -+++ coreutils-8.27/src/uniq.c	2017-03-11 23:47:13.098285938 -0600
  4.4110 -@@ -21,6 +21,17 @@
  4.4111 - #include <getopt.h>
  4.4112 - #include <sys/types.h>
  4.4113 - 
  4.4114 -+/* Get mbstate_t, mbrtowc(). */
  4.4115 -+#if HAVE_WCHAR_H
  4.4116 -+# include <wchar.h>
  4.4117 -+#endif
  4.4118 -+
  4.4119 -+/* Get isw* functions. */
  4.4120 -+#if HAVE_WCTYPE_H
  4.4121 -+# include <wctype.h>
  4.4122 -+#endif
  4.4123 -+#include <assert.h>
  4.4124 -+
  4.4125 - #include "system.h"
  4.4126 - #include "argmatch.h"
  4.4127 - #include "linebuffer.h"
  4.4128 -@@ -32,9 +43,21 @@
  4.4129 - #include "stdio--.h"
  4.4130 - #include "xmemcoll.h"
  4.4131 - #include "xstrtol.h"
  4.4132 --#include "memcasecmp.h"
  4.4133 -+#include "xmemcoll.h"
  4.4134 - #include "quote.h"
  4.4135 - 
  4.4136 -+/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
  4.4137 -+   installation; work around this configuration error.  */
  4.4138 -+#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
  4.4139 -+# define MB_LEN_MAX 16
  4.4140 -+#endif
  4.4141 -+
  4.4142 -+/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  4.4143 -+#if HAVE_MBRTOWC && defined mbstate_t
  4.4144 -+# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  4.4145 -+#endif
  4.4146 -+
  4.4147 -+
  4.4148 - /* The official name of this program (e.g., no 'g' prefix).  */
  4.4149 - #define PROGRAM_NAME "uniq"
  4.4150 - 
  4.4151 -@@ -144,6 +167,10 @@ enum
  4.4152 -   GROUP_OPTION = CHAR_MAX + 1
  4.4153 - };
  4.4154 - 
  4.4155 -+/* Function pointers. */
  4.4156 -+static char *
  4.4157 -+(*find_field) (struct linebuffer *line);
  4.4158 -+
  4.4159 - static struct option const longopts[] =
  4.4160 - {
  4.4161 -   {"count", no_argument, NULL, 'c'},
  4.4162 -@@ -260,7 +287,7 @@ size_opt (char const *opt, char const *m
  4.4163 -    return a pointer to the beginning of the line's field to be compared. */
  4.4164 - 
  4.4165 - static char * _GL_ATTRIBUTE_PURE
  4.4166 --find_field (struct linebuffer const *line)
  4.4167 -+find_field_uni (struct linebuffer *line)
  4.4168 - {
  4.4169 -   size_t count;
  4.4170 -   char const *lp = line->buffer;
  4.4171 -@@ -280,6 +307,83 @@ find_field (struct linebuffer const *lin
  4.4172 -   return line->buffer + i;
  4.4173 - }
  4.4174 - 
  4.4175 -+#if HAVE_MBRTOWC
  4.4176 -+
  4.4177 -+# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL)  \
  4.4178 -+  do                                                                        \
  4.4179 -+    {                                                                        \
  4.4180 -+      mbstate_t state_bak;                                                \
  4.4181 -+                                                                        \
  4.4182 -+      CONVFAIL = 0;                                                        \
  4.4183 -+      state_bak = *STATEP;                                                \
  4.4184 -+                                                                        \
  4.4185 -+      MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP);                \
  4.4186 -+                                                                        \
  4.4187 -+      switch (MBLENGTH)                                                        \
  4.4188 -+        {                                                                \
  4.4189 -+        case (size_t)-2:                                                \
  4.4190 -+        case (size_t)-1:                                                \
  4.4191 -+          *STATEP = state_bak;                                                \
  4.4192 -+          CONVFAIL++;                                                        \
  4.4193 -+          /* Fall through */                                                \
  4.4194 -+        case 0:                                                                \
  4.4195 -+          MBLENGTH = 1;                                                        \
  4.4196 -+        }                                                                \
  4.4197 -+    }                                                                        \
  4.4198 -+  while (0)
  4.4199 -+
  4.4200 -+static char *
  4.4201 -+find_field_multi (struct linebuffer *line)
  4.4202 -+{
  4.4203 -+  size_t count;
  4.4204 -+  char *lp = line->buffer;
  4.4205 -+  size_t size = line->length - 1;
  4.4206 -+  size_t pos;
  4.4207 -+  size_t mblength;
  4.4208 -+  wchar_t wc;
  4.4209 -+  mbstate_t *statep;
  4.4210 -+  int convfail = 0;
  4.4211 -+
  4.4212 -+  pos = 0;
  4.4213 -+  statep = &(line->state);
  4.4214 -+
  4.4215 -+  /* skip fields. */
  4.4216 -+  for (count = 0; count < skip_fields && pos < size; count++)
  4.4217 -+    {
  4.4218 -+      while (pos < size)
  4.4219 -+        {
  4.4220 -+          MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
  4.4221 -+
  4.4222 -+          if (convfail || !(iswblank (wc) || wc == '\n'))
  4.4223 -+            {
  4.4224 -+              pos += mblength;
  4.4225 -+              break;
  4.4226 -+            }
  4.4227 -+          pos += mblength;
  4.4228 -+        }
  4.4229 -+
  4.4230 -+      while (pos < size)
  4.4231 -+        {
  4.4232 -+          MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
  4.4233 -+
  4.4234 -+          if (!convfail && (iswblank (wc) || wc == '\n'))
  4.4235 -+            break;
  4.4236 -+
  4.4237 -+          pos += mblength;
  4.4238 -+        }
  4.4239 -+    }
  4.4240 -+
  4.4241 -+  /* skip fields. */
  4.4242 -+  for (count = 0; count < skip_chars && pos < size; count++)
  4.4243 -+    {
  4.4244 -+      MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
  4.4245 -+      pos += mblength;
  4.4246 -+    }
  4.4247 -+
  4.4248 -+  return lp + pos;
  4.4249 -+}
  4.4250 -+#endif
  4.4251 -+
  4.4252 - /* Return false if two strings OLD and NEW match, true if not.
  4.4253 -    OLD and NEW point not to the beginnings of the lines
  4.4254 -    but rather to the beginnings of the fields to compare.
  4.4255 -@@ -288,6 +392,8 @@ find_field (struct linebuffer const *lin
  4.4256 - static bool
  4.4257 - different (char *old, char *new, size_t oldlen, size_t newlen)
  4.4258 - {
  4.4259 -+  char *copy_old, *copy_new;
  4.4260 -+
  4.4261 -   if (check_chars < oldlen)
  4.4262 -     oldlen = check_chars;
  4.4263 -   if (check_chars < newlen)
  4.4264 -@@ -295,14 +401,103 @@ different (char *old, char *new, size_t
  4.4265 - 
  4.4266 -   if (ignore_case)
  4.4267 -     {
  4.4268 --      /* FIXME: This should invoke strcoll somehow.  */
  4.4269 --      return oldlen != newlen || memcasecmp (old, new, oldlen);
  4.4270 -+      size_t i;
  4.4271 -+
  4.4272 -+      copy_old = xmalloc (oldlen + 1);
  4.4273 -+      copy_new = xmalloc (oldlen + 1);
  4.4274 -+
  4.4275 -+      for (i = 0; i < oldlen; i++)
  4.4276 -+        {
  4.4277 -+          copy_old[i] = toupper (old[i]);
  4.4278 -+          copy_new[i] = toupper (new[i]);
  4.4279 -+        }
  4.4280 -+      bool rc = xmemcoll (copy_old, oldlen, copy_new, newlen);
  4.4281 -+      free (copy_old);
  4.4282 -+      free (copy_new);
  4.4283 -+      return rc;
  4.4284 -     }
  4.4285 --  else if (hard_LC_COLLATE)
  4.4286 --    return xmemcoll (old, oldlen, new, newlen) != 0;
  4.4287 -   else
  4.4288 --    return oldlen != newlen || memcmp (old, new, oldlen);
  4.4289 -+    {
  4.4290 -+      copy_old = (char *)old;
  4.4291 -+      copy_new = (char *)new;
  4.4292 -+    }
  4.4293 -+
  4.4294 -+  return xmemcoll (copy_old, oldlen, copy_new, newlen);
  4.4295 -+
  4.4296 -+}
  4.4297 -+
  4.4298 -+#if HAVE_MBRTOWC
  4.4299 -+static int
  4.4300 -+different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate)
  4.4301 -+{
  4.4302 -+  size_t i, j, chars;
  4.4303 -+  const char *str[2];
  4.4304 -+  char *copy[2];
  4.4305 -+  size_t len[2];
  4.4306 -+  mbstate_t state[2];
  4.4307 -+  size_t mblength;
  4.4308 -+  wchar_t wc, uwc;
  4.4309 -+  mbstate_t state_bak;
  4.4310 -+
  4.4311 -+  str[0] = old;
  4.4312 -+  str[1] = new;
  4.4313 -+  len[0] = oldlen;
  4.4314 -+  len[1] = newlen;
  4.4315 -+  state[0] = oldstate;
  4.4316 -+  state[1] = newstate;
  4.4317 -+
  4.4318 -+  for (i = 0; i < 2; i++)
  4.4319 -+    {
  4.4320 -+      copy[i] = xmalloc (len[i] + 1);
  4.4321 -+      memset (copy[i], '\0', len[i] + 1);
  4.4322 -+
  4.4323 -+      for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++)
  4.4324 -+        {
  4.4325 -+          state_bak = state[i];
  4.4326 -+          mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i]));
  4.4327 -+
  4.4328 -+          switch (mblength)
  4.4329 -+            {
  4.4330 -+            case (size_t)-1:
  4.4331 -+            case (size_t)-2:
  4.4332 -+              state[i] = state_bak;
  4.4333 -+              /* Fall through */
  4.4334 -+            case 0:
  4.4335 -+              mblength = 1;
  4.4336 -+              break;
  4.4337 -+
  4.4338 -+            default:
  4.4339 -+              if (ignore_case)
  4.4340 -+                {
  4.4341 -+                  uwc = towupper (wc);
  4.4342 -+
  4.4343 -+                  if (uwc != wc)
  4.4344 -+                    {
  4.4345 -+                      mbstate_t state_wc;
  4.4346 -+                      size_t mblen;
  4.4347 -+
  4.4348 -+                      memset (&state_wc, '\0', sizeof(mbstate_t));
  4.4349 -+                      mblen = wcrtomb (copy[i] + j, uwc, &state_wc);
  4.4350 -+                      assert (mblen != (size_t)-1);
  4.4351 -+                    }
  4.4352 -+                  else
  4.4353 -+                    memcpy (copy[i] + j, str[i] + j, mblength);
  4.4354 -+                }
  4.4355 -+              else
  4.4356 -+                memcpy (copy[i] + j, str[i] + j, mblength);
  4.4357 -+            }
  4.4358 -+          j += mblength;
  4.4359 -+        }
  4.4360 -+      copy[i][j] = '\0';
  4.4361 -+      len[i] = j;
  4.4362 -+    }
  4.4363 -+  int rc = xmemcoll (copy[0], len[0], copy[1], len[1]);
  4.4364 -+  free (copy[0]);
  4.4365 -+  free (copy[1]);
  4.4366 -+  return rc;
  4.4367 -+
  4.4368 - }
  4.4369 -+#endif
  4.4370 - 
  4.4371 - /* Output the line in linebuffer LINE to standard output
  4.4372 -    provided that the switches say it should be output.
  4.4373 -@@ -367,19 +562,38 @@ check_file (const char *infile, const ch
  4.4374 -       char *prevfield IF_LINT ( = NULL);
  4.4375 -       size_t prevlen IF_LINT ( = 0);
  4.4376 -       bool first_group_printed = false;
  4.4377 -+#if HAVE_MBRTOWC
  4.4378 -+      mbstate_t prevstate;
  4.4379 -+
  4.4380 -+      memset (&prevstate, '\0', sizeof (mbstate_t));
  4.4381 -+#endif
  4.4382 - 
  4.4383 -       while (!feof (stdin))
  4.4384 -         {
  4.4385 -           char *thisfield;
  4.4386 -           size_t thislen;
  4.4387 -           bool new_group;
  4.4388 -+#if HAVE_MBRTOWC
  4.4389 -+          mbstate_t thisstate;
  4.4390 -+#endif
  4.4391 - 
  4.4392 -           if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
  4.4393 -             break;
  4.4394 - 
  4.4395 -           thisfield = find_field (thisline);
  4.4396 -           thislen = thisline->length - 1 - (thisfield - thisline->buffer);
  4.4397 -+#if HAVE_MBRTOWC
  4.4398 -+          if (MB_CUR_MAX > 1)
  4.4399 -+            {
  4.4400 -+              thisstate = thisline->state;
  4.4401 - 
  4.4402 -+              new_group = (prevline->length == 0
  4.4403 -+                           || different_multi (thisfield, prevfield,
  4.4404 -+                                               thislen, prevlen,
  4.4405 -+                                               thisstate, prevstate));
  4.4406 -+            }
  4.4407 -+          else
  4.4408 -+#endif
  4.4409 -           new_group = (prevline->length == 0
  4.4410 -                        || different (thisfield, prevfield, thislen, prevlen));
  4.4411 - 
  4.4412 -@@ -397,6 +611,10 @@ check_file (const char *infile, const ch
  4.4413 -               SWAP_LINES (prevline, thisline);
  4.4414 -               prevfield = thisfield;
  4.4415 -               prevlen = thislen;
  4.4416 -+#if HAVE_MBRTOWC
  4.4417 -+              if (MB_CUR_MAX > 1)
  4.4418 -+                prevstate = thisstate;
  4.4419 -+#endif
  4.4420 -               first_group_printed = true;
  4.4421 -             }
  4.4422 -         }
  4.4423 -@@ -409,17 +627,26 @@ check_file (const char *infile, const ch
  4.4424 -       size_t prevlen;
  4.4425 -       uintmax_t match_count = 0;
  4.4426 -       bool first_delimiter = true;
  4.4427 -+#if HAVE_MBRTOWC
  4.4428 -+      mbstate_t prevstate;
  4.4429 -+#endif
  4.4430 - 
  4.4431 -       if (readlinebuffer_delim (prevline, stdin, delimiter) == 0)
  4.4432 -         goto closefiles;
  4.4433 -       prevfield = find_field (prevline);
  4.4434 -       prevlen = prevline->length - 1 - (prevfield - prevline->buffer);
  4.4435 -+#if HAVE_MBRTOWC
  4.4436 -+      prevstate = prevline->state;
  4.4437 -+#endif
  4.4438 - 
  4.4439 -       while (!feof (stdin))
  4.4440 -         {
  4.4441 -           bool match;
  4.4442 -           char *thisfield;
  4.4443 -           size_t thislen;
  4.4444 -+#if HAVE_MBRTOWC
  4.4445 -+          mbstate_t thisstate = thisline->state;
  4.4446 -+#endif
  4.4447 -           if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
  4.4448 -             {
  4.4449 -               if (ferror (stdin))
  4.4450 -@@ -428,6 +655,14 @@ check_file (const char *infile, const ch
  4.4451 -             }
  4.4452 -           thisfield = find_field (thisline);
  4.4453 -           thislen = thisline->length - 1 - (thisfield - thisline->buffer);
  4.4454 -+#if HAVE_MBRTOWC
  4.4455 -+          if (MB_CUR_MAX > 1)
  4.4456 -+            {
  4.4457 -+              match = !different_multi (thisfield, prevfield,
  4.4458 -+                                thislen, prevlen, thisstate, prevstate);
  4.4459 -+            }
  4.4460 -+          else
  4.4461 -+#endif
  4.4462 -           match = !different (thisfield, prevfield, thislen, prevlen);
  4.4463 -           match_count += match;
  4.4464 - 
  4.4465 -@@ -460,6 +695,9 @@ check_file (const char *infile, const ch
  4.4466 -               SWAP_LINES (prevline, thisline);
  4.4467 -               prevfield = thisfield;
  4.4468 -               prevlen = thislen;
  4.4469 -+#if HAVE_MBRTOWC
  4.4470 -+              prevstate = thisstate;
  4.4471 -+#endif
  4.4472 -               if (!match)
  4.4473 -                 match_count = 0;
  4.4474 -             }
  4.4475 -@@ -506,6 +744,19 @@ main (int argc, char **argv)
  4.4476 - 
  4.4477 -   atexit (close_stdout);
  4.4478 - 
  4.4479 -+#if HAVE_MBRTOWC
  4.4480 -+  if (MB_CUR_MAX > 1)
  4.4481 -+    {
  4.4482 -+      find_field = find_field_multi;
  4.4483 -+    }
  4.4484 -+  else
  4.4485 -+#endif
  4.4486 -+    {
  4.4487 -+      find_field = find_field_uni;
  4.4488 -+    }
  4.4489 -+
  4.4490 -+
  4.4491 -+
  4.4492 -   skip_chars = 0;
  4.4493 -   skip_fields = 0;
  4.4494 -   check_chars = SIZE_MAX;
  4.4495 -diff -Naurp coreutils-8.27-orig/tests/expand/mb.sh coreutils-8.27/tests/expand/mb.sh
  4.4496 ---- coreutils-8.27-orig/tests/expand/mb.sh	1969-12-31 18:00:00.000000000 -0600
  4.4497 -+++ coreutils-8.27/tests/expand/mb.sh	2017-03-11 23:49:06.759133489 -0600
  4.4498 -@@ -0,0 +1,183 @@
  4.4499 -+#!/bin/sh
  4.4500 -+
  4.4501 -+# Copyright (C) 2012-2017 Free Software Foundation, Inc.
  4.4502 -+
  4.4503 -+# This program is free software: you can redistribute it and/or modify
  4.4504 -+# it under the terms of the GNU General Public License as published by
  4.4505 -+# the Free Software Foundation, either version 3 of the License, or
  4.4506 -+# (at your option) any later version.
  4.4507 -+
  4.4508 -+# This program is distributed in the hope that it will be useful,
  4.4509 -+# but WITHOUT ANY WARRANTY; without even the implied warranty of
  4.4510 -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  4.4511 -+# GNU General Public License for more details.
  4.4512 -+
  4.4513 -+# You should have received a copy of the GNU General Public License
  4.4514 -+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
  4.4515 -+
  4.4516 -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  4.4517 -+print_ver_ expand
  4.4518 -+
  4.4519 -+export LC_ALL=en_US.UTF-8
  4.4520 -+
  4.4521 -+#input containing multibyte characters
  4.4522 -+cat <<\EOF > in || framework_failure_
  4.4523 -+1234567812345678123456781
  4.4524 -+.       .       .       .
  4.4525 -+a	b	c	d
  4.4526 -+.       .       .       .
  4.4527 -+ä	ö	ü	ß
  4.4528 -+.       .       .       .
  4.4529 -+EOF
  4.4530 -+env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
  4.4531 -+
  4.4532 -+cat <<\EOF > exp || framework_failure_
  4.4533 -+1234567812345678123456781
  4.4534 -+.       .       .       .
  4.4535 -+a       b       c       d
  4.4536 -+.       .       .       .
  4.4537 -+ä       ö       ü       ß
  4.4538 -+.       .       .       .
  4.4539 -+   äöü  .    öüä.       ä xx
  4.4540 -+EOF
  4.4541 -+
  4.4542 -+expand < in > out || fail=1
  4.4543 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4544 -+
  4.4545 -+#multiple files as an input
  4.4546 -+cat <<\EOF >> exp || framework_failure_
  4.4547 -+1234567812345678123456781
  4.4548 -+.       .       .       .
  4.4549 -+a       b       c       d
  4.4550 -+.       .       .       .
  4.4551 -+ä       ö       ü       ß
  4.4552 -+.       .       .       .
  4.4553 -+   äöü  .    öüä.       ä xx
  4.4554 -+EOF
  4.4555 -+
  4.4556 -+expand ./in ./in > out || fail=1
  4.4557 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4558 -+
  4.4559 -+#test characters with display widths != 1
  4.4560 -+env printf '12345678
  4.4561 -+e\t|ascii(1)
  4.4562 -+\u00E9\t|composed(1)
  4.4563 -+e\u0301\t|decomposed(1)
  4.4564 -+\u3000\t|ideo-space(2)
  4.4565 -+\uFF0D\t|full-hypen(2)
  4.4566 -+' > in || framework_failure_
  4.4567 -+
  4.4568 -+env printf '12345678
  4.4569 -+e       |ascii(1)
  4.4570 -+\u00E9       |composed(1)
  4.4571 -+e\u0301       |decomposed(1)
  4.4572 -+\u3000      |ideo-space(2)
  4.4573 -+\uFF0D      |full-hypen(2)
  4.4574 -+' > exp || framework_failure_
  4.4575 -+
  4.4576 -+expand < in > out || fail=1
  4.4577 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4578 -+
  4.4579 -+#shouldn't fail with "input line too long"
  4.4580 -+#when a line starts with a control character
  4.4581 -+env printf '\n' > in || framework_failure_
  4.4582 -+
  4.4583 -+expand < in > out || fail=1
  4.4584 -+compare in out > /dev/null 2>&1 || fail=1
  4.4585 -+
  4.4586 -+#non-Unicode characters interspersed between Unicode ones
  4.4587 -+env printf '12345678
  4.4588 -+\t\xFF|
  4.4589 -+\xFF\t|
  4.4590 -+\t\xFFä|
  4.4591 -+ä\xFF\t|
  4.4592 -+\tä\xFF|
  4.4593 -+\xFF\tä|
  4.4594 -+äbcdef\xFF\t|
  4.4595 -+' > in || framework_failure_
  4.4596 -+
  4.4597 -+env printf '12345678
  4.4598 -+        \xFF|
  4.4599 -+\xFF       |
  4.4600 -+        \xFFä|
  4.4601 -+ä\xFF      |
  4.4602 -+        ä\xFF|
  4.4603 -+\xFF       ä|
  4.4604 -+äbcdef\xFF |
  4.4605 -+' > exp || framework_failure_
  4.4606 -+
  4.4607 -+expand < in > out || fail=1
  4.4608 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4609 -+
  4.4610 -+
  4.4611 -+
  4.4612 -+#BOM header test 1
  4.4613 -+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_
  4.4614 -+1234567812345678123456781
  4.4615 -+.       .       .       .
  4.4616 -+a	b	c	d
  4.4617 -+.       .       .       .
  4.4618 -+ä	ö	ü	ß
  4.4619 -+.       .       .       .
  4.4620 -+EOF
  4.4621 -+env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
  4.4622 -+
  4.4623 -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
  4.4624 -+1234567812345678123456781
  4.4625 -+.       .       .       .
  4.4626 -+a       b       c       d
  4.4627 -+.       .       .       .
  4.4628 -+ä       ö       ü       ß
  4.4629 -+.       .       .       .
  4.4630 -+   äöü  .    öüä.       ä xx
  4.4631 -+EOF
  4.4632 -+
  4.4633 -+
  4.4634 -+expand < in > out || fail=1
  4.4635 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4636 -+
  4.4637 -+LANG=C expand < in > out || fail=1
  4.4638 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4639 -+
  4.4640 -+LC_ALL=C expand < in > out || fail=1
  4.4641 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4642 -+
  4.4643 -+
  4.4644 -+printf '\xEF\xBB\xBF' > in1; cat <<\EOF >> in1 || framework_failure_
  4.4645 -+1234567812345678123456781
  4.4646 -+.       .       .       .
  4.4647 -+a	b	c	d
  4.4648 -+.       .       .       .
  4.4649 -+ä	ö	ü	ß
  4.4650 -+.       .       .       .
  4.4651 -+EOF
  4.4652 -+env printf '   äöü\t.    öüä.   \tä xx\n' >> in1 || framework_failure_
  4.4653 -+
  4.4654 -+
  4.4655 -+printf '\xEF\xBB\xBF' > exp; cat <<\EOF >> exp || framework_failure_
  4.4656 -+1234567812345678123456781
  4.4657 -+.       .       .       .
  4.4658 -+a       b       c       d
  4.4659 -+.       .       .       .
  4.4660 -+ä       ö       ü       ß
  4.4661 -+.       .       .       .
  4.4662 -+   äöü  .    öüä.       ä xx
  4.4663 -+1234567812345678123456781
  4.4664 -+.       .       .       .
  4.4665 -+a       b       c       d
  4.4666 -+.       .       .       .
  4.4667 -+ä       ö       ü       ß
  4.4668 -+.       .       .       .
  4.4669 -+   äöü  .    öüä.       ä xx
  4.4670 -+EOF
  4.4671 -+
  4.4672 -+expand in1 in1 > out || fail=1
  4.4673 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4674 -+
  4.4675 -+LANG=C expand in1 in1  > out || fail=1
  4.4676 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4677 -+
  4.4678 -+LC_ALL=C expand in1 in1 > out || fail=1
  4.4679 -+compare exp out > /dev/null 2>&1 || fail=1
  4.4680 -+
  4.4681 -+exit $fail
  4.4682 -diff -Naurp coreutils-8.27-orig/tests/i18n/sort.sh coreutils-8.27/tests/i18n/sort.sh
  4.4683 ---- coreutils-8.27-orig/tests/i18n/sort.sh	1969-12-31 18:00:00.000000000 -0600
  4.4684 -+++ coreutils-8.27/tests/i18n/sort.sh	2017-03-11 23:47:13.100285838 -0600
  4.4685 -@@ -0,0 +1,29 @@
  4.4686 -+#!/bin/sh
  4.4687 -+# Verify sort's multi-byte support.
  4.4688 -+
  4.4689 -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  4.4690 -+print_ver_ sort
  4.4691 -+
  4.4692 -+export LC_ALL=en_US.UTF-8
  4.4693 -+locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \
  4.4694 -+  || skip_ "No UTF-8 locale available"
  4.4695 -+
  4.4696 -+# Enable heap consistency checkng on older systems
  4.4697 -+export MALLOC_CHECK_=2
  4.4698 -+
  4.4699 -+
  4.4700 -+# check buffer overflow issue due to
  4.4701 -+# expanding multi-byte representation due to case conversion
  4.4702 -+# https://bugzilla.suse.com/show_bug.cgi?id=928749
  4.4703 -+cat <<EOF > exp
  4.4704 -+.
  4.4705 -+ɑ
  4.4706 -+EOF
  4.4707 -+cat <<EOF | sort -f > out || fail=1
  4.4708 -+.
  4.4709 -+ɑ
  4.4710 -+EOF
  4.4711 -+compare exp out || { fail=1; cat out; }
  4.4712 -+
  4.4713 -+
  4.4714 -+Exit $fail
  4.4715 -diff -Naurp coreutils-8.27-orig/tests/local.mk coreutils-8.27/tests/local.mk
  4.4716 ---- coreutils-8.27-orig/tests/local.mk	2017-02-28 22:25:37.000000000 -0600
  4.4717 -+++ coreutils-8.27/tests/local.mk	2017-03-11 23:47:38.072058253 -0600
  4.4718 -@@ -352,6 +352,8 @@ all_tests =					\
  4.4719 -   tests/misc/sort-discrim.sh			\
  4.4720 -   tests/misc/sort-files0-from.pl		\
  4.4721 -   tests/misc/sort-float.sh			\
  4.4722 -+  tests/misc/sort-mb-tests.sh			\
  4.4723 -+  tests/i18n/sort.sh				\
  4.4724 -   tests/misc/sort-h-thousands-sep.sh		\
  4.4725 -   tests/misc/sort-merge.pl			\
  4.4726 -   tests/misc/sort-merge-fdlimit.sh		\
  4.4727 -@@ -544,6 +546,7 @@ all_tests =					\
  4.4728 -   tests/du/threshold.sh				\
  4.4729 -   tests/du/trailing-slash.sh			\
  4.4730 -   tests/du/two-args.sh				\
  4.4731 -+  tests/expand/mb.sh				\
  4.4732 -   tests/id/gnu-zero-uids.sh			\
  4.4733 -   tests/id/no-context.sh			\
  4.4734 -   tests/id/context.sh				\
  4.4735 -@@ -684,6 +687,7 @@ all_tests =					\
  4.4736 -   tests/touch/read-only.sh			\
  4.4737 -   tests/touch/relative.sh			\
  4.4738 -   tests/touch/trailing-slash.sh			\
  4.4739 -+  tests/unexpand/mb.sh				\
  4.4740 -   $(all_root_tests)
  4.4741 - 
  4.4742 - # See tests/factor/create-test.sh.
  4.4743 -diff -Naurp coreutils-8.27-orig/tests/misc/cut.pl coreutils-8.27/tests/misc/cut.pl
  4.4744 ---- coreutils-8.27-orig/tests/misc/cut.pl	2017-01-01 16:34:24.000000000 -0600
  4.4745 -+++ coreutils-8.27/tests/misc/cut.pl	2017-03-11 23:47:13.100285838 -0600
  4.4746 -@@ -23,9 +23,11 @@ use strict;
  4.4747 - # Turn off localization of executable's output.
  4.4748 - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  4.4749 - 
  4.4750 --my $mb_locale = $ENV{LOCALE_FR_UTF8};
  4.4751 -+my $mb_locale;
  4.4752 -+# uncommented enable multibyte paths
  4.4753 -+$mb_locale = $ENV{LOCALE_FR_UTF8};
  4.4754 - ! defined $mb_locale || $mb_locale eq 'none'
  4.4755 --  and $mb_locale = 'C';
  4.4756 -+ and $mb_locale = 'C';
  4.4757 - 
  4.4758 - my $prog = 'cut';
  4.4759 - my $try = "Try '$prog --help' for more information.\n";
  4.4760 -@@ -240,6 +242,7 @@ if ($mb_locale ne 'C')
  4.4761 -         my @new_t = @$t;
  4.4762 -         my $test_name = shift @new_t;
  4.4763 - 
  4.4764 -+        next if ($test_name =~ "newline-[12][0-9]");
  4.4765 -         push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.4766 -       }
  4.4767 -     push @Tests, @new;
  4.4768 -diff -Naurp coreutils-8.27-orig/tests/misc/expand.pl coreutils-8.27/tests/misc/expand.pl
  4.4769 ---- coreutils-8.27-orig/tests/misc/expand.pl	2017-03-01 11:16:46.000000000 -0600
  4.4770 -+++ coreutils-8.27/tests/misc/expand.pl	2017-03-11 23:47:13.101285788 -0600
  4.4771 -@@ -27,6 +27,15 @@ my $prog = 'expand';
  4.4772 - # Turn off localization of executable's output.
  4.4773 - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  4.4774 - 
  4.4775 -+#comment out next line to disable multibyte tests
  4.4776 -+my $mb_locale = $ENV{LOCALE_FR_UTF8};
  4.4777 -+! defined $mb_locale || $mb_locale eq 'none'
  4.4778 -+ and $mb_locale = 'C';
  4.4779 -+
  4.4780 -+my $prog = 'expand';
  4.4781 -+my $try = "Try \`$prog --help' for more information.\n";
  4.4782 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.4783 -+
  4.4784 - my @Tests =
  4.4785 -   (
  4.4786 -    ['t1', '--tabs=3',     {IN=>"a\tb"}, {OUT=>"a  b"}],
  4.4787 -@@ -152,6 +161,8 @@ my @Tests =
  4.4788 -    ['trail9', '--tab=1,2 -t/5',{IN=>"\ta\tb\tc"}, {OUT=>" a   b    c"}],
  4.4789 - 
  4.4790 -    # Test errors
  4.4791 -+   # FIXME: The following tests contain ‘quoting’ specific to LC_MESSAGES
  4.4792 -+   # So we force LC_MESSAGES=C to make them pass.
  4.4793 -    ['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1},
  4.4794 -     {ERR => "$prog: tab size contains invalid character(s): 'a'\n"}],
  4.4795 -    ['e2', "-t $UINTMAX_OFLOW", {IN=>''}, {OUT=>''}, {EXIT=>1},
  4.4796 -@@ -168,6 +179,37 @@ my @Tests =
  4.4797 -     {ERR => "$prog: '/' specifier not at start of number: '/'\n"}],
  4.4798 -   );
  4.4799 - 
  4.4800 -+if ($mb_locale ne 'C')
  4.4801 -+  {
  4.4802 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.4803 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.4804 -+    # provide coverage for the distro-added multi-byte code paths.
  4.4805 -+    my @new;
  4.4806 -+    foreach my $t (@Tests)
  4.4807 -+      {
  4.4808 -+        my @new_t = @$t;
  4.4809 -+        my $test_name = shift @new_t;
  4.4810 -+
  4.4811 -+        # Depending on whether expand is multi-byte-patched,
  4.4812 -+        # it emits different diagnostics:
  4.4813 -+        #   non-MB: invalid byte or field list
  4.4814 -+        #   MB:     invalid byte, character or field list
  4.4815 -+        # Adjust the expected error output accordingly.
  4.4816 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.4817 -+            (@new_t))
  4.4818 -+          {
  4.4819 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.4820 -+            push @new_t, $sub;
  4.4821 -+            push @$t, $sub;
  4.4822 -+          }
  4.4823 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LANG=$mb_locale LC_MESSAGES=C"}];
  4.4824 -+      }
  4.4825 -+    push @Tests, @new;
  4.4826 -+  }
  4.4827 -+
  4.4828 -+
  4.4829 -+@Tests = triple_test \@Tests;
  4.4830 -+
  4.4831 - my $save_temps = $ENV{DEBUG};
  4.4832 - my $verbose = $ENV{VERBOSE};
  4.4833 - 
  4.4834 -diff -Naurp coreutils-8.27-orig/tests/misc/fold.pl coreutils-8.27/tests/misc/fold.pl
  4.4835 ---- coreutils-8.27-orig/tests/misc/fold.pl	2017-01-01 16:34:24.000000000 -0600
  4.4836 -+++ coreutils-8.27/tests/misc/fold.pl	2017-03-11 23:47:13.101285788 -0600
  4.4837 -@@ -20,9 +20,18 @@ use strict;
  4.4838 - 
  4.4839 - (my $program_name = $0) =~ s|.*/||;
  4.4840 - 
  4.4841 -+my $prog = 'fold';
  4.4842 -+my $try = "Try \`$prog --help' for more information.\n";
  4.4843 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.4844 -+
  4.4845 - # Turn off localization of executable's output.
  4.4846 - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  4.4847 - 
  4.4848 -+# uncommented to enable multibyte paths
  4.4849 -+my $mb_locale = $ENV{LOCALE_FR_UTF8};
  4.4850 -+! defined $mb_locale || $mb_locale eq 'none'
  4.4851 -+ and $mb_locale = 'C';
  4.4852 -+
  4.4853 - my @Tests =
  4.4854 -   (
  4.4855 -    ['s1', '-w2 -s', {IN=>"a\t"}, {OUT=>"a\n\t"}],
  4.4856 -@@ -31,9 +40,48 @@ my @Tests =
  4.4857 -    ['s4', '-w4 -s', {IN=>"abc ef\n"}, {OUT=>"abc \nef\n"}],
  4.4858 -   );
  4.4859 - 
  4.4860 -+# Add _POSIX2_VERSION=199209 to the environment of each test
  4.4861 -+# that uses an old-style option like +1.
  4.4862 -+if ($mb_locale ne 'C')
  4.4863 -+  {
  4.4864 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.4865 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.4866 -+    # provide coverage for the distro-added multi-byte code paths.
  4.4867 -+    my @new;
  4.4868 -+    foreach my $t (@Tests)
  4.4869 -+      {
  4.4870 -+        my @new_t = @$t;
  4.4871 -+        my $test_name = shift @new_t;
  4.4872 -+
  4.4873 -+        # Depending on whether fold is multi-byte-patched,
  4.4874 -+        # it emits different diagnostics:
  4.4875 -+        #   non-MB: invalid byte or field list
  4.4876 -+        #   MB:     invalid byte, character or field list
  4.4877 -+        # Adjust the expected error output accordingly.
  4.4878 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.4879 -+            (@new_t))
  4.4880 -+          {
  4.4881 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.4882 -+            push @new_t, $sub;
  4.4883 -+            push @$t, $sub;
  4.4884 -+          }
  4.4885 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.4886 -+      }
  4.4887 -+    push @Tests, @new;
  4.4888 -+  }
  4.4889 -+
  4.4890 -+@Tests = triple_test \@Tests;
  4.4891 -+
  4.4892 -+# Remember that triple_test creates from each test with exactly one "IN"
  4.4893 -+# file two more tests (.p and .r suffix on name) corresponding to reading
  4.4894 -+# input from a file and from a pipe.  The pipe-reading test would fail
  4.4895 -+# due to a race condition about 1 in 20 times.
  4.4896 -+# Remove the IN_PIPE version of the "output-is-input" test above.
  4.4897 -+# The others aren't susceptible because they have three inputs each.
  4.4898 -+@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  4.4899 -+
  4.4900 - my $save_temps = $ENV{DEBUG};
  4.4901 - my $verbose = $ENV{VERBOSE};
  4.4902 - 
  4.4903 --my $prog = 'fold';
  4.4904 - my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
  4.4905 - exit $fail;
  4.4906 -diff -Naurp coreutils-8.27-orig/tests/misc/join.pl coreutils-8.27/tests/misc/join.pl
  4.4907 ---- coreutils-8.27-orig/tests/misc/join.pl	2017-01-01 16:34:24.000000000 -0600
  4.4908 -+++ coreutils-8.27/tests/misc/join.pl	2017-03-11 23:47:13.102285737 -0600
  4.4909 -@@ -25,6 +25,15 @@ my $limits = getlimits ();
  4.4910 - 
  4.4911 - my $prog = 'join';
  4.4912 - 
  4.4913 -+my $try = "Try \`$prog --help' for more information.\n";
  4.4914 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.4915 -+
  4.4916 -+my $mb_locale;
  4.4917 -+#Comment out next line to disable multibyte tests
  4.4918 -+$mb_locale = $ENV{LOCALE_FR_UTF8};
  4.4919 -+! defined $mb_locale || $mb_locale eq 'none'
  4.4920 -+  and $mb_locale = 'C';
  4.4921 -+
  4.4922 - my $delim = chr 0247;
  4.4923 - sub t_subst ($)
  4.4924 - {
  4.4925 -@@ -329,8 +338,49 @@ foreach my $t (@tv)
  4.4926 -     push @Tests, $new_ent;
  4.4927 -   }
  4.4928 - 
  4.4929 -+# Add _POSIX2_VERSION=199209 to the environment of each test
  4.4930 -+# that uses an old-style option like +1.
  4.4931 -+if ($mb_locale ne 'C')
  4.4932 -+  {
  4.4933 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.4934 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.4935 -+    # provide coverage for the distro-added multi-byte code paths.
  4.4936 -+    my @new;
  4.4937 -+    foreach my $t (@Tests)
  4.4938 -+      {
  4.4939 -+        my @new_t = @$t;
  4.4940 -+        my $test_name = shift @new_t;
  4.4941 -+
  4.4942 -+        # Depending on whether join is multi-byte-patched,
  4.4943 -+        # it emits different diagnostics:
  4.4944 -+        #   non-MB: invalid byte or field list
  4.4945 -+        #   MB:     invalid byte, character or field list
  4.4946 -+        # Adjust the expected error output accordingly.
  4.4947 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.4948 -+            (@new_t))
  4.4949 -+          {
  4.4950 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.4951 -+            push @new_t, $sub;
  4.4952 -+            push @$t, $sub;
  4.4953 -+          }
  4.4954 -+        #Adjust the output some error messages including test_name for mb
  4.4955 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR}}
  4.4956 -+             (@new_t))
  4.4957 -+          {
  4.4958 -+            my $sub2 = {ERR_SUBST => "s/$test_name-mb/$test_name/"};
  4.4959 -+            push @new_t, $sub2;
  4.4960 -+            push @$t, $sub2;
  4.4961 -+          }
  4.4962 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.4963 -+      }
  4.4964 -+    push @Tests, @new;
  4.4965 -+  }
  4.4966 -+
  4.4967 - @Tests = triple_test \@Tests;
  4.4968 - 
  4.4969 -+#skip invalid-j-mb test, it is failing because of the format
  4.4970 -+@Tests = grep {$_->[0] ne 'invalid-j-mb'} @Tests;
  4.4971 -+
  4.4972 - my $save_temps = $ENV{DEBUG};
  4.4973 - my $verbose = $ENV{VERBOSE};
  4.4974 - 
  4.4975 -diff -Naurp coreutils-8.27-orig/tests/misc/sort-mb-tests.sh coreutils-8.27/tests/misc/sort-mb-tests.sh
  4.4976 ---- coreutils-8.27-orig/tests/misc/sort-mb-tests.sh	1969-12-31 18:00:00.000000000 -0600
  4.4977 -+++ coreutils-8.27/tests/misc/sort-mb-tests.sh	2017-03-11 23:47:13.102285737 -0600
  4.4978 -@@ -0,0 +1,45 @@
  4.4979 -+#!/bin/sh
  4.4980 -+# Verify sort's multi-byte support.
  4.4981 -+
  4.4982 -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  4.4983 -+print_ver_ sort
  4.4984 -+
  4.4985 -+export LC_ALL=en_US.UTF-8
  4.4986 -+locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \
  4.4987 -+  || skip_ "No UTF-8 locale available"
  4.4988 -+
  4.4989 -+
  4.4990 -+cat <<EOF > exp
  4.4991 -+Banana@5
  4.4992 -+Apple@10
  4.4993 -+Citrus@20
  4.4994 -+Cherry@30
  4.4995 -+EOF
  4.4996 -+
  4.4997 -+cat <<EOF | sort -t @ -k2 -n > out || fail=1
  4.4998 -+Apple@10
  4.4999 -+Banana@5
  4.5000 -+Citrus@20
  4.5001 -+Cherry@30
  4.5002 -+EOF
  4.5003 -+
  4.5004 -+compare exp out || { fail=1; cat out; }
  4.5005 -+
  4.5006 -+
  4.5007 -+cat <<EOF > exp
  4.5008 -+Citrus@AA20@@5
  4.5009 -+Cherry@AA30@@10
  4.5010 -+Apple@AA10@@20
  4.5011 -+Banana@AA5@@30
  4.5012 -+EOF
  4.5013 -+
  4.5014 -+cat <<EOF | sort -t @ -k4 -n > out || fail=1
  4.5015 -+Apple@AA10@@20
  4.5016 -+Banana@AA5@@30
  4.5017 -+Citrus@AA20@@5
  4.5018 -+Cherry@AA30@@10
  4.5019 -+EOF
  4.5020 -+
  4.5021 -+compare exp out || { fail=1; cat out; }
  4.5022 -+
  4.5023 -+Exit $fail
  4.5024 -diff -Naurp coreutils-8.27-orig/tests/misc/sort-merge.pl coreutils-8.27/tests/misc/sort-merge.pl
  4.5025 ---- coreutils-8.27-orig/tests/misc/sort-merge.pl	2017-01-01 16:34:24.000000000 -0600
  4.5026 -+++ coreutils-8.27/tests/misc/sort-merge.pl	2017-03-11 23:47:13.102285737 -0600
  4.5027 -@@ -26,6 +26,15 @@ my $prog = 'sort';
  4.5028 - # Turn off localization of executable's output.
  4.5029 - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  4.5030 - 
  4.5031 -+my $mb_locale;
  4.5032 -+# uncommented according to upstream commit enabling multibyte paths
  4.5033 -+$mb_locale = $ENV{LOCALE_FR_UTF8};
  4.5034 -+! defined $mb_locale || $mb_locale eq 'none'
  4.5035 -+ and $mb_locale = 'C';
  4.5036 -+
  4.5037 -+my $try = "Try \`$prog --help' for more information.\n";
  4.5038 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.5039 -+
  4.5040 - # three empty files and one that says 'foo'
  4.5041 - my @inputs = (+(map{{IN=> {"empty$_"=> ''}}}1..3), {IN=> {foo=> "foo\n"}});
  4.5042 - 
  4.5043 -@@ -77,6 +86,39 @@ my @Tests =
  4.5044 -         {OUT=>$big_input}],
  4.5045 -     );
  4.5046 - 
  4.5047 -+# Add _POSIX2_VERSION=199209 to the environment of each test
  4.5048 -+# that uses an old-style option like +1.
  4.5049 -+if ($mb_locale ne 'C')
  4.5050 -+  {
  4.5051 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.5052 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.5053 -+    # provide coverage for the distro-added multi-byte code paths.
  4.5054 -+    my @new;
  4.5055 -+    foreach my $t (@Tests)
  4.5056 -+      {
  4.5057 -+        my @new_t = @$t;
  4.5058 -+        my $test_name = shift @new_t;
  4.5059 -+
  4.5060 -+        # Depending on whether sort is multi-byte-patched,
  4.5061 -+        # it emits different diagnostics:
  4.5062 -+        #   non-MB: invalid byte or field list
  4.5063 -+        #   MB:     invalid byte, character or field list
  4.5064 -+        # Adjust the expected error output accordingly.
  4.5065 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.5066 -+            (@new_t))
  4.5067 -+          {
  4.5068 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.5069 -+            push @new_t, $sub;
  4.5070 -+            push @$t, $sub;
  4.5071 -+          }
  4.5072 -+        next if ($test_name =~ "nmerge-.");
  4.5073 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.5074 -+      }
  4.5075 -+    push @Tests, @new;
  4.5076 -+  }
  4.5077 -+
  4.5078 -+@Tests = triple_test \@Tests;
  4.5079 -+
  4.5080 - my $save_temps = $ENV{DEBUG};
  4.5081 - my $verbose = $ENV{VERBOSE};
  4.5082 - 
  4.5083 -diff -Naurp coreutils-8.27-orig/tests/misc/sort.pl coreutils-8.27/tests/misc/sort.pl
  4.5084 ---- coreutils-8.27-orig/tests/misc/sort.pl	2017-01-21 08:53:43.000000000 -0600
  4.5085 -+++ coreutils-8.27/tests/misc/sort.pl	2017-03-11 23:47:13.103285687 -0600
  4.5086 -@@ -24,10 +24,15 @@ my $prog = 'sort';
  4.5087 - # Turn off localization of executable's output.
  4.5088 - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  4.5089 - 
  4.5090 --my $mb_locale = $ENV{LOCALE_FR_UTF8};
  4.5091 -+my $mb_locale;
  4.5092 -+#Comment out next line to disable multibyte tests
  4.5093 -+$mb_locale = $ENV{LOCALE_FR_UTF8};
  4.5094 - ! defined $mb_locale || $mb_locale eq 'none'
  4.5095 -   and $mb_locale = 'C';
  4.5096 - 
  4.5097 -+my $try = "Try \`$prog --help' for more information.\n";
  4.5098 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.5099 -+
  4.5100 - # Since each test is run with a file name and with redirected stdin,
  4.5101 - # the name in the diagnostic is either the file name or "-".
  4.5102 - # Normalize each diagnostic to use '-'.
  4.5103 -@@ -423,6 +428,38 @@ foreach my $t (@Tests)
  4.5104 -       }
  4.5105 -   }
  4.5106 - 
  4.5107 -+if ($mb_locale ne 'C')
  4.5108 -+   {
  4.5109 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.5110 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.5111 -+    # provide coverage for the distro-added multi-byte code paths.
  4.5112 -+    my @new;
  4.5113 -+    foreach my $t (@Tests)
  4.5114 -+       {
  4.5115 -+        my @new_t = @$t;
  4.5116 -+        my $test_name = shift @new_t;
  4.5117 -+
  4.5118 -+        # Depending on whether sort is multi-byte-patched,
  4.5119 -+        # it emits different diagnostics:
  4.5120 -+        #   non-MB: invalid byte or field list
  4.5121 -+        #   MB:     invalid byte, character or field list
  4.5122 -+        # Adjust the expected error output accordingly.
  4.5123 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.5124 -+            (@new_t))
  4.5125 -+          {
  4.5126 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.5127 -+            push @new_t, $sub;
  4.5128 -+            push @$t, $sub;
  4.5129 -+          }
  4.5130 -+        #disable several failing tests until investigation, disable all tests with envvars set
  4.5131 -+        next if (grep {ref $_ eq 'HASH' && exists $_->{ENV}} (@new_t));
  4.5132 -+        next if ($test_name =~ "18g" or $test_name =~ "sort-numeric" or $test_name =~ "08[ab]" or $test_name =~ "03[def]" or $test_name =~ "h4" or $test_name =~ "n1" or $test_name =~ "2[01]a");
  4.5133 -+        next if ($test_name =~ "11[ab]"); # avoid FP: expected result differs to MB result due to collation rules.
  4.5134 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.5135 -+       }
  4.5136 -+    push @Tests, @new;
  4.5137 -+   }
  4.5138 -+
  4.5139 - @Tests = triple_test \@Tests;
  4.5140 - 
  4.5141 - # Remember that triple_test creates from each test with exactly one "IN"
  4.5142 -@@ -432,6 +469,7 @@ foreach my $t (@Tests)
  4.5143 - # Remove the IN_PIPE version of the "output-is-input" test above.
  4.5144 - # The others aren't susceptible because they have three inputs each.
  4.5145 - @Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  4.5146 -+@Tests = grep {$_->[0] ne 'output-is-input-mb.p'} @Tests;
  4.5147 - 
  4.5148 - my $save_temps = $ENV{DEBUG};
  4.5149 - my $verbose = $ENV{VERBOSE};
  4.5150 -diff -Naurp coreutils-8.27-orig/tests/misc/unexpand.pl coreutils-8.27/tests/misc/unexpand.pl
  4.5151 ---- coreutils-8.27-orig/tests/misc/unexpand.pl	2017-01-01 16:34:24.000000000 -0600
  4.5152 -+++ coreutils-8.27/tests/misc/unexpand.pl	2017-03-11 23:47:13.103285687 -0600
  4.5153 -@@ -27,6 +27,14 @@ my $limits = getlimits ();
  4.5154 - 
  4.5155 - my $prog = 'unexpand';
  4.5156 - 
  4.5157 -+# comment out next line to disable multibyte tests
  4.5158 -+my $mb_locale = $ENV{LOCALE_FR_UTF8};
  4.5159 -+! defined $mb_locale || $mb_locale eq 'none'
  4.5160 -+ and $mb_locale = 'C';
  4.5161 -+
  4.5162 -+my $try = "Try \`$prog --help' for more information.\n";
  4.5163 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.5164 -+
  4.5165 - my @Tests =
  4.5166 -     (
  4.5167 -      ['a1', {IN=> ' 'x 1 ."y\n"}, {OUT=> ' 'x 1 ."y\n"}],
  4.5168 -@@ -128,6 +136,37 @@ my @Tests =
  4.5169 -      ['ts2', '-t5,8', {IN=>"x\t \t y\n"},    {OUT=>"x\t\t y\n"}],
  4.5170 -     );
  4.5171 - 
  4.5172 -+if ($mb_locale ne 'C')
  4.5173 -+  {
  4.5174 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.5175 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.5176 -+    # provide coverage for the distro-added multi-byte code paths.
  4.5177 -+    my @new;
  4.5178 -+    foreach my $t (@Tests)
  4.5179 -+      {
  4.5180 -+        my @new_t = @$t;
  4.5181 -+        my $test_name = shift @new_t;
  4.5182 -+
  4.5183 -+        # Depending on whether unexpand is multi-byte-patched,
  4.5184 -+        # it emits different diagnostics:
  4.5185 -+        #   non-MB: invalid byte or field list
  4.5186 -+        #   MB:     invalid byte, character or field list
  4.5187 -+        # Adjust the expected error output accordingly.
  4.5188 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.5189 -+            (@new_t))
  4.5190 -+          {
  4.5191 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.5192 -+            push @new_t, $sub;
  4.5193 -+            push @$t, $sub;
  4.5194 -+          }
  4.5195 -+        next if ($test_name =~ 'b-1');
  4.5196 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.5197 -+      }
  4.5198 -+    push @Tests, @new;
  4.5199 -+  }
  4.5200 -+
  4.5201 -+@Tests = triple_test \@Tests;
  4.5202 -+
  4.5203 - my $save_temps = $ENV{DEBUG};
  4.5204 - my $verbose = $ENV{VERBOSE};
  4.5205 - 
  4.5206 -diff -Naurp coreutils-8.27-orig/tests/misc/uniq.pl coreutils-8.27/tests/misc/uniq.pl
  4.5207 ---- coreutils-8.27-orig/tests/misc/uniq.pl	2017-01-01 16:34:24.000000000 -0600
  4.5208 -+++ coreutils-8.27/tests/misc/uniq.pl	2017-03-11 23:47:13.103285687 -0600
  4.5209 -@@ -23,9 +23,17 @@ my $limits = getlimits ();
  4.5210 - my $prog = 'uniq';
  4.5211 - my $try = "Try '$prog --help' for more information.\n";
  4.5212 - 
  4.5213 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.5214 -+
  4.5215 - # Turn off localization of executable's output.
  4.5216 - @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  4.5217 - 
  4.5218 -+my $mb_locale;
  4.5219 -+#Comment out next line to disable multibyte tests
  4.5220 -+$mb_locale = $ENV{LOCALE_FR_UTF8};
  4.5221 -+! defined $mb_locale || $mb_locale eq 'none'
  4.5222 -+  and $mb_locale = 'C';
  4.5223 -+
  4.5224 - # When possible, create a "-z"-testing variant of each test.
  4.5225 - sub add_z_variants($)
  4.5226 - {
  4.5227 -@@ -262,6 +270,53 @@ foreach my $t (@Tests)
  4.5228 -       and push @$t, {ENV=>'_POSIX2_VERSION=199209'};
  4.5229 -   }
  4.5230 - 
  4.5231 -+if ($mb_locale ne 'C')
  4.5232 -+  {
  4.5233 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.5234 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.5235 -+    # provide coverage for the distro-added multi-byte code paths.
  4.5236 -+    my @new;
  4.5237 -+    foreach my $t (@Tests)
  4.5238 -+      {
  4.5239 -+        my @new_t = @$t;
  4.5240 -+        my $test_name = shift @new_t;
  4.5241 -+
  4.5242 -+        # Depending on whether uniq is multi-byte-patched,
  4.5243 -+        # it emits different diagnostics:
  4.5244 -+        #   non-MB: invalid byte or field list
  4.5245 -+        #   MB:     invalid byte, character or field list
  4.5246 -+        # Adjust the expected error output accordingly.
  4.5247 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.5248 -+            (@new_t))
  4.5249 -+          {
  4.5250 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.5251 -+            push @new_t, $sub;
  4.5252 -+            push @$t, $sub;
  4.5253 -+          }
  4.5254 -+        # In test #145, replace the each ‘...’ by '...'.
  4.5255 -+        if ($test_name =~ "145")
  4.5256 -+          {
  4.5257 -+            my $sub = { ERR_SUBST => "s/‘([^’]+)’/'\$1'/g"};
  4.5258 -+            push @new_t, $sub;
  4.5259 -+            push @$t, $sub;
  4.5260 -+          }
  4.5261 -+        next if (   $test_name =~ "schar"
  4.5262 -+                 or $test_name =~ "^obs-plus"
  4.5263 -+                 or $test_name =~ "119");
  4.5264 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.5265 -+      }
  4.5266 -+    push @Tests, @new;
  4.5267 -+   }
  4.5268 -+
  4.5269 -+# Remember that triple_test creates from each test with exactly one "IN"
  4.5270 -+# file two more tests (.p and .r suffix on name) corresponding to reading
  4.5271 -+# input from a file and from a pipe.  The pipe-reading test would fail
  4.5272 -+# due to a race condition about 1 in 20 times.
  4.5273 -+# Remove the IN_PIPE version of the "output-is-input" test above.
  4.5274 -+# The others aren't susceptible because they have three inputs each.
  4.5275 -+
  4.5276 -+@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  4.5277 -+
  4.5278 - @Tests = add_z_variants \@Tests;
  4.5279 - @Tests = triple_test \@Tests;
  4.5280 - 
  4.5281 -diff -Naurp coreutils-8.27-orig/tests/pr/pr-tests.pl coreutils-8.27/tests/pr/pr-tests.pl
  4.5282 ---- coreutils-8.27-orig/tests/pr/pr-tests.pl	2017-01-01 16:34:24.000000000 -0600
  4.5283 -+++ coreutils-8.27/tests/pr/pr-tests.pl	2017-03-11 23:47:13.103285687 -0600
  4.5284 -@@ -24,6 +24,15 @@ use strict;
  4.5285 - my $prog = 'pr';
  4.5286 - my $normalize_strerror = "s/': .*/'/";
  4.5287 - 
  4.5288 -+my $mb_locale;
  4.5289 -+#Uncomment the following line to enable multibyte tests
  4.5290 -+$mb_locale = $ENV{LOCALE_FR_UTF8};
  4.5291 -+! defined $mb_locale || $mb_locale eq 'none'
  4.5292 -+  and $mb_locale = 'C';
  4.5293 -+
  4.5294 -+my $try = "Try \`$prog --help' for more information.\n";
  4.5295 -+my $inval = "$prog: invalid byte, character or field list\n$try";
  4.5296 -+
  4.5297 - my @tv = (
  4.5298 - 
  4.5299 - # -b option is no longer an official option. But it's still working to
  4.5300 -@@ -474,8 +483,48 @@ push @Tests,
  4.5301 -     {IN=>{2=>"a\n"}},
  4.5302 -      {OUT=>"a\t\t\t\t  \t\t\ta\n"} ];
  4.5303 - 
  4.5304 -+# Add _POSIX2_VERSION=199209 to the environment of each test
  4.5305 -+# that uses an old-style option like +1.
  4.5306 -+if ($mb_locale ne 'C')
  4.5307 -+  {
  4.5308 -+    # Duplicate each test vector, appending "-mb" to the test name and
  4.5309 -+    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  4.5310 -+    # provide coverage for the distro-added multi-byte code paths.
  4.5311 -+    my @new;
  4.5312 -+    foreach my $t (@Tests)
  4.5313 -+      {
  4.5314 -+        my @new_t = @$t;
  4.5315 -+        my $test_name = shift @new_t;
  4.5316 -+
  4.5317 -+        # Depending on whether pr is multi-byte-patched,
  4.5318 -+        # it emits different diagnostics:
  4.5319 -+        #   non-MB: invalid byte or field list
  4.5320 -+        #   MB:     invalid byte, character or field list
  4.5321 -+        # Adjust the expected error output accordingly.
  4.5322 -+        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  4.5323 -+            (@new_t))
  4.5324 -+          {
  4.5325 -+            my $sub = {ERR_SUBST => 's/, character//'};
  4.5326 -+            push @new_t, $sub;
  4.5327 -+            push @$t, $sub;
  4.5328 -+          }
  4.5329 -+        #temporarily skip some failing tests
  4.5330 -+        next if ($test_name =~ "col-0" or $test_name =~ "col-inval" or $test_name =~ "asan1");
  4.5331 -+        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  4.5332 -+      }
  4.5333 -+    push @Tests, @new;
  4.5334 -+  }
  4.5335 -+
  4.5336 - @Tests = triple_test \@Tests;
  4.5337 - 
  4.5338 -+# Remember that triple_test creates from each test with exactly one "IN"
  4.5339 -+# file two more tests (.p and .r suffix on name) corresponding to reading
  4.5340 -+# input from a file and from a pipe.  The pipe-reading test would fail
  4.5341 -+# due to a race condition about 1 in 20 times.
  4.5342 -+# Remove the IN_PIPE version of the "output-is-input" test above.
  4.5343 -+# The others aren't susceptible because they have three inputs each.
  4.5344 -+@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  4.5345 -+
  4.5346 - my $save_temps = $ENV{DEBUG};
  4.5347 - my $verbose = $ENV{VERBOSE};
  4.5348 - 
  4.5349 -diff -Naurp coreutils-8.27-orig/tests/unexpand/mb.sh coreutils-8.27/tests/unexpand/mb.sh
  4.5350 ---- coreutils-8.27-orig/tests/unexpand/mb.sh	1969-12-31 18:00:00.000000000 -0600
  4.5351 -+++ coreutils-8.27/tests/unexpand/mb.sh	2017-03-11 23:49:06.759133489 -0600
  4.5352 -@@ -0,0 +1,172 @@
  4.5353 -+#!/bin/sh
  4.5354 -+
  4.5355 -+# Copyright (C) 2012-2017 Free Software Foundation, Inc.
  4.5356 -+
  4.5357 -+# This program is free software: you can redistribute it and/or modify
  4.5358 -+# it under the terms of the GNU General Public License as published by
  4.5359 -+# the Free Software Foundation, either version 3 of the License, or
  4.5360 -+# (at your option) any later version.
  4.5361 -+
  4.5362 -+# This program is distributed in the hope that it will be useful,
  4.5363 -+# but WITHOUT ANY WARRANTY; without even the implied warranty of
  4.5364 -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  4.5365 -+# GNU General Public License for more details.
  4.5366 -+
  4.5367 -+# You should have received a copy of the GNU General Public License
  4.5368 -+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
  4.5369 -+
  4.5370 -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  4.5371 -+print_ver_ unexpand
  4.5372 -+
  4.5373 -+export LC_ALL=en_US.UTF-8
  4.5374 -+
  4.5375 -+#input containing multibyte characters
  4.5376 -+cat > in <<\EOF
  4.5377 -+1234567812345678123456781
  4.5378 -+.       .       .       .
  4.5379 -+a       b       c       d
  4.5380 -+.       .       .       .
  4.5381 -+ä       ö       ü       ß
  4.5382 -+.       .       .       .
  4.5383 -+   äöü  .    öüä.       ä xx
  4.5384 -+EOF
  4.5385 -+
  4.5386 -+cat > exp <<\EOF
  4.5387 -+1234567812345678123456781
  4.5388 -+.	.	.	.
  4.5389 -+a	b	c	d
  4.5390 -+.	.	.	.
  4.5391 -+ä	ö	ü	ß
  4.5392 -+.	.	.	.
  4.5393 -+   äöü	.    öüä.	ä xx
  4.5394 -+EOF
  4.5395 -+
  4.5396 -+unexpand -a < in > out || fail=1
  4.5397 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5398 -+
  4.5399 -+
  4.5400 -+#multiple files as an input
  4.5401 -+cat >> exp <<\EOF
  4.5402 -+1234567812345678123456781
  4.5403 -+.	.	.	.
  4.5404 -+a	b	c	d
  4.5405 -+.	.	.	.
  4.5406 -+ä	ö	ü	ß
  4.5407 -+.	.	.	.
  4.5408 -+   äöü	.    öüä.	ä xx
  4.5409 -+EOF
  4.5410 -+
  4.5411 -+
  4.5412 -+unexpand -a ./in ./in > out || fail=1
  4.5413 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5414 -+
  4.5415 -+#test characters with a display width larger than 1
  4.5416 -+
  4.5417 -+env printf '12345678
  4.5418 -+e       |ascii(1)
  4.5419 -+\u00E9       |composed(1)
  4.5420 -+e\u0301       |decomposed(1)
  4.5421 -+\u3000      |ideo-space(2)
  4.5422 -+\uFF0D      |full-hypen(2)
  4.5423 -+' > in || framework_failure_
  4.5424 -+
  4.5425 -+env printf '12345678
  4.5426 -+e\t|ascii(1)
  4.5427 -+\u00E9\t|composed(1)
  4.5428 -+e\u0301\t|decomposed(1)
  4.5429 -+\u3000\t|ideo-space(2)
  4.5430 -+\uFF0D\t|full-hypen(2)
  4.5431 -+' > exp || framework_failure_
  4.5432 -+
  4.5433 -+unexpand -a < in > out || fail=1
  4.5434 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5435 -+
  4.5436 -+#test input where a blank of width > 1 is not being substituted
  4.5437 -+in="$(LC_ALL=en_US.UTF-8 printf ' \u3000  ö       ü       ß')"
  4.5438 -+exp='    ö	     ü	     ß'
  4.5439 -+
  4.5440 -+unexpand -a < in > out || fail=1
  4.5441 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5442 -+
  4.5443 -+#non-Unicode characters interspersed between Unicode ones
  4.5444 -+env printf '12345678
  4.5445 -+        \xFF|
  4.5446 -+\xFF       |
  4.5447 -+        \xFFä|
  4.5448 -+ä\xFF      |
  4.5449 -+        ä\xFF|
  4.5450 -+\xFF       ä|
  4.5451 -+äbcdef\xFF |
  4.5452 -+' > in || framework_failure_
  4.5453 -+
  4.5454 -+env printf '12345678
  4.5455 -+\t\xFF|
  4.5456 -+\xFF\t|
  4.5457 -+\t\xFFä|
  4.5458 -+ä\xFF\t|
  4.5459 -+\tä\xFF|
  4.5460 -+\xFF\tä|
  4.5461 -+äbcdef\xFF\t|
  4.5462 -+' > exp || framework_failure_
  4.5463 -+
  4.5464 -+unexpand -a < in > out || fail=1
  4.5465 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5466 -+
  4.5467 -+#BOM header test 1
  4.5468 -+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_
  4.5469 -+1234567812345678123456781
  4.5470 -+.       .       .       .
  4.5471 -+a       b       c       d
  4.5472 -+.       .       .       .
  4.5473 -+ä       ö       ü       ß
  4.5474 -+.       .       .       .
  4.5475 -+   äöü  .    öüä.       ä xx
  4.5476 -+EOF
  4.5477 -+env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
  4.5478 -+
  4.5479 -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
  4.5480 -+1234567812345678123456781
  4.5481 -+.	.	.	.
  4.5482 -+a	b	c	d
  4.5483 -+.	.	.	.
  4.5484 -+ä	ö	ü	ß
  4.5485 -+.	.	.	.
  4.5486 -+   äöü	.    öüä.	ä xx
  4.5487 -+EOF
  4.5488 -+
  4.5489 -+unexpand < in > out || fail=1
  4.5490 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5491 -+
  4.5492 -+LANG=C unexpand < in > out || fail=1
  4.5493 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5494 -+
  4.5495 -+LC_ALL=C unexpand < in > out || fail=1
  4.5496 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5497 -+
  4.5498 -+
  4.5499 -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
  4.5500 -+1234567812345678123456781
  4.5501 -+.	.	.	.
  4.5502 -+a	b	c	d
  4.5503 -+.	.	.	.
  4.5504 -+ä	ö	ü	ß
  4.5505 -+.	.	.	.
  4.5506 -+   äöü	.    öüä.	ä xx
  4.5507 -+1234567812345678123456781
  4.5508 -+.	.	.	.
  4.5509 -+a	b	c	d
  4.5510 -+.	.	.	.
  4.5511 -+ä	ö	ü	ß
  4.5512 -+.	.	.	.
  4.5513 -+   äöü	.    öüä.	ä xx
  4.5514 -+EOF
  4.5515 -+
  4.5516 -+
  4.5517 -+unexpand in in > out || fail=1
  4.5518 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5519 -+
  4.5520 -+LANG=C unexpand in in > out || fail=1
  4.5521 -+compare exp out > /dev/null 2>&1 || fail=1
  4.5522 -+
  4.5523 -+LC_ALL=C unexpand in in > out || fail=1
  4.5524 -+compare exp out > /dev/null 2>&1 || fail=1
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/coreutils/stuff/patches/coreutils-8.30-i18n-1.patch	Tue Aug 07 00:30:45 2018 +0300
     5.3 @@ -0,0 +1,5521 @@
     5.4 +Submitted by:            DJ Lucas (dj_AT_linuxfromscratch_DOT_org)
     5.5 +Date:                    2017-03-12
     5.6 +Initial Package Version: 8.27
     5.7 +Upstream Status:         Rejected
     5.8 +Origin:                  Based on Fedora's i18n patches at
     5.9 +                         http://pkgs.fedoraproject.org/cgit/rpms/coreutils.git/tree/
    5.10 +Description:             Fixes i18n issues with various Coreutils programs
    5.11 +
    5.12 +diff -Naurp coreutils-8.27-orig/bootstrap.conf coreutils-8.27/bootstrap.conf
    5.13 +--- coreutils-8.27-orig/bootstrap.conf	2017-03-07 23:34:06.000000000 -0600
    5.14 ++++ coreutils-8.27/bootstrap.conf	2017-03-11 23:47:38.068058445 -0600
    5.15 +@@ -152,6 +152,7 @@ gnulib_modules="
    5.16 +   maintainer-makefile
    5.17 +   malloc-gnu
    5.18 +   manywarnings
    5.19 ++  mbfile
    5.20 +   mbrlen
    5.21 +   mbrtowc
    5.22 +   mbsalign
    5.23 +diff -Naurp coreutils-8.27-orig/configure.ac coreutils-8.27/configure.ac
    5.24 +--- coreutils-8.27-orig/configure.ac	2017-02-26 08:52:29.000000000 -0600
    5.25 ++++ coreutils-8.27/configure.ac	2017-03-11 23:47:38.068058445 -0600
    5.26 +@@ -429,6 +429,8 @@ fi
    5.27 + # I'm leaving it here for now.  This whole thing needs to be modernized...
    5.28 + gl_WINSIZE_IN_PTEM
    5.29 + 
    5.30 ++gl_MBFILE
    5.31 ++
    5.32 + gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H
    5.33 + 
    5.34 + if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \
    5.35 +diff -Naurp coreutils-8.27-orig/lib/linebuffer.h coreutils-8.27/lib/linebuffer.h
    5.36 +--- coreutils-8.27-orig/lib/linebuffer.h	2017-01-01 16:35:38.000000000 -0600
    5.37 ++++ coreutils-8.27/lib/linebuffer.h	2017-03-11 23:47:13.089286391 -0600
    5.38 +@@ -21,6 +21,11 @@
    5.39 + 
    5.40 + # include <stdio.h>
    5.41 + 
    5.42 ++/* Get mbstate_t.  */
    5.43 ++# if HAVE_WCHAR_H
    5.44 ++#  include <wchar.h>
    5.45 ++# endif
    5.46 ++
    5.47 + /* A 'struct linebuffer' holds a line of text. */
    5.48 + 
    5.49 + struct linebuffer
    5.50 +@@ -28,6 +33,9 @@ struct linebuffer
    5.51 +   size_t size;                  /* Allocated. */
    5.52 +   size_t length;                /* Used. */
    5.53 +   char *buffer;
    5.54 ++# if HAVE_WCHAR_H
    5.55 ++  mbstate_t state;
    5.56 ++# endif
    5.57 + };
    5.58 + 
    5.59 + /* Initialize linebuffer LINEBUFFER for use. */
    5.60 +diff -Naurp coreutils-8.27-orig/lib/mbfile.c coreutils-8.27/lib/mbfile.c
    5.61 +--- coreutils-8.27-orig/lib/mbfile.c	1969-12-31 18:00:00.000000000 -0600
    5.62 ++++ coreutils-8.27/lib/mbfile.c	2017-03-11 23:47:38.069058397 -0600
    5.63 +@@ -0,0 +1,3 @@
    5.64 ++#include <config.h>
    5.65 ++#define MBFILE_INLINE _GL_EXTERN_INLINE
    5.66 ++#include "mbfile.h"
    5.67 +diff -Naurp coreutils-8.27-orig/lib/mbfile.h coreutils-8.27/lib/mbfile.h
    5.68 +--- coreutils-8.27-orig/lib/mbfile.h	1969-12-31 18:00:00.000000000 -0600
    5.69 ++++ coreutils-8.27/lib/mbfile.h	2017-03-11 23:47:38.069058397 -0600
    5.70 +@@ -0,0 +1,255 @@
    5.71 ++/* Multibyte character I/O: macros for multi-byte encodings.
    5.72 ++   Copyright (C) 2001, 2005, 2009-2017 Free Software Foundation, Inc.
    5.73 ++
    5.74 ++   This program is free software: you can redistribute it and/or modify
    5.75 ++   it under the terms of the GNU General Public License as published by
    5.76 ++   the Free Software Foundation; either version 3 of the License, or
    5.77 ++   (at your option) any later version.
    5.78 ++
    5.79 ++   This program is distributed in the hope that it will be useful,
    5.80 ++   but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.81 ++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.82 ++   GNU General Public License for more details.
    5.83 ++
    5.84 ++   You should have received a copy of the GNU General Public License
    5.85 ++   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
    5.86 ++
    5.87 ++/* Written by Mitsuru Chinen <mchinen@yamato.ibm.com>
    5.88 ++   and Bruno Haible <bruno@clisp.org>.  */
    5.89 ++
    5.90 ++/* The macros in this file implement multi-byte character input from a
    5.91 ++   stream.
    5.92 ++
    5.93 ++   mb_file_t
    5.94 ++     is the type for multibyte character input stream, usable for variable
    5.95 ++     declarations.
    5.96 ++
    5.97 ++   mbf_char_t
    5.98 ++     is the type for multibyte character or EOF, usable for variable
    5.99 ++     declarations.
   5.100 ++
   5.101 ++   mbf_init (mbf, stream)
   5.102 ++     initializes the MB_FILE for reading from stream.
   5.103 ++
   5.104 ++   mbf_getc (mbc, mbf)
   5.105 ++     reads the next multibyte character from mbf and stores it in mbc.
   5.106 ++
   5.107 ++   mb_iseof (mbc)
   5.108 ++     returns true if mbc represents the EOF value.
   5.109 ++
   5.110 ++   Here are the function prototypes of the macros.
   5.111 ++
   5.112 ++   extern void          mbf_init (mb_file_t mbf, FILE *stream);
   5.113 ++   extern void          mbf_getc (mbf_char_t mbc, mb_file_t mbf);
   5.114 ++   extern bool          mb_iseof (const mbf_char_t mbc);
   5.115 ++ */
   5.116 ++
   5.117 ++#ifndef _MBFILE_H
   5.118 ++#define _MBFILE_H 1
   5.119 ++
   5.120 ++#include <assert.h>
   5.121 ++#include <stdbool.h>
   5.122 ++#include <stdio.h>
   5.123 ++#include <string.h>
   5.124 ++
   5.125 ++/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
   5.126 ++   <wchar.h>.
   5.127 ++   BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before
   5.128 ++   <wchar.h>.  */
   5.129 ++#include <stdio.h>
   5.130 ++#include <time.h>
   5.131 ++#include <wchar.h>
   5.132 ++
   5.133 ++#include "mbchar.h"
   5.134 ++
   5.135 ++#ifndef _GL_INLINE_HEADER_BEGIN
   5.136 ++ #error "Please include config.h first."
   5.137 ++#endif
   5.138 ++_GL_INLINE_HEADER_BEGIN
   5.139 ++#ifndef MBFILE_INLINE
   5.140 ++# define MBFILE_INLINE _GL_INLINE
   5.141 ++#endif
   5.142 ++
   5.143 ++struct mbfile_multi {
   5.144 ++  FILE *fp;
   5.145 ++  bool eof_seen;
   5.146 ++  bool have_pushback;
   5.147 ++  mbstate_t state;
   5.148 ++  unsigned int bufcount;
   5.149 ++  char buf[MBCHAR_BUF_SIZE];
   5.150 ++  struct mbchar pushback;
   5.151 ++};
   5.152 ++
   5.153 ++MBFILE_INLINE void
   5.154 ++mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf)
   5.155 ++{
   5.156 ++  size_t bytes;
   5.157 ++
   5.158 ++  /* If EOF has already been seen, don't use getc.  This matters if
   5.159 ++     mbf->fp is connected to an interactive tty.  */
   5.160 ++  if (mbf->eof_seen)
   5.161 ++    goto eof;
   5.162 ++
   5.163 ++  /* Return character pushed back, if there is one.  */
   5.164 ++  if (mbf->have_pushback)
   5.165 ++    {
   5.166 ++      mb_copy (mbc, &mbf->pushback);
   5.167 ++      mbf->have_pushback = false;
   5.168 ++      return;
   5.169 ++    }
   5.170 ++
   5.171 ++  /* Before using mbrtowc, we need at least one byte.  */
   5.172 ++  if (mbf->bufcount == 0)
   5.173 ++    {
   5.174 ++      int c = getc (mbf->fp);
   5.175 ++      if (c == EOF)
   5.176 ++        {
   5.177 ++          mbf->eof_seen = true;
   5.178 ++          goto eof;
   5.179 ++        }
   5.180 ++      mbf->buf[0] = (unsigned char) c;
   5.181 ++      mbf->bufcount++;
   5.182 ++    }
   5.183 ++
   5.184 ++  /* Handle most ASCII characters quickly, without calling mbrtowc().  */
   5.185 ++  if (mbf->bufcount == 1 && mbsinit (&mbf->state) && is_basic (mbf->buf[0]))
   5.186 ++    {
   5.187 ++      /* These characters are part of the basic character set.  ISO C 99
   5.188 ++         guarantees that their wide character code is identical to their
   5.189 ++         char code.  */
   5.190 ++      mbc->wc = mbc->buf[0] = mbf->buf[0];
   5.191 ++      mbc->wc_valid = true;
   5.192 ++      mbc->ptr = &mbc->buf[0];
   5.193 ++      mbc->bytes = 1;
   5.194 ++      mbf->bufcount = 0;
   5.195 ++      return;
   5.196 ++    }
   5.197 ++
   5.198 ++  /* Use mbrtowc on an increasing number of bytes.  Read only as many bytes
   5.199 ++     from mbf->fp as needed.  This is needed to give reasonable interactive
   5.200 ++     behaviour when mbf->fp is connected to an interactive tty.  */
   5.201 ++  for (;;)
   5.202 ++    {
   5.203 ++      /* We don't know whether the 'mbrtowc' function updates the state when
   5.204 ++         it returns -2, - this is the ISO C 99 and glibc-2.2 behaviour - or
   5.205 ++         not - amended ANSI C, glibc-2.1 and Solaris 2.7 behaviour.  We
   5.206 ++         don't have an autoconf test for this, yet.
   5.207 ++         The new behaviour would allow us to feed the bytes one by one into
   5.208 ++         mbrtowc.  But the old behaviour forces us to feed all bytes since
   5.209 ++         the end of the last character into mbrtowc.  Since we want to retry
   5.210 ++         with more bytes when mbrtowc returns -2, we must backup the state
   5.211 ++         before calling mbrtowc, because implementations with the new
   5.212 ++         behaviour will clobber it.  */
   5.213 ++      mbstate_t backup_state = mbf->state;
   5.214 ++
   5.215 ++      bytes = mbrtowc (&mbc->wc, &mbf->buf[0], mbf->bufcount, &mbf->state);
   5.216 ++
   5.217 ++      if (bytes == (size_t) -1)
   5.218 ++        {
   5.219 ++          /* An invalid multibyte sequence was encountered.  */
   5.220 ++          /* Return a single byte.  */
   5.221 ++          bytes = 1;
   5.222 ++          mbc->wc_valid = false;
   5.223 ++          break;
   5.224 ++        }
   5.225 ++      else if (bytes == (size_t) -2)
   5.226 ++        {
   5.227 ++          /* An incomplete multibyte character.  */
   5.228 ++          mbf->state = backup_state;
   5.229 ++          if (mbf->bufcount == MBCHAR_BUF_SIZE)
   5.230 ++            {
   5.231 ++              /* An overlong incomplete multibyte sequence was encountered.  */
   5.232 ++              /* Return a single byte.  */
   5.233 ++              bytes = 1;
   5.234 ++              mbc->wc_valid = false;
   5.235 ++              break;
   5.236 ++            }
   5.237 ++          else
   5.238 ++            {
   5.239 ++              /* Read one more byte and retry mbrtowc.  */
   5.240 ++              int c = getc (mbf->fp);
   5.241 ++              if (c == EOF)
   5.242 ++                {
   5.243 ++                  /* An incomplete multibyte character at the end.  */
   5.244 ++                  mbf->eof_seen = true;
   5.245 ++                  bytes = mbf->bufcount;
   5.246 ++                  mbc->wc_valid = false;
   5.247 ++                  break;
   5.248 ++                }
   5.249 ++              mbf->buf[mbf->bufcount] = (unsigned char) c;
   5.250 ++              mbf->bufcount++;
   5.251 ++            }
   5.252 ++        }
   5.253 ++      else
   5.254 ++        {
   5.255 ++          if (bytes == 0)
   5.256 ++            {
   5.257 ++              /* A null wide character was encountered.  */
   5.258 ++              bytes = 1;
   5.259 ++              assert (mbf->buf[0] == '\0');
   5.260 ++              assert (mbc->wc == 0);
   5.261 ++            }
   5.262 ++          mbc->wc_valid = true;
   5.263 ++          break;
   5.264 ++        }
   5.265 ++    }
   5.266 ++
   5.267 ++  /* Return the multibyte sequence mbf->buf[0..bytes-1].  */
   5.268 ++  mbc->ptr = &mbc->buf[0];
   5.269 ++  memcpy (&mbc->buf[0], &mbf->buf[0], bytes);
   5.270 ++  mbc->bytes = bytes;
   5.271 ++
   5.272 ++  mbf->bufcount -= bytes;
   5.273 ++  if (mbf->bufcount > 0)
   5.274 ++    {
   5.275 ++      /* It's not worth calling memmove() for so few bytes.  */
   5.276 ++      unsigned int count = mbf->bufcount;
   5.277 ++      char *p = &mbf->buf[0];
   5.278 ++
   5.279 ++      do
   5.280 ++        {
   5.281 ++          *p = *(p + bytes);
   5.282 ++          p++;
   5.283 ++        }
   5.284 ++      while (--count > 0);
   5.285 ++    }
   5.286 ++  return;
   5.287 ++
   5.288 ++eof:
   5.289 ++  /* An mbchar_t with bytes == 0 is used to indicate EOF.  */
   5.290 ++  mbc->ptr = NULL;
   5.291 ++  mbc->bytes = 0;
   5.292 ++  mbc->wc_valid = false;
   5.293 ++  return;
   5.294 ++}
   5.295 ++
   5.296 ++MBFILE_INLINE void
   5.297 ++mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf)
   5.298 ++{
   5.299 ++  mb_copy (&mbf->pushback, mbc);
   5.300 ++  mbf->have_pushback = true;
   5.301 ++}
   5.302 ++
   5.303 ++typedef struct mbfile_multi mb_file_t;
   5.304 ++
   5.305 ++typedef mbchar_t mbf_char_t;
   5.306 ++
   5.307 ++#define mbf_init(mbf, stream)                                           \
   5.308 ++  ((mbf).fp = (stream),                                                 \
   5.309 ++   (mbf).eof_seen = false,                                              \
   5.310 ++   (mbf).have_pushback = false,                                         \
   5.311 ++   memset (&(mbf).state, '\0', sizeof (mbstate_t)),                     \
   5.312 ++   (mbf).bufcount = 0)
   5.313 ++
   5.314 ++#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf))
   5.315 ++
   5.316 ++#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf))
   5.317 ++
   5.318 ++#define mb_iseof(mbc) ((mbc).bytes == 0)
   5.319 ++
   5.320 ++#ifndef _GL_INLINE_HEADER_BEGIN
   5.321 ++ #error "Please include config.h first."
   5.322 ++#endif
   5.323 ++_GL_INLINE_HEADER_BEGIN
   5.324 ++
   5.325 ++#endif /* _MBFILE_H */
   5.326 +diff -Naurp coreutils-8.27-orig/m4/mbfile.m4 coreutils-8.27/m4/mbfile.m4
   5.327 +--- coreutils-8.27-orig/m4/mbfile.m4	1969-12-31 18:00:00.000000000 -0600
   5.328 ++++ coreutils-8.27/m4/mbfile.m4	2017-03-11 23:47:38.070058349 -0600
   5.329 +@@ -0,0 +1,14 @@
   5.330 ++# mbfile.m4 serial 7
   5.331 ++dnl Copyright (C) 2005, 2008-2017 Free Software Foundation, Inc.
   5.332 ++dnl This file is free software; the Free Software Foundation
   5.333 ++dnl gives unlimited permission to copy and/or distribute it,
   5.334 ++dnl with or without modifications, as long as this notice is preserved.
   5.335 ++
   5.336 ++dnl autoconf tests required for use of mbfile.h
   5.337 ++dnl From Bruno Haible.
   5.338 ++
   5.339 ++AC_DEFUN([gl_MBFILE],
   5.340 ++[
   5.341 ++  AC_REQUIRE([AC_TYPE_MBSTATE_T])
   5.342 ++  :
   5.343 ++])
   5.344 +diff -Naurp coreutils-8.27-orig/src/cut.c coreutils-8.27/src/cut.c
   5.345 +--- coreutils-8.27-orig/src/cut.c	2017-01-01 16:34:24.000000000 -0600
   5.346 ++++ coreutils-8.27/src/cut.c	2017-03-11 23:47:59.526048471 -0600
   5.347 +@@ -28,6 +28,11 @@
   5.348 + #include <assert.h>
   5.349 + #include <getopt.h>
   5.350 + #include <sys/types.h>
   5.351 ++
   5.352 ++/* Get mbstate_t, mbrtowc().  */
   5.353 ++#if HAVE_WCHAR_H
   5.354 ++# include <wchar.h>
   5.355 ++#endif
   5.356 + #include "system.h"
   5.357 + 
   5.358 + #include "error.h"
   5.359 +@@ -38,6 +43,18 @@
   5.360 + 
   5.361 + #include "set-fields.h"
   5.362 + 
   5.363 ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
   5.364 ++   installation; work around this configuration error.        */
   5.365 ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
   5.366 ++# undef MB_LEN_MAX
   5.367 ++# define MB_LEN_MAX 16
   5.368 ++#endif
   5.369 ++
   5.370 ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
   5.371 ++#if HAVE_MBRTOWC && defined mbstate_t
   5.372 ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
   5.373 ++#endif
   5.374 ++
   5.375 + /* The official name of this program (e.g., no 'g' prefix).  */
   5.376 + #define PROGRAM_NAME "cut"
   5.377 + 
   5.378 +@@ -54,6 +71,52 @@
   5.379 +     }									\
   5.380 +   while (0)
   5.381 + 
   5.382 ++/* Refill the buffer BUF to get a multibyte character. */
   5.383 ++#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM)                        \
   5.384 ++  do                                                                        \
   5.385 ++    {                                                                        \
   5.386 ++      if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM))        \
   5.387 ++        {                                                                \
   5.388 ++          memmove (BUF, BUFPOS, BUFLEN);                                \
   5.389 ++          BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \
   5.390 ++          BUFPOS = BUF;                                                        \
   5.391 ++        }                                                                \
   5.392 ++    }                                                                        \
   5.393 ++  while (0)
   5.394 ++
   5.395 ++/* Get wide character on BUFPOS. BUFPOS is not included after that.
   5.396 ++   If byte sequence is not valid as a character, CONVFAIL is true. Otherwise false. */
   5.397 ++#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \
   5.398 ++  do                                                                        \
   5.399 ++    {                                                                        \
   5.400 ++      mbstate_t state_bak;                                                \
   5.401 ++                                                                        \
   5.402 ++      if (BUFLEN < 1)                                                        \
   5.403 ++        {                                                                \
   5.404 ++          WC = WEOF;                                                        \
   5.405 ++          break;                                                        \
   5.406 ++        }                                                                \
   5.407 ++                                                                        \
   5.408 ++      /* Get a wide character. */                                        \
   5.409 ++      CONVFAIL = false;                                                        \
   5.410 ++      state_bak = STATE;                                                \
   5.411 ++      MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE);        \
   5.412 ++                                                                        \
   5.413 ++      switch (MBLENGTH)                                                        \
   5.414 ++        {                                                                \
   5.415 ++        case (size_t)-1:                                                \
   5.416 ++        case (size_t)-2:                                                \
   5.417 ++          CONVFAIL = true;                                                        \
   5.418 ++          STATE = state_bak;                                                \
   5.419 ++          /* Fall througn. */                                                \
   5.420 ++                                                                        \
   5.421 ++        case 0:                                                                \
   5.422 ++          MBLENGTH = 1;                                                        \
   5.423 ++          break;                                                        \
   5.424 ++        }                                                                \
   5.425 ++    }                                                                        \
   5.426 ++  while (0)
   5.427 ++
   5.428 + 
   5.429 + /* Pointer inside RP.  When checking if a byte or field is selected
   5.430 +    by a finite range, we check if it is between CURRENT_RP.LO
   5.431 +@@ -61,6 +124,9 @@
   5.432 +    CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */
   5.433 + static struct field_range_pair *current_rp;
   5.434 + 
   5.435 ++/* Length of the delimiter given as argument to -d.  */
   5.436 ++size_t delimlen;
   5.437 ++
   5.438 + /* This buffer is used to support the semantics of the -s option
   5.439 +    (or lack of same) when the specified field list includes (does
   5.440 +    not include) the first field.  In both of those cases, the entire
   5.441 +@@ -77,15 +143,25 @@ enum operating_mode
   5.442 +   {
   5.443 +     undefined_mode,
   5.444 + 
   5.445 +-    /* Output characters that are in the given bytes. */
   5.446 ++    /* Output bytes that are at the given positions. */
   5.447 +     byte_mode,
   5.448 + 
   5.449 ++    /* Output characters that are at the given positions. */
   5.450 ++    character_mode,
   5.451 ++
   5.452 +     /* Output the given delimiter-separated fields. */
   5.453 +     field_mode
   5.454 +   };
   5.455 + 
   5.456 + static enum operating_mode operating_mode;
   5.457 + 
   5.458 ++/* If nonzero, when in byte mode, don't split multibyte characters.  */
   5.459 ++static int byte_mode_character_aware;
   5.460 ++
   5.461 ++/* If nonzero, the function for single byte locale is work
   5.462 ++   if this program runs on multibyte locale. */
   5.463 ++static int force_singlebyte_mode;
   5.464 ++
   5.465 + /* If true do not output lines containing no delimiter characters.
   5.466 +    Otherwise, all such lines are printed.  This option is valid only
   5.467 +    with field mode.  */
   5.468 +@@ -97,6 +173,9 @@ static bool complement;
   5.469 + 
   5.470 + /* The delimiter character for field mode. */
   5.471 + static unsigned char delim;
   5.472 ++#if HAVE_WCHAR_H
   5.473 ++static wchar_t wcdelim;
   5.474 ++#endif
   5.475 + 
   5.476 + /* The delimiter for each line/record. */
   5.477 + static unsigned char line_delim = '\n';
   5.478 +@@ -164,7 +243,7 @@ Print selected parts of lines from each
   5.479 +   -f, --fields=LIST       select only these fields;  also print any line\n\
   5.480 +                             that contains no delimiter character, unless\n\
   5.481 +                             the -s option is specified\n\
   5.482 +-  -n                      (ignored)\n\
   5.483 ++  -n                      with -b: don't split multibyte characters\n\
   5.484 + "), stdout);
   5.485 +       fputs (_("\
   5.486 +       --complement        complement the set of selected bytes, characters\n\
   5.487 +@@ -280,6 +359,82 @@ cut_bytes (FILE *stream)
   5.488 +     }
   5.489 + }
   5.490 + 
   5.491 ++#if HAVE_MBRTOWC
   5.492 ++/* This function is in use for the following case.
   5.493 ++
   5.494 ++   1. Read from the stream STREAM, printing to standard output any selected
   5.495 ++   characters.
   5.496 ++
   5.497 ++   2. Read from stream STREAM, printing to standard output any selected bytes,
   5.498 ++   without splitting multibyte characters.  */
   5.499 ++
   5.500 ++static void
   5.501 ++cut_characters_or_cut_bytes_no_split (FILE *stream)
   5.502 ++{
   5.503 ++  size_t idx;                /* number of bytes or characters in the line so far. */
   5.504 ++  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
   5.505 ++  char *bufpos;                /* Next read position of BUF. */
   5.506 ++  size_t buflen;        /* The length of the byte sequence in buf. */
   5.507 ++  wint_t wc;                /* A gotten wide character. */
   5.508 ++  size_t mblength;        /* The byte size of a multibyte character which shows
   5.509 ++                           as same character as WC. */
   5.510 ++  mbstate_t state;        /* State of the stream. */
   5.511 ++  bool convfail = false;  /* true, when conversion failed. Otherwise false. */
   5.512 ++  /* Whether to begin printing delimiters between ranges for the current line.
   5.513 ++     Set after we've begun printing data corresponding to the first range.  */
   5.514 ++  bool print_delimiter = false;
   5.515 ++
   5.516 ++  idx = 0;
   5.517 ++  buflen = 0;
   5.518 ++  bufpos = buf;
   5.519 ++  memset (&state, '\0', sizeof(mbstate_t));
   5.520 ++
   5.521 ++  current_rp = frp;
   5.522 ++
   5.523 ++  while (1)
   5.524 ++    {
   5.525 ++      REFILL_BUFFER (buf, bufpos, buflen, stream);
   5.526 ++
   5.527 ++      GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail);
   5.528 ++      (void) convfail;  /* ignore unused */
   5.529 ++
   5.530 ++      if (wc == WEOF)
   5.531 ++        {
   5.532 ++          if (idx > 0)
   5.533 ++            putchar (line_delim);
   5.534 ++          break;
   5.535 ++        }
   5.536 ++      else if (wc == line_delim)
   5.537 ++        {
   5.538 ++          putchar (line_delim);
   5.539 ++          idx = 0;
   5.540 ++          print_delimiter = false;
   5.541 ++          current_rp = frp;
   5.542 ++        }
   5.543 ++      else
   5.544 ++        {
   5.545 ++          next_item (&idx);
   5.546 ++          if (print_kth (idx))
   5.547 ++            {
   5.548 ++              if (output_delimiter_specified)
   5.549 ++                {
   5.550 ++                  if (print_delimiter && is_range_start_index (idx))
   5.551 ++                    {
   5.552 ++                      fwrite (output_delimiter_string, sizeof (char),
   5.553 ++                              output_delimiter_length, stdout);
   5.554 ++                    }
   5.555 ++                  print_delimiter = true;
   5.556 ++                }
   5.557 ++              fwrite (bufpos, mblength, sizeof(char), stdout);
   5.558 ++            }
   5.559 ++        }
   5.560 ++
   5.561 ++      buflen -= mblength;
   5.562 ++      bufpos += mblength;
   5.563 ++    }
   5.564 ++}
   5.565 ++#endif
   5.566 ++
   5.567 + /* Read from stream STREAM, printing to standard output any selected fields.  */
   5.568 + 
   5.569 + static void
   5.570 +@@ -425,13 +580,211 @@ cut_fields (FILE *stream)
   5.571 +     }
   5.572 + }
   5.573 + 
   5.574 ++#if HAVE_MBRTOWC
   5.575 ++static void
   5.576 ++cut_fields_mb (FILE *stream)
   5.577 ++{
   5.578 ++  int c;
   5.579 ++  size_t field_idx;
   5.580 ++  int found_any_selected_field;
   5.581 ++  int buffer_first_field;
   5.582 ++  int empty_input;
   5.583 ++  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
   5.584 ++  char *bufpos;                /* Next read position of BUF. */
   5.585 ++  size_t buflen;        /* The length of the byte sequence in buf. */
   5.586 ++  wint_t wc = 0;        /* A gotten wide character. */
   5.587 ++  size_t mblength;        /* The byte size of a multibyte character which shows
   5.588 ++                           as same character as WC. */
   5.589 ++  mbstate_t state;        /* State of the stream. */
   5.590 ++  bool convfail = false;  /* true, when conversion failed. Otherwise false. */
   5.591 ++
   5.592 ++  current_rp = frp;
   5.593 ++
   5.594 ++  found_any_selected_field = 0;
   5.595 ++  field_idx = 1;
   5.596 ++  bufpos = buf;
   5.597 ++  buflen = 0;
   5.598 ++  memset (&state, '\0', sizeof(mbstate_t));
   5.599 ++
   5.600 ++  c = getc (stream);
   5.601 ++  empty_input = (c == EOF);
   5.602 ++  if (c != EOF)
   5.603 ++  {
   5.604 ++    ungetc (c, stream);
   5.605 ++    wc = 0;
   5.606 ++  }
   5.607 ++  else
   5.608 ++    wc = WEOF;
   5.609 ++
   5.610 ++  /* To support the semantics of the -s flag, we may have to buffer
   5.611 ++     all of the first field to determine whether it is `delimited.'
   5.612 ++     But that is unnecessary if all non-delimited lines must be printed
   5.613 ++     and the first field has been selected, or if non-delimited lines
   5.614 ++     must be suppressed and the first field has *not* been selected.
   5.615 ++     That is because a non-delimited line has exactly one field.  */
   5.616 ++  buffer_first_field = (suppress_non_delimited ^ !print_kth (1));
   5.617 ++
   5.618 ++  while (1)
   5.619 ++    {
   5.620 ++      if (field_idx == 1 && buffer_first_field)
   5.621 ++        {
   5.622 ++          int len = 0;
   5.623 ++
   5.624 ++          while (1)
   5.625 ++            {
   5.626 ++              REFILL_BUFFER (buf, bufpos, buflen, stream);
   5.627 ++
   5.628 ++              GET_NEXT_WC_FROM_BUFFER
   5.629 ++                (wc, bufpos, buflen, mblength, state, convfail);
   5.630 ++
   5.631 ++              if (wc == WEOF)
   5.632 ++                break;
   5.633 ++
   5.634 ++              field_1_buffer = xrealloc (field_1_buffer, len + mblength);
   5.635 ++              memcpy (field_1_buffer + len, bufpos, mblength);
   5.636 ++              len += mblength;
   5.637 ++              buflen -= mblength;
   5.638 ++              bufpos += mblength;
   5.639 ++
   5.640 ++              if (!convfail && (wc == line_delim || wc == wcdelim))
   5.641 ++                break;
   5.642 ++            }
   5.643 ++
   5.644 ++          if (len <= 0 && wc == WEOF)
   5.645 ++            break;
   5.646 ++
   5.647 ++          /* If the first field extends to the end of line (it is not
   5.648 ++             delimited) and we are printing all non-delimited lines,
   5.649 ++             print this one.  */
   5.650 ++          if (convfail || (!convfail && wc != wcdelim))
   5.651 ++            {
   5.652 ++              if (suppress_non_delimited)
   5.653 ++                {
   5.654 ++                  /* Empty.        */
   5.655 ++                }
   5.656 ++              else
   5.657 ++                {
   5.658 ++                  fwrite (field_1_buffer, sizeof (char), len, stdout);
   5.659 ++                  /* Make sure the output line is newline terminated.  */
   5.660 ++                  if (convfail || (!convfail && wc != line_delim))
   5.661 ++                    putchar (line_delim);
   5.662 ++                }
   5.663 ++              continue;
   5.664 ++            }
   5.665 ++
   5.666 ++          if (print_kth (1))
   5.667 ++            {
   5.668 ++              /* Print the field, but not the trailing delimiter.  */
   5.669 ++              fwrite (field_1_buffer, sizeof (char), len - 1, stdout);
   5.670 ++              found_any_selected_field = 1;
   5.671 ++            }
   5.672 ++          next_item (&field_idx);
   5.673 ++        }
   5.674 ++
   5.675 ++      if (wc != WEOF)
   5.676 ++        {
   5.677 ++          if (print_kth (field_idx))
   5.678 ++            {
   5.679 ++              if (found_any_selected_field)
   5.680 ++                {
   5.681 ++                  fwrite (output_delimiter_string, sizeof (char),
   5.682 ++                          output_delimiter_length, stdout);
   5.683 ++                }
   5.684 ++              found_any_selected_field = 1;
   5.685 ++            }
   5.686 ++
   5.687 ++          while (1)
   5.688 ++            {
   5.689 ++              REFILL_BUFFER (buf, bufpos, buflen, stream);
   5.690 ++
   5.691 ++              GET_NEXT_WC_FROM_BUFFER
   5.692 ++                (wc, bufpos, buflen, mblength, state, convfail);
   5.693 ++
   5.694 ++              if (wc == WEOF)
   5.695 ++                break;
   5.696 ++              else if (!convfail && (wc == wcdelim || wc == line_delim))
   5.697 ++                {
   5.698 ++                  buflen -= mblength;
   5.699 ++                  bufpos += mblength;
   5.700 ++                  break;
   5.701 ++                }
   5.702 ++
   5.703 ++              if (print_kth (field_idx))
   5.704 ++                fwrite (bufpos, mblength, sizeof(char), stdout);
   5.705 ++
   5.706 ++              buflen -= mblength;
   5.707 ++              bufpos += mblength;
   5.708 ++            }
   5.709 ++        }
   5.710 ++
   5.711 ++      if ((!convfail || wc == line_delim) && buflen < 1)
   5.712 ++        wc = WEOF;
   5.713 ++
   5.714 ++      if (!convfail && wc == wcdelim)
   5.715 ++        next_item (&field_idx);
   5.716 ++      else if (wc == WEOF || (!convfail && wc == line_delim))
   5.717 ++        {
   5.718 ++          if (found_any_selected_field
   5.719 ++              || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
   5.720 ++            putchar (line_delim);
   5.721 ++          if (wc == WEOF)
   5.722 ++            break;
   5.723 ++          field_idx = 1;
   5.724 ++          current_rp = frp;
   5.725 ++          found_any_selected_field = 0;
   5.726 ++        }
   5.727 ++    }
   5.728 ++}
   5.729 ++#endif
   5.730 ++
   5.731 + static void
   5.732 + cut_stream (FILE *stream)
   5.733 + {
   5.734 +-  if (operating_mode == byte_mode)
   5.735 +-    cut_bytes (stream);
   5.736 ++#if HAVE_MBRTOWC
   5.737 ++  if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
   5.738 ++    {
   5.739 ++      switch (operating_mode)
   5.740 ++        {
   5.741 ++        case byte_mode:
   5.742 ++          if (byte_mode_character_aware)
   5.743 ++            cut_characters_or_cut_bytes_no_split (stream);
   5.744 ++          else
   5.745 ++            cut_bytes (stream);
   5.746 ++          break;
   5.747 ++
   5.748 ++        case character_mode:
   5.749 ++          cut_characters_or_cut_bytes_no_split (stream);
   5.750 ++          break;
   5.751 ++
   5.752 ++        case field_mode:
   5.753 ++          if (delimlen == 1)
   5.754 ++            {
   5.755 ++              /* Check if we have utf8 multibyte locale, so we can use this
   5.756 ++                 optimization because of uniqueness of characters, which is
   5.757 ++                 not true for e.g. SJIS */
   5.758 ++              char * loc = setlocale(LC_CTYPE, NULL);
   5.759 ++              if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") ||
   5.760 ++                  strstr (loc, "UTF8") || strstr (loc, "utf8")))
   5.761 ++                {
   5.762 ++                  cut_fields (stream);
   5.763 ++                  break;
   5.764 ++                }
   5.765 ++            }
   5.766 ++          cut_fields_mb (stream);
   5.767 ++          break;
   5.768 ++
   5.769 ++        default:
   5.770 ++          abort ();
   5.771 ++        }
   5.772 ++    }
   5.773 +   else
   5.774 +-    cut_fields (stream);
   5.775 ++#endif
   5.776 ++    {
   5.777 ++      if (operating_mode == field_mode)
   5.778 ++        cut_fields (stream);
   5.779 ++      else
   5.780 ++        cut_bytes (stream);
   5.781 ++    }
   5.782 + }
   5.783 + 
   5.784 + /* Process file FILE to standard output.
   5.785 +@@ -483,6 +836,7 @@ main (int argc, char **argv)
   5.786 +   bool ok;
   5.787 +   bool delim_specified = false;
   5.788 +   char *spec_list_string IF_LINT ( = NULL);
   5.789 ++  char mbdelim[MB_LEN_MAX + 1];
   5.790 + 
   5.791 +   initialize_main (&argc, &argv);
   5.792 +   set_program_name (argv[0]);
   5.793 +@@ -505,7 +859,6 @@ main (int argc, char **argv)
   5.794 +       switch (optc)
   5.795 +         {
   5.796 +         case 'b':
   5.797 +-        case 'c':
   5.798 +           /* Build the byte list. */
   5.799 +           if (operating_mode != undefined_mode)
   5.800 +             FATAL_ERROR (_("only one type of list may be specified"));
   5.801 +@@ -513,6 +866,14 @@ main (int argc, char **argv)
   5.802 +           spec_list_string = optarg;
   5.803 +           break;
   5.804 + 
   5.805 ++        case 'c':
   5.806 ++          /* Build the character list. */
   5.807 ++          if (operating_mode != undefined_mode)
   5.808 ++            FATAL_ERROR (_("only one type of list may be specified"));
   5.809 ++          operating_mode = character_mode;
   5.810 ++          spec_list_string = optarg;
   5.811 ++          break;
   5.812 ++
   5.813 +         case 'f':
   5.814 +           /* Build the field list. */
   5.815 +           if (operating_mode != undefined_mode)
   5.816 +@@ -524,10 +885,38 @@ main (int argc, char **argv)
   5.817 +         case 'd':
   5.818 +           /* New delimiter. */
   5.819 +           /* Interpret -d '' to mean 'use the NUL byte as the delimiter.'  */
   5.820 +-          if (optarg[0] != '\0' && optarg[1] != '\0')
   5.821 +-            FATAL_ERROR (_("the delimiter must be a single character"));
   5.822 +-          delim = optarg[0];
   5.823 +-          delim_specified = true;
   5.824 ++            {
   5.825 ++#if HAVE_MBRTOWC
   5.826 ++              if(MB_CUR_MAX > 1)
   5.827 ++                {
   5.828 ++                  mbstate_t state;
   5.829 ++
   5.830 ++                  memset (&state, '\0', sizeof(mbstate_t));
   5.831 ++                  delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
   5.832 ++
   5.833 ++                  if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
   5.834 ++                    ++force_singlebyte_mode;
   5.835 ++                  else
   5.836 ++                    {
   5.837 ++                      delimlen = (delimlen < 1) ? 1 : delimlen;
   5.838 ++                      if (wcdelim != L'\0' && *(optarg + delimlen) != '\0')
   5.839 ++                        FATAL_ERROR (_("the delimiter must be a single character"));
   5.840 ++                      memcpy (mbdelim, optarg, delimlen);
   5.841 ++                      mbdelim[delimlen] = '\0';
   5.842 ++                      if (delimlen == 1)
   5.843 ++                        delim = *optarg;
   5.844 ++                    }
   5.845 ++                }
   5.846 ++
   5.847 ++              if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
   5.848 ++#endif
   5.849 ++                {
   5.850 ++                  if (optarg[0] != '\0' && optarg[1] != '\0')
   5.851 ++                    FATAL_ERROR (_("the delimiter must be a single character"));
   5.852 ++                  delim = (unsigned char) optarg[0];
   5.853 ++                }
   5.854 ++            delim_specified = true;
   5.855 ++          }
   5.856 +           break;
   5.857 + 
   5.858 +         case OUTPUT_DELIMITER_OPTION:
   5.859 +@@ -540,6 +929,7 @@ main (int argc, char **argv)
   5.860 +           break;
   5.861 + 
   5.862 +         case 'n':
   5.863 ++          byte_mode_character_aware = 1;
   5.864 +           break;
   5.865 + 
   5.866 +         case 's':
   5.867 +@@ -579,15 +969,34 @@ main (int argc, char **argv)
   5.868 +               | (complement ? SETFLD_COMPLEMENT : 0) );
   5.869 + 
   5.870 +   if (!delim_specified)
   5.871 +-    delim = '\t';
   5.872 ++    {
   5.873 ++      delim = '\t';
   5.874 ++#ifdef HAVE_MBRTOWC
   5.875 ++      wcdelim = L'\t';
   5.876 ++      mbdelim[0] = '\t';
   5.877 ++      mbdelim[1] = '\0';
   5.878 ++      delimlen = 1;
   5.879 ++#endif
   5.880 ++    }
   5.881 + 
   5.882 +   if (output_delimiter_string == NULL)
   5.883 +     {
   5.884 +-      static char dummy[2];
   5.885 +-      dummy[0] = delim;
   5.886 +-      dummy[1] = '\0';
   5.887 +-      output_delimiter_string = dummy;
   5.888 +-      output_delimiter_length = 1;
   5.889 ++#ifdef HAVE_MBRTOWC
   5.890 ++      if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
   5.891 ++        {
   5.892 ++          output_delimiter_string = xstrdup(mbdelim);
   5.893 ++          output_delimiter_length = delimlen;
   5.894 ++        }
   5.895 ++
   5.896 ++      if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
   5.897 ++#endif
   5.898 ++        {
   5.899 ++          static char dummy[2];
   5.900 ++          dummy[0] = delim;
   5.901 ++          dummy[1] = '\0';
   5.902 ++          output_delimiter_string = dummy;
   5.903 ++          output_delimiter_length = 1;
   5.904 ++        }
   5.905 +     }
   5.906 + 
   5.907 +   if (optind == argc)
   5.908 +diff -Naurp coreutils-8.27-orig/src/expand.c coreutils-8.27/src/expand.c
   5.909 +--- coreutils-8.27-orig/src/expand.c	2017-02-26 15:42:25.000000000 -0600
   5.910 ++++ coreutils-8.27/src/expand.c	2017-03-11 23:49:06.758133530 -0600
   5.911 +@@ -37,6 +37,9 @@
   5.912 + #include <stdio.h>
   5.913 + #include <getopt.h>
   5.914 + #include <sys/types.h>
   5.915 ++
   5.916 ++#include <mbfile.h>
   5.917 ++
   5.918 + #include "system.h"
   5.919 + #include "die.h"
   5.920 + #include "xstrndup.h"
   5.921 +@@ -100,19 +103,41 @@ expand (void)
   5.922 + {
   5.923 +   /* Input stream.  */
   5.924 +   FILE *fp = next_file (NULL);
   5.925 ++  mb_file_t mbf;
   5.926 ++  mbf_char_t c;
   5.927 ++  /* True if the starting locale is utf8.  */
   5.928 ++  bool using_utf_locale;
   5.929 ++
   5.930 ++  /* True if the first file contains BOM header.  */
   5.931 ++  bool found_bom;
   5.932 ++  using_utf_locale=check_utf_locale();
   5.933 + 
   5.934 +   if (!fp)
   5.935 +     return;
   5.936 ++  mbf_init (mbf, fp);
   5.937 ++  found_bom=check_bom(fp,&mbf);
   5.938 + 
   5.939 +-  while (true)
   5.940 ++  if (using_utf_locale == false && found_bom == true)
   5.941 ++  {
   5.942 ++    /*try using some predefined locale */
   5.943 ++
   5.944 ++    if (set_utf_locale () != 0)
   5.945 +     {
   5.946 +-      /* Input character, or EOF.  */
   5.947 +-      int c;
   5.948 ++      error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
   5.949 ++    }
   5.950 ++  }
   5.951 ++
   5.952 + 
   5.953 ++  if (found_bom == true)
   5.954 ++  {
   5.955 ++    print_bom();
   5.956 ++  }
   5.957 ++
   5.958 ++  while (true)
   5.959 ++    {
   5.960 +       /* If true, perform translations.  */
   5.961 +       bool convert = true;
   5.962 + 
   5.963 +-
   5.964 +       /* The following variables have valid values only when CONVERT
   5.965 +          is true:  */
   5.966 + 
   5.967 +@@ -122,17 +147,48 @@ expand (void)
   5.968 +       /* Index in TAB_LIST of next tab stop to examine.  */
   5.969 +       size_t tab_index = 0;
   5.970 + 
   5.971 +-
   5.972 +       /* Convert a line of text.  */
   5.973 + 
   5.974 +       do
   5.975 +         {
   5.976 +-          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
   5.977 +-            continue;
   5.978 ++          while (true) {
   5.979 ++            mbf_getc (c, mbf);
   5.980 ++            if ((mb_iseof (c)) && (fp = next_file (fp)))
   5.981 ++              {
   5.982 ++                mbf_init (mbf, fp);
   5.983 ++                if (fp!=NULL)
   5.984 ++                {
   5.985 ++                  if (check_bom(fp,&mbf)==true)
   5.986 ++                  {
   5.987 ++                    /*Not the first file - check BOM header*/
   5.988 ++                    if (using_utf_locale==false && found_bom==false)
   5.989 ++                    {
   5.990 ++                      /*BOM header in subsequent file but not in the first one. */
   5.991 ++                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
   5.992 ++                    }
   5.993 ++                  }
   5.994 ++                  else
   5.995 ++                  {
   5.996 ++                    if(using_utf_locale==false && found_bom==true)
   5.997 ++                    {
   5.998 ++                      /*First file conatined BOM header - locale was switched to UTF
   5.999 ++                      /*all subsequent files should contain BOM. */
  5.1000 ++                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
  5.1001 ++                    }
  5.1002 ++                  }
  5.1003 ++                }
  5.1004 ++                continue;
  5.1005 ++              }
  5.1006 ++            else
  5.1007 ++              {
  5.1008 ++                break;
  5.1009 ++              }
  5.1010 ++            }
  5.1011 ++
  5.1012 + 
  5.1013 +           if (convert)
  5.1014 +             {
  5.1015 +-              if (c == '\t')
  5.1016 ++              if (mb_iseq (c, '\t'))
  5.1017 +                 {
  5.1018 +                   /* Column the next input tab stop is on.  */
  5.1019 +                   uintmax_t next_tab_column;
  5.1020 +@@ -151,32 +207,34 @@ expand (void)
  5.1021 +                     if (putchar (' ') < 0)
  5.1022 +                       die (EXIT_FAILURE, errno, _("write error"));
  5.1023 + 
  5.1024 +-                  c = ' ';
  5.1025 ++                  mb_setascii (&c, ' ');
  5.1026 +                 }
  5.1027 +-              else if (c == '\b')
  5.1028 ++              else if (mb_iseq (c, '\b'))
  5.1029 +                 {
  5.1030 +                   /* Go back one column, and force recalculation of the
  5.1031 +                      next tab stop.  */
  5.1032 +                   column -= !!column;
  5.1033 +                   tab_index -= !!tab_index;
  5.1034 +                 }
  5.1035 +-              else
  5.1036 ++              /* A leading control character could make us trip over.  */
  5.1037 ++              else if (!mb_iscntrl (c))
  5.1038 +                 {
  5.1039 +-                  column++;
  5.1040 ++                  column += mb_width (c);
  5.1041 +                   if (!column)
  5.1042 +                     die (EXIT_FAILURE, 0, _("input line is too long"));
  5.1043 +                 }
  5.1044 + 
  5.1045 +-              convert &= convert_entire_line || !! isblank (c);
  5.1046 ++              convert &= convert_entire_line || mb_isblank (c);
  5.1047 +             }
  5.1048 + 
  5.1049 +-          if (c < 0)
  5.1050 ++          if (mb_iseof (c))
  5.1051 +             return;
  5.1052 + 
  5.1053 +-          if (putchar (c) < 0)
  5.1054 ++          mb_putc (c, stdout);
  5.1055 ++          if (ferror (stdout))
  5.1056 +             die (EXIT_FAILURE, errno, _("write error"));
  5.1057 +         }
  5.1058 +-      while (c != '\n');
  5.1059 ++      while (!mb_iseq (c, '\n'));
  5.1060 +     }
  5.1061 + }
  5.1062 + 
  5.1063 +diff -Naurp coreutils-8.27-orig/src/expand-common.c coreutils-8.27/src/expand-common.c
  5.1064 +--- coreutils-8.27-orig/src/expand-common.c	2017-03-01 11:22:55.000000000 -0600
  5.1065 ++++ coreutils-8.27/src/expand-common.c	2017-03-11 23:49:06.757133570 -0600
  5.1066 +@@ -18,6 +18,7 @@
  5.1067 + 
  5.1068 + #include <stdio.h>
  5.1069 + #include <sys/types.h>
  5.1070 ++#include <mbfile.h>
  5.1071 + #include "system.h"
  5.1072 + #include "die.h"
  5.1073 + #include "error.h"
  5.1074 +@@ -105,6 +106,119 @@ set_extend_size (uintmax_t tabval)
  5.1075 +   return ok;
  5.1076 + }
  5.1077 + 
  5.1078 ++extern int
  5.1079 ++set_utf_locale (void)
  5.1080 ++{
  5.1081 ++      /*try using some predefined locale */
  5.1082 ++      const char* predef_locales[] = {"C.UTF8","en_US.UTF8","en_GB.UTF8"};
  5.1083 ++
  5.1084 ++      const int predef_locales_count=3;
  5.1085 ++      for (int i=0;i<predef_locales_count;i++)
  5.1086 ++        {
  5.1087 ++          if (setlocale(LC_ALL,predef_locales[i])!=NULL)
  5.1088 ++          {
  5.1089 ++            break;
  5.1090 ++          }
  5.1091 ++          else if (i==predef_locales_count-1)
  5.1092 ++          {
  5.1093 ++            return 1;
  5.1094 ++            error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
  5.1095 ++          }
  5.1096 ++        }
  5.1097 ++        return 0;
  5.1098 ++}
  5.1099 ++
  5.1100 ++extern bool
  5.1101 ++check_utf_locale(void)
  5.1102 ++{
  5.1103 ++  char* locale = setlocale (LC_CTYPE , NULL);
  5.1104 ++  if (locale == NULL)
  5.1105 ++  {
  5.1106 ++    return false;
  5.1107 ++  }
  5.1108 ++  else if (strcasestr(locale, "utf8") == NULL && strcasestr(locale, "utf-8") == NULL)
  5.1109 ++  {
  5.1110 ++    return false;
  5.1111 ++  }
  5.1112 ++  return true;
  5.1113 ++}
  5.1114 ++
  5.1115 ++extern bool
  5.1116 ++check_bom(FILE* fp, mb_file_t *mbf)
  5.1117 ++{
  5.1118 ++  int c;
  5.1119 ++
  5.1120 ++
  5.1121 ++  c=fgetc(fp);
  5.1122 ++
  5.1123 ++  /*test BOM header of the first file */
  5.1124 ++  mbf->bufcount=0;
  5.1125 ++  if (c == 0xEF)
  5.1126 ++  {
  5.1127 ++    c=fgetc(fp);
  5.1128 ++  }
  5.1129 ++  else
  5.1130 ++  {
  5.1131 ++    if (c != EOF)
  5.1132 ++    {
  5.1133 ++      ungetc(c,fp);
  5.1134 ++    }
  5.1135 ++    return false;
  5.1136 ++  }
  5.1137 ++
  5.1138 ++  if (c == 0xBB)
  5.1139 ++  {
  5.1140 ++    c=fgetc(fp);
  5.1141 ++  }
  5.1142 ++  else
  5.1143 ++  {
  5.1144 ++    if ( c!= EOF )
  5.1145 ++    {
  5.1146 ++      mbf->buf[0]=(unsigned char) 0xEF;
  5.1147 ++      mbf->bufcount=1;
  5.1148 ++      ungetc(c,fp);
  5.1149 ++      return false;
  5.1150 ++    }
  5.1151 ++    else
  5.1152 ++    {
  5.1153 ++      ungetc(0xEF,fp);
  5.1154 ++      return false;
  5.1155 ++    }
  5.1156 ++  }
  5.1157 ++  if (c == 0xBF)
  5.1158 ++  {
  5.1159 ++    mbf->bufcount=0;
  5.1160 ++    return true;
  5.1161 ++  }
  5.1162 ++  else
  5.1163 ++  {
  5.1164 ++    if (c != EOF)
  5.1165 ++    {
  5.1166 ++      mbf->buf[0]=(unsigned char) 0xEF;
  5.1167 ++      mbf->buf[1]=(unsigned char) 0xBB;
  5.1168 ++      mbf->bufcount=2;
  5.1169 ++      ungetc(c,fp);
  5.1170 ++      return false;
  5.1171 ++    }
  5.1172 ++    else
  5.1173 ++    {
  5.1174 ++      mbf->buf[0]=(unsigned char) 0xEF;
  5.1175 ++      mbf->bufcount=1;
  5.1176 ++      ungetc(0xBB,fp);
  5.1177 ++      return false;
  5.1178 ++    }
  5.1179 ++  }
  5.1180 ++  return false;
  5.1181 ++}
  5.1182 ++
  5.1183 ++extern void
  5.1184 ++print_bom(void)
  5.1185 ++{
  5.1186 ++  putc (0xEF, stdout);
  5.1187 ++  putc (0xBB, stdout);
  5.1188 ++  putc (0xBF, stdout);
  5.1189 ++}
  5.1190 ++
  5.1191 + /* Add the comma or blank separated list of tab stops STOPS
  5.1192 +    to the list of tab stops.  */
  5.1193 + extern void
  5.1194 +diff -Naurp coreutils-8.27-orig/src/expand-common.h coreutils-8.27/src/expand-common.h
  5.1195 +--- coreutils-8.27-orig/src/expand-common.h	2017-01-01 16:34:24.000000000 -0600
  5.1196 ++++ coreutils-8.27/src/expand-common.h	2017-03-11 23:49:06.758133530 -0600
  5.1197 +@@ -34,6 +34,18 @@ extern size_t max_column_width;
  5.1198 + /* The desired exit status.  */
  5.1199 + extern int exit_status;
  5.1200 + 
  5.1201 ++extern int
  5.1202 ++set_utf_locale (void);
  5.1203 ++
  5.1204 ++extern bool
  5.1205 ++check_utf_locale(void);
  5.1206 ++
  5.1207 ++extern bool
  5.1208 ++check_bom(FILE* fp, mb_file_t *mbf);
  5.1209 ++
  5.1210 ++extern void
  5.1211 ++print_bom(void);
  5.1212 ++
  5.1213 + /* Add tab stop TABVAL to the end of 'tab_list'.  */
  5.1214 + extern void
  5.1215 + add_tab_stop (uintmax_t tabval);
  5.1216 +diff -Naurp coreutils-8.27-orig/src/fold.c coreutils-8.27/src/fold.c
  5.1217 +--- coreutils-8.27-orig/src/fold.c	2017-01-01 16:34:24.000000000 -0600
  5.1218 ++++ coreutils-8.27/src/fold.c	2017-03-11 23:49:30.982169404 -0600
  5.1219 +@@ -22,12 +22,34 @@
  5.1220 + #include <getopt.h>
  5.1221 + #include <sys/types.h>
  5.1222 + 
  5.1223 ++/* Get mbstate_t, mbrtowc(), wcwidth().  */
  5.1224 ++#if HAVE_WCHAR_H
  5.1225 ++# include <wchar.h>
  5.1226 ++#endif
  5.1227 ++
  5.1228 ++/* Get iswprint(), iswblank(), wcwidth().  */
  5.1229 ++#if HAVE_WCTYPE_H
  5.1230 ++# include <wctype.h>
  5.1231 ++#endif
  5.1232 ++
  5.1233 + #include "system.h"
  5.1234 + #include "die.h"
  5.1235 + #include "error.h"
  5.1236 + #include "fadvise.h"
  5.1237 + #include "xdectoint.h"
  5.1238 + 
  5.1239 ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
  5.1240 ++      installation; work around this configuration error.  */
  5.1241 ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
  5.1242 ++# undef MB_LEN_MAX
  5.1243 ++# define MB_LEN_MAX 16
  5.1244 ++#endif
  5.1245 ++
  5.1246 ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  5.1247 ++#if HAVE_MBRTOWC && defined mbstate_t
  5.1248 ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  5.1249 ++#endif
  5.1250 ++
  5.1251 + #define TAB_WIDTH 8
  5.1252 + 
  5.1253 + /* The official name of this program (e.g., no 'g' prefix).  */
  5.1254 +@@ -35,20 +57,41 @@
  5.1255 + 
  5.1256 + #define AUTHORS proper_name ("David MacKenzie")
  5.1257 + 
  5.1258 ++#define FATAL_ERROR(Message)                                            \
  5.1259 ++  do                                                                    \
  5.1260 ++    {                                                                   \
  5.1261 ++      error (0, 0, (Message));                                          \
  5.1262 ++      usage (2);                                                        \
  5.1263 ++    }                                                                   \
  5.1264 ++  while (0)
  5.1265 ++
  5.1266 ++enum operating_mode
  5.1267 ++{
  5.1268 ++  /* Fold texts by columns that are at the given positions. */
  5.1269 ++  column_mode,
  5.1270 ++
  5.1271 ++  /* Fold texts by bytes that are at the given positions. */
  5.1272 ++  byte_mode,
  5.1273 ++
  5.1274 ++  /* Fold texts by characters that are at the given positions. */
  5.1275 ++  character_mode,
  5.1276 ++};
  5.1277 ++
  5.1278 ++/* The argument shows current mode. (Default: column_mode) */
  5.1279 ++static enum operating_mode operating_mode;
  5.1280 ++
  5.1281 + /* If nonzero, try to break on whitespace. */
  5.1282 + static bool break_spaces;
  5.1283 + 
  5.1284 +-/* If nonzero, count bytes, not column positions. */
  5.1285 +-static bool count_bytes;
  5.1286 +-
  5.1287 + /* If nonzero, at least one of the files we read was standard input. */
  5.1288 + static bool have_read_stdin;
  5.1289 + 
  5.1290 +-static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::";
  5.1291 ++static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::";
  5.1292 + 
  5.1293 + static struct option const longopts[] =
  5.1294 + {
  5.1295 +   {"bytes", no_argument, NULL, 'b'},
  5.1296 ++  {"characters", no_argument, NULL, 'c'},
  5.1297 +   {"spaces", no_argument, NULL, 's'},
  5.1298 +   {"width", required_argument, NULL, 'w'},
  5.1299 +   {GETOPT_HELP_OPTION_DECL},
  5.1300 +@@ -76,6 +119,7 @@ Wrap input lines in each FILE, writing t
  5.1301 + 
  5.1302 +       fputs (_("\
  5.1303 +   -b, --bytes         count bytes rather than columns\n\
  5.1304 ++  -c, --characters    count characters rather than columns\n\
  5.1305 +   -s, --spaces        break at spaces\n\
  5.1306 +   -w, --width=WIDTH   use WIDTH columns instead of 80\n\
  5.1307 + "), stdout);
  5.1308 +@@ -93,7 +137,7 @@ Wrap input lines in each FILE, writing t
  5.1309 + static size_t
  5.1310 + adjust_column (size_t column, char c)
  5.1311 + {
  5.1312 +-  if (!count_bytes)
  5.1313 ++  if (operating_mode != byte_mode)
  5.1314 +     {
  5.1315 +       if (c == '\b')
  5.1316 +         {
  5.1317 +@@ -116,30 +160,14 @@ adjust_column (size_t column, char c)
  5.1318 +    to stdout, with maximum line length WIDTH.
  5.1319 +    Return true if successful.  */
  5.1320 + 
  5.1321 +-static bool
  5.1322 +-fold_file (char const *filename, size_t width)
  5.1323 ++static void
  5.1324 ++fold_text (FILE *istream, size_t width, int *saved_errno)
  5.1325 + {
  5.1326 +-  FILE *istream;
  5.1327 +   int c;
  5.1328 +   size_t column = 0;		/* Screen column where next char will go. */
  5.1329 +   size_t offset_out = 0;	/* Index in 'line_out' for next char. */
  5.1330 +   static char *line_out = NULL;
  5.1331 +   static size_t allocated_out = 0;
  5.1332 +-  int saved_errno;
  5.1333 +-
  5.1334 +-  if (STREQ (filename, "-"))
  5.1335 +-    {
  5.1336 +-      istream = stdin;
  5.1337 +-      have_read_stdin = true;
  5.1338 +-    }
  5.1339 +-  else
  5.1340 +-    istream = fopen (filename, "r");
  5.1341 +-
  5.1342 +-  if (istream == NULL)
  5.1343 +-    {
  5.1344 +-      error (0, errno, "%s", quotef (filename));
  5.1345 +-      return false;
  5.1346 +-    }
  5.1347 + 
  5.1348 +   fadvise (istream, FADVISE_SEQUENTIAL);
  5.1349 + 
  5.1350 +@@ -169,6 +197,15 @@ fold_file (char const *filename, size_t
  5.1351 +               bool found_blank = false;
  5.1352 +               size_t logical_end = offset_out;
  5.1353 + 
  5.1354 ++              /* If LINE_OUT has no wide character,
  5.1355 ++                 put a new wide character in LINE_OUT
  5.1356 ++                 if column is bigger than width. */
  5.1357 ++              if (offset_out == 0)
  5.1358 ++                {
  5.1359 ++                  line_out[offset_out++] = c;
  5.1360 ++                  continue;
  5.1361 ++                }
  5.1362 ++
  5.1363 +               /* Look for the last blank. */
  5.1364 +               while (logical_end)
  5.1365 +                 {
  5.1366 +@@ -215,11 +252,220 @@ fold_file (char const *filename, size_t
  5.1367 +       line_out[offset_out++] = c;
  5.1368 +     }
  5.1369 + 
  5.1370 +-  saved_errno = errno;
  5.1371 ++  *saved_errno = errno;
  5.1372 ++
  5.1373 ++  if (offset_out)
  5.1374 ++    fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
  5.1375 ++
  5.1376 ++}
  5.1377 ++
  5.1378 ++#if HAVE_MBRTOWC
  5.1379 ++static void
  5.1380 ++fold_multibyte_text (FILE *istream, size_t width, int *saved_errno)
  5.1381 ++{
  5.1382 ++  char buf[MB_LEN_MAX + BUFSIZ];  /* For spooling a read byte sequence. */
  5.1383 ++  size_t buflen = 0;        /* The length of the byte sequence in buf. */
  5.1384 ++  char *bufpos = buf;         /* Next read position of BUF. */
  5.1385 ++  wint_t wc;                /* A gotten wide character. */
  5.1386 ++  size_t mblength;        /* The byte size of a multibyte character which shows
  5.1387 ++                           as same character as WC. */
  5.1388 ++  mbstate_t state, state_bak;        /* State of the stream. */
  5.1389 ++  int convfail = 0;                /* 1, when conversion is failed. Otherwise 0. */
  5.1390 ++
  5.1391 ++  static char *line_out = NULL;
  5.1392 ++  size_t offset_out = 0;        /* Index in `line_out' for next char. */
  5.1393 ++  static size_t allocated_out = 0;
  5.1394 ++
  5.1395 ++  int increment;
  5.1396 ++  size_t column = 0;
  5.1397 ++
  5.1398 ++  size_t last_blank_pos;
  5.1399 ++  size_t last_blank_column;
  5.1400 ++  int is_blank_seen;
  5.1401 ++  int last_blank_increment = 0;
  5.1402 ++  int is_bs_following_last_blank;
  5.1403 ++  size_t bs_following_last_blank_num;
  5.1404 ++  int is_cr_after_last_blank;
  5.1405 ++
  5.1406 ++#define CLEAR_FLAGS                                \
  5.1407 ++   do                                                \
  5.1408 ++     {                                                \
  5.1409 ++        last_blank_pos = 0;                        \
  5.1410 ++        last_blank_column = 0;                        \
  5.1411 ++        is_blank_seen = 0;                        \
  5.1412 ++        is_bs_following_last_blank = 0;                \
  5.1413 ++        bs_following_last_blank_num = 0;        \
  5.1414 ++        is_cr_after_last_blank = 0;                \
  5.1415 ++     }                                                \
  5.1416 ++   while (0)
  5.1417 ++
  5.1418 ++#define START_NEW_LINE                        \
  5.1419 ++   do                                        \
  5.1420 ++     {                                        \
  5.1421 ++      putchar ('\n');                        \
  5.1422 ++      column = 0;                        \
  5.1423 ++      offset_out = 0;                        \
  5.1424 ++      CLEAR_FLAGS;                        \
  5.1425 ++    }                                        \
  5.1426 ++   while (0)
  5.1427 ++
  5.1428 ++  CLEAR_FLAGS;
  5.1429 ++  memset (&state, '\0', sizeof(mbstate_t));
  5.1430 ++
  5.1431 ++  for (;; bufpos += mblength, buflen -= mblength)
  5.1432 ++    {
  5.1433 ++      if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream))
  5.1434 ++        {
  5.1435 ++          memmove (buf, bufpos, buflen);
  5.1436 ++          buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream);
  5.1437 ++          bufpos = buf;
  5.1438 ++        }
  5.1439 ++
  5.1440 ++      if (buflen < 1)
  5.1441 ++        break;
  5.1442 ++
  5.1443 ++      /* Get a wide character. */
  5.1444 ++      state_bak = state;
  5.1445 ++      mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state);
  5.1446 ++
  5.1447 ++      switch (mblength)
  5.1448 ++        {
  5.1449 ++        case (size_t)-1:
  5.1450 ++        case (size_t)-2:
  5.1451 ++          convfail++;
  5.1452 ++          state = state_bak;
  5.1453 ++          /* Fall through. */
  5.1454 ++
  5.1455 ++        case 0:
  5.1456 ++          mblength = 1;
  5.1457 ++          break;
  5.1458 ++        }
  5.1459 ++
  5.1460 ++rescan:
  5.1461 ++      if (convfail)
  5.1462 ++        increment = 1;
  5.1463 ++      else if (wc == L'\n')
  5.1464 ++        {
  5.1465 ++          /* preserve newline */
  5.1466 ++          fwrite (line_out, sizeof(char), offset_out, stdout);
  5.1467 ++          START_NEW_LINE;
  5.1468 ++          continue;
  5.1469 ++        }
  5.1470 ++      else if (operating_mode == byte_mode)                  /* byte mode */
  5.1471 ++        increment = mblength;
  5.1472 ++      else if (operating_mode == character_mode)        /* character mode */
  5.1473 ++        increment = 1;
  5.1474 ++      else                                                 /* column mode */
  5.1475 ++        {
  5.1476 ++          switch (wc)
  5.1477 ++            {
  5.1478 ++            case L'\b':
  5.1479 ++              increment = (column > 0) ? -1 : 0;
  5.1480 ++              break;
  5.1481 ++
  5.1482 ++            case L'\r':
  5.1483 ++              increment = -1 * column;
  5.1484 ++              break;
  5.1485 ++
  5.1486 ++            case L'\t':
  5.1487 ++              increment = 8 - column % 8;
  5.1488 ++              break;
  5.1489 ++
  5.1490 ++            default:
  5.1491 ++              increment = wcwidth (wc);
  5.1492 ++              increment = (increment < 0) ? 0 : increment;
  5.1493 ++            }
  5.1494 ++        }
  5.1495 ++
  5.1496 ++      if (column + increment > width && break_spaces && last_blank_pos)
  5.1497 ++        {
  5.1498 ++          fwrite (line_out, sizeof(char), last_blank_pos, stdout);
  5.1499 ++          putchar ('\n');
  5.1500 ++
  5.1501 ++          offset_out = offset_out - last_blank_pos;
  5.1502 ++          column = column - last_blank_column + ((is_cr_after_last_blank)
  5.1503 ++              ? last_blank_increment : bs_following_last_blank_num);
  5.1504 ++          memmove (line_out, line_out + last_blank_pos, offset_out);
  5.1505 ++          CLEAR_FLAGS;
  5.1506 ++          goto rescan;
  5.1507 ++        }
  5.1508 ++
  5.1509 ++      if (column + increment > width && column != 0)
  5.1510 ++        {
  5.1511 ++          fwrite (line_out, sizeof(char), offset_out, stdout);
  5.1512 ++          START_NEW_LINE;
  5.1513 ++          goto rescan;
  5.1514 ++        }
  5.1515 ++
  5.1516 ++      if (allocated_out < offset_out + mblength)
  5.1517 ++        {
  5.1518 ++          line_out = X2REALLOC (line_out, &allocated_out);
  5.1519 ++        }
  5.1520 ++
  5.1521 ++      memcpy (line_out + offset_out, bufpos, mblength);
  5.1522 ++      offset_out += mblength;
  5.1523 ++      column += increment;
  5.1524 ++
  5.1525 ++      if (is_blank_seen && !convfail && wc == L'\r')
  5.1526 ++        is_cr_after_last_blank = 1;
  5.1527 ++
  5.1528 ++      if (is_bs_following_last_blank && !convfail && wc == L'\b')
  5.1529 ++        ++bs_following_last_blank_num;
  5.1530 ++      else
  5.1531 ++        is_bs_following_last_blank = 0;
  5.1532 ++
  5.1533 ++      if (break_spaces && !convfail && iswblank (wc))
  5.1534 ++        {
  5.1535 ++          last_blank_pos = offset_out;
  5.1536 ++          last_blank_column = column;
  5.1537 ++          is_blank_seen = 1;
  5.1538 ++          last_blank_increment = increment;
  5.1539 ++          is_bs_following_last_blank = 1;
  5.1540 ++          bs_following_last_blank_num = 0;
  5.1541 ++          is_cr_after_last_blank = 0;
  5.1542 ++        }
  5.1543 ++    }
  5.1544 ++
  5.1545 ++  *saved_errno = errno;
  5.1546 + 
  5.1547 +   if (offset_out)
  5.1548 +     fwrite (line_out, sizeof (char), (size_t) offset_out, stdout);
  5.1549 + 
  5.1550 ++}
  5.1551 ++#endif
  5.1552 ++
  5.1553 ++/* Fold file FILENAME, or standard input if FILENAME is "-",
  5.1554 ++   to stdout, with maximum line length WIDTH.
  5.1555 ++   Return 0 if successful, 1 if an error occurs. */
  5.1556 ++
  5.1557 ++static bool
  5.1558 ++fold_file (char const *filename, size_t width)
  5.1559 ++{
  5.1560 ++  FILE *istream;
  5.1561 ++  int saved_errno;
  5.1562 ++
  5.1563 ++  if (STREQ (filename, "-"))
  5.1564 ++    {
  5.1565 ++      istream = stdin;
  5.1566 ++      have_read_stdin = 1;
  5.1567 ++    }
  5.1568 ++  else
  5.1569 ++    istream = fopen (filename, "r");
  5.1570 ++
  5.1571 ++  if (istream == NULL)
  5.1572 ++    {
  5.1573 ++      error (0, errno, "%s", filename);
  5.1574 ++      return 1;
  5.1575 ++    }
  5.1576 ++
  5.1577 ++  /* Define how ISTREAM is being folded. */
  5.1578 ++#if HAVE_MBRTOWC
  5.1579 ++  if (MB_CUR_MAX > 1)
  5.1580 ++    fold_multibyte_text (istream, width, &saved_errno);
  5.1581 ++  else
  5.1582 ++#endif
  5.1583 ++    fold_text (istream, width, &saved_errno);
  5.1584 ++
  5.1585 +   if (ferror (istream))
  5.1586 +     {
  5.1587 +       error (0, saved_errno, "%s", quotef (filename));
  5.1588 +@@ -252,7 +498,8 @@ main (int argc, char **argv)
  5.1589 + 
  5.1590 +   atexit (close_stdout);
  5.1591 + 
  5.1592 +-  break_spaces = count_bytes = have_read_stdin = false;
  5.1593 ++  operating_mode = column_mode;
  5.1594 ++  break_spaces = have_read_stdin = false;
  5.1595 + 
  5.1596 +   while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
  5.1597 +     {
  5.1598 +@@ -261,7 +508,15 @@ main (int argc, char **argv)
  5.1599 +       switch (optc)
  5.1600 +         {
  5.1601 +         case 'b':		/* Count bytes rather than columns. */
  5.1602 +-          count_bytes = true;
  5.1603 ++          if (operating_mode != column_mode)
  5.1604 ++            FATAL_ERROR (_("only one way of folding may be specified"));
  5.1605 ++          operating_mode = byte_mode;
  5.1606 ++          break;
  5.1607 ++
  5.1608 ++        case 'c':
  5.1609 ++          if (operating_mode != column_mode)
  5.1610 ++            FATAL_ERROR (_("only one way of folding may be specified"));
  5.1611 ++          operating_mode = character_mode;
  5.1612 +           break;
  5.1613 + 
  5.1614 +         case 's':		/* Break at word boundaries. */
  5.1615 +diff -Naurp coreutils-8.27-orig/src/join.c coreutils-8.27/src/join.c
  5.1616 +--- coreutils-8.27-orig/src/join.c	2017-01-01 16:34:24.000000000 -0600
  5.1617 ++++ coreutils-8.27/src/join.c	2017-03-11 23:47:13.091286290 -0600
  5.1618 +@@ -22,19 +22,33 @@
  5.1619 + #include <sys/types.h>
  5.1620 + #include <getopt.h>
  5.1621 + 
  5.1622 ++/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth().  */
  5.1623 ++#if HAVE_WCHAR_H
  5.1624 ++# include <wchar.h>
  5.1625 ++#endif
  5.1626 ++
  5.1627 ++/* Get iswblank(), towupper.  */
  5.1628 ++#if HAVE_WCTYPE_H
  5.1629 ++# include <wctype.h>
  5.1630 ++#endif
  5.1631 ++
  5.1632 + #include "system.h"
  5.1633 + #include "die.h"
  5.1634 + #include "error.h"
  5.1635 + #include "fadvise.h"
  5.1636 + #include "hard-locale.h"
  5.1637 + #include "linebuffer.h"
  5.1638 +-#include "memcasecmp.h"
  5.1639 + #include "quote.h"
  5.1640 + #include "stdio--.h"
  5.1641 + #include "xmemcoll.h"
  5.1642 + #include "xstrtol.h"
  5.1643 + #include "argmatch.h"
  5.1644 + 
  5.1645 ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  5.1646 ++#if HAVE_MBRTOWC && defined mbstate_t
  5.1647 ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  5.1648 ++#endif
  5.1649 ++
  5.1650 + /* The official name of this program (e.g., no 'g' prefix).  */
  5.1651 + #define PROGRAM_NAME "join"
  5.1652 + 
  5.1653 +@@ -136,10 +150,12 @@ static struct outlist outlist_head;
  5.1654 + /* Last element in 'outlist', where a new element can be added.  */
  5.1655 + static struct outlist *outlist_end = &outlist_head;
  5.1656 + 
  5.1657 +-/* Tab character separating fields.  If negative, fields are separated
  5.1658 +-   by any nonempty string of blanks, otherwise by exactly one
  5.1659 +-   tab character whose value (when cast to unsigned char) equals TAB.  */
  5.1660 +-static int tab = -1;
  5.1661 ++/* Tab character separating fields.  If NULL, fields are separated
  5.1662 ++   by any nonempty string of blanks.  */
  5.1663 ++static char *tab = NULL;
  5.1664 ++
  5.1665 ++/* The number of bytes used for tab. */
  5.1666 ++static size_t tablen = 0;
  5.1667 + 
  5.1668 + /* If nonzero, check that the input is correctly ordered. */
  5.1669 + static enum
  5.1670 +@@ -276,13 +292,14 @@ xfields (struct line *line)
  5.1671 +   if (ptr == lim)
  5.1672 +     return;
  5.1673 + 
  5.1674 +-  if (0 <= tab && tab != '\n')
  5.1675 ++  if (tab != NULL)
  5.1676 +     {
  5.1677 ++      unsigned char t = tab[0];
  5.1678 +       char *sep;
  5.1679 +-      for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
  5.1680 ++      for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1)
  5.1681 +         extract_field (line, ptr, sep - ptr);
  5.1682 +     }
  5.1683 +-  else if (tab < 0)
  5.1684 ++   else
  5.1685 +     {
  5.1686 +       /* Skip leading blanks before the first field.  */
  5.1687 +       while (field_sep (*ptr))
  5.1688 +@@ -306,6 +323,147 @@ xfields (struct line *line)
  5.1689 +   extract_field (line, ptr, lim - ptr);
  5.1690 + }
  5.1691 + 
  5.1692 ++#if HAVE_MBRTOWC
  5.1693 ++static void
  5.1694 ++xfields_multibyte (struct line *line)
  5.1695 ++{
  5.1696 ++  char *ptr = line->buf.buffer;
  5.1697 ++  char const *lim = ptr + line->buf.length - 1;
  5.1698 ++  wchar_t wc = 0;
  5.1699 ++  size_t mblength = 1;
  5.1700 ++  mbstate_t state, state_bak;
  5.1701 ++
  5.1702 ++  memset (&state, 0, sizeof (mbstate_t));
  5.1703 ++
  5.1704 ++  if (ptr >= lim)
  5.1705 ++    return;
  5.1706 ++
  5.1707 ++  if (tab != NULL)
  5.1708 ++    {
  5.1709 ++      char *sep = ptr;
  5.1710 ++      for (; ptr < lim; ptr = sep + mblength)
  5.1711 ++	{
  5.1712 ++	  sep = ptr;
  5.1713 ++	  while (sep < lim)
  5.1714 ++	    {
  5.1715 ++	      state_bak = state;
  5.1716 ++	      mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
  5.1717 ++
  5.1718 ++	      if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.1719 ++		{
  5.1720 ++		  mblength = 1;
  5.1721 ++		  state = state_bak;
  5.1722 ++		}
  5.1723 ++	      mblength = (mblength < 1) ? 1 : mblength;
  5.1724 ++
  5.1725 ++	      if (mblength == tablen && !memcmp (sep, tab, mblength))
  5.1726 ++		break;
  5.1727 ++	      else
  5.1728 ++		{
  5.1729 ++		  sep += mblength;
  5.1730 ++		  continue;
  5.1731 ++		}
  5.1732 ++	    }
  5.1733 ++
  5.1734 ++	  if (sep >= lim)
  5.1735 ++	    break;
  5.1736 ++
  5.1737 ++	  extract_field (line, ptr, sep - ptr);
  5.1738 ++	}
  5.1739 ++    }
  5.1740 ++  else
  5.1741 ++    {
  5.1742 ++      /* Skip leading blanks before the first field.  */
  5.1743 ++      while(ptr < lim)
  5.1744 ++      {
  5.1745 ++        state_bak = state;
  5.1746 ++        mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
  5.1747 ++
  5.1748 ++        if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.1749 ++          {
  5.1750 ++            mblength = 1;
  5.1751 ++            state = state_bak;
  5.1752 ++            break;
  5.1753 ++          }
  5.1754 ++        mblength = (mblength < 1) ? 1 : mblength;
  5.1755 ++
  5.1756 ++        if (!iswblank(wc) && wc != '\n')
  5.1757 ++          break;
  5.1758 ++        ptr += mblength;
  5.1759 ++      }
  5.1760 ++
  5.1761 ++      do
  5.1762 ++	{
  5.1763 ++	  char *sep;
  5.1764 ++	  state_bak = state;
  5.1765 ++	  mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
  5.1766 ++	  if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.1767 ++	    {
  5.1768 ++	      mblength = 1;
  5.1769 ++	      state = state_bak;
  5.1770 ++	      break;
  5.1771 ++	    }
  5.1772 ++	  mblength = (mblength < 1) ? 1 : mblength;
  5.1773 ++
  5.1774 ++	  sep = ptr + mblength;
  5.1775 ++	  while (sep < lim)
  5.1776 ++	    {
  5.1777 ++	      state_bak = state;
  5.1778 ++	      mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
  5.1779 ++	      if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.1780 ++		{
  5.1781 ++		  mblength = 1;
  5.1782 ++		  state = state_bak;
  5.1783 ++		  break;
  5.1784 ++		}
  5.1785 ++	      mblength = (mblength < 1) ? 1 : mblength;
  5.1786 ++
  5.1787 ++	      if (iswblank (wc) || wc == '\n')
  5.1788 ++		break;
  5.1789 ++
  5.1790 ++	      sep += mblength;
  5.1791 ++	    }
  5.1792 ++
  5.1793 ++	  extract_field (line, ptr, sep - ptr);
  5.1794 ++	  if (sep >= lim)
  5.1795 ++	    return;
  5.1796 ++
  5.1797 ++	  state_bak = state;
  5.1798 ++	  mblength = mbrtowc (&wc, sep, lim - sep + 1, &state);
  5.1799 ++	  if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.1800 ++	    {
  5.1801 ++	      mblength = 1;
  5.1802 ++	      state = state_bak;
  5.1803 ++	      break;
  5.1804 ++	    }
  5.1805 ++	  mblength = (mblength < 1) ? 1 : mblength;
  5.1806 ++
  5.1807 ++	  ptr = sep + mblength;
  5.1808 ++	  while (ptr < lim)
  5.1809 ++	    {
  5.1810 ++	      state_bak = state;
  5.1811 ++	      mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state);
  5.1812 ++	      if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.1813 ++		{
  5.1814 ++		  mblength = 1;
  5.1815 ++		  state = state_bak;
  5.1816 ++		  break;
  5.1817 ++		}
  5.1818 ++	      mblength = (mblength < 1) ? 1 : mblength;
  5.1819 ++
  5.1820 ++	      if (!iswblank (wc) && wc != '\n')
  5.1821 ++		break;
  5.1822 ++
  5.1823 ++	      ptr += mblength;
  5.1824 ++	    }
  5.1825 ++	}
  5.1826 ++      while (ptr < lim);
  5.1827 ++    }
  5.1828 ++
  5.1829 ++  extract_field (line, ptr, lim - ptr);
  5.1830 ++}
  5.1831 ++#endif
  5.1832 ++
  5.1833 + static void
  5.1834 + freeline (struct line *line)
  5.1835 + {
  5.1836 +@@ -327,56 +485,133 @@ keycmp (struct line const *line1, struct
  5.1837 +         size_t jf_1, size_t jf_2)
  5.1838 + {
  5.1839 +   /* Start of field to compare in each file.  */
  5.1840 +-  char *beg1;
  5.1841 +-  char *beg2;
  5.1842 +-
  5.1843 +-  size_t len1;
  5.1844 +-  size_t len2;		/* Length of fields to compare.  */
  5.1845 ++  char *beg[2];
  5.1846 ++  char *copy[2];
  5.1847 ++  size_t len[2]; 	/* Length of fields to compare.  */
  5.1848 +   int diff;
  5.1849 ++  int i, j;
  5.1850 ++  int mallocd = 0;
  5.1851 + 
  5.1852 +   if (jf_1 < line1->nfields)
  5.1853 +     {
  5.1854 +-      beg1 = line1->fields[jf_1].beg;
  5.1855 +-      len1 = line1->fields[jf_1].len;
  5.1856 ++      beg[0] = line1->fields[jf_1].beg;
  5.1857 ++      len[0] = line1->fields[jf_1].len;
  5.1858 +     }
  5.1859 +   else
  5.1860 +     {
  5.1861 +-      beg1 = NULL;
  5.1862 +-      len1 = 0;
  5.1863 ++      beg[0] = NULL;
  5.1864 ++      len[0] = 0;
  5.1865 +     }
  5.1866 + 
  5.1867 +   if (jf_2 < line2->nfields)
  5.1868 +     {
  5.1869 +-      beg2 = line2->fields[jf_2].beg;
  5.1870 +-      len2 = line2->fields[jf_2].len;
  5.1871 ++      beg[1] = line2->fields[jf_2].beg;
  5.1872 ++      len[1] = line2->fields[jf_2].len;
  5.1873 +     }
  5.1874 +   else
  5.1875 +     {
  5.1876 +-      beg2 = NULL;
  5.1877 +-      len2 = 0;
  5.1878 ++      beg[1] = NULL;
  5.1879 ++      len[1] = 0;
  5.1880 +     }
  5.1881 + 
  5.1882 +-  if (len1 == 0)
  5.1883 +-    return len2 == 0 ? 0 : -1;
  5.1884 +-  if (len2 == 0)
  5.1885 ++  if (len[0] == 0)
  5.1886 ++    return len[1] == 0 ? 0 : -1;
  5.1887 ++  if (len[1] == 0)
  5.1888 +     return 1;
  5.1889 + 
  5.1890 +   if (ignore_case)
  5.1891 +     {
  5.1892 +-      /* FIXME: ignore_case does not work with NLS (in particular,
  5.1893 +-         with multibyte chars).  */
  5.1894 +-      diff = memcasecmp (beg1, beg2, MIN (len1, len2));
  5.1895 ++#ifdef HAVE_MBRTOWC
  5.1896 ++      if (MB_CUR_MAX > 1)
  5.1897 ++      {
  5.1898 ++        size_t mblength;
  5.1899 ++        wchar_t wc, uwc;
  5.1900 ++        mbstate_t state, state_bak;
  5.1901 ++
  5.1902 ++        memset (&state, '\0', sizeof (mbstate_t));
  5.1903 ++
  5.1904 ++        for (i = 0; i < 2; i++)
  5.1905 ++          {
  5.1906 ++            mallocd = 1;
  5.1907 ++            copy[i] = xmalloc (len[i] + 1);
  5.1908 ++            memset (copy[i], '\0',len[i] + 1);
  5.1909 ++
  5.1910 ++            for (j = 0; j < MIN (len[0], len[1]);)
  5.1911 ++              {
  5.1912 ++                state_bak = state;
  5.1913 ++                mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state);
  5.1914 ++
  5.1915 ++                switch (mblength)
  5.1916 ++                  {
  5.1917 ++                  case (size_t) -1:
  5.1918 ++                  case (size_t) -2:
  5.1919 ++                    state = state_bak;
  5.1920 ++                    /* Fall through */
  5.1921 ++                  case 0:
  5.1922 ++                    mblength = 1;
  5.1923 ++                    break;
  5.1924 ++
  5.1925 ++                  default:
  5.1926 ++                    uwc = towupper (wc);
  5.1927 ++
  5.1928 ++                    if (uwc != wc)
  5.1929 ++                      {
  5.1930 ++                        mbstate_t state_wc;
  5.1931 ++                        size_t mblen;
  5.1932 ++
  5.1933 ++                        memset (&state_wc, '\0', sizeof (mbstate_t));
  5.1934 ++                        mblen = wcrtomb (copy[i] + j, uwc, &state_wc);
  5.1935 ++                        assert (mblen != (size_t)-1);
  5.1936 ++                      }
  5.1937 ++                    else
  5.1938 ++                      memcpy (copy[i] + j, beg[i] + j, mblength);
  5.1939 ++                  }
  5.1940 ++                j += mblength;
  5.1941 ++              }
  5.1942 ++            copy[i][j] = '\0';
  5.1943 ++          }
  5.1944 ++      }
  5.1945 ++      else
  5.1946 ++#endif
  5.1947 ++      {
  5.1948 ++        for (i = 0; i < 2; i++)
  5.1949 ++          {
  5.1950 ++            mallocd = 1;
  5.1951 ++            copy[i] = xmalloc (len[i] + 1);
  5.1952 ++
  5.1953 ++            for (j = 0; j < MIN (len[0], len[1]); j++)
  5.1954 ++              copy[i][j] = toupper (beg[i][j]);
  5.1955 ++
  5.1956 ++            copy[i][j] = '\0';
  5.1957 ++          }
  5.1958 ++      }
  5.1959 +     }
  5.1960 +   else
  5.1961 +     {
  5.1962 +-      if (hard_LC_COLLATE)
  5.1963 +-        return xmemcoll (beg1, len1, beg2, len2);
  5.1964 +-      diff = memcmp (beg1, beg2, MIN (len1, len2));
  5.1965 ++      copy[0] = beg[0];
  5.1966 ++      copy[1] = beg[1];
  5.1967 +     }
  5.1968 + 
  5.1969 ++  if (hard_LC_COLLATE)
  5.1970 ++    {
  5.1971 ++      diff = xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]);
  5.1972 ++
  5.1973 ++      if (mallocd)
  5.1974 ++        for (i = 0; i < 2; i++)
  5.1975 ++          free (copy[i]);
  5.1976 ++
  5.1977 ++      return diff;
  5.1978 ++    }
  5.1979 ++  diff = memcmp (copy[0], copy[1], MIN (len[0], len[1]));
  5.1980 ++
  5.1981 ++  if (mallocd)
  5.1982 ++    for (i = 0; i < 2; i++)
  5.1983 ++      free (copy[i]);
  5.1984 ++
  5.1985 ++
  5.1986 +   if (diff)
  5.1987 +     return diff;
  5.1988 +-  return len1 < len2 ? -1 : len1 != len2;
  5.1989 ++  return len[0] - len[1];
  5.1990 + }
  5.1991 + 
  5.1992 + /* Check that successive input lines PREV and CURRENT from input file
  5.1993 +@@ -468,6 +703,11 @@ get_line (FILE *fp, struct line **linep,
  5.1994 +     }
  5.1995 +   ++line_no[which - 1];
  5.1996 + 
  5.1997 ++#if HAVE_MBRTOWC
  5.1998 ++  if (MB_CUR_MAX > 1)
  5.1999 ++    xfields_multibyte (line);
  5.2000 ++  else
  5.2001 ++#endif
  5.2002 +   xfields (line);
  5.2003 + 
  5.2004 +   if (prevline[which - 1])
  5.2005 +@@ -567,21 +807,28 @@ prfield (size_t n, struct line const *li
  5.2006 + 
  5.2007 + /* Output all the fields in line, other than the join field.  */
  5.2008 + 
  5.2009 ++#define PUT_TAB_CHAR							\
  5.2010 ++  do									\
  5.2011 ++    {									\
  5.2012 ++      (tab != NULL) ?							\
  5.2013 ++	fwrite(tab, sizeof(char), tablen, stdout) : putchar (' ');	\
  5.2014 ++    }									\
  5.2015 ++  while (0)
  5.2016 ++
  5.2017 + static void
  5.2018 + prfields (struct line const *line, size_t join_field, size_t autocount)
  5.2019 + {
  5.2020 +   size_t i;
  5.2021 +   size_t nfields = autoformat ? autocount : line->nfields;
  5.2022 +-  char output_separator = tab < 0 ? ' ' : tab;
  5.2023 + 
  5.2024 +   for (i = 0; i < join_field && i < nfields; ++i)
  5.2025 +     {
  5.2026 +-      putchar (output_separator);
  5.2027 ++      PUT_TAB_CHAR;
  5.2028 +       prfield (i, line);
  5.2029 +     }
  5.2030 +   for (i = join_field + 1; i < nfields; ++i)
  5.2031 +     {
  5.2032 +-      putchar (output_separator);
  5.2033 ++      PUT_TAB_CHAR;
  5.2034 +       prfield (i, line);
  5.2035 +     }
  5.2036 + }
  5.2037 +@@ -592,7 +839,6 @@ static void
  5.2038 + prjoin (struct line const *line1, struct line const *line2)
  5.2039 + {
  5.2040 +   const struct outlist *outlist;
  5.2041 +-  char output_separator = tab < 0 ? ' ' : tab;
  5.2042 +   size_t field;
  5.2043 +   struct line const *line;
  5.2044 + 
  5.2045 +@@ -626,7 +872,7 @@ prjoin (struct line const *line1, struct
  5.2046 +           o = o->next;
  5.2047 +           if (o == NULL)
  5.2048 +             break;
  5.2049 +-          putchar (output_separator);
  5.2050 ++          PUT_TAB_CHAR;
  5.2051 +         }
  5.2052 +       putchar (eolchar);
  5.2053 +     }
  5.2054 +@@ -1104,20 +1350,43 @@ main (int argc, char **argv)
  5.2055 + 
  5.2056 +         case 't':
  5.2057 +           {
  5.2058 +-            unsigned char newtab = optarg[0];
  5.2059 ++            char *newtab = NULL;
  5.2060 ++            size_t newtablen;
  5.2061 ++            newtab = xstrdup (optarg);
  5.2062 ++#if HAVE_MBRTOWC
  5.2063 ++            if (MB_CUR_MAX > 1)
  5.2064 ++              {
  5.2065 ++                mbstate_t state;
  5.2066 ++
  5.2067 ++                memset (&state, 0, sizeof (mbstate_t));
  5.2068 ++                newtablen = mbrtowc (NULL, newtab,
  5.2069 ++                                     strnlen (newtab, MB_LEN_MAX),
  5.2070 ++                                     &state);
  5.2071 ++                if (newtablen == (size_t) 0
  5.2072 ++                    || newtablen == (size_t) -1
  5.2073 ++                    || newtablen == (size_t) -2)
  5.2074 ++                  newtablen = 1;
  5.2075 ++              }
  5.2076 ++            else
  5.2077 ++#endif
  5.2078 ++              newtablen = 1;
  5.2079 +             if (! newtab)
  5.2080 +-              newtab = '\n'; /* '' => process the whole line.  */
  5.2081 ++              newtab = (char*)"\n"; /* '' => process the whole line.  */
  5.2082 +             else if (optarg[1])
  5.2083 +               {
  5.2084 +-                if (STREQ (optarg, "\\0"))
  5.2085 +-                  newtab = '\0';
  5.2086 +-                else
  5.2087 +-                  die (EXIT_FAILURE, 0, _("multi-character tab %s"),
  5.2088 +-                       quote (optarg));
  5.2089 ++                if (newtablen == 1 && newtab[1])
  5.2090 ++                {
  5.2091 ++                  if (STREQ (newtab, "\\0"))
  5.2092 ++                     newtab[0] = '\0';
  5.2093 ++                }
  5.2094 ++              }
  5.2095 ++            if (tab != NULL && strcmp (tab, newtab))
  5.2096 ++              {
  5.2097 ++                free (newtab);
  5.2098 ++                die (EXIT_FAILURE, 0, _("incompatible tabs"));
  5.2099 +               }
  5.2100 +-            if (0 <= tab && tab != newtab)
  5.2101 +-              die (EXIT_FAILURE, 0, _("incompatible tabs"));
  5.2102 +             tab = newtab;
  5.2103 ++            tablen = newtablen;
  5.2104 +           }
  5.2105 +           break;
  5.2106 + 
  5.2107 +diff -Naurp coreutils-8.27-orig/src/pr.c coreutils-8.27/src/pr.c
  5.2108 +--- coreutils-8.27-orig/src/pr.c	2017-01-01 16:34:24.000000000 -0600
  5.2109 ++++ coreutils-8.27/src/pr.c	2017-03-11 23:47:13.094286139 -0600
  5.2110 +@@ -311,6 +311,24 @@
  5.2111 + 
  5.2112 + #include <getopt.h>
  5.2113 + #include <sys/types.h>
  5.2114 ++
  5.2115 ++/* Get MB_LEN_MAX.  */
  5.2116 ++#include <limits.h>
  5.2117 ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
  5.2118 ++   installation; work around this configuration error.  */
  5.2119 ++#if !defined MB_LEN_MAX || MB_LEN_MAX == 1
  5.2120 ++# define MB_LEN_MAX 16
  5.2121 ++#endif
  5.2122 ++
  5.2123 ++/* Get MB_CUR_MAX.  */
  5.2124 ++#include <stdlib.h>
  5.2125 ++
  5.2126 ++/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
  5.2127 ++/* Get mbstate_t, mbrtowc(), wcwidth().  */
  5.2128 ++#if HAVE_WCHAR_H
  5.2129 ++# include <wchar.h>
  5.2130 ++#endif
  5.2131 ++
  5.2132 + #include "system.h"
  5.2133 + #include "die.h"
  5.2134 + #include "error.h"
  5.2135 +@@ -324,6 +342,18 @@
  5.2136 + #include "xstrtol.h"
  5.2137 + #include "xdectoint.h"
  5.2138 + 
  5.2139 ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  5.2140 ++#if HAVE_MBRTOWC && defined mbstate_t
  5.2141 ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  5.2142 ++#endif
  5.2143 ++
  5.2144 ++#ifndef HAVE_DECL_WCWIDTH
  5.2145 ++"this configure-time declaration test was not run"
  5.2146 ++#endif
  5.2147 ++#if !HAVE_DECL_WCWIDTH
  5.2148 ++extern int wcwidth ();
  5.2149 ++#endif
  5.2150 ++
  5.2151 + /* The official name of this program (e.g., no 'g' prefix).  */
  5.2152 + #define PROGRAM_NAME "pr"
  5.2153 + 
  5.2154 +@@ -416,7 +446,20 @@ struct COLUMN
  5.2155 + 
  5.2156 + typedef struct COLUMN COLUMN;
  5.2157 + 
  5.2158 +-static int char_to_clump (char c);
  5.2159 ++/* Funtion pointers to switch functions for single byte locale or for
  5.2160 ++   multibyte locale. If multibyte functions do not exist in your sysytem,
  5.2161 ++   these pointers always point the function for single byte locale. */
  5.2162 ++static void (*print_char) (char c);
  5.2163 ++static int (*char_to_clump) (char c);
  5.2164 ++
  5.2165 ++/* Functions for single byte locale. */
  5.2166 ++static void print_char_single (char c);
  5.2167 ++static int char_to_clump_single (char c);
  5.2168 ++
  5.2169 ++/* Functions for multibyte locale. */
  5.2170 ++static void print_char_multi (char c);
  5.2171 ++static int char_to_clump_multi (char c);
  5.2172 ++
  5.2173 + static bool read_line (COLUMN *p);
  5.2174 + static bool print_page (void);
  5.2175 + static bool print_stored (COLUMN *p);
  5.2176 +@@ -428,6 +471,7 @@ static void add_line_number (COLUMN *p);
  5.2177 + static void getoptnum (const char *n_str, int min, int *num,
  5.2178 +                        const char *errfmt);
  5.2179 + static void getoptarg (char *arg, char switch_char, char *character,
  5.2180 ++                       int *character_length, int *character_width,
  5.2181 +                        int *number);
  5.2182 + static void print_files (int number_of_files, char **av);
  5.2183 + static void init_parameters (int number_of_files);
  5.2184 +@@ -441,7 +485,6 @@ static void store_char (char c);
  5.2185 + static void pad_down (unsigned int lines);
  5.2186 + static void read_rest_of_line (COLUMN *p);
  5.2187 + static void skip_read (COLUMN *p, int column_number);
  5.2188 +-static void print_char (char c);
  5.2189 + static void cleanup (void);
  5.2190 + static void print_sep_string (void);
  5.2191 + static void separator_string (const char *optarg_S);
  5.2192 +@@ -453,7 +496,7 @@ static COLUMN *column_vector;
  5.2193 +    we store the leftmost columns contiguously in buff.
  5.2194 +    To print a line from buff, get the index of the first character
  5.2195 +    from line_vector[i], and print up to line_vector[i + 1]. */
  5.2196 +-static char *buff;
  5.2197 ++static unsigned char *buff;
  5.2198 + 
  5.2199 + /* Index of the position in buff where the next character
  5.2200 +    will be stored. */
  5.2201 +@@ -557,7 +600,7 @@ static int chars_per_column;
  5.2202 + static bool untabify_input = false;
  5.2203 + 
  5.2204 + /* (-e) The input tab character. */
  5.2205 +-static char input_tab_char = '\t';
  5.2206 ++static char input_tab_char[MB_LEN_MAX] = "\t";
  5.2207 + 
  5.2208 + /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
  5.2209 +    where the leftmost column is 1. */
  5.2210 +@@ -567,7 +610,10 @@ static int chars_per_input_tab = 8;
  5.2211 + static bool tabify_output = false;
  5.2212 + 
  5.2213 + /* (-i) The output tab character. */
  5.2214 +-static char output_tab_char = '\t';
  5.2215 ++static char output_tab_char[MB_LEN_MAX] = "\t";
  5.2216 ++
  5.2217 ++/* (-i) The byte length of output tab character. */
  5.2218 ++static int output_tab_char_length = 1;
  5.2219 + 
  5.2220 + /* (-i) The width of the output tab. */
  5.2221 + static int chars_per_output_tab = 8;
  5.2222 +@@ -637,7 +683,13 @@ static int line_number;
  5.2223 + static bool numbered_lines = false;
  5.2224 + 
  5.2225 + /* (-n) Character which follows each line number. */
  5.2226 +-static char number_separator = '\t';
  5.2227 ++static char number_separator[MB_LEN_MAX] = "\t";
  5.2228 ++
  5.2229 ++/* (-n) The byte length of the character which follows each line number. */
  5.2230 ++static int number_separator_length = 1;
  5.2231 ++
  5.2232 ++/* (-n) The character width of the character which follows each line number. */
  5.2233 ++static int number_separator_width = 0;
  5.2234 + 
  5.2235 + /* (-n) line counting starts with 1st line of input file (not with 1st
  5.2236 +    line of 1st page printed). */
  5.2237 +@@ -690,6 +742,7 @@ static bool use_col_separator = false;
  5.2238 +    -a|COLUMN|-m is a 'space' and with the -J option a 'tab'. */
  5.2239 + static char const *col_sep_string = "";
  5.2240 + static int col_sep_length = 0;
  5.2241 ++static int col_sep_width = 0;
  5.2242 + static char *column_separator = (char *) " ";
  5.2243 + static char *line_separator = (char *) "\t";
  5.2244 + 
  5.2245 +@@ -851,6 +904,13 @@ separator_string (const char *optarg_S)
  5.2246 +     integer_overflow ();
  5.2247 +   col_sep_length = len;
  5.2248 +   col_sep_string = optarg_S;
  5.2249 ++
  5.2250 ++#if HAVE_MBRTOWC
  5.2251 ++  if (MB_CUR_MAX > 1)
  5.2252 ++    col_sep_width = mbswidth (col_sep_string, 0);
  5.2253 ++  else
  5.2254 ++#endif
  5.2255 ++    col_sep_width = col_sep_length;
  5.2256 + }
  5.2257 + 
  5.2258 + int
  5.2259 +@@ -875,6 +935,21 @@ main (int argc, char **argv)
  5.2260 + 
  5.2261 +   atexit (close_stdout);
  5.2262 + 
  5.2263 ++/* Define which functions are used, the ones for single byte locale or the ones
  5.2264 ++   for multibyte locale. */
  5.2265 ++#if HAVE_MBRTOWC
  5.2266 ++  if (MB_CUR_MAX > 1)
  5.2267 ++    {
  5.2268 ++      print_char = print_char_multi;
  5.2269 ++      char_to_clump = char_to_clump_multi;
  5.2270 ++    }
  5.2271 ++  else
  5.2272 ++#endif
  5.2273 ++    {
  5.2274 ++      print_char = print_char_single;
  5.2275 ++      char_to_clump = char_to_clump_single;
  5.2276 ++    }
  5.2277 ++
  5.2278 +   n_files = 0;
  5.2279 +   file_names = (argc > 1
  5.2280 +                 ? xnmalloc (argc - 1, sizeof (char *))
  5.2281 +@@ -951,8 +1026,12 @@ main (int argc, char **argv)
  5.2282 +           break;
  5.2283 +         case 'e':
  5.2284 +           if (optarg)
  5.2285 +-            getoptarg (optarg, 'e', &input_tab_char,
  5.2286 +-                       &chars_per_input_tab);
  5.2287 ++            {
  5.2288 ++              int dummy_length, dummy_width;
  5.2289 ++
  5.2290 ++              getoptarg (optarg, 'e', input_tab_char, &dummy_length,
  5.2291 ++                         &dummy_width, &chars_per_input_tab);
  5.2292 ++            }
  5.2293 +           /* Could check tab width > 0. */
  5.2294 +           untabify_input = true;
  5.2295 +           break;
  5.2296 +@@ -965,8 +1044,12 @@ main (int argc, char **argv)
  5.2297 +           break;
  5.2298 +         case 'i':
  5.2299 +           if (optarg)
  5.2300 +-            getoptarg (optarg, 'i', &output_tab_char,
  5.2301 +-                       &chars_per_output_tab);
  5.2302 ++            {
  5.2303 ++              int dummy_width;
  5.2304 ++
  5.2305 ++              getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length,
  5.2306 ++                         &dummy_width, &chars_per_output_tab);
  5.2307 ++            }
  5.2308 +           /* Could check tab width > 0. */
  5.2309 +           tabify_output = true;
  5.2310 +           break;
  5.2311 +@@ -984,8 +1067,8 @@ main (int argc, char **argv)
  5.2312 +         case 'n':
  5.2313 +           numbered_lines = true;
  5.2314 +           if (optarg)
  5.2315 +-            getoptarg (optarg, 'n', &number_separator,
  5.2316 +-                       &chars_per_number);
  5.2317 ++            getoptarg (optarg, 'n', number_separator, &number_separator_length,
  5.2318 ++                       &number_separator_width, &chars_per_number);
  5.2319 +           break;
  5.2320 +         case 'N':
  5.2321 +           skip_count = false;
  5.2322 +@@ -1010,6 +1093,7 @@ main (int argc, char **argv)
  5.2323 +           /* Reset an additional input of -s, -S dominates -s */
  5.2324 +           col_sep_string = "";
  5.2325 +           col_sep_length = 0;
  5.2326 ++          col_sep_width = 0;
  5.2327 +           use_col_separator = true;
  5.2328 +           if (optarg)
  5.2329 +             separator_string (optarg);
  5.2330 +@@ -1166,10 +1250,45 @@ getoptnum (const char *n_str, int min, i
  5.2331 +    a number. */
  5.2332 + 
  5.2333 + static void
  5.2334 +-getoptarg (char *arg, char switch_char, char *character, int *number)
  5.2335 ++getoptarg (char *arg, char switch_char, char *character, int *character_length,
  5.2336 ++           int *character_width, int *number)
  5.2337 + {
  5.2338 +   if (!ISDIGIT (*arg))
  5.2339 +-    *character = *arg++;
  5.2340 ++    {
  5.2341 ++#ifdef HAVE_MBRTOWC
  5.2342 ++      if (MB_CUR_MAX > 1)        /* for multibyte locale. */
  5.2343 ++        {
  5.2344 ++          wchar_t wc;
  5.2345 ++          size_t mblength;
  5.2346 ++          int width;
  5.2347 ++          mbstate_t state = {'\0'};
  5.2348 ++
  5.2349 ++          mblength = mbrtowc (&wc, arg, strnlen(arg, MB_LEN_MAX), &state);
  5.2350 ++
  5.2351 ++          if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.2352 ++            {
  5.2353 ++              *character_length = 1;
  5.2354 ++              *character_width = 1;
  5.2355 ++            }
  5.2356 ++          else
  5.2357 ++            {
  5.2358 ++              *character_length = (mblength < 1) ? 1 : mblength;
  5.2359 ++              width = wcwidth (wc);
  5.2360 ++              *character_width = (width < 0) ? 0 : width;
  5.2361 ++            }
  5.2362 ++
  5.2363 ++          strncpy (character, arg, *character_length);
  5.2364 ++          arg += *character_length;
  5.2365 ++        }
  5.2366 ++      else                        /* for single byte locale. */
  5.2367 ++#endif
  5.2368 ++        {
  5.2369 ++          *character = *arg++;
  5.2370 ++          *character_length = 1;
  5.2371 ++          *character_width = 1;
  5.2372 ++        }
  5.2373 ++    }
  5.2374 ++
  5.2375 +   if (*arg)
  5.2376 +     {
  5.2377 +       long int tmp_long;
  5.2378 +@@ -1191,6 +1310,11 @@ static void
  5.2379 + init_parameters (int number_of_files)
  5.2380 + {
  5.2381 +   int chars_used_by_number = 0;
  5.2382 ++  int mb_len = 1;
  5.2383 ++#if HAVE_MBRTOWC
  5.2384 ++  if (MB_CUR_MAX > 1)
  5.2385 ++    mb_len = MB_LEN_MAX;
  5.2386 ++#endif
  5.2387 + 
  5.2388 +   lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
  5.2389 +   if (lines_per_body <= 0)
  5.2390 +@@ -1228,7 +1352,7 @@ init_parameters (int number_of_files)
  5.2391 +           else
  5.2392 +             col_sep_string = column_separator;
  5.2393 + 
  5.2394 +-          col_sep_length = 1;
  5.2395 ++          col_sep_length = col_sep_width = 1;
  5.2396 +           use_col_separator = true;
  5.2397 +         }
  5.2398 +       /* It's rather pointless to define a TAB separator with column
  5.2399 +@@ -1258,11 +1382,11 @@ init_parameters (int number_of_files)
  5.2400 +              + TAB_WIDTH (chars_per_input_tab, chars_per_number);   */
  5.2401 + 
  5.2402 +       /* Estimate chars_per_text without any margin and keep it constant. */
  5.2403 +-      if (number_separator == '\t')
  5.2404 ++      if (number_separator[0] == '\t')
  5.2405 +         number_width = (chars_per_number
  5.2406 +                         + TAB_WIDTH (chars_per_default_tab, chars_per_number));
  5.2407 +       else
  5.2408 +-        number_width = chars_per_number + 1;
  5.2409 ++        number_width = chars_per_number + number_separator_width;
  5.2410 + 
  5.2411 +       /* The number is part of the column width unless we are
  5.2412 +          printing files in parallel. */
  5.2413 +@@ -1271,7 +1395,7 @@ init_parameters (int number_of_files)
  5.2414 +     }
  5.2415 + 
  5.2416 +   int sep_chars, useful_chars;
  5.2417 +-  if (INT_MULTIPLY_WRAPV (columns - 1, col_sep_length, &sep_chars))
  5.2418 ++  if (INT_MULTIPLY_WRAPV (columns - 1, col_sep_width, &sep_chars))
  5.2419 +     sep_chars = INT_MAX;
  5.2420 +   if (INT_SUBTRACT_WRAPV (chars_per_line - chars_used_by_number, sep_chars,
  5.2421 +                           &useful_chars))
  5.2422 +@@ -1294,7 +1418,7 @@ init_parameters (int number_of_files)
  5.2423 +      We've to use 8 as the lower limit, if we use chars_per_default_tab = 8
  5.2424 +      to expand a tab which is not an input_tab-char. */
  5.2425 +   free (clump_buff);
  5.2426 +-  clump_buff = xmalloc (MAX (8, chars_per_input_tab));
  5.2427 ++  clump_buff = xmalloc (mb_len * MAX (8, chars_per_input_tab));
  5.2428 + }
  5.2429 + 
  5.2430 + /* Open the necessary files,
  5.2431 +@@ -1402,7 +1526,7 @@ init_funcs (void)
  5.2432 + 
  5.2433 +   /* Enlarge p->start_position of first column to use the same form of
  5.2434 +      padding_not_printed with all columns. */
  5.2435 +-  h = h + col_sep_length;
  5.2436 ++  h = h + col_sep_width;
  5.2437 + 
  5.2438 +   /* This loop takes care of all but the rightmost column. */
  5.2439 + 
  5.2440 +@@ -1436,7 +1560,7 @@ init_funcs (void)
  5.2441 +         }
  5.2442 +       else
  5.2443 +         {
  5.2444 +-          h = h_next + col_sep_length;
  5.2445 ++          h = h_next + col_sep_width;
  5.2446 +           h_next = h + chars_per_column;
  5.2447 +         }
  5.2448 +     }
  5.2449 +@@ -1727,9 +1851,9 @@ static void
  5.2450 + align_column (COLUMN *p)
  5.2451 + {
  5.2452 +   padding_not_printed = p->start_position;
  5.2453 +-  if (col_sep_length < padding_not_printed)
  5.2454 ++  if (col_sep_width < padding_not_printed)
  5.2455 +     {
  5.2456 +-      pad_across_to (padding_not_printed - col_sep_length);
  5.2457 ++      pad_across_to (padding_not_printed - col_sep_width);
  5.2458 +       padding_not_printed = ANYWHERE;
  5.2459 +     }
  5.2460 + 
  5.2461 +@@ -2004,13 +2128,13 @@ store_char (char c)
  5.2462 +       /* May be too generous. */
  5.2463 +       buff = X2REALLOC (buff, &buff_allocated);
  5.2464 +     }
  5.2465 +-  buff[buff_current++] = c;
  5.2466 ++  buff[buff_current++] = (unsigned char) c;
  5.2467 + }
  5.2468 + 
  5.2469 + static void
  5.2470 + add_line_number (COLUMN *p)
  5.2471 + {
  5.2472 +-  int i;
  5.2473 ++  int i, j;
  5.2474 +   char *s;
  5.2475 +   int num_width;
  5.2476 + 
  5.2477 +@@ -2027,22 +2151,24 @@ add_line_number (COLUMN *p)
  5.2478 +       /* Tabification is assumed for multiple columns, also for n-separators,
  5.2479 +          but 'default n-separator = TAB' hasn't been given priority over
  5.2480 +          equal column_width also specified by POSIX. */
  5.2481 +-      if (number_separator == '\t')
  5.2482 ++      if (number_separator[0] == '\t')
  5.2483 +         {
  5.2484 +           i = number_width - chars_per_number;
  5.2485 +           while (i-- > 0)
  5.2486 +             (p->char_func) (' ');
  5.2487 +         }
  5.2488 +       else
  5.2489 +-        (p->char_func) (number_separator);
  5.2490 ++        for (j = 0; j < number_separator_length; j++)
  5.2491 ++          (p->char_func) (number_separator[j]);
  5.2492 +     }
  5.2493 +   else
  5.2494 +     /* To comply with POSIX, we avoid any expansion of default TAB
  5.2495 +        separator with a single column output. No column_width requirement
  5.2496 +        has to be considered. */
  5.2497 +     {
  5.2498 +-      (p->char_func) (number_separator);
  5.2499 +-      if (number_separator == '\t')
  5.2500 ++      for (j = 0; j < number_separator_length; j++)
  5.2501 ++        (p->char_func) (number_separator[j]);
  5.2502 ++      if (number_separator[0] == '\t')
  5.2503 +         output_position = POS_AFTER_TAB (chars_per_output_tab,
  5.2504 +                           output_position);
  5.2505 +     }
  5.2506 +@@ -2203,7 +2329,7 @@ print_white_space (void)
  5.2507 +   while (goal - h_old > 1
  5.2508 +          && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)
  5.2509 +     {
  5.2510 +-      putchar (output_tab_char);
  5.2511 ++      fwrite (output_tab_char, sizeof(char), output_tab_char_length, stdout);
  5.2512 +       h_old = h_new;
  5.2513 +     }
  5.2514 +   while (++h_old <= goal)
  5.2515 +@@ -2223,6 +2349,7 @@ print_sep_string (void)
  5.2516 + {
  5.2517 +   char const *s = col_sep_string;
  5.2518 +   int l = col_sep_length;
  5.2519 ++  int not_space_flag;
  5.2520 + 
  5.2521 +   if (separators_not_printed <= 0)
  5.2522 +     {
  5.2523 +@@ -2234,6 +2361,7 @@ print_sep_string (void)
  5.2524 +     {
  5.2525 +       for (; separators_not_printed > 0; --separators_not_printed)
  5.2526 +         {
  5.2527 ++          not_space_flag = 0;
  5.2528 +           while (l-- > 0)
  5.2529 +             {
  5.2530 +               /* 3 types of sep_strings: spaces only, spaces and chars,
  5.2531 +@@ -2247,12 +2375,15 @@ print_sep_string (void)
  5.2532 +                 }
  5.2533 +               else
  5.2534 +                 {
  5.2535 ++                  not_space_flag = 1;
  5.2536 +                   if (spaces_not_printed > 0)
  5.2537 +                     print_white_space ();
  5.2538 +                   putchar (*s++);
  5.2539 +-                  ++output_position;
  5.2540 +                 }
  5.2541 +             }
  5.2542 ++          if (not_space_flag)
  5.2543 ++            output_position += col_sep_width;
  5.2544 ++
  5.2545 +           /* sep_string ends with some spaces */
  5.2546 +           if (spaces_not_printed > 0)
  5.2547 +             print_white_space ();
  5.2548 +@@ -2280,7 +2411,7 @@ print_clump (COLUMN *p, int n, char *clu
  5.2549 +    required number of tabs and spaces. */
  5.2550 + 
  5.2551 + static void
  5.2552 +-print_char (char c)
  5.2553 ++print_char_single (char c)
  5.2554 + {
  5.2555 +   if (tabify_output)
  5.2556 +     {
  5.2557 +@@ -2304,6 +2435,74 @@ print_char (char c)
  5.2558 +   putchar (c);
  5.2559 + }
  5.2560 + 
  5.2561 ++#ifdef HAVE_MBRTOWC
  5.2562 ++static void
  5.2563 ++print_char_multi (char c)
  5.2564 ++{
  5.2565 ++  static size_t mbc_pos = 0;
  5.2566 ++  static char mbc[MB_LEN_MAX] = {'\0'};
  5.2567 ++  static mbstate_t state = {'\0'};
  5.2568 ++  mbstate_t state_bak;
  5.2569 ++  wchar_t wc;
  5.2570 ++  size_t mblength;
  5.2571 ++  int width;
  5.2572 ++
  5.2573 ++  if (tabify_output)
  5.2574 ++    {
  5.2575 ++      state_bak = state;
  5.2576 ++      mbc[mbc_pos++] = c;
  5.2577 ++      mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
  5.2578 ++
  5.2579 ++      while (mbc_pos > 0)
  5.2580 ++        {
  5.2581 ++          switch (mblength)
  5.2582 ++            {
  5.2583 ++            case (size_t)-2:
  5.2584 ++              state = state_bak;
  5.2585 ++              return;
  5.2586 ++
  5.2587 ++            case (size_t)-1:
  5.2588 ++              state = state_bak;
  5.2589 ++              ++output_position;
  5.2590 ++              putchar (mbc[0]);
  5.2591 ++              memmove (mbc, mbc + 1, MB_CUR_MAX - 1);
  5.2592 ++              --mbc_pos;
  5.2593 ++              break;
  5.2594 ++
  5.2595 ++            case 0:
  5.2596 ++              mblength = 1;
  5.2597 ++
  5.2598 ++            default:
  5.2599 ++              if (wc == L' ')
  5.2600 ++                {
  5.2601 ++                  memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
  5.2602 ++                  --mbc_pos;
  5.2603 ++                  ++spaces_not_printed;
  5.2604 ++                  return;
  5.2605 ++                }
  5.2606 ++              else if (spaces_not_printed > 0)
  5.2607 ++                print_white_space ();
  5.2608 ++
  5.2609 ++              /* Nonprintables are assumed to have width 0, except L'\b'. */
  5.2610 ++              if ((width = wcwidth (wc)) < 1)
  5.2611 ++                {
  5.2612 ++                  if (wc == L'\b')
  5.2613 ++                    --output_position;
  5.2614 ++                }
  5.2615 ++              else
  5.2616 ++                output_position += width;
  5.2617 ++
  5.2618 ++              fwrite (mbc, sizeof(char), mblength, stdout);
  5.2619 ++              memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
  5.2620 ++              mbc_pos -= mblength;
  5.2621 ++            }
  5.2622 ++        }
  5.2623 ++      return;
  5.2624 ++    }
  5.2625 ++  putchar (c);
  5.2626 ++}
  5.2627 ++#endif
  5.2628 ++
  5.2629 + /* Skip to page PAGE before printing.
  5.2630 +    PAGE may be larger than total number of pages. */
  5.2631 + 
  5.2632 +@@ -2483,9 +2682,9 @@ read_line (COLUMN *p)
  5.2633 +           align_empty_cols = false;
  5.2634 +         }
  5.2635 + 
  5.2636 +-      if (col_sep_length < padding_not_printed)
  5.2637 ++      if (col_sep_width < padding_not_printed)
  5.2638 +         {
  5.2639 +-          pad_across_to (padding_not_printed - col_sep_length);
  5.2640 ++          pad_across_to (padding_not_printed - col_sep_width);
  5.2641 +           padding_not_printed = ANYWHERE;
  5.2642 +         }
  5.2643 + 
  5.2644 +@@ -2555,7 +2754,7 @@ print_stored (COLUMN *p)
  5.2645 +   int i;
  5.2646 + 
  5.2647 +   int line = p->current_line++;
  5.2648 +-  char *first = &buff[line_vector[line]];
  5.2649 ++  unsigned char *first = &buff[line_vector[line]];
  5.2650 +   /* FIXME
  5.2651 +      UMR: Uninitialized memory read:
  5.2652 +      * This is occurring while in:
  5.2653 +@@ -2567,7 +2766,7 @@ print_stored (COLUMN *p)
  5.2654 +      xmalloc        [xmalloc.c:94]
  5.2655 +      init_store_cols [pr.c:1648]
  5.2656 +      */
  5.2657 +-  char *last = &buff[line_vector[line + 1]];
  5.2658 ++  unsigned char *last = &buff[line_vector[line + 1]];
  5.2659 + 
  5.2660 +   pad_vertically = true;
  5.2661 + 
  5.2662 +@@ -2586,9 +2785,9 @@ print_stored (COLUMN *p)
  5.2663 +         }
  5.2664 +     }
  5.2665 + 
  5.2666 +-  if (col_sep_length < padding_not_printed)
  5.2667 ++  if (col_sep_width < padding_not_printed)
  5.2668 +     {
  5.2669 +-      pad_across_to (padding_not_printed - col_sep_length);
  5.2670 ++      pad_across_to (padding_not_printed - col_sep_width);
  5.2671 +       padding_not_printed = ANYWHERE;
  5.2672 +     }
  5.2673 + 
  5.2674 +@@ -2601,8 +2800,8 @@ print_stored (COLUMN *p)
  5.2675 +   if (spaces_not_printed == 0)
  5.2676 +     {
  5.2677 +       output_position = p->start_position + end_vector[line];
  5.2678 +-      if (p->start_position - col_sep_length == chars_per_margin)
  5.2679 +-        output_position -= col_sep_length;
  5.2680 ++      if (p->start_position - col_sep_width == chars_per_margin)
  5.2681 ++        output_position -= col_sep_width;
  5.2682 +     }
  5.2683 + 
  5.2684 +   return true;
  5.2685 +@@ -2621,7 +2820,7 @@ print_stored (COLUMN *p)
  5.2686 +    number of characters is 1.) */
  5.2687 + 
  5.2688 + static int
  5.2689 +-char_to_clump (char c)
  5.2690 ++char_to_clump_single (char c)
  5.2691 + {
  5.2692 +   unsigned char uc = c;
  5.2693 +   char *s = clump_buff;
  5.2694 +@@ -2631,10 +2830,10 @@ char_to_clump (char c)
  5.2695 +   int chars;
  5.2696 +   int chars_per_c = 8;
  5.2697 + 
  5.2698 +-  if (c == input_tab_char)
  5.2699 ++  if (c == input_tab_char[0])
  5.2700 +     chars_per_c = chars_per_input_tab;
  5.2701 + 
  5.2702 +-  if (c == input_tab_char || c == '\t')
  5.2703 ++  if (c == input_tab_char[0] || c == '\t')
  5.2704 +     {
  5.2705 +       width = TAB_WIDTH (chars_per_c, input_position);
  5.2706 + 
  5.2707 +@@ -2715,6 +2914,164 @@ char_to_clump (char c)
  5.2708 +   return chars;
  5.2709 + }
  5.2710 + 
  5.2711 ++#ifdef HAVE_MBRTOWC
  5.2712 ++static int
  5.2713 ++char_to_clump_multi (char c)
  5.2714 ++{
  5.2715 ++  static size_t mbc_pos = 0;
  5.2716 ++  static char mbc[MB_LEN_MAX] = {'\0'};
  5.2717 ++  static mbstate_t state = {'\0'};
  5.2718 ++  mbstate_t state_bak;
  5.2719 ++  wchar_t wc;
  5.2720 ++  size_t mblength;
  5.2721 ++  int wc_width;
  5.2722 ++  register char *s = clump_buff;
  5.2723 ++  register int i, j;
  5.2724 ++  char esc_buff[4];
  5.2725 ++  int width;
  5.2726 ++  int chars;
  5.2727 ++  int chars_per_c = 8;
  5.2728 ++
  5.2729 ++  state_bak = state;
  5.2730 ++  mbc[mbc_pos++] = c;
  5.2731 ++  mblength = mbrtowc (&wc, mbc, mbc_pos, &state);
  5.2732 ++
  5.2733 ++  width = 0;
  5.2734 ++  chars = 0;
  5.2735 ++  while (mbc_pos > 0)
  5.2736 ++    {
  5.2737 ++      switch (mblength)
  5.2738 ++        {
  5.2739 ++        case (size_t)-2:
  5.2740 ++          state = state_bak;
  5.2741 ++          return 0;
  5.2742 ++
  5.2743 ++        case (size_t)-1:
  5.2744 ++          state = state_bak;
  5.2745 ++          mblength = 1;
  5.2746 ++
  5.2747 ++          if (use_esc_sequence || use_cntrl_prefix)
  5.2748 ++            {
  5.2749 ++              width = +4;
  5.2750 ++              chars = +4;
  5.2751 ++              *s++ = '\\';
  5.2752 ++              sprintf (esc_buff, "%03o", (unsigned char) mbc[0]);
  5.2753 ++              for (i = 0; i <= 2; ++i)
  5.2754 ++                *s++ = (int) esc_buff[i];
  5.2755 ++            }
  5.2756 ++          else
  5.2757 ++            {
  5.2758 ++              width += 1;
  5.2759 ++              chars += 1;
  5.2760 ++              *s++ = mbc[0];
  5.2761 ++            }
  5.2762 ++          break;
  5.2763 ++
  5.2764 ++        case 0:
  5.2765 ++          mblength = 1;
  5.2766 ++                /* Fall through */
  5.2767 ++
  5.2768 ++        default:
  5.2769 ++          if (memcmp (mbc, input_tab_char, mblength) == 0)
  5.2770 ++            chars_per_c = chars_per_input_tab;
  5.2771 ++
  5.2772 ++          if (memcmp (mbc, input_tab_char, mblength) == 0 || c == '\t')
  5.2773 ++            {
  5.2774 ++              int  width_inc;
  5.2775 ++
  5.2776 ++              width_inc = TAB_WIDTH (chars_per_c, input_position);
  5.2777 ++              width += width_inc;
  5.2778 ++
  5.2779 ++              if (untabify_input)
  5.2780 ++                {
  5.2781 ++                  for (i = width_inc; i; --i)
  5.2782 ++                    *s++ = ' ';
  5.2783 ++                  chars += width_inc;
  5.2784 ++                }
  5.2785 ++              else
  5.2786 ++                {
  5.2787 ++                  for (i = 0; i <  mblength; i++)
  5.2788 ++                    *s++ = mbc[i];
  5.2789 ++                  chars += mblength;
  5.2790 ++                }
  5.2791 ++            }
  5.2792 ++          else if ((wc_width = wcwidth (wc)) < 1)
  5.2793 ++            {
  5.2794 ++              if (use_esc_sequence)
  5.2795 ++                {
  5.2796 ++                  for (i = 0; i < mblength; i++)
  5.2797 ++                    {
  5.2798 ++                      width += 4;
  5.2799 ++                      chars += 4;
  5.2800 ++                      *s++ = '\\';
  5.2801 ++                      sprintf (esc_buff, "%03o", (unsigned char) mbc[i]);
  5.2802 ++                      for (j = 0; j <= 2; ++j)
  5.2803 ++                        *s++ = (int) esc_buff[j];
  5.2804 ++                    }
  5.2805 ++                }
  5.2806 ++              else if (use_cntrl_prefix)
  5.2807 ++                {
  5.2808 ++                  if (wc < 0200)
  5.2809 ++                    {
  5.2810 ++                      width += 2;
  5.2811 ++                      chars += 2;
  5.2812 ++                      *s++ = '^';
  5.2813 ++                      *s++ = wc ^ 0100;
  5.2814 ++                    }
  5.2815 ++                  else
  5.2816 ++                    {
  5.2817 ++                      for (i = 0; i < mblength; i++)
  5.2818 ++                        {
  5.2819 ++                          width += 4;
  5.2820 ++                          chars += 4;
  5.2821 ++                          *s++ = '\\';
  5.2822 ++                          sprintf (esc_buff, "%03o", (unsigned char) mbc[i]);
  5.2823 ++                          for (j = 0; j <= 2; ++j)
  5.2824 ++                            *s++ = (int) esc_buff[j];
  5.2825 ++                        }
  5.2826 ++                    }
  5.2827 ++                }
  5.2828 ++              else if (wc == L'\b')
  5.2829 ++                {
  5.2830 ++                  width += -1;
  5.2831 ++                  chars += 1;
  5.2832 ++                  *s++ = c;
  5.2833 ++                }
  5.2834 ++              else
  5.2835 ++                {
  5.2836 ++                  width += 0;
  5.2837 ++                  chars += mblength;
  5.2838 ++                  for (i = 0; i < mblength; i++)
  5.2839 ++                    *s++ = mbc[i];
  5.2840 ++                }
  5.2841 ++            }
  5.2842 ++          else
  5.2843 ++            {
  5.2844 ++              width += wc_width;
  5.2845 ++              chars += mblength;
  5.2846 ++              for (i = 0; i < mblength; i++)
  5.2847 ++                *s++ = mbc[i];
  5.2848 ++            }
  5.2849 ++        }
  5.2850 ++      memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength);
  5.2851 ++      mbc_pos -= mblength;
  5.2852 ++    }
  5.2853 ++
  5.2854 ++  /* Too many backspaces must put us in position 0 -- never negative. */
  5.2855 ++  if (width < 0 && input_position == 0)
  5.2856 ++    {
  5.2857 ++      chars = 0;
  5.2858 ++      input_position = 0;
  5.2859 ++    }
  5.2860 ++  else if (width < 0 && input_position <= -width)
  5.2861 ++    input_position = 0;
  5.2862 ++  else
  5.2863 ++   input_position += width;
  5.2864 ++
  5.2865 ++  return chars;
  5.2866 ++}
  5.2867 ++#endif
  5.2868 ++
  5.2869 + /* We've just printed some files and need to clean up things before
  5.2870 +    looking for more options and printing the next batch of files.
  5.2871 + 
  5.2872 +diff -Naurp coreutils-8.27-orig/src/sort.c coreutils-8.27/src/sort.c
  5.2873 +--- coreutils-8.27-orig/src/sort.c	2017-01-01 16:34:24.000000000 -0600
  5.2874 ++++ coreutils-8.27/src/sort.c	2017-03-11 23:49:22.416505389 -0600
  5.2875 +@@ -29,6 +29,14 @@
  5.2876 + #include <sys/wait.h>
  5.2877 + #include <signal.h>
  5.2878 + #include <assert.h>
  5.2879 ++#if HAVE_WCHAR_H
  5.2880 ++# include <wchar.h>
  5.2881 ++#endif
  5.2882 ++/* Get isw* functions. */
  5.2883 ++#if HAVE_WCTYPE_H
  5.2884 ++# include <wctype.h>
  5.2885 ++#endif
  5.2886 ++
  5.2887 + #include "system.h"
  5.2888 + #include "argmatch.h"
  5.2889 + #include "die.h"
  5.2890 +@@ -165,14 +173,39 @@ static int decimal_point;
  5.2891 + /* Thousands separator; if -1, then there isn't one.  */
  5.2892 + static int thousands_sep;
  5.2893 + 
  5.2894 ++/* True if -f is specified.  */
  5.2895 ++static bool folding;
  5.2896 ++
  5.2897 + /* Nonzero if the corresponding locales are hard.  */
  5.2898 + static bool hard_LC_COLLATE;
  5.2899 +-#if HAVE_NL_LANGINFO
  5.2900 ++#if HAVE_LANGINFO_CODESET
  5.2901 + static bool hard_LC_TIME;
  5.2902 + #endif
  5.2903 + 
  5.2904 + #define NONZERO(x) ((x) != 0)
  5.2905 + 
  5.2906 ++/* get a multibyte character's byte length. */
  5.2907 ++#define GET_BYTELEN_OF_CHAR(LIM, PTR, MBLENGTH, STATE)                        \
  5.2908 ++  do                                                                        \
  5.2909 ++    {                                                                        \
  5.2910 ++      wchar_t wc;                                                        \
  5.2911 ++      mbstate_t state_bak;                                                \
  5.2912 ++                                                                        \
  5.2913 ++      state_bak = STATE;                                                \
  5.2914 ++      mblength = mbrtowc (&wc, PTR, LIM - PTR, &STATE);                        \
  5.2915 ++                                                                        \
  5.2916 ++      switch (MBLENGTH)                                                        \
  5.2917 ++        {                                                                \
  5.2918 ++        case (size_t)-1:                                                \
  5.2919 ++        case (size_t)-2:                                                \
  5.2920 ++          STATE = state_bak;                                                \
  5.2921 ++                /* Fall through. */                                        \
  5.2922 ++        case 0:                                                                \
  5.2923 ++          MBLENGTH = 1;                                                        \
  5.2924 ++      }                                                                        \
  5.2925 ++    }                                                                        \
  5.2926 ++  while (0)
  5.2927 ++
  5.2928 + /* The kind of blanks for '-b' to skip in various options. */
  5.2929 + enum blanktype { bl_start, bl_end, bl_both };
  5.2930 + 
  5.2931 +@@ -346,13 +379,11 @@ static bool reverse;
  5.2932 +    they were read if all keys compare equal.  */
  5.2933 + static bool stable;
  5.2934 + 
  5.2935 +-/* If TAB has this value, blanks separate fields.  */
  5.2936 +-enum { TAB_DEFAULT = CHAR_MAX + 1 };
  5.2937 +-
  5.2938 +-/* Tab character separating fields.  If TAB_DEFAULT, then fields are
  5.2939 ++/* Tab character separating fields.  If tab_length is 0, then fields are
  5.2940 +    separated by the empty string between a non-blank character and a blank
  5.2941 +    character. */
  5.2942 +-static int tab = TAB_DEFAULT;
  5.2943 ++static char tab[MB_LEN_MAX + 1];
  5.2944 ++static size_t tab_length = 0;
  5.2945 + 
  5.2946 + /* Flag to remove consecutive duplicate lines from the output.
  5.2947 +    Only the last of a sequence of equal lines will be output. */
  5.2948 +@@ -811,6 +842,46 @@ reap_all (void)
  5.2949 +     reap (-1);
  5.2950 + }
  5.2951 + 
  5.2952 ++/* Function pointers. */
  5.2953 ++static void
  5.2954 ++(*inittables) (void);
  5.2955 ++static char *
  5.2956 ++(*begfield) (const struct line*, const struct keyfield *);
  5.2957 ++static char *
  5.2958 ++(*limfield) (const struct line*, const struct keyfield *);
  5.2959 ++static void
  5.2960 ++(*skipblanks) (char **ptr, char *lim);
  5.2961 ++static int
  5.2962 ++(*getmonth) (char const *, size_t, char **);
  5.2963 ++static int
  5.2964 ++(*keycompare) (const struct line *, const struct line *);
  5.2965 ++static int
  5.2966 ++(*numcompare) (const char *, const char *);
  5.2967 ++
  5.2968 ++/* Test for white space multibyte character.
  5.2969 ++   Set LENGTH the byte length of investigated multibyte character. */
  5.2970 ++#if HAVE_MBRTOWC
  5.2971 ++static int
  5.2972 ++ismbblank (const char *str, size_t len, size_t *length)
  5.2973 ++{
  5.2974 ++  size_t mblength;
  5.2975 ++  wchar_t wc;
  5.2976 ++  mbstate_t state;
  5.2977 ++
  5.2978 ++  memset (&state, '\0', sizeof(mbstate_t));
  5.2979 ++  mblength = mbrtowc (&wc, str, len, &state);
  5.2980 ++
  5.2981 ++  if (mblength == (size_t)-1 || mblength == (size_t)-2)
  5.2982 ++    {
  5.2983 ++      *length = 1;
  5.2984 ++      return 0;
  5.2985 ++    }
  5.2986 ++
  5.2987 ++  *length = (mblength < 1) ? 1 : mblength;
  5.2988 ++  return iswblank (wc) || wc == '\n';
  5.2989 ++}
  5.2990 ++#endif
  5.2991 ++
  5.2992 + /* Clean up any remaining temporary files.  */
  5.2993 + 
  5.2994 + static void
  5.2995 +@@ -1255,7 +1326,7 @@ zaptemp (char const *name)
  5.2996 +   free (node);
  5.2997 + }
  5.2998 + 
  5.2999 +-#if HAVE_NL_LANGINFO
  5.3000 ++#if HAVE_LANGINFO_CODESET
  5.3001 + 
  5.3002 + static int
  5.3003 + struct_month_cmp (void const *m1, void const *m2)
  5.3004 +@@ -1270,7 +1341,7 @@ struct_month_cmp (void const *m1, void c
  5.3005 + /* Initialize the character class tables. */
  5.3006 + 
  5.3007 + static void
  5.3008 +-inittables (void)
  5.3009 ++inittables_uni (void)
  5.3010 + {
  5.3011 +   size_t i;
  5.3012 + 
  5.3013 +@@ -1282,7 +1353,7 @@ inittables (void)
  5.3014 +       fold_toupper[i] = toupper (i);
  5.3015 +     }
  5.3016 + 
  5.3017 +-#if HAVE_NL_LANGINFO
  5.3018 ++#if HAVE_LANGINFO_CODESET
  5.3019 +   /* If we're not in the "C" locale, read different names for months.  */
  5.3020 +   if (hard_LC_TIME)
  5.3021 +     {
  5.3022 +@@ -1364,6 +1435,84 @@ specify_nmerge (int oi, char c, char con
  5.3023 +     xstrtol_fatal (e, oi, c, long_options, s);
  5.3024 + }
  5.3025 + 
  5.3026 ++#if HAVE_MBRTOWC
  5.3027 ++static void
  5.3028 ++inittables_mb (void)
  5.3029 ++{
  5.3030 ++  int i, j, k, l;
  5.3031 ++  char *name, *s, *lc_time, *lc_ctype;
  5.3032 ++  size_t s_len, mblength;
  5.3033 ++  char mbc[MB_LEN_MAX];
  5.3034 ++  wchar_t wc, pwc;
  5.3035 ++  mbstate_t state_mb, state_wc;
  5.3036 ++
  5.3037 ++  lc_time = setlocale (LC_TIME, "");
  5.3038 ++  if (lc_time)
  5.3039 ++    lc_time = xstrdup (lc_time);
  5.3040 ++
  5.3041 ++  lc_ctype = setlocale (LC_CTYPE, "");
  5.3042 ++  if (lc_ctype)
  5.3043 ++    lc_ctype = xstrdup (lc_ctype);
  5.3044 ++
  5.3045 ++  if (lc_time && lc_ctype)
  5.3046 ++    /* temporarily set LC_CTYPE to match LC_TIME, so that we can convert
  5.3047 ++     * the names of months to upper case */
  5.3048 ++    setlocale (LC_CTYPE, lc_time);
  5.3049 ++
  5.3050 ++  for (i = 0; i < MONTHS_PER_YEAR; i++)
  5.3051 ++    {
  5.3052 ++      s = (char *) nl_langinfo (ABMON_1 + i);
  5.3053 ++      s_len = strlen (s);
  5.3054 ++      monthtab[i].name = name = (char *) xmalloc (s_len + 1);
  5.3055 ++      monthtab[i].val = i + 1;
  5.3056 ++
  5.3057 ++      memset (&state_mb, '\0', sizeof (mbstate_t));
  5.3058 ++      memset (&state_wc, '\0', sizeof (mbstate_t));
  5.3059 ++
  5.3060 ++      for (j = 0; j < s_len;)
  5.3061 ++        {
  5.3062 ++          if (!ismbblank (s + j, s_len - j, &mblength))
  5.3063 ++            break;
  5.3064 ++          j += mblength;
  5.3065 ++        }
  5.3066 ++
  5.3067 ++      for (k = 0; j < s_len;)
  5.3068 ++        {
  5.3069 ++          mblength = mbrtowc (&wc, (s + j), (s_len - j), &state_mb);
  5.3070 ++          assert (mblength != (size_t)-1 && mblength != (size_t)-2);
  5.3071 ++          if (mblength == 0)
  5.3072 ++            break;
  5.3073 ++
  5.3074 ++          pwc = towupper (wc);
  5.3075 ++          if (pwc == wc)
  5.3076 ++            {
  5.3077 ++              memcpy (mbc, s + j, mblength);
  5.3078 ++              j += mblength;
  5.3079 ++            }
  5.3080 ++          else
  5.3081 ++            {
  5.3082 ++              j += mblength;
  5.3083 ++              mblength = wcrtomb (mbc, pwc, &state_wc);
  5.3084 ++              assert (mblength != (size_t)0 && mblength != (size_t)-1);
  5.3085 ++            }
  5.3086 ++
  5.3087 ++          for (l = 0; l < mblength; l++)
  5.3088 ++            name[k++] = mbc[l];
  5.3089 ++        }
  5.3090 ++      name[k] = '\0';
  5.3091 ++    }
  5.3092 ++  qsort ((void *) monthtab, MONTHS_PER_YEAR,
  5.3093 ++      sizeof (struct month), struct_month_cmp);
  5.3094 ++
  5.3095 ++  if (lc_time && lc_ctype)
  5.3096 ++    /* restore the original locales */
  5.3097 ++    setlocale (LC_CTYPE, lc_ctype);
  5.3098 ++
  5.3099 ++  free (lc_ctype);
  5.3100 ++  free (lc_time);
  5.3101 ++}
  5.3102 ++#endif
  5.3103 ++
  5.3104 + /* Specify the amount of main memory to use when sorting.  */
  5.3105 + static void
  5.3106 + specify_sort_size (int oi, char c, char const *s)
  5.3107 +@@ -1597,7 +1746,7 @@ buffer_linelim (struct buffer const *buf
  5.3108 +    by KEY in LINE. */
  5.3109 + 
  5.3110 + static char *
  5.3111 +-begfield (struct line const *line, struct keyfield const *key)
  5.3112 ++begfield_uni (const struct line *line, const struct keyfield *key)
  5.3113 + {
  5.3114 +   char *ptr = line->text, *lim = ptr + line->length - 1;
  5.3115 +   size_t sword = key->sword;
  5.3116 +@@ -1606,10 +1755,10 @@ begfield (struct line const *line, struc
  5.3117 +   /* The leading field separator itself is included in a field when -t
  5.3118 +      is absent.  */
  5.3119 + 
  5.3120 +-  if (tab != TAB_DEFAULT)
  5.3121 ++  if (tab_length)
  5.3122 +     while (ptr < lim && sword--)
  5.3123 +       {
  5.3124 +-        while (ptr < lim && *ptr != tab)
  5.3125 ++        while (ptr < lim && *ptr != tab[0])
  5.3126 +           ++ptr;
  5.3127 +         if (ptr < lim)
  5.3128 +           ++ptr;
  5.3129 +@@ -1635,11 +1784,70 @@ begfield (struct line const *line, struc
  5.3130 +   return ptr;
  5.3131 + }
  5.3132 + 
  5.3133 ++#if HAVE_MBRTOWC
  5.3134 ++static char *
  5.3135 ++begfield_mb (const struct line *line, const struct keyfield *key)
  5.3136 ++{
  5.3137 ++  int i;
  5.3138 ++  char *ptr = line->text, *lim = ptr + line->length - 1;
  5.3139 ++  size_t sword = key->sword;
  5.3140 ++  size_t schar = key->schar;
  5.3141 ++  size_t mblength;
  5.3142 ++  mbstate_t state;
  5.3143 ++
  5.3144 ++  memset (&state, '\0', sizeof(mbstate_t));
  5.3145 ++
  5.3146 ++  if (tab_length)
  5.3147 ++    while (ptr < lim && sword--)
  5.3148 ++      {
  5.3149 ++        while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
  5.3150 ++          {
  5.3151 ++            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3152 ++            ptr += mblength;
  5.3153 ++          }
  5.3154 ++        if (ptr < lim)
  5.3155 ++          {
  5.3156 ++            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3157 ++            ptr += mblength;
  5.3158 ++          }
  5.3159 ++      }
  5.3160 ++  else
  5.3161 ++    while (ptr < lim && sword--)
  5.3162 ++      {
  5.3163 ++        while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  5.3164 ++          ptr += mblength;
  5.3165 ++        if (ptr < lim)
  5.3166 ++          {
  5.3167 ++            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3168 ++            ptr += mblength;
  5.3169 ++          }
  5.3170 ++        while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
  5.3171 ++          ptr += mblength;
  5.3172 ++      }
  5.3173 ++
  5.3174 ++  if (key->skipsblanks)
  5.3175 ++    while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  5.3176 ++      ptr += mblength;
  5.3177 ++
  5.3178 ++  for (i = 0; i < schar; i++)
  5.3179 ++    {
  5.3180 ++      GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3181 ++
  5.3182 ++      if (ptr + mblength > lim)
  5.3183 ++        break;
  5.3184 ++      else
  5.3185 ++        ptr += mblength;
  5.3186 ++    }
  5.3187 ++
  5.3188 ++  return ptr;
  5.3189 ++}
  5.3190 ++#endif
  5.3191 ++
  5.3192 + /* Return the limit of (a pointer to the first character after) the field
  5.3193 +    in LINE specified by KEY. */
  5.3194 + 
  5.3195 + static char *
  5.3196 +-limfield (struct line const *line, struct keyfield const *key)
  5.3197 ++limfield_uni (const struct line *line, const struct keyfield *key)
  5.3198 + {
  5.3199 +   char *ptr = line->text, *lim = ptr + line->length - 1;
  5.3200 +   size_t eword = key->eword, echar = key->echar;
  5.3201 +@@ -1654,10 +1862,10 @@ limfield (struct line const *line, struc
  5.3202 +      'beginning' is the first character following the delimiting TAB.
  5.3203 +      Otherwise, leave PTR pointing at the first 'blank' character after
  5.3204 +      the preceding field.  */
  5.3205 +-  if (tab != TAB_DEFAULT)
  5.3206 ++  if (tab_length)
  5.3207 +     while (ptr < lim && eword--)
  5.3208 +       {
  5.3209 +-        while (ptr < lim && *ptr != tab)
  5.3210 ++        while (ptr < lim && *ptr != tab[0])
  5.3211 +           ++ptr;
  5.3212 +         if (ptr < lim && (eword || echar))
  5.3213 +           ++ptr;
  5.3214 +@@ -1703,10 +1911,10 @@ limfield (struct line const *line, struc
  5.3215 +      */
  5.3216 + 
  5.3217 +   /* Make LIM point to the end of (one byte past) the current field.  */
  5.3218 +-  if (tab != TAB_DEFAULT)
  5.3219 ++  if (tab_length)
  5.3220 +     {
  5.3221 +       char *newlim;
  5.3222 +-      newlim = memchr (ptr, tab, lim - ptr);
  5.3223 ++      newlim = memchr (ptr, tab[0], lim - ptr);
  5.3224 +       if (newlim)
  5.3225 +         lim = newlim;
  5.3226 +     }
  5.3227 +@@ -1737,6 +1945,130 @@ limfield (struct line const *line, struc
  5.3228 +   return ptr;
  5.3229 + }
  5.3230 + 
  5.3231 ++#if HAVE_MBRTOWC
  5.3232 ++static char *
  5.3233 ++limfield_mb (const struct line *line, const struct keyfield *key)
  5.3234 ++{
  5.3235 ++  char *ptr = line->text, *lim = ptr + line->length - 1;
  5.3236 ++  size_t eword = key->eword, echar = key->echar;
  5.3237 ++  int i;
  5.3238 ++  size_t mblength;
  5.3239 ++  mbstate_t state;
  5.3240 ++
  5.3241 ++  if (echar == 0)
  5.3242 ++    eword++; /* skip all of end field. */
  5.3243 ++
  5.3244 ++  memset (&state, '\0', sizeof(mbstate_t));
  5.3245 ++
  5.3246 ++  if (tab_length)
  5.3247 ++    while (ptr < lim && eword--)
  5.3248 ++      {
  5.3249 ++        while (ptr < lim && memcmp (ptr, tab, tab_length) != 0)
  5.3250 ++          {
  5.3251 ++            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3252 ++            ptr += mblength;
  5.3253 ++          }
  5.3254 ++        if (ptr < lim && (eword | echar))
  5.3255 ++          {
  5.3256 ++            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3257 ++            ptr += mblength;
  5.3258 ++          }
  5.3259 ++      }
  5.3260 ++  else
  5.3261 ++    while (ptr < lim && eword--)
  5.3262 ++      {
  5.3263 ++        while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  5.3264 ++          ptr += mblength;
  5.3265 ++        if (ptr < lim)
  5.3266 ++          {
  5.3267 ++            GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3268 ++            ptr += mblength;
  5.3269 ++          }
  5.3270 ++        while (ptr < lim && !ismbblank (ptr, lim - ptr, &mblength))
  5.3271 ++          ptr += mblength;
  5.3272 ++      }
  5.3273 ++
  5.3274 ++
  5.3275 ++# ifdef POSIX_UNSPECIFIED
  5.3276 ++  /* Make LIM point to the end of (one byte past) the current field.  */
  5.3277 ++  if (tab_length)
  5.3278 ++    {
  5.3279 ++      char *newlim, *p;
  5.3280 ++
  5.3281 ++      newlim = NULL;
  5.3282 ++      for (p = ptr; p < lim;)
  5.3283 ++         {
  5.3284 ++          if (memcmp (p, tab, tab_length) == 0)
  5.3285 ++            {
  5.3286 ++              newlim = p;
  5.3287 ++              break;
  5.3288 ++            }
  5.3289 ++
  5.3290 ++          GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3291 ++          p += mblength;
  5.3292 ++        }
  5.3293 ++    }
  5.3294 ++  else
  5.3295 ++    {
  5.3296 ++      char *newlim;
  5.3297 ++      newlim = ptr;
  5.3298 ++
  5.3299 ++      while (newlim < lim && ismbblank (newlim, lim - newlim, &mblength))
  5.3300 ++        newlim += mblength;
  5.3301 ++      if (ptr < lim)
  5.3302 ++        {
  5.3303 ++          GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3304 ++          ptr += mblength;
  5.3305 ++        }
  5.3306 ++      while (newlim < lim && !ismbblank (newlim, lim - newlim, &mblength))
  5.3307 ++        newlim += mblength;
  5.3308 ++      lim = newlim;
  5.3309 ++    }
  5.3310 ++# endif
  5.3311 ++
  5.3312 ++  if (echar != 0)
  5.3313 ++  {
  5.3314 ++    /* If we're skipping leading blanks, don't start counting characters
  5.3315 ++     *      until after skipping past any leading blanks.  */
  5.3316 ++    if (key->skipeblanks)
  5.3317 ++      while (ptr < lim && ismbblank (ptr, lim - ptr, &mblength))
  5.3318 ++        ptr += mblength;
  5.3319 ++
  5.3320 ++    memset (&state, '\0', sizeof(mbstate_t));
  5.3321 ++
  5.3322 ++    /* Advance PTR by ECHAR (if possible), but no further than LIM.  */
  5.3323 ++    for (i = 0; i < echar; i++)
  5.3324 ++     {
  5.3325 ++        GET_BYTELEN_OF_CHAR (lim, ptr, mblength, state);
  5.3326 ++
  5.3327 ++        if (ptr + mblength > lim)
  5.3328 ++          break;
  5.3329 ++        else
  5.3330 ++          ptr += mblength;
  5.3331 ++      }
  5.3332 ++  }
  5.3333 ++
  5.3334 ++  return ptr;
  5.3335 ++}
  5.3336 ++#endif
  5.3337 ++
  5.3338 ++static void
  5.3339 ++skipblanks_uni (char **ptr, char *lim)
  5.3340 ++{
  5.3341 ++  while (*ptr < lim && blanks[to_uchar (**ptr)])
  5.3342 ++    ++(*ptr);
  5.3343 ++}
  5.3344 ++
  5.3345 ++#if HAVE_MBRTOWC
  5.3346 ++static void
  5.3347 ++skipblanks_mb (char **ptr, char *lim)
  5.3348 ++{
  5.3349 ++  size_t mblength;
  5.3350 ++  while (*ptr < lim && ismbblank (*ptr, lim - *ptr, &mblength))
  5.3351 ++    (*ptr) += mblength;
  5.3352 ++}
  5.3353 ++#endif
  5.3354 ++
  5.3355 + /* Fill BUF reading from FP, moving buf->left bytes from the end
  5.3356 +    of buf->buf to the beginning first.  If EOF is reached and the
  5.3357 +    file wasn't terminated by a newline, supply one.  Set up BUF's line
  5.3358 +@@ -1823,8 +2155,22 @@ fillbuf (struct buffer *buf, FILE *fp, c
  5.3359 +                   else
  5.3360 +                     {
  5.3361 +                       if (key->skipsblanks)
  5.3362 +-                        while (blanks[to_uchar (*line_start)])
  5.3363 +-                          line_start++;
  5.3364 ++                        {
  5.3365 ++#if HAVE_MBRTOWC
  5.3366 ++                          if (MB_CUR_MAX > 1)
  5.3367 ++                            {
  5.3368 ++                              size_t mblength;
  5.3369 ++                              while (line_start < line->keylim &&
  5.3370 ++                                     ismbblank (line_start,
  5.3371 ++                                                line->keylim - line_start,
  5.3372 ++                                                &mblength))
  5.3373 ++                                line_start += mblength;
  5.3374 ++                            }
  5.3375 ++                          else
  5.3376 ++#endif
  5.3377 ++                          while (blanks[to_uchar (*line_start)])
  5.3378 ++                            line_start++;
  5.3379 ++                        }
  5.3380 +                       line->keybeg = line_start;
  5.3381 +                     }
  5.3382 +                 }
  5.3383 +@@ -1958,12 +2304,10 @@ find_unit_order (char const *number)
  5.3384 +        <none/unknown> < K/k < M < G < T < P < E < Z < Y  */
  5.3385 + 
  5.3386 + static int
  5.3387 +-human_numcompare (char const *a, char const *b)
  5.3388 ++human_numcompare (char *a, char *b)
  5.3389 + {
  5.3390 +-  while (blanks[to_uchar (*a)])
  5.3391 +-    a++;
  5.3392 +-  while (blanks[to_uchar (*b)])
  5.3393 +-    b++;
  5.3394 ++  skipblanks(&a, a + strlen(a));
  5.3395 ++  skipblanks(&b, b + strlen(b));
  5.3396 + 
  5.3397 +   int diff = find_unit_order (a) - find_unit_order (b);
  5.3398 +   return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep));
  5.3399 +@@ -1974,7 +2318,7 @@ human_numcompare (char const *a, char co
  5.3400 +    hideously fast. */
  5.3401 + 
  5.3402 + static int
  5.3403 +-numcompare (char const *a, char const *b)
  5.3404 ++numcompare_uni (const char *a, const char *b)
  5.3405 + {
  5.3406 +   while (blanks[to_uchar (*a)])
  5.3407 +     a++;
  5.3408 +@@ -1984,6 +2328,25 @@ numcompare (char const *a, char const *b
  5.3409 +   return strnumcmp (a, b, decimal_point, thousands_sep);
  5.3410 + }
  5.3411 + 
  5.3412 ++#if HAVE_MBRTOWC
  5.3413 ++static int
  5.3414 ++numcompare_mb (const char *a, const char *b)
  5.3415 ++{
  5.3416 ++  size_t mblength, len;
  5.3417 ++  len = strlen (a); /* okay for UTF-8 */
  5.3418 ++  while (*a && ismbblank (a, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
  5.3419 ++    {
  5.3420 ++      a += mblength;
  5.3421 ++      len -= mblength;
  5.3422 ++    }
  5.3423 ++  len = strlen (b); /* okay for UTF-8 */
  5.3424 ++  while (*b && ismbblank (b, len > MB_CUR_MAX ? MB_CUR_MAX : len, &mblength))
  5.3425 ++    b += mblength;
  5.3426 ++
  5.3427 ++  return strnumcmp (a, b, decimal_point, thousands_sep);
  5.3428 ++}
  5.3429 ++#endif /* HAV_EMBRTOWC */
  5.3430 ++
  5.3431 + /* Work around a problem whereby the long double value returned by glibc's
  5.3432 +    strtold ("NaN", ...) contains uninitialized bits: clear all bytes of
  5.3433 +    A and B before calling strtold.  FIXME: remove this function once
  5.3434 +@@ -2034,7 +2397,7 @@ general_numcompare (char const *sa, char
  5.3435 +    Return 0 if the name in S is not recognized.  */
  5.3436 + 
  5.3437 + static int
  5.3438 +-getmonth (char const *month, char **ea)
  5.3439 ++getmonth_uni (char const *month, size_t len, char **ea)
  5.3440 + {
  5.3441 +   size_t lo = 0;
  5.3442 +   size_t hi = MONTHS_PER_YEAR;
  5.3443 +@@ -2310,15 +2673,14 @@ debug_key (struct line const *line, stru
  5.3444 +           char saved = *lim;
  5.3445 +           *lim = '\0';
  5.3446 + 
  5.3447 +-          while (blanks[to_uchar (*beg)])
  5.3448 +-            beg++;
  5.3449 ++          skipblanks (&beg, lim);
  5.3450 + 
  5.3451 +           char *tighter_lim = beg;
  5.3452 + 
  5.3453 +           if (lim < beg)
  5.3454 +             tighter_lim = lim;
  5.3455 +           else if (key->month)
  5.3456 +-            getmonth (beg, &tighter_lim);
  5.3457 ++            getmonth (beg, lim-beg, &tighter_lim);
  5.3458 +           else if (key->general_numeric)
  5.3459 +             ignore_value (strtold (beg, &tighter_lim));
  5.3460 +           else if (key->numeric || key->human_numeric)
  5.3461 +@@ -2452,7 +2814,7 @@ key_warnings (struct keyfield const *gke
  5.3462 +       /* Warn about significant leading blanks.  */
  5.3463 +       bool implicit_skip = key_numeric (key) || key->month;
  5.3464 +       bool line_offset = key->eword == 0 && key->echar != 0; /* -k1.x,1.y  */
  5.3465 +-      if (!zero_width && !gkey_only && tab == TAB_DEFAULT && !line_offset
  5.3466 ++      if (!zero_width && !gkey_only && !tab_length && !line_offset
  5.3467 +           && ((!key->skipsblanks && !implicit_skip)
  5.3468 +               || (!key->skipsblanks && key->schar)
  5.3469 +               || (!key->skipeblanks && key->echar)))
  5.3470 +@@ -2510,11 +2872,87 @@ key_warnings (struct keyfield const *gke
  5.3471 +     error (0, 0, _("option '-r' only applies to last-resort comparison"));
  5.3472 + }
  5.3473 + 
  5.3474 ++#if HAVE_MBRTOWC
  5.3475 ++static int
  5.3476 ++getmonth_mb (const char *s, size_t len, char **ea)
  5.3477 ++{
  5.3478 ++  char *month;
  5.3479 ++  register size_t i;
  5.3480 ++  register int lo = 0, hi = MONTHS_PER_YEAR, result;
  5.3481 ++  char *tmp;
  5.3482 ++  size_t wclength, mblength;
  5.3483 ++  const char *pp;
  5.3484 ++  const wchar_t *wpp;
  5.3485 ++  wchar_t *month_wcs;
  5.3486 ++  mbstate_t state;
  5.3487 ++
  5.3488 ++  while (len > 0 && ismbblank (s, len, &mblength))
  5.3489 ++    {
  5.3490 ++      s += mblength;
  5.3491 ++      len -= mblength;
  5.3492 ++    }
  5.3493 ++
  5.3494 ++  if (len == 0)
  5.3495 ++    return 0;
  5.3496 ++
  5.3497 ++  if (SIZE_MAX - len < 1)
  5.3498 ++    xalloc_die ();
  5.3499 ++
  5.3500 ++  month = (char *) xnmalloc (len + 1, MB_CUR_MAX);
  5.3501 ++
  5.3502 ++  pp = tmp = (char *) xnmalloc (len + 1, MB_CUR_MAX);
  5.3503 ++  memcpy (tmp, s, len);
  5.3504 ++  tmp[len] = '\0';
  5.3505 ++  wpp = month_wcs = (wchar_t *) xnmalloc (len + 1, sizeof (wchar_t));
  5.3506 ++  memset (&state, '\0', sizeof (mbstate_t));
  5.3507 ++
  5.3508 ++  wclength = mbsrtowcs (month_wcs, &pp, len + 1, &state);
  5.3509 ++  if (wclength == (size_t)-1 || pp != NULL)
  5.3510 ++    error (SORT_FAILURE, 0, _("Invalid multibyte input %s."), quote(s));
  5.3511 ++
  5.3512 ++  for (i = 0; i < wclength; i++)
  5.3513 ++    {
  5.3514 ++      month_wcs[i] = towupper(month_wcs[i]);
  5.3515 ++      if (iswblank (month_wcs[i]))
  5.3516 ++        {
  5.3517 ++          month_wcs[i] = L'\0';
  5.3518 ++          break;
  5.3519 ++        }
  5.3520 ++    }
  5.3521 ++
  5.3522 ++  mblength = wcsrtombs (month, &wpp, (len + 1) * MB_CUR_MAX, &state);
  5.3523 ++  assert (mblength != (-1) && wpp == NULL);
  5.3524 ++
  5.3525 ++  do
  5.3526 ++    {
  5.3527 ++      int ix = (lo + hi) / 2;
  5.3528 ++
  5.3529 ++      if (strncmp (month, monthtab[ix].name, strlen (monthtab[ix].name)) < 0)
  5.3530 ++        hi = ix;
  5.3531 ++      else
  5.3532 ++        lo = ix;
  5.3533 ++    }
  5.3534 ++  while (hi - lo > 1);
  5.3535 ++
  5.3536 ++  result = (!strncmp (month, monthtab[lo].name, strlen (monthtab[lo].name))
  5.3537 ++      ? monthtab[lo].val : 0);
  5.3538 ++
  5.3539 ++  if (ea && result)
  5.3540 ++     *ea = (char*) s + strlen (monthtab[lo].name);
  5.3541 ++
  5.3542 ++  free (month);
  5.3543 ++  free (tmp);
  5.3544 ++  free (month_wcs);
  5.3545 ++
  5.3546 ++  return result;
  5.3547 ++}
  5.3548 ++#endif
  5.3549 ++
  5.3550 + /* Compare two lines A and B trying every key in sequence until there
  5.3551 +    are no more keys or a difference is found. */
  5.3552 + 
  5.3553 + static int
  5.3554 +-keycompare (struct line const *a, struct line const *b)
  5.3555 ++keycompare_uni (const struct line *a, const struct line *b)
  5.3556 + {
  5.3557 +   struct keyfield *key = keylist;
  5.3558 + 
  5.3559 +@@ -2599,7 +3037,7 @@ keycompare (struct line const *a, struct
  5.3560 +           else if (key->human_numeric)
  5.3561 +             diff = human_numcompare (ta, tb);
  5.3562 +           else if (key->month)
  5.3563 +-            diff = getmonth (ta, NULL) - getmonth (tb, NULL);
  5.3564 ++            diff = getmonth (ta, tlena, NULL) - getmonth (tb, tlenb, NULL);
  5.3565 +           else if (key->random)
  5.3566 +             diff = compare_random (ta, tlena, tb, tlenb);
  5.3567 +           else if (key->version)
  5.3568 +@@ -2715,6 +3153,211 @@ keycompare (struct line const *a, struct
  5.3569 +   return key->reverse ? -diff : diff;
  5.3570 + }
  5.3571 + 
  5.3572 ++#if HAVE_MBRTOWC
  5.3573 ++static int
  5.3574 ++keycompare_mb (const struct line *a, const struct line *b)
  5.3575 ++{
  5.3576 ++  struct keyfield *key = keylist;
  5.3577 ++
  5.3578 ++  /* For the first iteration only, the key positions have been
  5.3579 ++     precomputed for us. */
  5.3580 ++  char *texta = a->keybeg;
  5.3581 ++  char *textb = b->keybeg;
  5.3582 ++  char *lima = a->keylim;
  5.3583 ++  char *limb = b->keylim;
  5.3584 ++
  5.3585 ++  size_t mblength_a, mblength_b;
  5.3586 ++  wchar_t wc_a, wc_b;
  5.3587 ++  mbstate_t state_a, state_b;
  5.3588 ++
  5.3589 ++  int diff = 0;
  5.3590 ++
  5.3591 ++  memset (&state_a, '\0', sizeof(mbstate_t));
  5.3592 ++  memset (&state_b, '\0', sizeof(mbstate_t));
  5.3593 ++  /* Ignore keys with start after end.  */
  5.3594 ++  if (a->keybeg - a->keylim > 0)
  5.3595 ++    return 0;
  5.3596 ++
  5.3597 ++
  5.3598 ++              /* Ignore and/or translate chars before comparing.  */
  5.3599 ++# define IGNORE_CHARS(NEW_LEN, LEN, TEXT, COPY, WC, MBLENGTH, STATE)        \
  5.3600 ++  do                                                                        \
  5.3601 ++    {                                                                        \
  5.3602 ++      wchar_t uwc;                                                        \
  5.3603 ++      char mbc[MB_LEN_MAX];                                                \
  5.3604 ++      mbstate_t state_wc;                                                \
  5.3605 ++                                                                        \
  5.3606 ++      for (NEW_LEN = i = 0; i < LEN;)                                        \
  5.3607 ++        {                                                                \
  5.3608 ++          mbstate_t state_bak;                                                \
  5.3609 ++                                                                        \
  5.3610 ++          state_bak = STATE;                                                \
  5.3611 ++          MBLENGTH = mbrtowc (&WC, TEXT + i, LEN - i, &STATE);                \
  5.3612 ++                                                                        \
  5.3613 ++          if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1                \
  5.3614 ++              || MBLENGTH == 0)                                                \
  5.3615 ++            {                                                                \
  5.3616 ++              if (MBLENGTH == (size_t)-2 || MBLENGTH == (size_t)-1)        \
  5.3617 ++                STATE = state_bak;                                        \
  5.3618 ++              if (!ignore)                                                \
  5.3619 ++                COPY[NEW_LEN++] = TEXT[i];                                \
  5.3620 ++              i++;                                                         \
  5.3621 ++              continue;                                                        \
  5.3622 ++            }                                                                \
  5.3623 ++                                                                        \
  5.3624 ++          if (ignore)                                                        \
  5.3625 ++            {                                                                \
  5.3626 ++              if ((ignore == nonprinting && !iswprint (WC))                \
  5.3627 ++                   || (ignore == nondictionary                                \
  5.3628 ++                       && !iswalnum (WC) && !iswblank (WC)))                \
  5.3629 ++                {                                                        \
  5.3630 ++                  i += MBLENGTH;                                        \
  5.3631 ++                  continue;                                                \
  5.3632 ++                }                                                        \
  5.3633 ++            }                                                                \
  5.3634 ++                                                                        \
  5.3635 ++          if (translate)                                                \
  5.3636 ++            {                                                                \
  5.3637 ++                                                                        \
  5.3638 ++              uwc = towupper(WC);                                        \
  5.3639 ++              if (WC == uwc)                                                \
  5.3640 ++                {                                                        \
  5.3641 ++                  memcpy (mbc, TEXT + i, MBLENGTH);                        \
  5.3642 ++                  i += MBLENGTH;                                        \
  5.3643 ++                }                                                        \
  5.3644 ++              else                                                        \
  5.3645 ++                {                                                        \
  5.3646 ++                  i += MBLENGTH;                                        \
  5.3647 ++                  WC = uwc;                                                \
  5.3648 ++                  memset (&state_wc, '\0', sizeof (mbstate_t));                \
  5.3649 ++                                                                        \
  5.3650 ++                  MBLENGTH = wcrtomb (mbc, WC, &state_wc);                \
  5.3651 ++                  assert (MBLENGTH != (size_t)-1 && MBLENGTH != 0);        \
  5.3652 ++                }                                                        \
  5.3653 ++                                                                        \
  5.3654 ++              for (j = 0; j < MBLENGTH; j++)                                \
  5.3655 ++                COPY[NEW_LEN++] = mbc[j];                                \
  5.3656 ++            }                                                                \
  5.3657 ++          else                                                                \
  5.3658 ++            for (j = 0; j < MBLENGTH; j++)                                \
  5.3659 ++              COPY[NEW_LEN++] = TEXT[i++];                                \
  5.3660 ++        }                                                                \
  5.3661 ++      COPY[NEW_LEN] = '\0';                                                \
  5.3662 ++    }                                                                        \
  5.3663 ++  while (0)
  5.3664 ++
  5.3665 ++      /* Actually compare the fields. */
  5.3666 ++
  5.3667 ++  for (;;)
  5.3668 ++    {
  5.3669 ++      /* Find the lengths. */
  5.3670 ++      size_t lena = lima <= texta ? 0 : lima - texta;
  5.3671 ++      size_t lenb = limb <= textb ? 0 : limb - textb;
  5.3672 ++
  5.3673 ++      char enda IF_LINT (= 0);
  5.3674 ++      char endb IF_LINT (= 0);
  5.3675 ++
  5.3676 ++      char const *translate = key->translate;
  5.3677 ++      bool const *ignore = key->ignore;
  5.3678 ++
  5.3679 ++      if (ignore || translate)
  5.3680 ++        {
  5.3681 ++          if (SIZE_MAX - lenb - 2 < lena)
  5.3682 ++            xalloc_die ();
  5.3683 ++          char *copy_a = (char *) xnmalloc (lena + lenb + 2, MB_CUR_MAX);
  5.3684 ++          char *copy_b = copy_a + lena * MB_CUR_MAX + 1;
  5.3685 ++          size_t new_len_a, new_len_b;
  5.3686 ++          size_t i, j;
  5.3687 ++
  5.3688 ++          IGNORE_CHARS (new_len_a, lena, texta, copy_a,
  5.3689 ++                        wc_a, mblength_a, state_a);
  5.3690 ++          IGNORE_CHARS (new_len_b, lenb, textb, copy_b,
  5.3691 ++                        wc_b, mblength_b, state_b);
  5.3692 ++          texta = copy_a; textb = copy_b;
  5.3693 ++          lena = new_len_a; lenb = new_len_b;
  5.3694 ++        }
  5.3695 ++      else
  5.3696 ++        {
  5.3697 ++          /* Use the keys in-place, temporarily null-terminated.  */
  5.3698 ++          enda = texta[lena]; texta[lena] = '\0';
  5.3699 ++          endb = textb[lenb]; textb[lenb] = '\0';
  5.3700 ++        }
  5.3701 ++
  5.3702 ++      if (key->random)
  5.3703 ++        diff = compare_random (texta, lena, textb, lenb);
  5.3704 ++      else if (key->numeric | key->general_numeric | key->human_numeric)
  5.3705 ++        {
  5.3706 ++          char savea = *lima, saveb = *limb;
  5.3707 ++
  5.3708 ++          *lima = *limb = '\0';
  5.3709 ++          diff = (key->numeric ? numcompare (texta, textb)
  5.3710 ++                  : key->general_numeric ? general_numcompare (texta, textb)
  5.3711 ++                  : human_numcompare (texta, textb));
  5.3712 ++          *lima = savea, *limb = saveb;
  5.3713 ++        }
  5.3714 ++      else if (key->version)
  5.3715 ++        diff = filevercmp (texta, textb);
  5.3716 ++      else if (key->month)
  5.3717 ++        diff = getmonth (texta, lena, NULL) - getmonth (textb, lenb, NULL);
  5.3718 ++      else if (lena == 0)
  5.3719 ++        diff = - NONZERO (lenb);
  5.3720 ++      else if (lenb == 0)
  5.3721 ++        diff = 1;
  5.3722 ++      else if (hard_LC_COLLATE && !folding)
  5.3723 ++        {
  5.3724 ++          diff = xmemcoll0 (texta, lena + 1, textb, lenb + 1);
  5.3725 ++        }
  5.3726 ++      else
  5.3727 ++        {
  5.3728 ++          diff = memcmp (texta, textb, MIN (lena, lenb));
  5.3729 ++          if (diff == 0)
  5.3730 ++            diff = lena < lenb ? -1 : lena != lenb;
  5.3731 ++        }
  5.3732 ++
  5.3733 ++      if (ignore || translate)
  5.3734 ++        free (texta);
  5.3735 ++      else
  5.3736 ++        {
  5.3737 ++          texta[lena] = enda;
  5.3738 ++          textb[lenb] = endb;
  5.3739 ++        }
  5.3740 ++
  5.3741 ++      if (diff)
  5.3742 ++        goto not_equal;
  5.3743 ++
  5.3744 ++      key = key->next;
  5.3745 ++      if (! key)
  5.3746 ++        break;
  5.3747 ++
  5.3748 ++      /* Find the beginning and limit of the next field.  */
  5.3749 ++      if (key->eword != -1)
  5.3750 ++        lima = limfield (a, key), limb = limfield (b, key);
  5.3751 ++      else
  5.3752 ++        lima = a->text + a->length - 1, limb = b->text + b->length - 1;
  5.3753 ++
  5.3754 ++      if (key->sword != -1)
  5.3755 ++        texta = begfield (a, key), textb = begfield (b, key);
  5.3756 ++      else
  5.3757 ++        {
  5.3758 ++          texta = a->text, textb = b->text;
  5.3759 ++          if (key->skipsblanks)
  5.3760 ++            {
  5.3761 ++              while (texta < lima && ismbblank (texta, lima - texta, &mblength_a))
  5.3762 ++                texta += mblength_a;
  5.3763 ++              while (textb < limb && ismbblank (textb, limb - textb, &mblength_b))
  5.3764 ++                textb += mblength_b;
  5.3765 ++            }
  5.3766 ++        }
  5.3767 ++    }
  5.3768 ++
  5.3769 ++not_equal:
  5.3770 ++  if (key && key->reverse)
  5.3771 ++    return -diff;
  5.3772 ++  else
  5.3773 ++    return diff;
  5.3774 ++}
  5.3775 ++#endif
  5.3776 ++
  5.3777 + /* Compare two lines A and B, returning negative, zero, or positive
  5.3778 +    depending on whether A compares less than, equal to, or greater than B. */
  5.3779 + 
  5.3780 +@@ -2742,7 +3385,7 @@ compare (struct line const *a, struct li
  5.3781 +     diff = - NONZERO (blen);
  5.3782 +   else if (blen == 0)
  5.3783 +     diff = 1;
  5.3784 +-  else if (hard_LC_COLLATE)
  5.3785 ++  else if (hard_LC_COLLATE && !folding)
  5.3786 +     {
  5.3787 +       /* Note xmemcoll0 is a performance enhancement as
  5.3788 +          it will not unconditionally write '\0' after the
  5.3789 +@@ -4139,6 +4782,7 @@ set_ordering (char const *s, struct keyf
  5.3790 +           break;
  5.3791 +         case 'f':
  5.3792 +           key->translate = fold_toupper;
  5.3793 ++          folding = true;
  5.3794 +           break;
  5.3795 +         case 'g':
  5.3796 +           key->general_numeric = true;
  5.3797 +@@ -4218,7 +4862,7 @@ main (int argc, char **argv)
  5.3798 +   initialize_exit_failure (SORT_FAILURE);
  5.3799 + 
  5.3800 +   hard_LC_COLLATE = hard_locale (LC_COLLATE);
  5.3801 +-#if HAVE_NL_LANGINFO
  5.3802 ++#if HAVE_LANGINFO_CODESET
  5.3803 +   hard_LC_TIME = hard_locale (LC_TIME);
  5.3804 + #endif
  5.3805 + 
  5.3806 +@@ -4239,6 +4883,29 @@ main (int argc, char **argv)
  5.3807 +       thousands_sep = -1;
  5.3808 +   }
  5.3809 + 
  5.3810 ++#if HAVE_MBRTOWC
  5.3811 ++  if (MB_CUR_MAX > 1)
  5.3812 ++    {
  5.3813 ++      inittables = inittables_mb;
  5.3814 ++      begfield = begfield_mb;
  5.3815 ++      limfield = limfield_mb;
  5.3816 ++      skipblanks = skipblanks_mb;
  5.3817 ++      getmonth = getmonth_mb;
  5.3818 ++      keycompare = keycompare_mb;
  5.3819 ++      numcompare = numcompare_mb;
  5.3820 ++    }
  5.3821 ++  else
  5.3822 ++#endif
  5.3823 ++    {
  5.3824 ++      inittables = inittables_uni;
  5.3825 ++      begfield = begfield_uni;
  5.3826 ++      limfield = limfield_uni;
  5.3827 ++      skipblanks = skipblanks_uni;
  5.3828 ++      getmonth = getmonth_uni;
  5.3829 ++      keycompare = keycompare_uni;
  5.3830 ++      numcompare = numcompare_uni;
  5.3831 ++    }
  5.3832 ++
  5.3833 +   have_read_stdin = false;
  5.3834 +   inittables ();
  5.3835 + 
  5.3836 +@@ -4513,13 +5180,34 @@ main (int argc, char **argv)
  5.3837 + 
  5.3838 +         case 't':
  5.3839 +           {
  5.3840 +-            char newtab = optarg[0];
  5.3841 +-            if (! newtab)
  5.3842 ++            char newtab[MB_LEN_MAX + 1];
  5.3843 ++            size_t newtab_length = 1;
  5.3844 ++            strncpy (newtab, optarg, MB_LEN_MAX);
  5.3845 ++            if (! newtab[0])
  5.3846 +               die (SORT_FAILURE, 0, _("empty tab"));
  5.3847 +-            if (optarg[1])
  5.3848 ++#if HAVE_MBRTOWC
  5.3849 ++            if (MB_CUR_MAX > 1)
  5.3850 ++              {
  5.3851 ++                wchar_t wc;
  5.3852 ++                mbstate_t state;
  5.3853 ++
  5.3854 ++                memset (&state, '\0', sizeof (mbstate_t));
  5.3855 ++                newtab_length = mbrtowc (&wc, newtab, strnlen (newtab,
  5.3856 ++                                                               MB_LEN_MAX),
  5.3857 ++                                         &state);
  5.3858 ++                switch (newtab_length)
  5.3859 ++                  {
  5.3860 ++                  case (size_t) -1:
  5.3861 ++                  case (size_t) -2:
  5.3862 ++                  case 0:
  5.3863 ++                    newtab_length = 1;
  5.3864 ++                  }
  5.3865 ++              }
  5.3866 ++#endif
  5.3867 ++            if (newtab_length == 1 && optarg[1])
  5.3868 +               {
  5.3869 +                 if (STREQ (optarg, "\\0"))
  5.3870 +-                  newtab = '\0';
  5.3871 ++                  newtab[0] = '\0';
  5.3872 +                 else
  5.3873 +                   {
  5.3874 +                     /* Provoke with 'sort -txx'.  Complain about
  5.3875 +@@ -4530,9 +5218,11 @@ main (int argc, char **argv)
  5.3876 +                          quote (optarg));
  5.3877 +                   }
  5.3878 +               }
  5.3879 +-            if (tab != TAB_DEFAULT && tab != newtab)
  5.3880 ++            if (tab_length && (tab_length != newtab_length
  5.3881 ++                        || memcmp (tab, newtab, tab_length) != 0))
  5.3882 +               die (SORT_FAILURE, 0, _("incompatible tabs"));
  5.3883 +-            tab = newtab;
  5.3884 ++            memcpy (tab, newtab, newtab_length);
  5.3885 ++            tab_length = newtab_length;
  5.3886 +           }
  5.3887 +           break;
  5.3888 + 
  5.3889 +@@ -4770,12 +5460,10 @@ main (int argc, char **argv)
  5.3890 +       sort (files, nfiles, outfile, nthreads);
  5.3891 +     }
  5.3892 + 
  5.3893 +-#ifdef lint
  5.3894 +   if (files_from)
  5.3895 +     readtokens0_free (&tok);
  5.3896 +   else
  5.3897 +     free (files);
  5.3898 +-#endif
  5.3899 + 
  5.3900 +   if (have_read_stdin && fclose (stdin) == EOF)
  5.3901 +     sort_die (_("close failed"), "-");
  5.3902 +diff -Naurp coreutils-8.27-orig/src/unexpand.c coreutils-8.27/src/unexpand.c
  5.3903 +--- coreutils-8.27-orig/src/unexpand.c	2017-01-01 16:34:24.000000000 -0600
  5.3904 ++++ coreutils-8.27/src/unexpand.c	2017-03-11 23:49:06.758133530 -0600
  5.3905 +@@ -38,6 +38,9 @@
  5.3906 + #include <stdio.h>
  5.3907 + #include <getopt.h>
  5.3908 + #include <sys/types.h>
  5.3909 ++
  5.3910 ++#include <mbfile.h>
  5.3911 ++
  5.3912 + #include "system.h"
  5.3913 + #include "die.h"
  5.3914 + #include "xstrndup.h"
  5.3915 +@@ -107,24 +110,47 @@ unexpand (void)
  5.3916 + {
  5.3917 +   /* Input stream.  */
  5.3918 +   FILE *fp = next_file (NULL);
  5.3919 ++  mb_file_t mbf;
  5.3920 + 
  5.3921 +   /* The array of pending blanks.  In non-POSIX locales, blanks can
  5.3922 +      include characters other than spaces, so the blanks must be
  5.3923 +      stored, not merely counted.  */
  5.3924 +-  char *pending_blank;
  5.3925 ++  mbf_char_t *pending_blank;
  5.3926 ++  /* True if the starting locale is utf8.  */
  5.3927 ++  bool using_utf_locale;
  5.3928 ++
  5.3929 ++  /* True if the first file contains BOM header.  */
  5.3930 ++  bool found_bom;
  5.3931 ++  using_utf_locale=check_utf_locale();
  5.3932 + 
  5.3933 +   if (!fp)
  5.3934 +     return;
  5.3935 ++  mbf_init (mbf, fp);
  5.3936 ++  found_bom=check_bom(fp,&mbf);
  5.3937 + 
  5.3938 ++  if (using_utf_locale == false && found_bom == true)
  5.3939 ++  {
  5.3940 ++    /*try using some predefined locale */
  5.3941 ++
  5.3942 ++    if (set_utf_locale () != 0)
  5.3943 ++    {
  5.3944 ++      error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale"));
  5.3945 ++    }
  5.3946 ++  }
  5.3947 +   /* The worst case is a non-blank character, then one blank, then a
  5.3948 +      tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so
  5.3949 +      allocate MAX_COLUMN_WIDTH bytes to store the blanks.  */
  5.3950 +-  pending_blank = xmalloc (max_column_width);
  5.3951 ++  pending_blank = xmalloc (max_column_width * sizeof (mbf_char_t));
  5.3952 ++
  5.3953 ++  if (found_bom == true)
  5.3954 ++  {
  5.3955 ++    print_bom();
  5.3956 ++  }
  5.3957 + 
  5.3958 +   while (true)
  5.3959 +     {
  5.3960 +       /* Input character, or EOF.  */
  5.3961 +-      int c;
  5.3962 ++      mbf_char_t c;
  5.3963 + 
  5.3964 +       /* If true, perform translations.  */
  5.3965 +       bool convert = true;
  5.3966 +@@ -158,12 +184,44 @@ unexpand (void)
  5.3967 + 
  5.3968 +       do
  5.3969 +         {
  5.3970 +-          while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
  5.3971 +-            continue;
  5.3972 ++          while (true) {
  5.3973 ++            mbf_getc (c, mbf);
  5.3974 ++            if ((mb_iseof (c)) && (fp = next_file (fp)))
  5.3975 ++              {
  5.3976 ++                mbf_init (mbf, fp);
  5.3977 ++                if (fp!=NULL)
  5.3978 ++                {
  5.3979 ++                  if (check_bom(fp,&mbf)==true)
  5.3980 ++                  {
  5.3981 ++                    /*Not the first file - check BOM header*/
  5.3982 ++                    if (using_utf_locale==false && found_bom==false)
  5.3983 ++                    {
  5.3984 ++                      /*BOM header in subsequent file but not in the first one. */
  5.3985 ++                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
  5.3986 ++                    }
  5.3987 ++                  }
  5.3988 ++                  else
  5.3989 ++                  {
  5.3990 ++                    if(using_utf_locale==false && found_bom==true)
  5.3991 ++                    {
  5.3992 ++                      /*First file conatined BOM header - locale was switched to UTF
  5.3993 ++                      /*all subsequent files should contain BOM. */
  5.3994 ++                      error (EXIT_FAILURE, errno, _("combination of files with and without BOM header"));
  5.3995 ++                    }
  5.3996 ++                  }
  5.3997 ++                }
  5.3998 ++                continue;
  5.3999 ++              }
  5.4000 ++            else
  5.4001 ++              {
  5.4002 ++                break;
  5.4003 ++              }
  5.4004 ++            }
  5.4005 ++
  5.4006 + 
  5.4007 +           if (convert)
  5.4008 +             {
  5.4009 +-              bool blank = !! isblank (c);
  5.4010 ++              bool blank = mb_isblank (c);
  5.4011 + 
  5.4012 +               if (blank)
  5.4013 +                 {
  5.4014 +@@ -180,16 +238,16 @@ unexpand (void)
  5.4015 +                       if (next_tab_column < column)
  5.4016 +                         die (EXIT_FAILURE, 0, _("input line is too long"));
  5.4017 + 
  5.4018 +-                      if (c == '\t')
  5.4019 ++                      if (mb_iseq (c, '\t'))
  5.4020 +                         {
  5.4021 +                           column = next_tab_column;
  5.4022 + 
  5.4023 +                           if (pending)
  5.4024 +-                            pending_blank[0] = '\t';
  5.4025 ++                            mb_setascii (&pending_blank[0], '\t');
  5.4026 +                         }
  5.4027 +                       else
  5.4028 +                         {
  5.4029 +-                          column++;
  5.4030 ++                          column += mb_width (c);
  5.4031 + 
  5.4032 +                           if (! (prev_blank && column == next_tab_column))
  5.4033 +                             {
  5.4034 +@@ -197,13 +255,14 @@ unexpand (void)
  5.4035 +                                  will be replaced by tabs.  */
  5.4036 +                               if (column == next_tab_column)
  5.4037 +                                 one_blank_before_tab_stop = true;
  5.4038 +-                              pending_blank[pending++] = c;
  5.4039 ++                              mb_copy (&pending_blank[pending++], &c);
  5.4040 +                               prev_blank = true;
  5.4041 +                               continue;
  5.4042 +                             }
  5.4043 + 
  5.4044 +                           /* Replace the pending blanks by a tab or two.  */
  5.4045 +-                          pending_blank[0] = c = '\t';
  5.4046 ++                          mb_setascii (&c, '\t');
  5.4047 ++                          mb_setascii (&pending_blank[0], '\t');
  5.4048 +                         }
  5.4049 + 
  5.4050 +                       /* Discard pending blanks, unless it was a single
  5.4051 +@@ -211,7 +270,7 @@ unexpand (void)
  5.4052 +                       pending = one_blank_before_tab_stop;
  5.4053 +                     }
  5.4054 +                 }
  5.4055 +-              else if (c == '\b')
  5.4056 ++              else if (mb_iseq (c, '\b'))
  5.4057 +                 {
  5.4058 +                   /* Go back one column, and force recalculation of the
  5.4059 +                      next tab stop.  */
  5.4060 +@@ -219,9 +278,9 @@ unexpand (void)
  5.4061 +                   next_tab_column = column;
  5.4062 +                   tab_index -= !!tab_index;
  5.4063 +                 }
  5.4064 +-              else
  5.4065 ++              else if (!mb_iseq (c, '\n'))
  5.4066 +                 {
  5.4067 +-                  column++;
  5.4068 ++                  column += mb_width (c);
  5.4069 +                   if (!column)
  5.4070 +                     die (EXIT_FAILURE, 0, _("input line is too long"));
  5.4071 +                 }
  5.4072 +@@ -229,8 +288,11 @@ unexpand (void)
  5.4073 +               if (pending)
  5.4074 +                 {
  5.4075 +                   if (pending > 1 && one_blank_before_tab_stop)
  5.4076 +-                    pending_blank[0] = '\t';
  5.4077 +-                  if (fwrite (pending_blank, 1, pending, stdout) != pending)
  5.4078 ++                    mb_setascii (&pending_blank[0], '\t');
  5.4079 ++
  5.4080 ++                  for (int n = 0; n < pending; ++n)
  5.4081 ++                    mb_putc (pending_blank[n], stdout);
  5.4082 ++                  if (ferror (stdout))
  5.4083 +                     die (EXIT_FAILURE, errno, _("write error"));
  5.4084 +                   pending = 0;
  5.4085 +                   one_blank_before_tab_stop = false;
  5.4086 +@@ -240,16 +302,17 @@ unexpand (void)
  5.4087 +               convert &= convert_entire_line || blank;
  5.4088 +             }
  5.4089 + 
  5.4090 +-          if (c < 0)
  5.4091 ++          if (mb_iseof (c))
  5.4092 +             {
  5.4093 +               free (pending_blank);
  5.4094 +               return;
  5.4095 +             }
  5.4096 + 
  5.4097 +-          if (putchar (c) < 0)
  5.4098 ++          mb_putc (c, stdout);
  5.4099 ++          if (ferror (stdout))
  5.4100 +             die (EXIT_FAILURE, errno, _("write error"));
  5.4101 +         }
  5.4102 +-      while (c != '\n');
  5.4103 ++      while (!mb_iseq (c, '\n'));
  5.4104 +     }
  5.4105 + }
  5.4106 + 
  5.4107 +diff -Naurp coreutils-8.27-orig/src/uniq.c coreutils-8.27/src/uniq.c
  5.4108 +--- coreutils-8.27-orig/src/uniq.c	2017-01-01 16:34:24.000000000 -0600
  5.4109 ++++ coreutils-8.27/src/uniq.c	2017-03-11 23:47:13.098285938 -0600
  5.4110 +@@ -21,6 +21,17 @@
  5.4111 + #include <getopt.h>
  5.4112 + #include <sys/types.h>
  5.4113 + 
  5.4114 ++/* Get mbstate_t, mbrtowc(). */
  5.4115 ++#if HAVE_WCHAR_H
  5.4116 ++# include <wchar.h>
  5.4117 ++#endif
  5.4118 ++
  5.4119 ++/* Get isw* functions. */
  5.4120 ++#if HAVE_WCTYPE_H
  5.4121 ++# include <wctype.h>
  5.4122 ++#endif
  5.4123 ++#include <assert.h>
  5.4124 ++
  5.4125 + #include "system.h"
  5.4126 + #include "argmatch.h"
  5.4127 + #include "linebuffer.h"
  5.4128 +@@ -32,9 +43,21 @@
  5.4129 + #include "stdio--.h"
  5.4130 + #include "xmemcoll.h"
  5.4131 + #include "xstrtol.h"
  5.4132 +-#include "memcasecmp.h"
  5.4133 ++#include "xmemcoll.h"
  5.4134 + #include "quote.h"
  5.4135 + 
  5.4136 ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC
  5.4137 ++   installation; work around this configuration error.  */
  5.4138 ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2
  5.4139 ++# define MB_LEN_MAX 16
  5.4140 ++#endif
  5.4141 ++
  5.4142 ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
  5.4143 ++#if HAVE_MBRTOWC && defined mbstate_t
  5.4144 ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
  5.4145 ++#endif
  5.4146 ++
  5.4147 ++
  5.4148 + /* The official name of this program (e.g., no 'g' prefix).  */
  5.4149 + #define PROGRAM_NAME "uniq"
  5.4150 + 
  5.4151 +@@ -144,6 +167,10 @@ enum
  5.4152 +   GROUP_OPTION = CHAR_MAX + 1
  5.4153 + };
  5.4154 + 
  5.4155 ++/* Function pointers. */
  5.4156 ++static char *
  5.4157 ++(*find_field) (struct linebuffer *line);
  5.4158 ++
  5.4159 + static struct option const longopts[] =
  5.4160 + {
  5.4161 +   {"count", no_argument, NULL, 'c'},
  5.4162 +@@ -260,7 +287,7 @@ size_opt (char const *opt, char const *m
  5.4163 +    return a pointer to the beginning of the line's field to be compared. */
  5.4164 + 
  5.4165 + static char * _GL_ATTRIBUTE_PURE
  5.4166 +-find_field (struct linebuffer const *line)
  5.4167 ++find_field_uni (struct linebuffer *line)
  5.4168 + {
  5.4169 +   size_t count;
  5.4170 +   char const *lp = line->buffer;
  5.4171 +@@ -280,6 +307,83 @@ find_field (struct linebuffer const *lin
  5.4172 +   return line->buffer + i;
  5.4173 + }
  5.4174 + 
  5.4175 ++#if HAVE_MBRTOWC
  5.4176 ++
  5.4177 ++# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL)  \
  5.4178 ++  do                                                                        \
  5.4179 ++    {                                                                        \
  5.4180 ++      mbstate_t state_bak;                                                \
  5.4181 ++                                                                        \
  5.4182 ++      CONVFAIL = 0;                                                        \
  5.4183 ++      state_bak = *STATEP;                                                \
  5.4184 ++                                                                        \
  5.4185 ++      MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP);                \
  5.4186 ++                                                                        \
  5.4187 ++      switch (MBLENGTH)                                                        \
  5.4188 ++        {                                                                \
  5.4189 ++        case (size_t)-2:                                                \
  5.4190 ++        case (size_t)-1:                                                \
  5.4191 ++          *STATEP = state_bak;                                                \
  5.4192 ++          CONVFAIL++;                                                        \
  5.4193 ++          /* Fall through */                                                \
  5.4194 ++        case 0:                                                                \
  5.4195 ++          MBLENGTH = 1;                                                        \
  5.4196 ++        }                                                                \
  5.4197 ++    }                                                                        \
  5.4198 ++  while (0)
  5.4199 ++
  5.4200 ++static char *
  5.4201 ++find_field_multi (struct linebuffer *line)
  5.4202 ++{
  5.4203 ++  size_t count;
  5.4204 ++  char *lp = line->buffer;
  5.4205 ++  size_t size = line->length - 1;
  5.4206 ++  size_t pos;
  5.4207 ++  size_t mblength;
  5.4208 ++  wchar_t wc;
  5.4209 ++  mbstate_t *statep;
  5.4210 ++  int convfail = 0;
  5.4211 ++
  5.4212 ++  pos = 0;
  5.4213 ++  statep = &(line->state);
  5.4214 ++
  5.4215 ++  /* skip fields. */
  5.4216 ++  for (count = 0; count < skip_fields && pos < size; count++)
  5.4217 ++    {
  5.4218 ++      while (pos < size)
  5.4219 ++        {
  5.4220 ++          MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
  5.4221 ++
  5.4222 ++          if (convfail || !(iswblank (wc) || wc == '\n'))
  5.4223 ++            {
  5.4224 ++              pos += mblength;
  5.4225 ++              break;
  5.4226 ++            }
  5.4227 ++          pos += mblength;
  5.4228 ++        }
  5.4229 ++
  5.4230 ++      while (pos < size)
  5.4231 ++        {
  5.4232 ++          MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
  5.4233 ++
  5.4234 ++          if (!convfail && (iswblank (wc) || wc == '\n'))
  5.4235 ++            break;
  5.4236 ++
  5.4237 ++          pos += mblength;
  5.4238 ++        }
  5.4239 ++    }
  5.4240 ++
  5.4241 ++  /* skip fields. */
  5.4242 ++  for (count = 0; count < skip_chars && pos < size; count++)
  5.4243 ++    {
  5.4244 ++      MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail);
  5.4245 ++      pos += mblength;
  5.4246 ++    }
  5.4247 ++
  5.4248 ++  return lp + pos;
  5.4249 ++}
  5.4250 ++#endif
  5.4251 ++
  5.4252 + /* Return false if two strings OLD and NEW match, true if not.
  5.4253 +    OLD and NEW point not to the beginnings of the lines
  5.4254 +    but rather to the beginnings of the fields to compare.
  5.4255 +@@ -288,6 +392,8 @@ find_field (struct linebuffer const *lin
  5.4256 + static bool
  5.4257 + different (char *old, char *new, size_t oldlen, size_t newlen)
  5.4258 + {
  5.4259 ++  char *copy_old, *copy_new;
  5.4260 ++
  5.4261 +   if (check_chars < oldlen)
  5.4262 +     oldlen = check_chars;
  5.4263 +   if (check_chars < newlen)
  5.4264 +@@ -295,14 +401,103 @@ different (char *old, char *new, size_t
  5.4265 + 
  5.4266 +   if (ignore_case)
  5.4267 +     {
  5.4268 +-      /* FIXME: This should invoke strcoll somehow.  */
  5.4269 +-      return oldlen != newlen || memcasecmp (old, new, oldlen);
  5.4270 ++      size_t i;
  5.4271 ++
  5.4272 ++      copy_old = xmalloc (oldlen + 1);
  5.4273 ++      copy_new = xmalloc (oldlen + 1);
  5.4274 ++
  5.4275 ++      for (i = 0; i < oldlen; i++)
  5.4276 ++        {
  5.4277 ++          copy_old[i] = toupper (old[i]);
  5.4278 ++          copy_new[i] = toupper (new[i]);
  5.4279 ++        }
  5.4280 ++      bool rc = xmemcoll (copy_old, oldlen, copy_new, newlen);
  5.4281 ++      free (copy_old);
  5.4282 ++      free (copy_new);
  5.4283 ++      return rc;
  5.4284 +     }
  5.4285 +-  else if (hard_LC_COLLATE)
  5.4286 +-    return xmemcoll (old, oldlen, new, newlen) != 0;
  5.4287 +   else
  5.4288 +-    return oldlen != newlen || memcmp (old, new, oldlen);
  5.4289 ++    {
  5.4290 ++      copy_old = (char *)old;
  5.4291 ++      copy_new = (char *)new;
  5.4292 ++    }
  5.4293 ++
  5.4294 ++  return xmemcoll (copy_old, oldlen, copy_new, newlen);
  5.4295 ++
  5.4296 ++}
  5.4297 ++
  5.4298 ++#if HAVE_MBRTOWC
  5.4299 ++static int
  5.4300 ++different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate)
  5.4301 ++{
  5.4302 ++  size_t i, j, chars;
  5.4303 ++  const char *str[2];
  5.4304 ++  char *copy[2];
  5.4305 ++  size_t len[2];
  5.4306 ++  mbstate_t state[2];
  5.4307 ++  size_t mblength;
  5.4308 ++  wchar_t wc, uwc;
  5.4309 ++  mbstate_t state_bak;
  5.4310 ++
  5.4311 ++  str[0] = old;
  5.4312 ++  str[1] = new;
  5.4313 ++  len[0] = oldlen;
  5.4314 ++  len[1] = newlen;
  5.4315 ++  state[0] = oldstate;
  5.4316 ++  state[1] = newstate;
  5.4317 ++
  5.4318 ++  for (i = 0; i < 2; i++)
  5.4319 ++    {
  5.4320 ++      copy[i] = xmalloc (len[i] + 1);
  5.4321 ++      memset (copy[i], '\0', len[i] + 1);
  5.4322 ++
  5.4323 ++      for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++)
  5.4324 ++        {
  5.4325 ++          state_bak = state[i];
  5.4326 ++          mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i]));
  5.4327 ++
  5.4328 ++          switch (mblength)
  5.4329 ++            {
  5.4330 ++            case (size_t)-1:
  5.4331 ++            case (size_t)-2:
  5.4332 ++              state[i] = state_bak;
  5.4333 ++              /* Fall through */
  5.4334 ++            case 0:
  5.4335 ++              mblength = 1;
  5.4336 ++              break;
  5.4337 ++
  5.4338 ++            default:
  5.4339 ++              if (ignore_case)
  5.4340 ++                {
  5.4341 ++                  uwc = towupper (wc);
  5.4342 ++
  5.4343 ++                  if (uwc != wc)
  5.4344 ++                    {
  5.4345 ++                      mbstate_t state_wc;
  5.4346 ++                      size_t mblen;
  5.4347 ++
  5.4348 ++                      memset (&state_wc, '\0', sizeof(mbstate_t));
  5.4349 ++                      mblen = wcrtomb (copy[i] + j, uwc, &state_wc);
  5.4350 ++                      assert (mblen != (size_t)-1);
  5.4351 ++                    }
  5.4352 ++                  else
  5.4353 ++                    memcpy (copy[i] + j, str[i] + j, mblength);
  5.4354 ++                }
  5.4355 ++              else
  5.4356 ++                memcpy (copy[i] + j, str[i] + j, mblength);
  5.4357 ++            }
  5.4358 ++          j += mblength;
  5.4359 ++        }
  5.4360 ++      copy[i][j] = '\0';
  5.4361 ++      len[i] = j;
  5.4362 ++    }
  5.4363 ++  int rc = xmemcoll (copy[0], len[0], copy[1], len[1]);
  5.4364 ++  free (copy[0]);
  5.4365 ++  free (copy[1]);
  5.4366 ++  return rc;
  5.4367 ++
  5.4368 + }
  5.4369 ++#endif
  5.4370 + 
  5.4371 + /* Output the line in linebuffer LINE to standard output
  5.4372 +    provided that the switches say it should be output.
  5.4373 +@@ -367,19 +562,38 @@ check_file (const char *infile, const ch
  5.4374 +       char *prevfield IF_LINT ( = NULL);
  5.4375 +       size_t prevlen IF_LINT ( = 0);
  5.4376 +       bool first_group_printed = false;
  5.4377 ++#if HAVE_MBRTOWC
  5.4378 ++      mbstate_t prevstate;
  5.4379 ++
  5.4380 ++      memset (&prevstate, '\0', sizeof (mbstate_t));
  5.4381 ++#endif
  5.4382 + 
  5.4383 +       while (!feof (stdin))
  5.4384 +         {
  5.4385 +           char *thisfield;
  5.4386 +           size_t thislen;
  5.4387 +           bool new_group;
  5.4388 ++#if HAVE_MBRTOWC
  5.4389 ++          mbstate_t thisstate;
  5.4390 ++#endif
  5.4391 + 
  5.4392 +           if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
  5.4393 +             break;
  5.4394 + 
  5.4395 +           thisfield = find_field (thisline);
  5.4396 +           thislen = thisline->length - 1 - (thisfield - thisline->buffer);
  5.4397 ++#if HAVE_MBRTOWC
  5.4398 ++          if (MB_CUR_MAX > 1)
  5.4399 ++            {
  5.4400 ++              thisstate = thisline->state;
  5.4401 + 
  5.4402 ++              new_group = (prevline->length == 0
  5.4403 ++                           || different_multi (thisfield, prevfield,
  5.4404 ++                                               thislen, prevlen,
  5.4405 ++                                               thisstate, prevstate));
  5.4406 ++            }
  5.4407 ++          else
  5.4408 ++#endif
  5.4409 +           new_group = (prevline->length == 0
  5.4410 +                        || different (thisfield, prevfield, thislen, prevlen));
  5.4411 + 
  5.4412 +@@ -397,6 +611,10 @@ check_file (const char *infile, const ch
  5.4413 +               SWAP_LINES (prevline, thisline);
  5.4414 +               prevfield = thisfield;
  5.4415 +               prevlen = thislen;
  5.4416 ++#if HAVE_MBRTOWC
  5.4417 ++              if (MB_CUR_MAX > 1)
  5.4418 ++                prevstate = thisstate;
  5.4419 ++#endif
  5.4420 +               first_group_printed = true;
  5.4421 +             }
  5.4422 +         }
  5.4423 +@@ -409,17 +627,26 @@ check_file (const char *infile, const ch
  5.4424 +       size_t prevlen;
  5.4425 +       uintmax_t match_count = 0;
  5.4426 +       bool first_delimiter = true;
  5.4427 ++#if HAVE_MBRTOWC
  5.4428 ++      mbstate_t prevstate;
  5.4429 ++#endif
  5.4430 + 
  5.4431 +       if (readlinebuffer_delim (prevline, stdin, delimiter) == 0)
  5.4432 +         goto closefiles;
  5.4433 +       prevfield = find_field (prevline);
  5.4434 +       prevlen = prevline->length - 1 - (prevfield - prevline->buffer);
  5.4435 ++#if HAVE_MBRTOWC
  5.4436 ++      prevstate = prevline->state;
  5.4437 ++#endif
  5.4438 + 
  5.4439 +       while (!feof (stdin))
  5.4440 +         {
  5.4441 +           bool match;
  5.4442 +           char *thisfield;
  5.4443 +           size_t thislen;
  5.4444 ++#if HAVE_MBRTOWC
  5.4445 ++          mbstate_t thisstate = thisline->state;
  5.4446 ++#endif
  5.4447 +           if (readlinebuffer_delim (thisline, stdin, delimiter) == 0)
  5.4448 +             {
  5.4449 +               if (ferror (stdin))
  5.4450 +@@ -428,6 +655,14 @@ check_file (const char *infile, const ch
  5.4451 +             }
  5.4452 +           thisfield = find_field (thisline);
  5.4453 +           thislen = thisline->length - 1 - (thisfield - thisline->buffer);
  5.4454 ++#if HAVE_MBRTOWC
  5.4455 ++          if (MB_CUR_MAX > 1)
  5.4456 ++            {
  5.4457 ++              match = !different_multi (thisfield, prevfield,
  5.4458 ++                                thislen, prevlen, thisstate, prevstate);
  5.4459 ++            }
  5.4460 ++          else
  5.4461 ++#endif
  5.4462 +           match = !different (thisfield, prevfield, thislen, prevlen);
  5.4463 +           match_count += match;
  5.4464 + 
  5.4465 +@@ -460,6 +695,9 @@ check_file (const char *infile, const ch
  5.4466 +               SWAP_LINES (prevline, thisline);
  5.4467 +               prevfield = thisfield;
  5.4468 +               prevlen = thislen;
  5.4469 ++#if HAVE_MBRTOWC
  5.4470 ++              prevstate = thisstate;
  5.4471 ++#endif
  5.4472 +               if (!match)
  5.4473 +                 match_count = 0;
  5.4474 +             }
  5.4475 +@@ -506,6 +744,19 @@ main (int argc, char **argv)
  5.4476 + 
  5.4477 +   atexit (close_stdout);
  5.4478 + 
  5.4479 ++#if HAVE_MBRTOWC
  5.4480 ++  if (MB_CUR_MAX > 1)
  5.4481 ++    {
  5.4482 ++      find_field = find_field_multi;
  5.4483 ++    }
  5.4484 ++  else
  5.4485 ++#endif
  5.4486 ++    {
  5.4487 ++      find_field = find_field_uni;
  5.4488 ++    }
  5.4489 ++
  5.4490 ++
  5.4491 ++
  5.4492 +   skip_chars = 0;
  5.4493 +   skip_fields = 0;
  5.4494 +   check_chars = SIZE_MAX;
  5.4495 +diff -Naurp coreutils-8.27-orig/tests/expand/mb.sh coreutils-8.27/tests/expand/mb.sh
  5.4496 +--- coreutils-8.27-orig/tests/expand/mb.sh	1969-12-31 18:00:00.000000000 -0600
  5.4497 ++++ coreutils-8.27/tests/expand/mb.sh	2017-03-11 23:49:06.759133489 -0600
  5.4498 +@@ -0,0 +1,183 @@
  5.4499 ++#!/bin/sh
  5.4500 ++
  5.4501 ++# Copyright (C) 2012-2017 Free Software Foundation, Inc.
  5.4502 ++
  5.4503 ++# This program is free software: you can redistribute it and/or modify
  5.4504 ++# it under the terms of the GNU General Public License as published by
  5.4505 ++# the Free Software Foundation, either version 3 of the License, or
  5.4506 ++# (at your option) any later version.
  5.4507 ++
  5.4508 ++# This program is distributed in the hope that it will be useful,
  5.4509 ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
  5.4510 ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  5.4511 ++# GNU General Public License for more details.
  5.4512 ++
  5.4513 ++# You should have received a copy of the GNU General Public License
  5.4514 ++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
  5.4515 ++
  5.4516 ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  5.4517 ++print_ver_ expand
  5.4518 ++
  5.4519 ++export LC_ALL=en_US.UTF-8
  5.4520 ++
  5.4521 ++#input containing multibyte characters
  5.4522 ++cat <<\EOF > in || framework_failure_
  5.4523 ++1234567812345678123456781
  5.4524 ++.       .       .       .
  5.4525 ++a	b	c	d
  5.4526 ++.       .       .       .
  5.4527 ++ä	ö	ü	ß
  5.4528 ++.       .       .       .
  5.4529 ++EOF
  5.4530 ++env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
  5.4531 ++
  5.4532 ++cat <<\EOF > exp || framework_failure_
  5.4533 ++1234567812345678123456781
  5.4534 ++.       .       .       .
  5.4535 ++a       b       c       d
  5.4536 ++.       .       .       .
  5.4537 ++ä       ö       ü       ß
  5.4538 ++.       .       .       .
  5.4539 ++   äöü  .    öüä.       ä xx
  5.4540 ++EOF
  5.4541 ++
  5.4542 ++expand < in > out || fail=1
  5.4543 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4544 ++
  5.4545 ++#multiple files as an input
  5.4546 ++cat <<\EOF >> exp || framework_failure_
  5.4547 ++1234567812345678123456781
  5.4548 ++.       .       .       .
  5.4549 ++a       b       c       d
  5.4550 ++.       .       .       .
  5.4551 ++ä       ö       ü       ß
  5.4552 ++.       .       .       .
  5.4553 ++   äöü  .    öüä.       ä xx
  5.4554 ++EOF
  5.4555 ++
  5.4556 ++expand ./in ./in > out || fail=1
  5.4557 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4558 ++
  5.4559 ++#test characters with display widths != 1
  5.4560 ++env printf '12345678
  5.4561 ++e\t|ascii(1)
  5.4562 ++\u00E9\t|composed(1)
  5.4563 ++e\u0301\t|decomposed(1)
  5.4564 ++\u3000\t|ideo-space(2)
  5.4565 ++\uFF0D\t|full-hypen(2)
  5.4566 ++' > in || framework_failure_
  5.4567 ++
  5.4568 ++env printf '12345678
  5.4569 ++e       |ascii(1)
  5.4570 ++\u00E9       |composed(1)
  5.4571 ++e\u0301       |decomposed(1)
  5.4572 ++\u3000      |ideo-space(2)
  5.4573 ++\uFF0D      |full-hypen(2)
  5.4574 ++' > exp || framework_failure_
  5.4575 ++
  5.4576 ++expand < in > out || fail=1
  5.4577 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4578 ++
  5.4579 ++#shouldn't fail with "input line too long"
  5.4580 ++#when a line starts with a control character
  5.4581 ++env printf '\n' > in || framework_failure_
  5.4582 ++
  5.4583 ++expand < in > out || fail=1
  5.4584 ++compare in out > /dev/null 2>&1 || fail=1
  5.4585 ++
  5.4586 ++#non-Unicode characters interspersed between Unicode ones
  5.4587 ++env printf '12345678
  5.4588 ++\t\xFF|
  5.4589 ++\xFF\t|
  5.4590 ++\t\xFFä|
  5.4591 ++ä\xFF\t|
  5.4592 ++\tä\xFF|
  5.4593 ++\xFF\tä|
  5.4594 ++äbcdef\xFF\t|
  5.4595 ++' > in || framework_failure_
  5.4596 ++
  5.4597 ++env printf '12345678
  5.4598 ++        \xFF|
  5.4599 ++\xFF       |
  5.4600 ++        \xFFä|
  5.4601 ++ä\xFF      |
  5.4602 ++        ä\xFF|
  5.4603 ++\xFF       ä|
  5.4604 ++äbcdef\xFF |
  5.4605 ++' > exp || framework_failure_
  5.4606 ++
  5.4607 ++expand < in > out || fail=1
  5.4608 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4609 ++
  5.4610 ++
  5.4611 ++
  5.4612 ++#BOM header test 1
  5.4613 ++printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_
  5.4614 ++1234567812345678123456781
  5.4615 ++.       .       .       .
  5.4616 ++a	b	c	d
  5.4617 ++.       .       .       .
  5.4618 ++ä	ö	ü	ß
  5.4619 ++.       .       .       .
  5.4620 ++EOF
  5.4621 ++env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
  5.4622 ++
  5.4623 ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
  5.4624 ++1234567812345678123456781
  5.4625 ++.       .       .       .
  5.4626 ++a       b       c       d
  5.4627 ++.       .       .       .
  5.4628 ++ä       ö       ü       ß
  5.4629 ++.       .       .       .
  5.4630 ++   äöü  .    öüä.       ä xx
  5.4631 ++EOF
  5.4632 ++
  5.4633 ++
  5.4634 ++expand < in > out || fail=1
  5.4635 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4636 ++
  5.4637 ++LANG=C expand < in > out || fail=1
  5.4638 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4639 ++
  5.4640 ++LC_ALL=C expand < in > out || fail=1
  5.4641 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4642 ++
  5.4643 ++
  5.4644 ++printf '\xEF\xBB\xBF' > in1; cat <<\EOF >> in1 || framework_failure_
  5.4645 ++1234567812345678123456781
  5.4646 ++.       .       .       .
  5.4647 ++a	b	c	d
  5.4648 ++.       .       .       .
  5.4649 ++ä	ö	ü	ß
  5.4650 ++.       .       .       .
  5.4651 ++EOF
  5.4652 ++env printf '   äöü\t.    öüä.   \tä xx\n' >> in1 || framework_failure_
  5.4653 ++
  5.4654 ++
  5.4655 ++printf '\xEF\xBB\xBF' > exp; cat <<\EOF >> exp || framework_failure_
  5.4656 ++1234567812345678123456781
  5.4657 ++.       .       .       .
  5.4658 ++a       b       c       d
  5.4659 ++.       .       .       .
  5.4660 ++ä       ö       ü       ß
  5.4661 ++.       .       .       .
  5.4662 ++   äöü  .    öüä.       ä xx
  5.4663 ++1234567812345678123456781
  5.4664 ++.       .       .       .
  5.4665 ++a       b       c       d
  5.4666 ++.       .       .       .
  5.4667 ++ä       ö       ü       ß
  5.4668 ++.       .       .       .
  5.4669 ++   äöü  .    öüä.       ä xx
  5.4670 ++EOF
  5.4671 ++
  5.4672 ++expand in1 in1 > out || fail=1
  5.4673 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4674 ++
  5.4675 ++LANG=C expand in1 in1  > out || fail=1
  5.4676 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4677 ++
  5.4678 ++LC_ALL=C expand in1 in1 > out || fail=1
  5.4679 ++compare exp out > /dev/null 2>&1 || fail=1
  5.4680 ++
  5.4681 ++exit $fail
  5.4682 +diff -Naurp coreutils-8.27-orig/tests/i18n/sort.sh coreutils-8.27/tests/i18n/sort.sh
  5.4683 +--- coreutils-8.27-orig/tests/i18n/sort.sh	1969-12-31 18:00:00.000000000 -0600
  5.4684 ++++ coreutils-8.27/tests/i18n/sort.sh	2017-03-11 23:47:13.100285838 -0600
  5.4685 +@@ -0,0 +1,29 @@
  5.4686 ++#!/bin/sh
  5.4687 ++# Verify sort's multi-byte support.
  5.4688 ++
  5.4689 ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  5.4690 ++print_ver_ sort
  5.4691 ++
  5.4692 ++export LC_ALL=en_US.UTF-8
  5.4693 ++locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \
  5.4694 ++  || skip_ "No UTF-8 locale available"
  5.4695 ++
  5.4696 ++# Enable heap consistency checkng on older systems
  5.4697 ++export MALLOC_CHECK_=2
  5.4698 ++
  5.4699 ++
  5.4700 ++# check buffer overflow issue due to
  5.4701 ++# expanding multi-byte representation due to case conversion
  5.4702 ++# https://bugzilla.suse.com/show_bug.cgi?id=928749
  5.4703 ++cat <<EOF > exp
  5.4704 ++.
  5.4705 ++ɑ
  5.4706 ++EOF
  5.4707 ++cat <<EOF | sort -f > out || fail=1
  5.4708 ++.
  5.4709 ++ɑ
  5.4710 ++EOF
  5.4711 ++compare exp out || { fail=1; cat out; }
  5.4712 ++
  5.4713 ++
  5.4714 ++Exit $fail
  5.4715 +diff -Naurp coreutils-8.27-orig/tests/local.mk coreutils-8.27/tests/local.mk
  5.4716 +--- coreutils-8.27-orig/tests/local.mk	2017-02-28 22:25:37.000000000 -0600
  5.4717 ++++ coreutils-8.27/tests/local.mk	2017-03-11 23:47:38.072058253 -0600
  5.4718 +@@ -352,6 +352,8 @@ all_tests =					\
  5.4719 +   tests/misc/sort-discrim.sh			\
  5.4720 +   tests/misc/sort-files0-from.pl		\
  5.4721 +   tests/misc/sort-float.sh			\
  5.4722 ++  tests/misc/sort-mb-tests.sh			\
  5.4723 ++  tests/i18n/sort.sh				\
  5.4724 +   tests/misc/sort-h-thousands-sep.sh		\
  5.4725 +   tests/misc/sort-merge.pl			\
  5.4726 +   tests/misc/sort-merge-fdlimit.sh		\
  5.4727 +@@ -544,6 +546,7 @@ all_tests =					\
  5.4728 +   tests/du/threshold.sh				\
  5.4729 +   tests/du/trailing-slash.sh			\
  5.4730 +   tests/du/two-args.sh				\
  5.4731 ++  tests/expand/mb.sh				\
  5.4732 +   tests/id/gnu-zero-uids.sh			\
  5.4733 +   tests/id/no-context.sh			\
  5.4734 +   tests/id/context.sh				\
  5.4735 +@@ -684,6 +687,7 @@ all_tests =					\
  5.4736 +   tests/touch/read-only.sh			\
  5.4737 +   tests/touch/relative.sh			\
  5.4738 +   tests/touch/trailing-slash.sh			\
  5.4739 ++  tests/unexpand/mb.sh				\
  5.4740 +   $(all_root_tests)
  5.4741 + 
  5.4742 + # See tests/factor/create-test.sh.
  5.4743 +diff -Naurp coreutils-8.27-orig/tests/misc/cut.pl coreutils-8.27/tests/misc/cut.pl
  5.4744 +--- coreutils-8.27-orig/tests/misc/cut.pl	2017-01-01 16:34:24.000000000 -0600
  5.4745 ++++ coreutils-8.27/tests/misc/cut.pl	2017-03-11 23:47:13.100285838 -0600
  5.4746 +@@ -23,9 +23,11 @@ use strict;
  5.4747 + # Turn off localization of executable's output.
  5.4748 + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  5.4749 + 
  5.4750 +-my $mb_locale = $ENV{LOCALE_FR_UTF8};
  5.4751 ++my $mb_locale;
  5.4752 ++# uncommented enable multibyte paths
  5.4753 ++$mb_locale = $ENV{LOCALE_FR_UTF8};
  5.4754 + ! defined $mb_locale || $mb_locale eq 'none'
  5.4755 +-  and $mb_locale = 'C';
  5.4756 ++ and $mb_locale = 'C';
  5.4757 + 
  5.4758 + my $prog = 'cut';
  5.4759 + my $try = "Try '$prog --help' for more information.\n";
  5.4760 +@@ -240,6 +242,7 @@ if ($mb_locale ne 'C')
  5.4761 +         my @new_t = @$t;
  5.4762 +         my $test_name = shift @new_t;
  5.4763 + 
  5.4764 ++        next if ($test_name =~ "newline-[12][0-9]");
  5.4765 +         push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.4766 +       }
  5.4767 +     push @Tests, @new;
  5.4768 +diff -Naurp coreutils-8.27-orig/tests/misc/expand.pl coreutils-8.27/tests/misc/expand.pl
  5.4769 +--- coreutils-8.27-orig/tests/misc/expand.pl	2017-03-01 11:16:46.000000000 -0600
  5.4770 ++++ coreutils-8.27/tests/misc/expand.pl	2017-03-11 23:47:13.101285788 -0600
  5.4771 +@@ -27,6 +27,15 @@ my $prog = 'expand';
  5.4772 + # Turn off localization of executable's output.
  5.4773 + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  5.4774 + 
  5.4775 ++#comment out next line to disable multibyte tests
  5.4776 ++my $mb_locale = $ENV{LOCALE_FR_UTF8};
  5.4777 ++! defined $mb_locale || $mb_locale eq 'none'
  5.4778 ++ and $mb_locale = 'C';
  5.4779 ++
  5.4780 ++my $prog = 'expand';
  5.4781 ++my $try = "Try \`$prog --help' for more information.\n";
  5.4782 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.4783 ++
  5.4784 + my @Tests =
  5.4785 +   (
  5.4786 +    ['t1', '--tabs=3',     {IN=>"a\tb"}, {OUT=>"a  b"}],
  5.4787 +@@ -152,6 +161,8 @@ my @Tests =
  5.4788 +    ['trail9', '--tab=1,2 -t/5',{IN=>"\ta\tb\tc"}, {OUT=>" a   b    c"}],
  5.4789 + 
  5.4790 +    # Test errors
  5.4791 ++   # FIXME: The following tests contain ‘quoting’ specific to LC_MESSAGES
  5.4792 ++   # So we force LC_MESSAGES=C to make them pass.
  5.4793 +    ['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1},
  5.4794 +     {ERR => "$prog: tab size contains invalid character(s): 'a'\n"}],
  5.4795 +    ['e2', "-t $UINTMAX_OFLOW", {IN=>''}, {OUT=>''}, {EXIT=>1},
  5.4796 +@@ -168,6 +179,37 @@ my @Tests =
  5.4797 +     {ERR => "$prog: '/' specifier not at start of number: '/'\n"}],
  5.4798 +   );
  5.4799 + 
  5.4800 ++if ($mb_locale ne 'C')
  5.4801 ++  {
  5.4802 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.4803 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.4804 ++    # provide coverage for the distro-added multi-byte code paths.
  5.4805 ++    my @new;
  5.4806 ++    foreach my $t (@Tests)
  5.4807 ++      {
  5.4808 ++        my @new_t = @$t;
  5.4809 ++        my $test_name = shift @new_t;
  5.4810 ++
  5.4811 ++        # Depending on whether expand is multi-byte-patched,
  5.4812 ++        # it emits different diagnostics:
  5.4813 ++        #   non-MB: invalid byte or field list
  5.4814 ++        #   MB:     invalid byte, character or field list
  5.4815 ++        # Adjust the expected error output accordingly.
  5.4816 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.4817 ++            (@new_t))
  5.4818 ++          {
  5.4819 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.4820 ++            push @new_t, $sub;
  5.4821 ++            push @$t, $sub;
  5.4822 ++          }
  5.4823 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LANG=$mb_locale LC_MESSAGES=C"}];
  5.4824 ++      }
  5.4825 ++    push @Tests, @new;
  5.4826 ++  }
  5.4827 ++
  5.4828 ++
  5.4829 ++@Tests = triple_test \@Tests;
  5.4830 ++
  5.4831 + my $save_temps = $ENV{DEBUG};
  5.4832 + my $verbose = $ENV{VERBOSE};
  5.4833 + 
  5.4834 +diff -Naurp coreutils-8.27-orig/tests/misc/fold.pl coreutils-8.27/tests/misc/fold.pl
  5.4835 +--- coreutils-8.27-orig/tests/misc/fold.pl	2017-01-01 16:34:24.000000000 -0600
  5.4836 ++++ coreutils-8.27/tests/misc/fold.pl	2017-03-11 23:47:13.101285788 -0600
  5.4837 +@@ -20,9 +20,18 @@ use strict;
  5.4838 + 
  5.4839 + (my $program_name = $0) =~ s|.*/||;
  5.4840 + 
  5.4841 ++my $prog = 'fold';
  5.4842 ++my $try = "Try \`$prog --help' for more information.\n";
  5.4843 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.4844 ++
  5.4845 + # Turn off localization of executable's output.
  5.4846 + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  5.4847 + 
  5.4848 ++# uncommented to enable multibyte paths
  5.4849 ++my $mb_locale = $ENV{LOCALE_FR_UTF8};
  5.4850 ++! defined $mb_locale || $mb_locale eq 'none'
  5.4851 ++ and $mb_locale = 'C';
  5.4852 ++
  5.4853 + my @Tests =
  5.4854 +   (
  5.4855 +    ['s1', '-w2 -s', {IN=>"a\t"}, {OUT=>"a\n\t"}],
  5.4856 +@@ -31,9 +40,48 @@ my @Tests =
  5.4857 +    ['s4', '-w4 -s', {IN=>"abc ef\n"}, {OUT=>"abc \nef\n"}],
  5.4858 +   );
  5.4859 + 
  5.4860 ++# Add _POSIX2_VERSION=199209 to the environment of each test
  5.4861 ++# that uses an old-style option like +1.
  5.4862 ++if ($mb_locale ne 'C')
  5.4863 ++  {
  5.4864 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.4865 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.4866 ++    # provide coverage for the distro-added multi-byte code paths.
  5.4867 ++    my @new;
  5.4868 ++    foreach my $t (@Tests)
  5.4869 ++      {
  5.4870 ++        my @new_t = @$t;
  5.4871 ++        my $test_name = shift @new_t;
  5.4872 ++
  5.4873 ++        # Depending on whether fold is multi-byte-patched,
  5.4874 ++        # it emits different diagnostics:
  5.4875 ++        #   non-MB: invalid byte or field list
  5.4876 ++        #   MB:     invalid byte, character or field list
  5.4877 ++        # Adjust the expected error output accordingly.
  5.4878 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.4879 ++            (@new_t))
  5.4880 ++          {
  5.4881 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.4882 ++            push @new_t, $sub;
  5.4883 ++            push @$t, $sub;
  5.4884 ++          }
  5.4885 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.4886 ++      }
  5.4887 ++    push @Tests, @new;
  5.4888 ++  }
  5.4889 ++
  5.4890 ++@Tests = triple_test \@Tests;
  5.4891 ++
  5.4892 ++# Remember that triple_test creates from each test with exactly one "IN"
  5.4893 ++# file two more tests (.p and .r suffix on name) corresponding to reading
  5.4894 ++# input from a file and from a pipe.  The pipe-reading test would fail
  5.4895 ++# due to a race condition about 1 in 20 times.
  5.4896 ++# Remove the IN_PIPE version of the "output-is-input" test above.
  5.4897 ++# The others aren't susceptible because they have three inputs each.
  5.4898 ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  5.4899 ++
  5.4900 + my $save_temps = $ENV{DEBUG};
  5.4901 + my $verbose = $ENV{VERBOSE};
  5.4902 + 
  5.4903 +-my $prog = 'fold';
  5.4904 + my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
  5.4905 + exit $fail;
  5.4906 +diff -Naurp coreutils-8.27-orig/tests/misc/join.pl coreutils-8.27/tests/misc/join.pl
  5.4907 +--- coreutils-8.27-orig/tests/misc/join.pl	2017-01-01 16:34:24.000000000 -0600
  5.4908 ++++ coreutils-8.27/tests/misc/join.pl	2017-03-11 23:47:13.102285737 -0600
  5.4909 +@@ -25,6 +25,15 @@ my $limits = getlimits ();
  5.4910 + 
  5.4911 + my $prog = 'join';
  5.4912 + 
  5.4913 ++my $try = "Try \`$prog --help' for more information.\n";
  5.4914 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.4915 ++
  5.4916 ++my $mb_locale;
  5.4917 ++#Comment out next line to disable multibyte tests
  5.4918 ++$mb_locale = $ENV{LOCALE_FR_UTF8};
  5.4919 ++! defined $mb_locale || $mb_locale eq 'none'
  5.4920 ++  and $mb_locale = 'C';
  5.4921 ++
  5.4922 + my $delim = chr 0247;
  5.4923 + sub t_subst ($)
  5.4924 + {
  5.4925 +@@ -329,8 +338,49 @@ foreach my $t (@tv)
  5.4926 +     push @Tests, $new_ent;
  5.4927 +   }
  5.4928 + 
  5.4929 ++# Add _POSIX2_VERSION=199209 to the environment of each test
  5.4930 ++# that uses an old-style option like +1.
  5.4931 ++if ($mb_locale ne 'C')
  5.4932 ++  {
  5.4933 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.4934 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.4935 ++    # provide coverage for the distro-added multi-byte code paths.
  5.4936 ++    my @new;
  5.4937 ++    foreach my $t (@Tests)
  5.4938 ++      {
  5.4939 ++        my @new_t = @$t;
  5.4940 ++        my $test_name = shift @new_t;
  5.4941 ++
  5.4942 ++        # Depending on whether join is multi-byte-patched,
  5.4943 ++        # it emits different diagnostics:
  5.4944 ++        #   non-MB: invalid byte or field list
  5.4945 ++        #   MB:     invalid byte, character or field list
  5.4946 ++        # Adjust the expected error output accordingly.
  5.4947 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.4948 ++            (@new_t))
  5.4949 ++          {
  5.4950 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.4951 ++            push @new_t, $sub;
  5.4952 ++            push @$t, $sub;
  5.4953 ++          }
  5.4954 ++        #Adjust the output some error messages including test_name for mb
  5.4955 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR}}
  5.4956 ++             (@new_t))
  5.4957 ++          {
  5.4958 ++            my $sub2 = {ERR_SUBST => "s/$test_name-mb/$test_name/"};
  5.4959 ++            push @new_t, $sub2;
  5.4960 ++            push @$t, $sub2;
  5.4961 ++          }
  5.4962 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.4963 ++      }
  5.4964 ++    push @Tests, @new;
  5.4965 ++  }
  5.4966 ++
  5.4967 + @Tests = triple_test \@Tests;
  5.4968 + 
  5.4969 ++#skip invalid-j-mb test, it is failing because of the format
  5.4970 ++@Tests = grep {$_->[0] ne 'invalid-j-mb'} @Tests;
  5.4971 ++
  5.4972 + my $save_temps = $ENV{DEBUG};
  5.4973 + my $verbose = $ENV{VERBOSE};
  5.4974 + 
  5.4975 +diff -Naurp coreutils-8.27-orig/tests/misc/sort-mb-tests.sh coreutils-8.27/tests/misc/sort-mb-tests.sh
  5.4976 +--- coreutils-8.27-orig/tests/misc/sort-mb-tests.sh	1969-12-31 18:00:00.000000000 -0600
  5.4977 ++++ coreutils-8.27/tests/misc/sort-mb-tests.sh	2017-03-11 23:47:13.102285737 -0600
  5.4978 +@@ -0,0 +1,45 @@
  5.4979 ++#!/bin/sh
  5.4980 ++# Verify sort's multi-byte support.
  5.4981 ++
  5.4982 ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  5.4983 ++print_ver_ sort
  5.4984 ++
  5.4985 ++export LC_ALL=en_US.UTF-8
  5.4986 ++locale -k LC_CTYPE | grep -q "charmap.*UTF-8" \
  5.4987 ++  || skip_ "No UTF-8 locale available"
  5.4988 ++
  5.4989 ++
  5.4990 ++cat <<EOF > exp
  5.4991 ++Banana@5
  5.4992 ++Apple@10
  5.4993 ++Citrus@20
  5.4994 ++Cherry@30
  5.4995 ++EOF
  5.4996 ++
  5.4997 ++cat <<EOF | sort -t @ -k2 -n > out || fail=1
  5.4998 ++Apple@10
  5.4999 ++Banana@5
  5.5000 ++Citrus@20
  5.5001 ++Cherry@30
  5.5002 ++EOF
  5.5003 ++
  5.5004 ++compare exp out || { fail=1; cat out; }
  5.5005 ++
  5.5006 ++
  5.5007 ++cat <<EOF > exp
  5.5008 ++Citrus@AA20@@5
  5.5009 ++Cherry@AA30@@10
  5.5010 ++Apple@AA10@@20
  5.5011 ++Banana@AA5@@30
  5.5012 ++EOF
  5.5013 ++
  5.5014 ++cat <<EOF | sort -t @ -k4 -n > out || fail=1
  5.5015 ++Apple@AA10@@20
  5.5016 ++Banana@AA5@@30
  5.5017 ++Citrus@AA20@@5
  5.5018 ++Cherry@AA30@@10
  5.5019 ++EOF
  5.5020 ++
  5.5021 ++compare exp out || { fail=1; cat out; }
  5.5022 ++
  5.5023 ++Exit $fail
  5.5024 +diff -Naurp coreutils-8.27-orig/tests/misc/sort-merge.pl coreutils-8.27/tests/misc/sort-merge.pl
  5.5025 +--- coreutils-8.27-orig/tests/misc/sort-merge.pl	2017-01-01 16:34:24.000000000 -0600
  5.5026 ++++ coreutils-8.27/tests/misc/sort-merge.pl	2017-03-11 23:47:13.102285737 -0600
  5.5027 +@@ -26,6 +26,15 @@ my $prog = 'sort';
  5.5028 + # Turn off localization of executable's output.
  5.5029 + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  5.5030 + 
  5.5031 ++my $mb_locale;
  5.5032 ++# uncommented according to upstream commit enabling multibyte paths
  5.5033 ++$mb_locale = $ENV{LOCALE_FR_UTF8};
  5.5034 ++! defined $mb_locale || $mb_locale eq 'none'
  5.5035 ++ and $mb_locale = 'C';
  5.5036 ++
  5.5037 ++my $try = "Try \`$prog --help' for more information.\n";
  5.5038 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.5039 ++
  5.5040 + # three empty files and one that says 'foo'
  5.5041 + my @inputs = (+(map{{IN=> {"empty$_"=> ''}}}1..3), {IN=> {foo=> "foo\n"}});
  5.5042 + 
  5.5043 +@@ -77,6 +86,39 @@ my @Tests =
  5.5044 +         {OUT=>$big_input}],
  5.5045 +     );
  5.5046 + 
  5.5047 ++# Add _POSIX2_VERSION=199209 to the environment of each test
  5.5048 ++# that uses an old-style option like +1.
  5.5049 ++if ($mb_locale ne 'C')
  5.5050 ++  {
  5.5051 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.5052 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.5053 ++    # provide coverage for the distro-added multi-byte code paths.
  5.5054 ++    my @new;
  5.5055 ++    foreach my $t (@Tests)
  5.5056 ++      {
  5.5057 ++        my @new_t = @$t;
  5.5058 ++        my $test_name = shift @new_t;
  5.5059 ++
  5.5060 ++        # Depending on whether sort is multi-byte-patched,
  5.5061 ++        # it emits different diagnostics:
  5.5062 ++        #   non-MB: invalid byte or field list
  5.5063 ++        #   MB:     invalid byte, character or field list
  5.5064 ++        # Adjust the expected error output accordingly.
  5.5065 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.5066 ++            (@new_t))
  5.5067 ++          {
  5.5068 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.5069 ++            push @new_t, $sub;
  5.5070 ++            push @$t, $sub;
  5.5071 ++          }
  5.5072 ++        next if ($test_name =~ "nmerge-.");
  5.5073 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.5074 ++      }
  5.5075 ++    push @Tests, @new;
  5.5076 ++  }
  5.5077 ++
  5.5078 ++@Tests = triple_test \@Tests;
  5.5079 ++
  5.5080 + my $save_temps = $ENV{DEBUG};
  5.5081 + my $verbose = $ENV{VERBOSE};
  5.5082 + 
  5.5083 +diff -Naurp coreutils-8.27-orig/tests/misc/sort.pl coreutils-8.27/tests/misc/sort.pl
  5.5084 +--- coreutils-8.27-orig/tests/misc/sort.pl	2017-01-21 08:53:43.000000000 -0600
  5.5085 ++++ coreutils-8.27/tests/misc/sort.pl	2017-03-11 23:47:13.103285687 -0600
  5.5086 +@@ -24,10 +24,15 @@ my $prog = 'sort';
  5.5087 + # Turn off localization of executable's output.
  5.5088 + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  5.5089 + 
  5.5090 +-my $mb_locale = $ENV{LOCALE_FR_UTF8};
  5.5091 ++my $mb_locale;
  5.5092 ++#Comment out next line to disable multibyte tests
  5.5093 ++$mb_locale = $ENV{LOCALE_FR_UTF8};
  5.5094 + ! defined $mb_locale || $mb_locale eq 'none'
  5.5095 +   and $mb_locale = 'C';
  5.5096 + 
  5.5097 ++my $try = "Try \`$prog --help' for more information.\n";
  5.5098 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.5099 ++
  5.5100 + # Since each test is run with a file name and with redirected stdin,
  5.5101 + # the name in the diagnostic is either the file name or "-".
  5.5102 + # Normalize each diagnostic to use '-'.
  5.5103 +@@ -423,6 +428,38 @@ foreach my $t (@Tests)
  5.5104 +       }
  5.5105 +   }
  5.5106 + 
  5.5107 ++if ($mb_locale ne 'C')
  5.5108 ++   {
  5.5109 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.5110 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.5111 ++    # provide coverage for the distro-added multi-byte code paths.
  5.5112 ++    my @new;
  5.5113 ++    foreach my $t (@Tests)
  5.5114 ++       {
  5.5115 ++        my @new_t = @$t;
  5.5116 ++        my $test_name = shift @new_t;
  5.5117 ++
  5.5118 ++        # Depending on whether sort is multi-byte-patched,
  5.5119 ++        # it emits different diagnostics:
  5.5120 ++        #   non-MB: invalid byte or field list
  5.5121 ++        #   MB:     invalid byte, character or field list
  5.5122 ++        # Adjust the expected error output accordingly.
  5.5123 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.5124 ++            (@new_t))
  5.5125 ++          {
  5.5126 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.5127 ++            push @new_t, $sub;
  5.5128 ++            push @$t, $sub;
  5.5129 ++          }
  5.5130 ++        #disable several failing tests until investigation, disable all tests with envvars set
  5.5131 ++        next if (grep {ref $_ eq 'HASH' && exists $_->{ENV}} (@new_t));
  5.5132 ++        next if ($test_name =~ "18g" or $test_name =~ "sort-numeric" or $test_name =~ "08[ab]" or $test_name =~ "03[def]" or $test_name =~ "h4" or $test_name =~ "n1" or $test_name =~ "2[01]a");
  5.5133 ++        next if ($test_name =~ "11[ab]"); # avoid FP: expected result differs to MB result due to collation rules.
  5.5134 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.5135 ++       }
  5.5136 ++    push @Tests, @new;
  5.5137 ++   }
  5.5138 ++
  5.5139 + @Tests = triple_test \@Tests;
  5.5140 + 
  5.5141 + # Remember that triple_test creates from each test with exactly one "IN"
  5.5142 +@@ -432,6 +469,7 @@ foreach my $t (@Tests)
  5.5143 + # Remove the IN_PIPE version of the "output-is-input" test above.
  5.5144 + # The others aren't susceptible because they have three inputs each.
  5.5145 + @Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  5.5146 ++@Tests = grep {$_->[0] ne 'output-is-input-mb.p'} @Tests;
  5.5147 + 
  5.5148 + my $save_temps = $ENV{DEBUG};
  5.5149 + my $verbose = $ENV{VERBOSE};
  5.5150 +diff -Naurp coreutils-8.27-orig/tests/misc/unexpand.pl coreutils-8.27/tests/misc/unexpand.pl
  5.5151 +--- coreutils-8.27-orig/tests/misc/unexpand.pl	2017-01-01 16:34:24.000000000 -0600
  5.5152 ++++ coreutils-8.27/tests/misc/unexpand.pl	2017-03-11 23:47:13.103285687 -0600
  5.5153 +@@ -27,6 +27,14 @@ my $limits = getlimits ();
  5.5154 + 
  5.5155 + my $prog = 'unexpand';
  5.5156 + 
  5.5157 ++# comment out next line to disable multibyte tests
  5.5158 ++my $mb_locale = $ENV{LOCALE_FR_UTF8};
  5.5159 ++! defined $mb_locale || $mb_locale eq 'none'
  5.5160 ++ and $mb_locale = 'C';
  5.5161 ++
  5.5162 ++my $try = "Try \`$prog --help' for more information.\n";
  5.5163 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.5164 ++
  5.5165 + my @Tests =
  5.5166 +     (
  5.5167 +      ['a1', {IN=> ' 'x 1 ."y\n"}, {OUT=> ' 'x 1 ."y\n"}],
  5.5168 +@@ -128,6 +136,37 @@ my @Tests =
  5.5169 +      ['ts2', '-t5,8', {IN=>"x\t \t y\n"},    {OUT=>"x\t\t y\n"}],
  5.5170 +     );
  5.5171 + 
  5.5172 ++if ($mb_locale ne 'C')
  5.5173 ++  {
  5.5174 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.5175 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.5176 ++    # provide coverage for the distro-added multi-byte code paths.
  5.5177 ++    my @new;
  5.5178 ++    foreach my $t (@Tests)
  5.5179 ++      {
  5.5180 ++        my @new_t = @$t;
  5.5181 ++        my $test_name = shift @new_t;
  5.5182 ++
  5.5183 ++        # Depending on whether unexpand is multi-byte-patched,
  5.5184 ++        # it emits different diagnostics:
  5.5185 ++        #   non-MB: invalid byte or field list
  5.5186 ++        #   MB:     invalid byte, character or field list
  5.5187 ++        # Adjust the expected error output accordingly.
  5.5188 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.5189 ++            (@new_t))
  5.5190 ++          {
  5.5191 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.5192 ++            push @new_t, $sub;
  5.5193 ++            push @$t, $sub;
  5.5194 ++          }
  5.5195 ++        next if ($test_name =~ 'b-1');
  5.5196 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.5197 ++      }
  5.5198 ++    push @Tests, @new;
  5.5199 ++  }
  5.5200 ++
  5.5201 ++@Tests = triple_test \@Tests;
  5.5202 ++
  5.5203 + my $save_temps = $ENV{DEBUG};
  5.5204 + my $verbose = $ENV{VERBOSE};
  5.5205 + 
  5.5206 +diff -Naurp coreutils-8.27-orig/tests/misc/uniq.pl coreutils-8.27/tests/misc/uniq.pl
  5.5207 +--- coreutils-8.27-orig/tests/misc/uniq.pl	2017-01-01 16:34:24.000000000 -0600
  5.5208 ++++ coreutils-8.27/tests/misc/uniq.pl	2017-03-11 23:47:13.103285687 -0600
  5.5209 +@@ -23,9 +23,17 @@ my $limits = getlimits ();
  5.5210 + my $prog = 'uniq';
  5.5211 + my $try = "Try '$prog --help' for more information.\n";
  5.5212 + 
  5.5213 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.5214 ++
  5.5215 + # Turn off localization of executable's output.
  5.5216 + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
  5.5217 + 
  5.5218 ++my $mb_locale;
  5.5219 ++#Comment out next line to disable multibyte tests
  5.5220 ++$mb_locale = $ENV{LOCALE_FR_UTF8};
  5.5221 ++! defined $mb_locale || $mb_locale eq 'none'
  5.5222 ++  and $mb_locale = 'C';
  5.5223 ++
  5.5224 + # When possible, create a "-z"-testing variant of each test.
  5.5225 + sub add_z_variants($)
  5.5226 + {
  5.5227 +@@ -262,6 +270,53 @@ foreach my $t (@Tests)
  5.5228 +       and push @$t, {ENV=>'_POSIX2_VERSION=199209'};
  5.5229 +   }
  5.5230 + 
  5.5231 ++if ($mb_locale ne 'C')
  5.5232 ++  {
  5.5233 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.5234 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.5235 ++    # provide coverage for the distro-added multi-byte code paths.
  5.5236 ++    my @new;
  5.5237 ++    foreach my $t (@Tests)
  5.5238 ++      {
  5.5239 ++        my @new_t = @$t;
  5.5240 ++        my $test_name = shift @new_t;
  5.5241 ++
  5.5242 ++        # Depending on whether uniq is multi-byte-patched,
  5.5243 ++        # it emits different diagnostics:
  5.5244 ++        #   non-MB: invalid byte or field list
  5.5245 ++        #   MB:     invalid byte, character or field list
  5.5246 ++        # Adjust the expected error output accordingly.
  5.5247 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.5248 ++            (@new_t))
  5.5249 ++          {
  5.5250 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.5251 ++            push @new_t, $sub;
  5.5252 ++            push @$t, $sub;
  5.5253 ++          }
  5.5254 ++        # In test #145, replace the each ‘...’ by '...'.
  5.5255 ++        if ($test_name =~ "145")
  5.5256 ++          {
  5.5257 ++            my $sub = { ERR_SUBST => "s/‘([^’]+)’/'\$1'/g"};
  5.5258 ++            push @new_t, $sub;
  5.5259 ++            push @$t, $sub;
  5.5260 ++          }
  5.5261 ++        next if (   $test_name =~ "schar"
  5.5262 ++                 or $test_name =~ "^obs-plus"
  5.5263 ++                 or $test_name =~ "119");
  5.5264 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.5265 ++      }
  5.5266 ++    push @Tests, @new;
  5.5267 ++   }
  5.5268 ++
  5.5269 ++# Remember that triple_test creates from each test with exactly one "IN"
  5.5270 ++# file two more tests (.p and .r suffix on name) corresponding to reading
  5.5271 ++# input from a file and from a pipe.  The pipe-reading test would fail
  5.5272 ++# due to a race condition about 1 in 20 times.
  5.5273 ++# Remove the IN_PIPE version of the "output-is-input" test above.
  5.5274 ++# The others aren't susceptible because they have three inputs each.
  5.5275 ++
  5.5276 ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  5.5277 ++
  5.5278 + @Tests = add_z_variants \@Tests;
  5.5279 + @Tests = triple_test \@Tests;
  5.5280 + 
  5.5281 +diff -Naurp coreutils-8.27-orig/tests/pr/pr-tests.pl coreutils-8.27/tests/pr/pr-tests.pl
  5.5282 +--- coreutils-8.27-orig/tests/pr/pr-tests.pl	2017-01-01 16:34:24.000000000 -0600
  5.5283 ++++ coreutils-8.27/tests/pr/pr-tests.pl	2017-03-11 23:47:13.103285687 -0600
  5.5284 +@@ -24,6 +24,15 @@ use strict;
  5.5285 + my $prog = 'pr';
  5.5286 + my $normalize_strerror = "s/': .*/'/";
  5.5287 + 
  5.5288 ++my $mb_locale;
  5.5289 ++#Uncomment the following line to enable multibyte tests
  5.5290 ++$mb_locale = $ENV{LOCALE_FR_UTF8};
  5.5291 ++! defined $mb_locale || $mb_locale eq 'none'
  5.5292 ++  and $mb_locale = 'C';
  5.5293 ++
  5.5294 ++my $try = "Try \`$prog --help' for more information.\n";
  5.5295 ++my $inval = "$prog: invalid byte, character or field list\n$try";
  5.5296 ++
  5.5297 + my @tv = (
  5.5298 + 
  5.5299 + # -b option is no longer an official option. But it's still working to
  5.5300 +@@ -474,8 +483,48 @@ push @Tests,
  5.5301 +     {IN=>{2=>"a\n"}},
  5.5302 +      {OUT=>"a\t\t\t\t  \t\t\ta\n"} ];
  5.5303 + 
  5.5304 ++# Add _POSIX2_VERSION=199209 to the environment of each test
  5.5305 ++# that uses an old-style option like +1.
  5.5306 ++if ($mb_locale ne 'C')
  5.5307 ++  {
  5.5308 ++    # Duplicate each test vector, appending "-mb" to the test name and
  5.5309 ++    # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
  5.5310 ++    # provide coverage for the distro-added multi-byte code paths.
  5.5311 ++    my @new;
  5.5312 ++    foreach my $t (@Tests)
  5.5313 ++      {
  5.5314 ++        my @new_t = @$t;
  5.5315 ++        my $test_name = shift @new_t;
  5.5316 ++
  5.5317 ++        # Depending on whether pr is multi-byte-patched,
  5.5318 ++        # it emits different diagnostics:
  5.5319 ++        #   non-MB: invalid byte or field list
  5.5320 ++        #   MB:     invalid byte, character or field list
  5.5321 ++        # Adjust the expected error output accordingly.
  5.5322 ++        if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval}
  5.5323 ++            (@new_t))
  5.5324 ++          {
  5.5325 ++            my $sub = {ERR_SUBST => 's/, character//'};
  5.5326 ++            push @new_t, $sub;
  5.5327 ++            push @$t, $sub;
  5.5328 ++          }
  5.5329 ++        #temporarily skip some failing tests
  5.5330 ++        next if ($test_name =~ "col-0" or $test_name =~ "col-inval" or $test_name =~ "asan1");
  5.5331 ++        push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
  5.5332 ++      }
  5.5333 ++    push @Tests, @new;
  5.5334 ++  }
  5.5335 ++
  5.5336 + @Tests = triple_test \@Tests;
  5.5337 + 
  5.5338 ++# Remember that triple_test creates from each test with exactly one "IN"
  5.5339 ++# file two more tests (.p and .r suffix on name) corresponding to reading
  5.5340 ++# input from a file and from a pipe.  The pipe-reading test would fail
  5.5341 ++# due to a race condition about 1 in 20 times.
  5.5342 ++# Remove the IN_PIPE version of the "output-is-input" test above.
  5.5343 ++# The others aren't susceptible because they have three inputs each.
  5.5344 ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests;
  5.5345 ++
  5.5346 + my $save_temps = $ENV{DEBUG};
  5.5347 + my $verbose = $ENV{VERBOSE};
  5.5348 + 
  5.5349 +diff -Naurp coreutils-8.27-orig/tests/unexpand/mb.sh coreutils-8.27/tests/unexpand/mb.sh
  5.5350 +--- coreutils-8.27-orig/tests/unexpand/mb.sh	1969-12-31 18:00:00.000000000 -0600
  5.5351 ++++ coreutils-8.27/tests/unexpand/mb.sh	2017-03-11 23:49:06.759133489 -0600
  5.5352 +@@ -0,0 +1,172 @@
  5.5353 ++#!/bin/sh
  5.5354 ++
  5.5355 ++# Copyright (C) 2012-2017 Free Software Foundation, Inc.
  5.5356 ++
  5.5357 ++# This program is free software: you can redistribute it and/or modify
  5.5358 ++# it under the terms of the GNU General Public License as published by
  5.5359 ++# the Free Software Foundation, either version 3 of the License, or
  5.5360 ++# (at your option) any later version.
  5.5361 ++
  5.5362 ++# This program is distributed in the hope that it will be useful,
  5.5363 ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
  5.5364 ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  5.5365 ++# GNU General Public License for more details.
  5.5366 ++
  5.5367 ++# You should have received a copy of the GNU General Public License
  5.5368 ++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
  5.5369 ++
  5.5370 ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
  5.5371 ++print_ver_ unexpand
  5.5372 ++
  5.5373 ++export LC_ALL=en_US.UTF-8
  5.5374 ++
  5.5375 ++#input containing multibyte characters
  5.5376 ++cat > in <<\EOF
  5.5377 ++1234567812345678123456781
  5.5378 ++.       .       .       .
  5.5379 ++a       b       c       d
  5.5380 ++.       .       .       .
  5.5381 ++ä       ö       ü       ß
  5.5382 ++.       .       .       .
  5.5383 ++   äöü  .    öüä.       ä xx
  5.5384 ++EOF
  5.5385 ++
  5.5386 ++cat > exp <<\EOF
  5.5387 ++1234567812345678123456781
  5.5388 ++.	.	.	.
  5.5389 ++a	b	c	d
  5.5390 ++.	.	.	.
  5.5391 ++ä	ö	ü	ß
  5.5392 ++.	.	.	.
  5.5393 ++   äöü	.    öüä.	ä xx
  5.5394 ++EOF
  5.5395 ++
  5.5396 ++unexpand -a < in > out || fail=1
  5.5397 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5398 ++
  5.5399 ++
  5.5400 ++#multiple files as an input
  5.5401 ++cat >> exp <<\EOF
  5.5402 ++1234567812345678123456781
  5.5403 ++.	.	.	.
  5.5404 ++a	b	c	d
  5.5405 ++.	.	.	.
  5.5406 ++ä	ö	ü	ß
  5.5407 ++.	.	.	.
  5.5408 ++   äöü	.    öüä.	ä xx
  5.5409 ++EOF
  5.5410 ++
  5.5411 ++
  5.5412 ++unexpand -a ./in ./in > out || fail=1
  5.5413 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5414 ++
  5.5415 ++#test characters with a display width larger than 1
  5.5416 ++
  5.5417 ++env printf '12345678
  5.5418 ++e       |ascii(1)
  5.5419 ++\u00E9       |composed(1)
  5.5420 ++e\u0301       |decomposed(1)
  5.5421 ++\u3000      |ideo-space(2)
  5.5422 ++\uFF0D      |full-hypen(2)
  5.5423 ++' > in || framework_failure_
  5.5424 ++
  5.5425 ++env printf '12345678
  5.5426 ++e\t|ascii(1)
  5.5427 ++\u00E9\t|composed(1)
  5.5428 ++e\u0301\t|decomposed(1)
  5.5429 ++\u3000\t|ideo-space(2)
  5.5430 ++\uFF0D\t|full-hypen(2)
  5.5431 ++' > exp || framework_failure_
  5.5432 ++
  5.5433 ++unexpand -a < in > out || fail=1
  5.5434 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5435 ++
  5.5436 ++#test input where a blank of width > 1 is not being substituted
  5.5437 ++in="$(LC_ALL=en_US.UTF-8 printf ' \u3000  ö       ü       ß')"
  5.5438 ++exp='    ö	     ü	     ß'
  5.5439 ++
  5.5440 ++unexpand -a < in > out || fail=1
  5.5441 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5442 ++
  5.5443 ++#non-Unicode characters interspersed between Unicode ones
  5.5444 ++env printf '12345678
  5.5445 ++        \xFF|
  5.5446 ++\xFF       |
  5.5447 ++        \xFFä|
  5.5448 ++ä\xFF      |
  5.5449 ++        ä\xFF|
  5.5450 ++\xFF       ä|
  5.5451 ++äbcdef\xFF |
  5.5452 ++' > in || framework_failure_
  5.5453 ++
  5.5454 ++env printf '12345678
  5.5455 ++\t\xFF|
  5.5456 ++\xFF\t|
  5.5457 ++\t\xFFä|
  5.5458 ++ä\xFF\t|
  5.5459 ++\tä\xFF|
  5.5460 ++\xFF\tä|
  5.5461 ++äbcdef\xFF\t|
  5.5462 ++' > exp || framework_failure_
  5.5463 ++
  5.5464 ++unexpand -a < in > out || fail=1
  5.5465 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5466 ++
  5.5467 ++#BOM header test 1
  5.5468 ++printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_
  5.5469 ++1234567812345678123456781
  5.5470 ++.       .       .       .
  5.5471 ++a       b       c       d
  5.5472 ++.       .       .       .
  5.5473 ++ä       ö       ü       ß
  5.5474 ++.       .       .       .
  5.5475 ++   äöü  .    öüä.       ä xx
  5.5476 ++EOF
  5.5477 ++env printf '   äöü\t.    öüä.   \tä xx\n' >> in || framework_failure_
  5.5478 ++
  5.5479 ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
  5.5480 ++1234567812345678123456781
  5.5481 ++.	.	.	.
  5.5482 ++a	b	c	d
  5.5483 ++.	.	.	.
  5.5484 ++ä	ö	ü	ß
  5.5485 ++.	.	.	.
  5.5486 ++   äöü	.    öüä.	ä xx
  5.5487 ++EOF
  5.5488 ++
  5.5489 ++unexpand < in > out || fail=1
  5.5490 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5491 ++
  5.5492 ++LANG=C unexpand < in > out || fail=1
  5.5493 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5494 ++
  5.5495 ++LC_ALL=C unexpand < in > out || fail=1
  5.5496 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5497 ++
  5.5498 ++
  5.5499 ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_
  5.5500 ++1234567812345678123456781
  5.5501 ++.	.	.	.
  5.5502 ++a	b	c	d
  5.5503 ++.	.	.	.
  5.5504 ++ä	ö	ü	ß
  5.5505 ++.	.	.	.
  5.5506 ++   äöü	.    öüä.	ä xx
  5.5507 ++1234567812345678123456781
  5.5508 ++.	.	.	.
  5.5509 ++a	b	c	d
  5.5510 ++.	.	.	.
  5.5511 ++ä	ö	ü	ß
  5.5512 ++.	.	.	.
  5.5513 ++   äöü	.    öüä.	ä xx
  5.5514 ++EOF
  5.5515 ++
  5.5516 ++
  5.5517 ++unexpand in in > out || fail=1
  5.5518 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5519 ++
  5.5520 ++LANG=C unexpand in in > out || fail=1
  5.5521 ++compare exp out > /dev/null 2>&1 || fail=1
  5.5522 ++
  5.5523 ++LC_ALL=C unexpand in in > out || fail=1
  5.5524 ++compare exp out > /dev/null 2>&1 || fail=1
     6.1 --- a/coreutils/stuff/patches/series	Mon Jul 30 23:44:42 2018 +0300
     6.2 +++ b/coreutils/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
     6.3 @@ -1,5 +1,5 @@
     6.4  # LFS: Coreutils Internationalization Fixes Patch
     6.5 -#coreutils-8.29-i18n-1.patch
     6.6 +#coreutils-8.30-i18n-1.patch
     6.7  
     6.8  # SliTaz: show extended info touching CPU via uname
     6.9  uname.u
     7.1 --- a/expect/receipt	Mon Jul 30 23:44:42 2018 +0300
     7.2 +++ b/expect/receipt	Tue Aug 07 00:30:45 2018 +0300
     7.3 @@ -1,7 +1,7 @@
     7.4  # SliTaz package receipt v2.
     7.5  
     7.6  PACKAGE="expect"
     7.7 -VERSION="5.45"
     7.8 +VERSION="5.45.4"
     7.9  CATEGORY="utilities"
    7.10  SHORT_DESC="A tool for automating interactive applications"
    7.11  MAINTAINER="samuel_trassare@yahoo.com"
    7.12 @@ -9,14 +9,16 @@
    7.13  WEB_SITE="http://expect.sourceforge.net"
    7.14  
    7.15  TARBALL="$PACKAGE$VERSION.tar.gz"
    7.16 -WGET_URL="http://sourceforge.net/projects/$PACKAGE/files/Expect/$VERSION/$TARBALL"
    7.17 +WGET_URL="$SF_MIRROR/$PACKAGE/$TARBALL"
    7.18  
    7.19  BUILD_DEPENDS="tcl-dev"
    7.20  COOKOPTS="!skip-log-errors" # for:
    7.21  # chmod: cannot access './install-sh': No such file or directory
    7.22  
    7.23  compile_rules() {
    7.24 -	./configure $CONFIGURE_ARGS && make && make DESTDIR=$DESTDIR install
    7.25 +	./configure $CONFIGURE_ARGS &&
    7.26 +	make &&
    7.27 +	make DESTDIR=$DESTDIR install
    7.28  }
    7.29  
    7.30  genpkg_rules() {
     8.1 --- a/file/receipt	Mon Jul 30 23:44:42 2018 +0300
     8.2 +++ b/file/receipt	Tue Aug 07 00:30:45 2018 +0300
     8.3 @@ -1,7 +1,7 @@
     8.4  # SliTaz package receipt v2.
     8.5  
     8.6  PACKAGE="file"
     8.7 -VERSION="5.33"
     8.8 +VERSION="5.34"
     8.9  CATEGORY="system-tools"
    8.10  SHORT_DESC="Determines file type using 'magic' numbers"
    8.11  MAINTAINER="erjo@slitaz.org"
     9.1 --- a/fribidi/receipt	Mon Jul 30 23:44:42 2018 +0300
     9.2 +++ b/fribidi/receipt	Tue Aug 07 00:30:45 2018 +0300
     9.3 @@ -1,13 +1,13 @@
     9.4  # SliTaz package receipt v2.
     9.5  
     9.6  PACKAGE="fribidi"
     9.7 -VERSION="1.0.1"
     9.8 +VERSION="1.0.5"
     9.9  CATEGORY="x-window"
    9.10  SHORT_DESC="Implementation of the Unicode Bidirectional Algorithm"
    9.11  MAINTAINER="pankso@slitaz.org"
    9.12  LICENSE="LGPL2.1"
    9.13  WEB_SITE="https://github.com/fribidi/fribidi/"
    9.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/fribidi.html"
    9.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/fribidi.html"
    9.16  
    9.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
    9.18  WGET_URL="https://github.com/fribidi/fribidi/releases/download/v$VERSION/$TARBALL"
    10.1 --- a/gdbm/receipt	Mon Jul 30 23:44:42 2018 +0300
    10.2 +++ b/gdbm/receipt	Tue Aug 07 00:30:45 2018 +0300
    10.3 @@ -1,13 +1,13 @@
    10.4  # SliTaz package receipt v2.
    10.5  
    10.6  PACKAGE="gdbm"
    10.7 -VERSION="1.13"
    10.8 +VERSION="1.16"
    10.9  CATEGORY="misc"
   10.10  SHORT_DESC="GNU database manager"
   10.11  MAINTAINER="pascal.bellard@slitaz.org"
   10.12  LICENSE="GPL3"
   10.13  WEB_SITE="https://www.gnu.org/software/gdbm"
   10.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/gdbm.html"
   10.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/gdbm.html"
   10.16  
   10.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   10.18  WGET_URL="$GNU_MIRROR/$PACKAGE/$TARBALL"
    11.1 --- a/gzip/receipt	Mon Jul 30 23:44:42 2018 +0300
    11.2 +++ b/gzip/receipt	Tue Aug 07 00:30:45 2018 +0300
    11.3 @@ -1,13 +1,13 @@
    11.4  # SliTaz package receipt v2.
    11.5  
    11.6  PACKAGE="gzip"
    11.7 -VERSION="1.8"
    11.8 +VERSION="1.9"
    11.9  CATEGORY="system-tools"
   11.10  SHORT_DESC="GNU compression utilities"
   11.11  MAINTAINER="erjo@slitaz.org"
   11.12  LICENSE="GPL3"
   11.13  WEB_SITE="https://www.gnu.org/software/gzip/"
   11.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/gzip.html"
   11.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/gzip.html"
   11.16  HOST_ARCH="i486 x86_64"
   11.17  
   11.18  TARBALL="$PACKAGE-$VERSION.tar.xz"
   11.19 @@ -17,7 +17,9 @@
   11.20  SPLIT="gzip-full"
   11.21  
   11.22  compile_rules() {
   11.23 -	./configure $CONFIGURE_ARGS && make && make install
   11.24 +	./configure $CONFIGURE_ARGS &&
   11.25 +	make &&
   11.26 +	make install || return 1
   11.27  
   11.28  	mkdir -p $install/bin
   11.29  	mv -v $install/usr/bin/gzip $install/bin
    12.1 --- a/harfbuzz/receipt	Mon Jul 30 23:44:42 2018 +0300
    12.2 +++ b/harfbuzz/receipt	Tue Aug 07 00:30:45 2018 +0300
    12.3 @@ -1,18 +1,19 @@
    12.4  # SliTaz package receipt v2.
    12.5  
    12.6  PACKAGE="harfbuzz"
    12.7 -VERSION="1.7.5"
    12.8 +VERSION="1.8.4"
    12.9  CATEGORY="system-tools"
   12.10  SHORT_DESC="OpenType text shaping engine"
   12.11  MAINTAINER="pankso@slitaz.org"
   12.12  LICENSE="GPL2"
   12.13  WEB_SITE="https://www.freedesktop.org/wiki/Software/HarfBuzz/"
   12.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/harfbuzz.html"
   12.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/harfbuzz.html"
   12.16  
   12.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   12.18  WGET_URL="https://www.freedesktop.org/software/harfbuzz/release/$TARBALL"
   12.19  
   12.20 -BUILD_DEPENDS="glib-dev cairo-dev freetype-dev fontconfig-dev icu-dev"
   12.21 +BUILD_DEPENDS="glib-dev gobject-introspection-dev cairo-dev freetype-dev \
   12.22 +fontconfig-dev icu-dev"
   12.23  SPLIT="libharfbuzz libharfbuzz-icu harfbuzz-icu-dev harfbuzz-dev"
   12.24  
   12.25  compile_rules() {
   12.26 @@ -37,7 +38,7 @@
   12.27  			DEPENDS="cairo freetype glib libharfbuzz"
   12.28  			;;
   12.29  		libharfbuzz)
   12.30 -			copy libharfbuzz.so* libharfbuzz-gobject.so*
   12.31 +			copy libharfbuzz.so* libharfbuzz-gobject.so* libharfbuzz-subset.so*
   12.32  			CAT="libs|shared library"
   12.33  			DEPENDS="freetype glib"
   12.34  			;;
    13.1 --- a/hicolor-icon-theme/receipt	Mon Jul 30 23:44:42 2018 +0300
    13.2 +++ b/hicolor-icon-theme/receipt	Tue Aug 07 00:30:45 2018 +0300
    13.3 @@ -1,7 +1,7 @@
    13.4  # SliTaz package receipt v2.
    13.5  
    13.6  PACKAGE="hicolor-icon-theme"
    13.7 -VERSION="0.15"
    13.8 +VERSION="0.17"
    13.9  CATEGORY="misc"
   13.10  SHORT_DESC="Icon theme that all icon themes automatically inherit from"
   13.11  MAINTAINER="pankso@slitaz.org"
   13.12 @@ -11,14 +11,12 @@
   13.13  TARBALL="$PACKAGE-$VERSION.tar.xz"
   13.14  WGET_URL="https://icon-theme.freedesktop.org/releases/$TARBALL"
   13.15  
   13.16 -# Rules to configure and make the package.
   13.17 -compile_rules()
   13.18 -{
   13.19 -	./configure $CONFIGURE_ARGS && make && make install
   13.20 +compile_rules() {
   13.21 +	./configure $CONFIGURE_ARGS &&
   13.22 +	make &&
   13.23 +	make install
   13.24  }
   13.25  
   13.26 -# Rules to gen a SliTaz package suitable for Tazpkg.
   13.27 -genpkg_rules()
   13.28 -{
   13.29 +genpkg_rules() {
   13.30  	copy index.theme 16x16/
   13.31  }
    14.1 --- a/imlib2/receipt	Mon Jul 30 23:44:42 2018 +0300
    14.2 +++ b/imlib2/receipt	Tue Aug 07 00:30:45 2018 +0300
    14.3 @@ -1,7 +1,7 @@
    14.4  # SliTaz package receipt v2.
    14.5  
    14.6  PACKAGE="imlib2"
    14.7 -VERSION="1.4.9"
    14.8 +VERSION="1.5.1"
    14.9  CATEGORY="graphics"
   14.10  SHORT_DESC="Imlib2 graphic library"
   14.11  MAINTAINER="pankso@slitaz.org"
   14.12 @@ -23,7 +23,8 @@
   14.13  		--disable-static \
   14.14  		$CONFIGURE_ARGS &&
   14.15  	fix libtool &&
   14.16 -	make && make install || return 1
   14.17 +	make &&
   14.18 +	make install || return 1
   14.19  
   14.20  	cook_pick_docs doc/*.gif doc/index.html
   14.21  }
    15.1 Binary file intel-microcode/.icon.png has changed
    16.1 --- a/intel-microcode/receipt	Mon Jul 30 23:44:42 2018 +0300
    16.2 +++ b/intel-microcode/receipt	Tue Aug 07 00:30:45 2018 +0300
    16.3 @@ -1,7 +1,7 @@
    16.4  # SliTaz package receipt v2.
    16.5  
    16.6  PACKAGE="intel-microcode"
    16.7 -VERSION="20180312"
    16.8 +VERSION="20180703"; DL_ID="27945"
    16.9  CATEGORY="kernel"
   16.10  SHORT_DESC="Intel processor microcode update for Linux"
   16.11  MAINTAINER="al.bobylev@gmail.com"
   16.12 @@ -13,19 +13,19 @@
   16.13  # http://linuxfromscratch.org/blfs/view/svn/postlfs/firmware.html#early-microcode
   16.14  
   16.15  TARBALL="$PACKAGE-$VERSION.tgz"
   16.16 -WGET_URL="https://downloadmirror.intel.com/27591/eng/microcode-$VERSION.tgz"
   16.17 -TARBALL_MD5="be315cd99a7ca392a2f917ceacbe14f2"
   16.18 +WGET_URL="https://downloadmirror.intel.com/$DL_ID/eng/microcode-$VERSION.tgz"
   16.19 +TARBALL_MD5="873f2bdd7c0edf317f416f54fee74b42"
   16.20 +
   16.21 +BUILD_DEPENDS="iucode-tool"
   16.22  SPLIT="intel-microcode-initrd"
   16.23  
   16.24  compile_rules() {
   16.25  	mkdir -p $install/lib/firmware/
   16.26  	cp -r $src/intel-ucode/ $install/lib/firmware/
   16.27  
   16.28 -	gcc -Wall $CFLAGS -o intel-microcode2ucode $stuff/intel-microcode2ucode.c
   16.29 -	./intel-microcode2ucode ./microcode.dat
   16.30  	mkdir -p $install/boot
   16.31  	mkdir -p kernel/x86/microcode
   16.32 -	mv microcode.bin kernel/x86/microcode/GenuineIntel.bin
   16.33 +	iucode_tool -w kernel/x86/microcode/GenuineIntel.bin intel-ucode/ intel-ucode-with-caveats/
   16.34  	echo kernel/x86/microcode/GenuineIntel.bin \
   16.35  	| cpio -o -H newc \
   16.36  	> $install/boot/intel-ucode.img
    17.1 --- a/intel-microcode/stuff/intel-microcode2ucode.c	Mon Jul 30 23:44:42 2018 +0300
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,156 +0,0 @@
    17.4 -/*
    17.5 - * Convert Intel microcode.dat into a single binary microcode.bin file
    17.6 - *
    17.7 - * Based on code by Kay Sievers <kay.sievers@vrfy.org>
    17.8 - * Changed to create a single file by Thomas Bächler <thomas@archlinux.org>
    17.9 - */
   17.10 -
   17.11 -
   17.12 -#ifndef _GNU_SOURCE
   17.13 -# define _GNU_SOURCE 1
   17.14 -#endif
   17.15 -
   17.16 -#include <stdio.h>
   17.17 -#include <unistd.h>
   17.18 -#include <stdlib.h>
   17.19 -#include <string.h>
   17.20 -#include <time.h>
   17.21 -#include <limits.h>
   17.22 -#include <stdbool.h>
   17.23 -#include <inttypes.h>
   17.24 -#include <fcntl.h>
   17.25 -#include <errno.h>
   17.26 -#include <sys/stat.h>
   17.27 -
   17.28 -struct microcode_header_intel {
   17.29 -	unsigned int hdrver;
   17.30 -	unsigned int rev;
   17.31 -	unsigned int date;
   17.32 -	unsigned int sig;
   17.33 -	unsigned int cksum;
   17.34 -	unsigned int ldrver;
   17.35 -	unsigned int pf;
   17.36 -	unsigned int datasize;
   17.37 -	unsigned int totalsize;
   17.38 -	unsigned int reserved[3];
   17.39 -};
   17.40 -
   17.41 -union mcbuf {
   17.42 -	struct microcode_header_intel hdr;
   17.43 -	unsigned int i[0];
   17.44 -	char c[0];
   17.45 -};
   17.46 -
   17.47 -int main(int argc, char *argv[])
   17.48 -{
   17.49 -	const char *filename = "/lib/firmware/microcode.dat";
   17.50 -	FILE *f;
   17.51 -	char line[LINE_MAX];
   17.52 -	char buf[4000000];
   17.53 -	union mcbuf *mc;
   17.54 -	size_t bufsize, count, start;
   17.55 -	int rc = EXIT_SUCCESS;
   17.56 -
   17.57 -	if (argv[1] != NULL)
   17.58 -		filename = argv[1];
   17.59 -
   17.60 -	count = 0;
   17.61 -	mc = (union mcbuf *) buf;
   17.62 -	f = fopen(filename, "re");
   17.63 -	if (f == NULL) {
   17.64 -		printf("open %s: %m\n", filename);
   17.65 -		rc = EXIT_FAILURE;
   17.66 -		goto out;
   17.67 -	}
   17.68 -
   17.69 -	while (fgets(line, sizeof(line), f) != NULL) {
   17.70 -		if (sscanf(line, "%x, %x, %x, %x",
   17.71 -		    &mc->i[count],
   17.72 -		    &mc->i[count + 1],
   17.73 -		    &mc->i[count + 2],
   17.74 -		    &mc->i[count + 3]) != 4)
   17.75 -			continue;
   17.76 -		count += 4;
   17.77 -	}
   17.78 -	fclose(f);
   17.79 -
   17.80 -	bufsize = count * sizeof(int);
   17.81 -	printf("%s: %lu(%luk) bytes, %zu integers\n",
   17.82 -	       filename,
   17.83 -	       bufsize,
   17.84 -	       bufsize / 1024,
   17.85 -	       count);
   17.86 -
   17.87 -	if (bufsize < sizeof(struct microcode_header_intel))
   17.88 -		goto out;
   17.89 -
   17.90 -	f = fopen("microcode.bin", "we");
   17.91 -	if (f == NULL) {
   17.92 -		printf("open microcode.bin: %m\n");
   17.93 -		rc = EXIT_FAILURE;
   17.94 -		goto out;
   17.95 -	}
   17.96 -
   17.97 -	start = 0;
   17.98 -	for (;;) {
   17.99 -		size_t size;
  17.100 -		unsigned int family, model, stepping, type;
  17.101 -		unsigned int year, month, day;
  17.102 -
  17.103 -		mc = (union mcbuf *) &buf[start];
  17.104 -
  17.105 -		if (mc->hdr.totalsize)
  17.106 -			size = mc->hdr.totalsize;
  17.107 -		else
  17.108 -			size = 2000 + sizeof(struct microcode_header_intel);
  17.109 -
  17.110 -		if (mc->hdr.ldrver != 1 || mc->hdr.hdrver != 1) {
  17.111 -			printf("unknown version/format:\n");
  17.112 -			rc = EXIT_FAILURE;
  17.113 -			break;
  17.114 -		}
  17.115 -
  17.116 -		/*
  17.117 -		 *  0- 3 stepping
  17.118 -		 *  4- 7 model
  17.119 -		 *  8-11 family
  17.120 -		 * 12-13 type
  17.121 -		 * 16-19 extended model
  17.122 -		 * 20-27 extended family
  17.123 -		 */
  17.124 -		stepping = mc->hdr.sig & 0x0f;
  17.125 -		model = (mc->hdr.sig >> 4) & 0x0f;
  17.126 -		family = (mc->hdr.sig >> 8) & 0x0f;
  17.127 -		type = (mc->hdr.sig >> 12) & 0x0f;
  17.128 -		if (family == 0x06)
  17.129 -			model += ((mc->hdr.sig >> 16) & 0x0f) << 4;
  17.130 -		if (family == 0x0f)
  17.131 -			family += (mc->hdr.sig >> 20) & 0xff;
  17.132 -
  17.133 -		year = mc->hdr.date & 0xffff;
  17.134 -		month = mc->hdr.date >> 24;
  17.135 -		day = (mc->hdr.date >> 16) & 0xff;
  17.136 -
  17.137 -		printf("\n");
  17.138 -		printf("signature: 0x%02x (stepping %d, model %d, family %d, type %d)\n",
  17.139 -			mc->hdr.sig, stepping, model, family, type);
  17.140 -		printf("flags:     0x%02x\n", mc->hdr.pf);
  17.141 -		printf("revision:  0x%02x\n", mc->hdr.rev);
  17.142 -		printf("date:      %04x-%02x-%02x\n", year, month, day);
  17.143 -		printf("size:      %zu\n", size);
  17.144 -
  17.145 -		if (fwrite(mc, size, 1, f) != 1) {
  17.146 -			printf("write microcode.bin: %m\n");
  17.147 -			rc = EXIT_FAILURE;
  17.148 -			goto out;
  17.149 -		}
  17.150 -
  17.151 -		start += size;
  17.152 -		if (start >= bufsize)
  17.153 -			break;
  17.154 -	}
  17.155 -	fclose(f);
  17.156 -	printf("\n");
  17.157 -out:
  17.158 -	return rc;
  17.159 -}
    18.1 --- a/iproute2/receipt	Mon Jul 30 23:44:42 2018 +0300
    18.2 +++ b/iproute2/receipt	Tue Aug 07 00:30:45 2018 +0300
    18.3 @@ -1,13 +1,13 @@
    18.4  # SliTaz package receipt v2.
    18.5  
    18.6  PACKAGE="iproute2"
    18.7 -VERSION="4.12.0"
    18.8 +VERSION="4.17.0"
    18.9  CATEGORY="network"
   18.10  SHORT_DESC="Utilites for networking and traffic control"
   18.11  MAINTAINER="allan316@gmail.com"
   18.12  LICENSE="GPL2"
   18.13  WEB_SITE="http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2"
   18.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/iproute2.html"
   18.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/iproute2.html"
   18.16  
   18.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   18.18  WGET_URL="https://www.kernel.org/pub/linux/utils/net/$PACKAGE/$TARBALL"
    19.1 --- a/ipxe/receipt	Mon Jul 30 23:44:42 2018 +0300
    19.2 +++ b/ipxe/receipt	Tue Aug 07 00:30:45 2018 +0300
    19.3 @@ -1,7 +1,8 @@
    19.4  # SliTaz package receipt v2.
    19.5  
    19.6  PACKAGE="ipxe"
    19.7 -VERSION="41f786c"
    19.8 +VERSION="20180708"
    19.9 +COMMIT="d2063b7"
   19.10  CATEGORY="system-tools"
   19.11  SHORT_DESC="Open source network boot firmware"
   19.12  MAINTAINER="pascal.bellard@slitaz.org"
   19.13 @@ -9,7 +10,7 @@
   19.14  WEB_SITE="http://ipxe.org/"
   19.15  
   19.16  TARBALL="$PACKAGE-$VERSION.tar.gz"
   19.17 -WGET_URL="$GITHUB/ipxe/ipxe/tarball/$VERSION"
   19.18 +WGET_URL="$GITHUB/ipxe/ipxe/tarball/$COMMIT"
   19.19  
   19.20  BUILD_DEPENDS="perl xz-dev"
   19.21  SPLIT="ipxe-pxe"
   19.22 @@ -22,13 +23,15 @@
   19.23  		arch/x86/transitions/librm.S
   19.24  
   19.25  	#sed -i 's/^ASFLAGS.*/& -adhlns=$(<:.S=.lst)/' Makefile
   19.26 -	sed -i 's/-llzma/& -lpthread/' Makefile.*
   19.27 -	sed -i 's|//\(#define.*CONSOLE_FRAMEBUFFER\)|\1|' config/console.h
   19.28 -	sed -i 's|//\(#define.*CONSOLE_SERIAL\)|\1|' config/console.h
   19.29 -	sed -i -e 's|//\(#define.*IMAGE_PNG\)|\1|' \
   19.30 -	    -e 's|//\(#define.*CONSOLE_CMD\)|\1|' \
   19.31 -	    -e 's|//\(#define.*REBOOT_CMD\)|\1|' config/general.h
   19.32 -	cp $stuff/lkrnprefix.S arch/i386/prefix
   19.33 +	sed -i 's|-llzma|& -lpthread|' Makefile.*
   19.34 +	sed -i '
   19.35 +		s|//\(#define.*CONSOLE_FRAMEBUFFER\)|\1|;
   19.36 +		s|//\(#define.*CONSOLE_SERIAL\)|\1|' config/console.h
   19.37 +	sed -i '
   19.38 +		s|//\(#define.*IMAGE_PNG\)|\1|;
   19.39 +		s|//\(#define.*CONSOLE_CMD\)|\1|;
   19.40 +		s|//\(#define.*REBOOT_CMD\)|\1|' config/general.h
   19.41 +#	cp $stuff/lkrnprefix.S arch/i386/prefix
   19.42  
   19.43  	# refer to http://ipxe.org/appnote/buildtargets
   19.44  	case $ARCH in
    20.1 --- a/ipxe/stuff/patches/gcc7.patch	Mon Jul 30 23:44:42 2018 +0300
    20.2 +++ b/ipxe/stuff/patches/gcc7.patch	Tue Aug 07 00:30:45 2018 +0300
    20.3 @@ -1,128 +1,6 @@
    20.4 ---- a/src/drivers/net/igbvf/igbvf_vf.c
    20.5 -+++ b/src/drivers/net/igbvf/igbvf_vf.c
    20.6 -@@ -357,8 +357,10 @@
    20.7 - 		break;
    20.8 - 	case e1000_promisc_enabled:
    20.9 - 		msgbuf |= E1000_VF_SET_PROMISC_MULTICAST;
   20.10 -+		/* FALLTHROUGH */
   20.11 - 	case e1000_promisc_unicast:
   20.12 - 		msgbuf |= E1000_VF_SET_PROMISC_UNICAST;
   20.13 -+		/* FALLTHROUGH */
   20.14 - 	case e1000_promisc_disabled:
   20.15 - 		break;
   20.16 - 	default:
   20.17 ---- a/src/drivers/net/ath/ath5k/ath5k_desc.c
   20.18 -+++ b/src/drivers/net/ath/ath5k/ath5k_desc.c
   20.19 -@@ -104,8 +104,10 @@
   20.20 - 		case AR5K_PKT_TYPE_BEACON:
   20.21 - 		case AR5K_PKT_TYPE_PROBE_RESP:
   20.22 - 			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
   20.23 -+			/* FALLTHROUGH */
   20.24 - 		case AR5K_PKT_TYPE_PIFS:
   20.25 - 			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
   20.26 -+			/* FALLTHROUGH */
   20.27 - 		default:
   20.28 - 			frame_type = type /*<< 2 ?*/;
   20.29 - 		}
   20.30 ---- a/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
   20.31 -+++ b/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
   20.32 -@@ -539,6 +539,7 @@
   20.33 - 	case 0x5:
   20.34 - 		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
   20.35 - 			    AR_PHY_SWAP_ALT_CHAIN);
   20.36 -+		/* FALLTHROUGH */
   20.37 - 	case 0x3:
   20.38 - 	case 0x1:
   20.39 - 	case 0x2:
   20.40 ---- a/src/drivers/net/ath/ath9k/ath9k_ar9002_phy.c
   20.41 -+++ b/src/drivers/net/ath/ath9k/ath9k_ar9002_phy.c
   20.42 -@@ -122,6 +122,7 @@
   20.43 - 				aModeRefSel = 2;
   20.44 - 			if (aModeRefSel)
   20.45 - 				break;
   20.46 -+			/* FALLTHROUGH */
   20.47 - 		case 1:
   20.48 - 		default:
   20.49 - 			aModeRefSel = 0;
   20.50 ---- a/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
   20.51 -+++ b/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
   20.52 -@@ -640,12 +640,14 @@
   20.53 - 	case 0x5:
   20.54 - 		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
   20.55 - 			    AR_PHY_SWAP_ALT_CHAIN);
   20.56 -+		/* FALLTHROUGH */
   20.57 - 	case 0x3:
   20.58 - 		if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
   20.59 - 			REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
   20.60 - 			REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
   20.61 - 			break;
   20.62 - 		}
   20.63 -+		/* FALLTHROUGH */
   20.64 - 	case 0x1:
   20.65 - 	case 0x2:
   20.66 - 	case 0x7:
   20.67 ---- a/src/drivers/net/tg3/tg3_hw.c
   20.68 -+++ b/src/drivers/net/tg3/tg3_hw.c
   20.69 -@@ -2518,32 +2518,46 @@
   20.70 - 	switch (limit) {
   20.71 - 	case 16:
   20.72 - 		tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
   20.73 -+		/* FALLTHROUGH */
   20.74 - 	case 15:
   20.75 - 		tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
   20.76 -+		/* FALLTHROUGH */
   20.77 - 	case 14:
   20.78 - 		tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
   20.79 -+		/* FALLTHROUGH */
   20.80 - 	case 13:
   20.81 - 		tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
   20.82 -+		/* FALLTHROUGH */
   20.83 - 	case 12:
   20.84 - 		tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
   20.85 -+		/* FALLTHROUGH */
   20.86 - 	case 11:
   20.87 - 		tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
   20.88 -+		/* FALLTHROUGH */
   20.89 - 	case 10:
   20.90 - 		tw32(MAC_RCV_RULE_9,  0); tw32(MAC_RCV_VALUE_9,  0);
   20.91 -+		/* FALLTHROUGH */
   20.92 - 	case 9:
   20.93 - 		tw32(MAC_RCV_RULE_8,  0); tw32(MAC_RCV_VALUE_8,  0);
   20.94 -+		/* FALLTHROUGH */
   20.95 - 	case 8:
   20.96 - 		tw32(MAC_RCV_RULE_7,  0); tw32(MAC_RCV_VALUE_7,  0);
   20.97 -+		/* FALLTHROUGH */
   20.98 - 	case 7:
   20.99 - 		tw32(MAC_RCV_RULE_6,  0); tw32(MAC_RCV_VALUE_6,  0);
  20.100 -+		/* FALLTHROUGH */
  20.101 - 	case 6:
  20.102 - 		tw32(MAC_RCV_RULE_5,  0); tw32(MAC_RCV_VALUE_5,  0);
  20.103 -+		/* FALLTHROUGH */
  20.104 - 	case 5:
  20.105 - 		tw32(MAC_RCV_RULE_4,  0); tw32(MAC_RCV_VALUE_4,  0);
  20.106 -+		/* FALLTHROUGH */
  20.107 - 	case 4:
  20.108 - 		/* tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0); */
  20.109 -+		/* FALLTHROUGH */
  20.110 - 	case 3:
  20.111 - 		/* tw32(MAC_RCV_RULE_2,  0); tw32(MAC_RCV_VALUE_2,  0); */
  20.112 -+		/* FALLTHROUGH */
  20.113 - 	case 2:
  20.114 - 	case 1:
  20.115 - 
  20.116 ---- a/src/drivers/infiniband/golan.c
  20.117 -+++ b/src/drivers/infiniband/golan.c
  20.118 -@@ -2024,6 +2024,7 @@
  20.119 - 	case GOLAN_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
  20.120 - 	case GOLAN_PORT_CHANGE_SUBTYPE_ACTIVE:
  20.121 - 		golan_ib_update ( ibdev );
  20.122 -+		/* FALLTHROUGH */
  20.123 - 	case GOLAN_PORT_CHANGE_SUBTYPE_DOWN:
  20.124 - 	case GOLAN_PORT_CHANGE_SUBTYPE_LID:
  20.125 - 	case GOLAN_PORT_CHANGE_SUBTYPE_PKEY:
  20.126  --- a/src/tests/setjmp_test.c
  20.127  +++ b/src/tests/setjmp_test.c
  20.128 -@@ -153,12 +153,19 @@
  20.129 +@@ -154,12 +154,19 @@
  20.130   		case 0: setjmp_ok ( &alpha ); break;
  20.131   		case 1: setjmp_ok ( &beta ); break;
  20.132   		case 2:	longjmp_ok ( &alpha, 0 );
  20.133 @@ -142,28 +20,3 @@
  20.134   		case 9: longjmp_ok ( &beta, 42 );
  20.135   		}
  20.136   	}
  20.137 ---- a/src/include/curses.h
  20.138 -+++ b/src/include/curses.h
  20.139 -@@ -443,7 +443,7 @@
  20.140 - extern int wclrtobot ( WINDOW * ) __nonnull;
  20.141 - extern int wclrtoeol ( WINDOW * ) __nonnull;
  20.142 - extern void wcursyncup ( WINDOW * );
  20.143 --extern int wcolour_set ( WINDOW *, short, void * ) __nonnull;
  20.144 -+extern int wcolour_set ( WINDOW *, short, void * );
  20.145 - #define wcolor_set(w,s,v) wcolour_set((w),(s),(v))
  20.146 - extern int wdelch ( WINDOW * ) __nonnull;
  20.147 - extern int wdeleteln ( WINDOW * ) __nonnull;
  20.148 ---- a/src/arch/x86/image/bzimage.c
  20.149 -+++ b/src/arch/x86/image/bzimage.c
  20.150 -@@ -282,9 +282,11 @@
  20.151 - 		case 'G':
  20.152 - 		case 'g':
  20.153 - 			bzimg->mem_limit <<= 10;
  20.154 -+			/* FALLTHROUGH */
  20.155 - 		case 'M':
  20.156 - 		case 'm':
  20.157 - 			bzimg->mem_limit <<= 10;
  20.158 -+			/* FALLTHROUGH */
  20.159 - 		case 'K':
  20.160 - 		case 'k':
  20.161 - 			bzimg->mem_limit <<= 10;
    21.1 --- a/itstool/receipt	Mon Jul 30 23:44:42 2018 +0300
    21.2 +++ b/itstool/receipt	Tue Aug 07 00:30:45 2018 +0300
    21.3 @@ -1,7 +1,7 @@
    21.4  # SliTaz package receipt v2.
    21.5  
    21.6  PACKAGE="itstool"
    21.7 -VERSION="2.0.2"
    21.8 +VERSION="2.0.4"
    21.9  CATEGORY="utilities"
   21.10  SHORT_DESC="ITS-based XML translation tool"
   21.11  MAINTAINER="al.bobylev@gmail.com"
   21.12 @@ -14,7 +14,9 @@
   21.13  BUILD_DEPENDS="libxml2-python"
   21.14  
   21.15  compile_rules() {
   21.16 -	./configure $CONFIGURE_ARGS && make && make install
   21.17 +	./configure $CONFIGURE_ARGS &&
   21.18 +	make &&
   21.19 +	make install
   21.20  }
   21.21  
   21.22  genpkg_rules() {
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/iucode-tool/receipt	Tue Aug 07 00:30:45 2018 +0300
    22.3 @@ -0,0 +1,26 @@
    22.4 +# SliTaz package receipt v2.
    22.5 +
    22.6 +PACKAGE="iucode-tool"
    22.7 +VERSION="2.3.1"
    22.8 +CATEGORY="kernel"
    22.9 +SHORT_DESC="Tool to manipulate Intel(R) i686/X86-64 microcode bundles"
   22.10 +MAINTAINER="al.bobylev@gmail.com"
   22.11 +LICENSE="GPL"
   22.12 +WEB_SITE="https://gitlab.com/iucode-tool/iucode-tool/wikis/home"
   22.13 +
   22.14 +TARBALL="${PACKAGE}_$VERSION.tar.xz"
   22.15 +WGET_URL="https://gitlab.com/iucode-tool/releases/raw/master/$TARBALL"
   22.16 +
   22.17 +compile_rules() {
   22.18 +	./configure \
   22.19 +		--prefix=/usr \
   22.20 +		--sbindir=/usr/bin \
   22.21 +		$CONFIGURE_ARGS &&
   22.22 +	make &&
   22.23 +	make install
   22.24 +}
   22.25 +
   22.26 +genpkg_rules() {
   22.27 +	copy @std
   22.28 +	DEPENDS=""
   22.29 +}
    23.1 --- a/jansson/receipt	Mon Jul 30 23:44:42 2018 +0300
    23.2 +++ b/jansson/receipt	Tue Aug 07 00:30:45 2018 +0300
    23.3 @@ -1,7 +1,7 @@
    23.4  # SliTaz package receipt v2.
    23.5  
    23.6  PACKAGE="jansson"
    23.7 -VERSION="2.10"
    23.8 +VERSION="2.11"
    23.9  CATEGORY="x-window"
   23.10  SHORT_DESC="C library for encoding, decoding and manipulating JSON data"
   23.11  MAINTAINER="pankso@slitaz.org"
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/keybinder/receipt	Tue Aug 07 00:30:45 2018 +0300
    24.3 @@ -0,0 +1,43 @@
    24.4 +# SliTaz package receipt v2.
    24.5 +
    24.6 +PACKAGE="keybinder"
    24.7 +VERSION="0.3.1"
    24.8 +CATEGORY="x-window"
    24.9 +SHORT_DESC="Library for registering global keyboard shortcuts"
   24.10 +MAINTAINER="al.bobylev@gmail.com"
   24.11 +LICENSE="GPL2"
   24.12 +WEB_SITE="https://github.com/kupferlauncher/keybinder"
   24.13 +
   24.14 +TARBALL="$PACKAGE-$VERSION.tar.gz"
   24.15 +WGET_URL="https://github.com/kupferlauncher/keybinder/releases/download/v$VERSION/$TARBALL"
   24.16 +
   24.17 +BUILD_DEPENDS="gtk+-dev gobject-introspection-dev xorg-libXext-dev python-dev \
   24.18 +pygtk-dev pygobject-dev automake autoconf libtool"
   24.19 +SPLIT="keybinder-python keybinder-dev"
   24.20 +
   24.21 +compile_rules() {
   24.22 +	autoreconf -vif &&
   24.23 +	./configure $CONFIGURE_ARGS &&
   24.24 +	fix libtool &&
   24.25 +	make &&
   24.26 +	make install
   24.27 +}
   24.28 +
   24.29 +genpkg_rules() {
   24.30 +	case $PACKAGE in
   24.31 +		keybinder)
   24.32 +			copy libkeybinder.so*
   24.33 +			DEPENDS="glib gtk+ xorg-libX11"
   24.34 +			;;
   24.35 +		keybinder-python)
   24.36 +			copy @std @rm
   24.37 +			CAT="x-window|python bindings"
   24.38 +			DEPENDS="glib keybinder python"
   24.39 +			;;
   24.40 +		*-dev)
   24.41 +			copy @dev
   24.42 +			DEPENDS="keybinder keybinder-python \
   24.43 +			gtk+-dev"
   24.44 +			;;
   24.45 +	esac
   24.46 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/keybinder3/receipt	Tue Aug 07 00:30:45 2018 +0300
    25.3 @@ -0,0 +1,37 @@
    25.4 +# SliTaz package receipt v2.
    25.5 +
    25.6 +PACKAGE="keybinder3"
    25.7 +VERSION="0.3.2"
    25.8 +CATEGORY="x-window"
    25.9 +SHORT_DESC="Library for registering global keyboard shortcuts. GTK+3 version"
   25.10 +MAINTAINER="al.bobylev@gmail.com"
   25.11 +LICENSE="GPL2"
   25.12 +WEB_SITE="https://github.com/kupferlauncher/keybinder"
   25.13 +REPOLOGY="keybinder-3.0"
   25.14 +
   25.15 +TARBALL="$PACKAGE-$VERSION.tar.gz"
   25.16 +WGET_URL="https://github.com/kupferlauncher/keybinder/releases/download/keybinder-3.0-v$VERSION/keybinder-3.0-$VERSION.tar.gz"
   25.17 +
   25.18 +BUILD_DEPENDS="gtk+3-dev gobject-introspection-dev xorg-libXext-dev \
   25.19 +xorg-libXrender-dev"
   25.20 +SPLIT="keybinder3-dev"
   25.21 +
   25.22 +compile_rules() {
   25.23 +	./configure $CONFIGURE_ARGS &&
   25.24 +	fix libtool &&
   25.25 +	make &&
   25.26 +	make install
   25.27 +}
   25.28 +
   25.29 +genpkg_rules() {
   25.30 +	case $PACKAGE in
   25.31 +		keybinder3)
   25.32 +			copy @std
   25.33 +			DEPENDS="glib gtk+3 xorg-libX11"
   25.34 +			;;
   25.35 +		*-dev)
   25.36 +			copy @dev
   25.37 +			DEPENDS="keybinder3 gtk+3-dev"
   25.38 +			;;
   25.39 +	esac
   25.40 +}
    26.1 --- a/libblockdev/receipt	Mon Jul 30 23:44:42 2018 +0300
    26.2 +++ b/libblockdev/receipt	Tue Aug 07 00:30:45 2018 +0300
    26.3 @@ -1,21 +1,21 @@
    26.4  # SliTaz package receipt v2.
    26.5  
    26.6  PACKAGE="libblockdev"
    26.7 -VERSION="2.16"
    26.8 +VERSION="2.18"
    26.9  CATEGORY="libs"
   26.10  SHORT_DESC="A library for manipulating block devices"
   26.11  MAINTAINER="al.bobylev@gmail.com"
   26.12  LICENSE="LGPL2.1"
   26.13  WEB_SITE="https://github.com/storaged-project/libblockdev/"
   26.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libblockdev.html"
   26.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libblockdev.html"
   26.16  
   26.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   26.18  WGET_URL="https://github.com/storaged-project/libblockdev/releases/download/$VERSION-1/$TARBALL"
   26.19  
   26.20 -BUILD_DEPENDS="automake libtool python glib-dev eudev-dev cryptsetup-dev \
   26.21 -nss-dev coreutils-file-special libdevmapper-dev kmod-dev parted-dev \
   26.22 -util-linux-mount-dev util-linux-blkid-dev libbytesize-dev volume_key-dev \
   26.23 -python3"
   26.24 +BUILD_DEPENDS="automake libtool python python3 glib-dev \
   26.25 +gobject-introspection-dev eudev-dev kmod-dev cryptsetup-dev nss-dev \
   26.26 +coreutils-file-special volume_key-dev libdevmapper-dev parted-dev \
   26.27 +util-linux-mount-dev util-linux-blkid-dev libbytesize-dev ndctl-dev yaml-dev"
   26.28  SPLIT="libblockdev-python libblockdev-python3 libblockdev libblockdev-dev"
   26.29  
   26.30  compile_rules() {
   26.31 @@ -44,7 +44,8 @@
   26.32  		libblockdev)
   26.33  			copy @std @rm
   26.34  			DEPENDS="cryptsetup eudev glib kmod libbytesize libdevmapper \
   26.35 -			nss parted util-linux-blkid util-linux-mount volume_key"
   26.36 +			ndctl nss parted util-linux-blkid util-linux-mount util-linux-uuid \
   26.37 +			volume_key yaml"
   26.38  			;;
   26.39  		*-dev)
   26.40  			copy @dev
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/libbluray/description.txt	Tue Aug 07 00:30:45 2018 +0300
    27.3 @@ -0,0 +1,27 @@
    27.4 +`libbluray` is an **open-source** library designed for Blu-Ray Discs playback
    27.5 +for media players, like [VLC](http://www.videolan.org/vlc/) or MPlayer.
    27.6 +
    27.7 +This **research** project is developed by an international team of developers
    27.8 +from [Doom9](http://www.doom9.org/).
    27.9 +
   27.10 +Features
   27.11 +
   27.12 +  * Portability: Currently supported platforms are GNU/Linux, Windows, MacOS X.
   27.13 +    Dependencies are very limited.
   27.14 +  * Freedom: `libbluray` is released under a Free Software license, LGPL,
   27.15 +    ensuring it will stay free.
   27.16 +  * Features: the library integrates navigation, playlist parsing, menus and
   27.17 +    BD-J.
   27.18 +  * Legal: libbluray is DRM-circumvention free, and thus, safe to integrate in
   27.19 +    your software.
   27.20 +  * Fun: libbluray is a fun to hack on project, in its starting phase.
   27.21 +
   27.22 +**NB:** Most commercial Blu-Ray are protected by [AACS](http://www.aacsla.com/)
   27.23 +or [BD+](http://www.bdplusllc.com/) technologies and this library is not enough
   27.24 +to playback those discs.
   27.25 +
   27.26 +People interested in AACS technologies should have a look at
   27.27 +[libaacs](http://www.videolan.org/developers/libaacs.html).
   27.28 +
   27.29 +People interested in BD+ technologies should have a look at
   27.30 +[libbdplus](http://www.videolan.org/developers/libbdplus.html).
    28.1 --- a/libbluray/receipt	Mon Jul 30 23:44:42 2018 +0300
    28.2 +++ b/libbluray/receipt	Tue Aug 07 00:30:45 2018 +0300
    28.3 @@ -1,7 +1,7 @@
    28.4  # SliTaz package receipt v2.
    28.5  
    28.6  PACKAGE="libbluray"
    28.7 -VERSION="1.0.0"
    28.8 +VERSION="1.0.2"
    28.9  CATEGORY="libs"
   28.10  SHORT_DESC="Blu-Ray Discs playback library"
   28.11  MAINTAINER="al.bobylev@gmail.com"
   28.12 @@ -16,7 +16,8 @@
   28.13  
   28.14  compile_rules() {
   28.15  	./configure \
   28.16 -		--disable-bdjava \
   28.17 +		--disable-bdjava-jar \
   28.18 +		--disable-static \
   28.19  		$CONFIGURE_ARGS &&
   28.20  	fix libtool &&
   28.21  	make &&
   28.22 @@ -27,7 +28,7 @@
   28.23  	case $PACKAGE in
   28.24  		libbluray)
   28.25  			copy @std
   28.26 -			DEPENDS="freetype libxml2"
   28.27 +			DEPENDS="fontconfig freetype libxml2"
   28.28  			;;
   28.29  		*-dev)
   28.30  			copy @dev
    29.1 --- a/libbsd/receipt	Mon Jul 30 23:44:42 2018 +0300
    29.2 +++ b/libbsd/receipt	Tue Aug 07 00:30:45 2018 +0300
    29.3 @@ -1,7 +1,7 @@
    29.4  # SliTaz package receipt v2.
    29.5  
    29.6  PACKAGE="libbsd"
    29.7 -VERSION="0.8.6"
    29.8 +VERSION="0.9.1"
    29.9  CATEGORY="development"
   29.10  SHORT_DESC="Provides useful functions commonly found on BSD systems"
   29.11  MAINTAINER="claudinei@slitaz.org"
    30.1 --- a/libbytesize/receipt	Mon Jul 30 23:44:42 2018 +0300
    30.2 +++ b/libbytesize/receipt	Tue Aug 07 00:30:45 2018 +0300
    30.3 @@ -1,13 +1,13 @@
    30.4  # SliTaz package receipt v2.
    30.5  
    30.6  PACKAGE="libbytesize"
    30.7 -VERSION="1.2"
    30.8 +VERSION="1.3"
    30.9  CATEGORY="libs"
   30.10  SHORT_DESC="C class for working with arbitrary big sizes"
   30.11  MAINTAINER="al.bobylev@gmail.com"
   30.12  LICENSE="LGPL2.1"
   30.13  WEB_SITE="https://github.com/storaged-project/libbytesize/"
   30.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libbytesize.html"
   30.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libbytesize.html"
   30.16  
   30.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   30.18  WGET_URL="https://github.com/storaged-project/libbytesize/releases/download/$VERSION/$TARBALL"
    31.1 --- a/libconfig/receipt	Mon Jul 30 23:44:42 2018 +0300
    31.2 +++ b/libconfig/receipt	Tue Aug 07 00:30:45 2018 +0300
    31.3 @@ -1,7 +1,7 @@
    31.4  # SliTaz package receipt v2.
    31.5  
    31.6  PACKAGE="libconfig"
    31.7 -VERSION="1.6"
    31.8 +VERSION="1.7.2"
    31.9  CATEGORY="misc"
   31.10  SHORT_DESC="C/C++ Configuration File Library"
   31.11  MAINTAINER="pascal.bellard@slitaz.org"
   31.12 @@ -11,13 +11,19 @@
   31.13  TARBALL="$PACKAGE-$VERSION.tar.gz"
   31.14  WGET_URL="https://github.com/hyperrealm/libconfig/archive/v$VERSION.tar.gz"
   31.15  
   31.16 -BUILD_DEPENDS="texinfo"
   31.17 +BUILD_DEPENDS="automake libtool texinfo"
   31.18  SPLIT="libconfig-dev"
   31.19  
   31.20  compile_rules() {
   31.21 -	# See: https://github.com/hyperrealm/libconfig/issues/47
   31.22 -	rm lib/scanner.c
   31.23 +#?	# See: https://github.com/hyperrealm/libconfig/issues/47
   31.24 +#	rm lib/scanner.c
   31.25  
   31.26 +#	mkdir build
   31.27 +#	cd    build
   31.28 +#	cmake .. &&
   31.29 +#
   31.30 +#
   31.31 +	autoreconf -vi &&
   31.32  	./configure $CONFIGURE_ARGS &&
   31.33  	fix libtool &&
   31.34  	make &&
    32.1 --- a/libdrm/receipt	Mon Jul 30 23:44:42 2018 +0300
    32.2 +++ b/libdrm/receipt	Tue Aug 07 00:30:45 2018 +0300
    32.3 @@ -1,13 +1,13 @@
    32.4  # SliTaz package receipt v2.
    32.5  
    32.6  PACKAGE="libdrm"
    32.7 -VERSION="2.4.89"
    32.8 +VERSION="2.4.92"
    32.9  CATEGORY="x-window"
   32.10  SHORT_DESC="Freedesktop DRM Library"
   32.11  MAINTAINER="al.bobylev@gmail.com"
   32.12  LICENSE="MIT"
   32.13  WEB_SITE="https://dri.freedesktop.org/"
   32.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/x/libdrm.html"
   32.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/x/libdrm.html"
   32.16  
   32.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   32.18  WGET_URL="https://dri.freedesktop.org/libdrm/$TARBALL"
   32.19 @@ -18,9 +18,10 @@
   32.20  libdrm-omap libdrm-radeon libdrm-tegra libdrm-dev"
   32.21  
   32.22  compile_rules() {
   32.23 -#	sed -i "/pthread-stubs/d" configure.ac &&
   32.24  	autoreconf -fiv &&
   32.25  
   32.26 +	# Freedreno API and VC4 API enabled on the ARM
   32.27 +	GREP=grep \
   32.28  	./configure \
   32.29  		--enable-udev \
   32.30  		--enable-vmwgfx \
   32.31 @@ -38,7 +39,7 @@
   32.32  	case $PACKAGE in
   32.33  		libdrm)
   32.34  			copy libdrm.so* libkms.so*
   32.35 -			DEPENDS="eudev linux-drm xorg-libpciaccess"
   32.36 +			DEPENDS="eudev linux-drm xorg-libpciaccess" # all deps are implicit
   32.37  			;;
   32.38  		*-amdgpu)
   32.39  			copy libdrm_amdgpu.so* amdgpu.ids
    33.1 --- a/libevdev/receipt	Mon Jul 30 23:44:42 2018 +0300
    33.2 +++ b/libevdev/receipt	Tue Aug 07 00:30:45 2018 +0300
    33.3 @@ -1,7 +1,7 @@
    33.4  # SliTaz package receipt v2.
    33.5  
    33.6  PACKAGE="libevdev"
    33.7 -VERSION="1.5.7"
    33.8 +VERSION="1.5.9"
    33.9  CATEGORY="x-window"
   33.10  SHORT_DESC="Common functions for Xorg input drivers"
   33.11  MAINTAINER="al.bobylev@gmail.com"
    34.1 --- a/libgpg-error/receipt	Mon Jul 30 23:44:42 2018 +0300
    34.2 +++ b/libgpg-error/receipt	Tue Aug 07 00:30:45 2018 +0300
    34.3 @@ -1,18 +1,18 @@
    34.4  # SliTaz package receipt v2.
    34.5  
    34.6  PACKAGE="libgpg-error"
    34.7 -VERSION="1.31"
    34.8 +VERSION="1.32"
    34.9  CATEGORY="security"
   34.10  SHORT_DESC="Commons error messages for GnuPG"
   34.11  MAINTAINER="erjo@slitaz.org"
   34.12  LICENSE="GPL2"
   34.13  WEB_SITE="https://www.gnupg.org/related_software/libgpg-error/"
   34.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libgpg-error.html"
   34.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libgpg-error.html"
   34.16  
   34.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   34.18  WGET_URL="https://www.gnupg.org/ftp/gcrypt/libgpg-error/$TARBALL"
   34.19  # https://www.gnupg.org/download/integrity_check.html
   34.20 -TARBALL_SHA1="2bafad316d4e3e12bae4822b14ed9020090e6acf"
   34.21 +TARBALL_SHA1="e310718c7737c816cb1313a2f3baf60fd6a6d5d3"
   34.22  
   34.23  BUILD_DEPENDS="gettext"
   34.24  SPLIT="libgpg-error-dev"
    35.1 --- a/libgphoto2/receipt	Mon Jul 30 23:44:42 2018 +0300
    35.2 +++ b/libgphoto2/receipt	Tue Aug 07 00:30:45 2018 +0300
    35.3 @@ -1,7 +1,7 @@
    35.4  # SliTaz package receipt v2.
    35.5  
    35.6  PACKAGE="libgphoto2"
    35.7 -VERSION="2.5.15"
    35.8 +VERSION="2.5.19"
    35.9  CATEGORY="graphics"
   35.10  SHORT_DESC="Core library of gphoto2 to access photos from digital camera"
   35.11  MAINTAINER="jozee@slitaz.org"
   35.12 @@ -12,7 +12,8 @@
   35.13  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   35.14  WGET_URL="$SF_MIRROR/gphoto/$TARBALL"
   35.15  
   35.16 -BUILD_DEPENDS="libtool gettext libjpeg-turbo-dev libexif-dev libusb-dev"
   35.17 +BUILD_DEPENDS="libtool gettext libjpeg-turbo-dev libexif-dev libusb-dev \
   35.18 +libxml2-dev libgd-dev" # use of libusb-compat-dev disabled while libusb found
   35.19  SPLIT="libgphoto2-dev"
   35.20  
   35.21  compile_rules() {
   35.22 @@ -23,52 +24,53 @@
   35.23  		$CONFIGURE_ARGS &&
   35.24  	fix libtool &&
   35.25  	make &&
   35.26 -	make install
   35.27 +	make install || return 1
   35.28 +
   35.29 +	# Remove recursive symlink
   35.30 +	rm $install/usr/include/gphoto2/gphoto2
   35.31 +
   35.32 +	# fix line:
   35.33 +	# driverdir=$(libdir)/$(PACKAGE_TARNAME)/$(VERSION)
   35.34 +	sed -i 's|^driverdir=.*|driverdir=${libdir}/libgphoto2_port/${VERSION}|' \
   35.35 +		$install/usr/lib/pkgconfig/libgphoto2_port.pc
   35.36 +
   35.37 +	mkdir -p $install/lib/udev/rules.d/
   35.38 +	export LD_LIBRARY_PATH="$install/usr/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH"
   35.39 +	export CAMLIBS="$install/usr/lib/libgphoto2/$VERSION"
   35.40 +	$install/usr/lib/libgphoto2/print-camera-list hwdb \
   35.41 +		| install -Dm644 /dev/stdin $install/lib/udev/hwdb.d/20-gphoto.hwdb
   35.42 +	# version <num> is UDEV version, one of: "pre-0.98", "0.98", "136", "175", "201"
   35.43 +	# See #src/packaging/generic/print-camera-list.c.
   35.44 +	# We use eudev, so maybe udev version here should be changed.
   35.45 +	$install/usr/lib/libgphoto2/print-camera-list udev-rules version 201 group camera mode 0660 \
   35.46 +		| install -Dm644 /dev/stdin $install/lib/udev/rules.d/40-gphoto.rules
   35.47  }
   35.48  
   35.49  genpkg_rules() {
   35.50  	case $PACKAGE in
   35.51  		libgphoto2)
   35.52  			copy @std
   35.53 -			DEPENDS="eudev libexif libjpeg-turbo libltdl liblzma libusb \
   35.54 -			libxml2 zlib"
   35.55 +			DEPENDS="libexif libgd libjpeg-turbo libltdl libusb libxml2   eudev"
   35.56  			TAGS="camera photo"
   35.57  			;;
   35.58  		libgphoto2-dev)
   35.59  			copy @dev
   35.60 -			DEPENDS="libgphoto2 eudev-dev libjpeg-turbo-dev libexif-dev \
   35.61 -			libtool libusb-dev libxml2-dev xz-dev zlib"
   35.62 +			DEPENDS="libgphoto2 libexif-dev"
   35.63  			;;
   35.64  	esac
   35.65  }
   35.66  
   35.67  post_install_libgphoto2() {
   35.68 -	HAL_FDI="$1/usr/share/hal/fdi/information/20thirdparty/10-camera-libgphoto2.fdi"
   35.69 -	UDEV_RULE="$1/etc/udev/rules.d/70-libgphoto2.rules"
   35.70 -	CAM_LIST="$1/usr/lib/libgphoto2/print-camera-list"
   35.71 -
   35.72 -	# Let print-camera-list find libgphoto2.so
   35.73 -	export LD_LIBRARY_PATH="$1/usr/lib"
   35.74 -	# Let libgphoto2 find its camera-modules before running print-camera-list
   35.75 -	export CAMLIBS="$1/usr/lib/libgphoto2/$VERSION"
   35.76 -
   35.77 -	# HAL file
   35.78 -	mkdir -p "$(dirname "$HAL_FDI")"
   35.79 -	"$CAM_LIST" hal-fdi > "$HAL_FDI"
   35.80 -
   35.81 -	#udev rule
   35.82 -	"$CAM_LIST" udev-rules version 0.98 group camera mode 0660 > "$UDEV_RULE"
   35.83 -
   35.84 -	# tazpkg reconfigure eudev --root="$1"
   35.85 -
   35.86  	# add group camera
   35.87 -	if ! grep -q camera "$1/etc/group"; then
   35.88 -		chroot "$1/" addgroup -g 97 -S camera
   35.89 -	fi
   35.90 +	grep -q camera "$1/etc/group" || chroot "$1/" addgroup -g 97 -S camera
   35.91  
   35.92  	[ -n "$quiet" ] || cat <<EOT
   35.93 -Don't forget to add yourself to group camera to use libgphoto2:
   35.94 -    # addgroup tux camera
   35.95 +
   35.96 +	.-----------------------------------------------------------------.
   35.97 +	| Don't forget to add yourself to group camera to use libgphoto2: |
   35.98 +	|                                                                 |
   35.99 +	| # addgroup tux camera                                           |
  35.100 +	'-----------------------------------------------------------------'
  35.101  EOT
  35.102  }
  35.103  
    36.1 --- a/libidn2/receipt	Mon Jul 30 23:44:42 2018 +0300
    36.2 +++ b/libidn2/receipt	Tue Aug 07 00:30:45 2018 +0300
    36.3 @@ -1,18 +1,18 @@
    36.4  # SliTaz package receipt v2.
    36.5  
    36.6  PACKAGE="libidn2"
    36.7 -VERSION="2.0.4"
    36.8 +VERSION="2.0.5"
    36.9  CATEGORY="system-tools"
   36.10  SHORT_DESC="Encode and decode internationalized domain names"
   36.11  MAINTAINER="al.bobylev@gmail.com"
   36.12  LICENSE="GPL3 LGPL2.1"
   36.13  WEB_SITE="https://www.gnu.org/software/libidn/"
   36.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libidn2.html"
   36.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libidn2.html"
   36.16  
   36.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   36.18  WGET_URL="$GNU_MIRROR/libidn/$TARBALL"
   36.19  
   36.20 -BUILD_DEPENDS="gtk-doc gettext glib-dev"
   36.21 +BUILD_DEPENDS="gtk-doc gettext glib-dev git libunistring-dev"
   36.22  SPLIT="libidn2-dev"
   36.23  
   36.24  compile_rules() {
   36.25 @@ -26,7 +26,13 @@
   36.26  
   36.27  genpkg_rules() {
   36.28  	case $PACKAGE in
   36.29 -		libidn2) copy @std;;
   36.30 -		*-dev)   copy @dev;;
   36.31 +		libidn2)
   36.32 +			copy @std
   36.33 +			DEPENDS="libunistring"
   36.34 +			;;
   36.35 +		*-dev)
   36.36 +			copy @dev
   36.37 +			DEPENDS="libidn2 libunistring-dev"
   36.38 +			;;
   36.39  	esac
   36.40  }
    37.1 Binary file libjpeg-turbo/.icon.png has changed
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/libjpeg-turbo/description.txt	Tue Aug 07 00:30:45 2018 +0300
    38.3 @@ -0,0 +1,26 @@
    38.4 +libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
    38.5 +NEON, AltiVec) to accelerate baseline JPEG compression and decompression on
    38.6 +x86, x86-64, ARM, and PowerPC systems. On such systems, libjpeg-turbo is
    38.7 +generally 2-6x as fast as libjpeg, all else being equal. On other types of
    38.8 +systems, libjpeg-turbo can still outperform libjpeg by a significant amount,
    38.9 +by virtue of its highly-optimized Huffman coding routines. In many cases, the
   38.10 +performance of libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
   38.11 +
   38.12 +libjpeg-turbo implements both the traditional libjpeg API as well as the less
   38.13 +powerful but more straightforward TurboJPEG API. libjpeg-turbo also features
   38.14 +colorspace extensions that allow it to compress from/decompress to 32-bit and
   38.15 +big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java
   38.16 +interface.
   38.17 +
   38.18 +Features
   38.19 +
   38.20 +  * 2-6x as fast as libjpeg on x86, x86-64, and ARM platforms
   38.21 +  * 32-bit and 64-bit binaries provided for popular Linux distributions,
   38.22 +    Windows, OS X, and iOS
   38.23 +  * Can be used in GPL and proprietary applications
   38.24 +  * Provides the industry-standard libjpeg API/ABI (can emulate libjpeg v6b,
   38.25 +    v7, or v8, although libjpeg-turbo does not support the non-standard
   38.26 +    SmartScale format introduced in libjpeg v8)
   38.27 +  * Provides the TurboJPEG API used by VirtualGL and TurboVNC
   38.28 +  * Similar performance to commercial/closed source accelerated JPEG codecs
   38.29 +  * Full-featured Java wrapper
    39.1 --- a/libjpeg-turbo/receipt	Mon Jul 30 23:44:42 2018 +0300
    39.2 +++ b/libjpeg-turbo/receipt	Tue Aug 07 00:30:45 2018 +0300
    39.3 @@ -1,27 +1,30 @@
    39.4  # SliTaz package receipt v2.
    39.5  
    39.6  PACKAGE="libjpeg-turbo"
    39.7 -VERSION="1.5.3"
    39.8 -CATEGORY="libs"
    39.9 +VERSION="2.0.0"
   39.10 +CATEGORY="graphics"
   39.11  SHORT_DESC="Accelerated JPEG image codec"
   39.12  MAINTAINER="pascal.bellard@slitaz.org"
   39.13  LICENSE="MIT"
   39.14  WEB_SITE="https://libjpeg-turbo.org/"
   39.15 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libjpeg.html"
   39.16 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libjpeg.html"
   39.17  HOST_ARCH="i486 x86_64"
   39.18  
   39.19  TARBALL="$PACKAGE-$VERSION.tar.gz"
   39.20  WGET_URL="$SF_MIRROR/$PACKAGE/$TARBALL"
   39.21  
   39.22 -BUILD_DEPENDS="nasm"
   39.23 +BUILD_DEPENDS="cmake nasm"
   39.24  SPLIT="jpeg-turbo libjpeg-turbo-dev"
   39.25  
   39.26  compile_rules() {
   39.27 -	./configure \
   39.28 -		--with-jpeg8 \
   39.29 -		--disable-static \
   39.30 -		$CONFIGURE_ARGS &&
   39.31 -	fix libtool &&
   39.32 +	mkdir build
   39.33 +	cd    build
   39.34 +	cmake \
   39.35 +		-DCMAKE_INSTALL_PREFIX=/usr \
   39.36 +		-DCMAKE_INSTALL_LIBDIR=/usr/lib \
   39.37 +		-DENABLE_STATIC=FALSE \
   39.38 +		-DWITH_JPEG8=TRUE \
   39.39 +		.. &&
   39.40  	make &&
   39.41  	make install
   39.42  }
    40.1 --- a/libkeybinder/receipt	Mon Jul 30 23:44:42 2018 +0300
    40.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.3 @@ -1,44 +0,0 @@
    40.4 -# SliTaz package receipt v2.
    40.5 -
    40.6 -PACKAGE="libkeybinder"
    40.7 -VERSION="0.3.1"
    40.8 -CATEGORY="x-window"
    40.9 -SHORT_DESC="Library for registering global keyboard shortcuts"
   40.10 -MAINTAINER="al.bobylev@gmail.com"
   40.11 -LICENSE="GPL2"
   40.12 -WEB_SITE="https://github.com/kupferlauncher/keybinder"
   40.13 -
   40.14 -TARBALL="$PACKAGE-$VERSION.tar.gz"
   40.15 -WGET_URL="https://github.com/kupferlauncher/keybinder/releases/download/keybinder-3.0-v$VERSION/keybinder-3.0-$VERSION.tar.gz"
   40.16 -WGET_URL="https://github.com/kupferlauncher/keybinder/releases/download/v$VERSION/keybinder-$VERSION.tar.gz"
   40.17 -
   40.18 -BUILD_DEPENDS="gtk+-dev gobject-introspection-dev xorg-libXext-dev python-dev \
   40.19 -pygtk-dev pygobject-dev automake autoconf libtool"
   40.20 -SPLIT="libkeybinder-python libkeybinder-dev"
   40.21 -
   40.22 -compile_rules() {
   40.23 -	autoreconf -vif &&
   40.24 -	./configure $CONFIGURE_ARGS &&
   40.25 -	fix libtool &&
   40.26 -	make &&
   40.27 -	make install
   40.28 -}
   40.29 -
   40.30 -genpkg_rules() {
   40.31 -	case $PACKAGE in
   40.32 -		libkeybinder)
   40.33 -			copy libkeybinder.so*
   40.34 -			DEPENDS="glib gtk+ xorg-libX11"
   40.35 -			;;
   40.36 -		libkeybinder-python)
   40.37 -			copy @std @rm
   40.38 -			CAT="x-window|python bindings"
   40.39 -			DEPENDS="glib libkeybinder python"
   40.40 -			;;
   40.41 -		*-dev)
   40.42 -			copy @dev
   40.43 -			DEPENDS="libkeybinder libkeybinder-python \
   40.44 -			gtk+-dev"
   40.45 -			;;
   40.46 -	esac
   40.47 -}
    41.1 --- a/libmtp/receipt	Mon Jul 30 23:44:42 2018 +0300
    41.2 +++ b/libmtp/receipt	Tue Aug 07 00:30:45 2018 +0300
    41.3 @@ -1,7 +1,7 @@
    41.4  # SliTaz package receipt v2.
    41.5  
    41.6  PACKAGE="libmtp"
    41.7 -VERSION="1.1.13"
    41.8 +VERSION="1.1.15"
    41.9  CATEGORY="system-tools"
   41.10  SHORT_DESC="Access to MTP devices: mp3 players, Android phones"
   41.11  MAINTAINER="keupont@no-log.org"
    42.1 --- a/libnfs/receipt	Mon Jul 30 23:44:42 2018 +0300
    42.2 +++ b/libnfs/receipt	Tue Aug 07 00:30:45 2018 +0300
    42.3 @@ -1,7 +1,7 @@
    42.4  # SliTaz package receipt v2.
    42.5  
    42.6  PACKAGE="libnfs"
    42.7 -VERSION="2.0.0"
    42.8 +VERSION="3.0.0"
    42.9  CATEGORY="network"
   42.10  SHORT_DESC="Client library for accessing NFS shares"
   42.11  MAINTAINER="al.bobylev@gmail.com"
    43.1 --- a/libogg/receipt	Mon Jul 30 23:44:42 2018 +0300
    43.2 +++ b/libogg/receipt	Tue Aug 07 00:30:45 2018 +0300
    43.3 @@ -1,13 +1,13 @@
    43.4  # SliTaz package receipt v2.
    43.5  
    43.6  PACKAGE="libogg"
    43.7 -VERSION="1.3.2"
    43.8 +VERSION="1.3.3"
    43.9  CATEGORY="multimedia"
   43.10  SHORT_DESC="OGG library from Xiph.org project"
   43.11  MAINTAINER="pankso@slitaz.org"
   43.12  LICENSE="BSD"
   43.13  WEB_SITE="http://www.xiph.org/"
   43.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/multimedia/libogg.html"
   43.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/multimedia/libogg.html"
   43.16  
   43.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   43.18  WGET_URL="http://downloads.xiph.org/releases/ogg/$TARBALL"
    44.1 --- a/libpipeline/receipt	Mon Jul 30 23:44:42 2018 +0300
    44.2 +++ b/libpipeline/receipt	Tue Aug 07 00:30:45 2018 +0300
    44.3 @@ -1,13 +1,13 @@
    44.4  # SliTaz package receipt v2.
    44.5  
    44.6  PACKAGE="libpipeline"
    44.7 -VERSION="1.4.2"
    44.8 +VERSION="1.5.0"
    44.9  CATEGORY="system-tools"
   44.10  SHORT_DESC="Pipeline manipulation library"
   44.11  MAINTAINER="al.bobylev@gmail.com"
   44.12  LICENSE="GPL3"
   44.13  WEB_SITE="http://libpipeline.nongnu.org/"
   44.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/libpipeline.html"
   44.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/libpipeline.html"
   44.16  
   44.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   44.18  WGET_URL="http://download.savannah.gnu.org/releases/$PACKAGE/$TARBALL"
    45.1 --- a/libpng16/receipt	Mon Jul 30 23:44:42 2018 +0300
    45.2 +++ b/libpng16/receipt	Tue Aug 07 00:30:45 2018 +0300
    45.3 @@ -1,13 +1,13 @@
    45.4  # SliTaz package receipt v2.
    45.5  
    45.6  PACKAGE="libpng16"
    45.7 -VERSION="1.6.34"
    45.8 +VERSION="1.6.35"
    45.9  CATEGORY="libs"
   45.10  SHORT_DESC="PNG images library 1.6 series with APNG support"
   45.11  MAINTAINER="al.bobylev@gmail.com"
   45.12  LICENSE="zlib/libpng"
   45.13  WEB_SITE="http://www.libpng.org/pub/png/libpng.html"
   45.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libpng.html"
   45.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libpng.html"
   45.16  REPOLOGY="libpng"
   45.17  
   45.18  TARBALL="libpng-$VERSION.tar.xz"
    46.1 --- a/libpng16/stuff/patches/libpng-1.6.34-apng.patch	Mon Jul 30 23:44:42 2018 +0300
    46.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.3 @@ -1,1728 +0,0 @@
    46.4 -diff -Naru libpng-1.6.34.org/png.h libpng-1.6.34/png.h
    46.5 ---- libpng-1.6.34.org/png.h	2017-09-29 18:55:30.653711999 +0900
    46.6 -+++ libpng-1.6.34/png.h	2017-09-29 18:56:30.306850103 +0900
    46.7 -@@ -361,6 +361,10 @@
    46.8 - #   include "pnglibconf.h"
    46.9 - #endif
   46.10 - 
   46.11 -+#define PNG_APNG_SUPPORTED
   46.12 -+#define PNG_READ_APNG_SUPPORTED
   46.13 -+#define PNG_WRITE_APNG_SUPPORTED
   46.14 -+
   46.15 - #ifndef PNG_VERSION_INFO_ONLY
   46.16 - /* Machine specific configuration. */
   46.17 - #  include "pngconf.h"
   46.18 -@@ -456,6 +460,17 @@
   46.19 -  * See pngconf.h for base types that vary by machine/system
   46.20 -  */
   46.21 - 
   46.22 -+#ifdef PNG_APNG_SUPPORTED
   46.23 -+/* dispose_op flags from inside fcTL */
   46.24 -+#define PNG_DISPOSE_OP_NONE        0x00U
   46.25 -+#define PNG_DISPOSE_OP_BACKGROUND  0x01U
   46.26 -+#define PNG_DISPOSE_OP_PREVIOUS    0x02U
   46.27 -+
   46.28 -+/* blend_op flags from inside fcTL */
   46.29 -+#define PNG_BLEND_OP_SOURCE        0x00U
   46.30 -+#define PNG_BLEND_OP_OVER          0x01U
   46.31 -+#endif /* PNG_APNG_SUPPORTED */
   46.32 -+
   46.33 - /* This triggers a compiler error in png.c, if png.c and png.h
   46.34 -  * do not agree upon the version number.
   46.35 -  */
   46.36 -@@ -777,6 +792,10 @@
   46.37 - #define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */
   46.38 - #define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */
   46.39 - #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
   46.40 -+#ifdef PNG_APNG_SUPPORTED
   46.41 -+#define PNG_INFO_acTL 0x20000U
   46.42 -+#define PNG_INFO_fcTL 0x40000U
   46.43 -+#endif
   46.44 - 
   46.45 - /* This is used for the transformation routines, as some of them
   46.46 -  * change these values for the row.  It also should enable using
   46.47 -@@ -814,6 +833,10 @@
   46.48 - #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
   46.49 - typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
   46.50 - typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
   46.51 -+#ifdef PNG_APNG_SUPPORTED
   46.52 -+typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
   46.53 -+    png_uint_32));
   46.54 -+#endif
   46.55 - 
   46.56 - /* The following callback receives png_uint_32 row_number, int pass for the
   46.57 -  * png_bytep data of the row.  When transforming an interlaced image the
   46.58 -@@ -3257,6 +3280,74 @@
   46.59 - /*******************************************************************************
   46.60 -  *  END OF HARDWARE AND SOFTWARE OPTIONS
   46.61 -  ******************************************************************************/
   46.62 -+#ifdef PNG_APNG_SUPPORTED
   46.63 -+PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
   46.64 -+   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
   46.65 -+
   46.66 -+PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
   46.67 -+   png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
   46.68 -+
   46.69 -+PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
   46.70 -+   png_infop info_ptr));
   46.71 -+
   46.72 -+PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
   46.73 -+   png_infop info_ptr));
   46.74 -+
   46.75 -+PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
   46.76 -+   (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
   46.77 -+   png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
   46.78 -+   png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
   46.79 -+   png_byte *blend_op));
   46.80 -+
   46.81 -+PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
   46.82 -+   (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
   46.83 -+   png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
   46.84 -+   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
   46.85 -+   png_byte blend_op));
   46.86 -+
   46.87 -+PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
   46.88 -+   (png_structp png_ptr, png_infop info_ptr));
   46.89 -+PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
   46.90 -+   (png_structp png_ptr, png_infop info_ptr));
   46.91 -+PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
   46.92 -+   (png_structp png_ptr, png_infop info_ptr));
   46.93 -+PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
   46.94 -+   (png_structp png_ptr, png_infop info_ptr));
   46.95 -+PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
   46.96 -+   (png_structp png_ptr, png_infop info_ptr));
   46.97 -+PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
   46.98 -+   (png_structp png_ptr, png_infop info_ptr));
   46.99 -+PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
  46.100 -+   (png_structp png_ptr, png_infop info_ptr));
  46.101 -+PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
  46.102 -+   (png_structp png_ptr, png_infop info_ptr));
  46.103 -+PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
  46.104 -+   (png_structp png_ptr, png_infop info_ptr));
  46.105 -+PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
  46.106 -+   (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
  46.107 -+
  46.108 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.109 -+PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
  46.110 -+   png_infop info_ptr));
  46.111 -+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  46.112 -+PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
  46.113 -+   png_progressive_frame_ptr frame_info_fn,
  46.114 -+   png_progressive_frame_ptr frame_end_fn));
  46.115 -+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
  46.116 -+#endif /* PNG_READ_APNG_SUPPORTED */
  46.117 -+
  46.118 -+#ifdef PNG_WRITE_APNG_SUPPORTED
  46.119 -+PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
  46.120 -+   png_infop info_ptr, png_bytepp row_pointers,
  46.121 -+   png_uint_32 width, png_uint_32 height,
  46.122 -+   png_uint_32 x_offset, png_uint_32 y_offset,
  46.123 -+   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
  46.124 -+   png_byte blend_op));
  46.125 -+
  46.126 -+PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
  46.127 -+   png_infop info_ptr));
  46.128 -+#endif /* PNG_WRITE_APNG_SUPPORTED */
  46.129 -+#endif /* PNG_APNG_SUPPORTED */
  46.130 - 
  46.131 - /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
  46.132 -  * defs, and in scripts/symbols.def.
  46.133 -@@ -3266,7 +3357,11 @@
  46.134 -  * one to use is one more than this.)
  46.135 -  */
  46.136 - #ifdef PNG_EXPORT_LAST_ORDINAL
  46.137 -+#ifdef PNG_APNG_SUPPORTED
  46.138 -+  PNG_EXPORT_LAST_ORDINAL(269);
  46.139 -+#else
  46.140 -   PNG_EXPORT_LAST_ORDINAL(249);
  46.141 -+#endif /* PNG_APNG_SUPPORTED */
  46.142 - #endif
  46.143 - 
  46.144 - #ifdef __cplusplus
  46.145 -diff -Naru libpng-1.6.34.org/pngget.c libpng-1.6.34/pngget.c
  46.146 ---- libpng-1.6.34.org/pngget.c	2017-09-29 18:53:22.698691668 +0900
  46.147 -+++ libpng-1.6.34/pngget.c	2017-09-29 18:56:30.286848380 +0900
  46.148 -@@ -1245,4 +1245,166 @@
  46.149 - #  endif
  46.150 - #endif
  46.151 - 
  46.152 -+#ifdef PNG_APNG_SUPPORTED
  46.153 -+png_uint_32 PNGAPI
  46.154 -+png_get_acTL(png_structp png_ptr, png_infop info_ptr,
  46.155 -+             png_uint_32 *num_frames, png_uint_32 *num_plays)
  46.156 -+{
  46.157 -+    png_debug1(1, "in %s retrieval function", "acTL");
  46.158 -+
  46.159 -+    if (png_ptr != NULL && info_ptr != NULL &&
  46.160 -+        (info_ptr->valid & PNG_INFO_acTL) &&
  46.161 -+        num_frames != NULL && num_plays != NULL)
  46.162 -+    {
  46.163 -+        *num_frames = info_ptr->num_frames;
  46.164 -+        *num_plays = info_ptr->num_plays;
  46.165 -+        return (1);
  46.166 -+    }
  46.167 -+
  46.168 -+    return (0);
  46.169 -+}
  46.170 -+
  46.171 -+png_uint_32 PNGAPI
  46.172 -+png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
  46.173 -+{
  46.174 -+    png_debug(1, "in png_get_num_frames()");
  46.175 -+
  46.176 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.177 -+        return (info_ptr->num_frames);
  46.178 -+    return (0);
  46.179 -+}
  46.180 -+
  46.181 -+png_uint_32 PNGAPI
  46.182 -+png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
  46.183 -+{
  46.184 -+    png_debug(1, "in png_get_num_plays()");
  46.185 -+
  46.186 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.187 -+        return (info_ptr->num_plays);
  46.188 -+    return (0);
  46.189 -+}
  46.190 -+
  46.191 -+png_uint_32 PNGAPI
  46.192 -+png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
  46.193 -+             png_uint_32 *width, png_uint_32 *height,
  46.194 -+             png_uint_32 *x_offset, png_uint_32 *y_offset,
  46.195 -+             png_uint_16 *delay_num, png_uint_16 *delay_den,
  46.196 -+             png_byte *dispose_op, png_byte *blend_op)
  46.197 -+{
  46.198 -+    png_debug1(1, "in %s retrieval function", "fcTL");
  46.199 -+
  46.200 -+    if (png_ptr != NULL && info_ptr != NULL &&
  46.201 -+        (info_ptr->valid & PNG_INFO_fcTL) &&
  46.202 -+        width != NULL && height != NULL &&
  46.203 -+        x_offset != NULL && y_offset != NULL &&
  46.204 -+        delay_num != NULL && delay_den != NULL &&
  46.205 -+        dispose_op != NULL && blend_op != NULL)
  46.206 -+    {
  46.207 -+        *width = info_ptr->next_frame_width;
  46.208 -+        *height = info_ptr->next_frame_height;
  46.209 -+        *x_offset = info_ptr->next_frame_x_offset;
  46.210 -+        *y_offset = info_ptr->next_frame_y_offset;
  46.211 -+        *delay_num = info_ptr->next_frame_delay_num;
  46.212 -+        *delay_den = info_ptr->next_frame_delay_den;
  46.213 -+        *dispose_op = info_ptr->next_frame_dispose_op;
  46.214 -+        *blend_op = info_ptr->next_frame_blend_op;
  46.215 -+        return (1);
  46.216 -+    }
  46.217 -+
  46.218 -+    return (0);
  46.219 -+}
  46.220 -+
  46.221 -+png_uint_32 PNGAPI
  46.222 -+png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
  46.223 -+{
  46.224 -+    png_debug(1, "in png_get_next_frame_width()");
  46.225 -+
  46.226 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.227 -+        return (info_ptr->next_frame_width);
  46.228 -+    return (0);
  46.229 -+}
  46.230 -+
  46.231 -+png_uint_32 PNGAPI
  46.232 -+png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
  46.233 -+{
  46.234 -+    png_debug(1, "in png_get_next_frame_height()");
  46.235 -+
  46.236 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.237 -+        return (info_ptr->next_frame_height);
  46.238 -+    return (0);
  46.239 -+}
  46.240 -+
  46.241 -+png_uint_32 PNGAPI
  46.242 -+png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
  46.243 -+{
  46.244 -+    png_debug(1, "in png_get_next_frame_x_offset()");
  46.245 -+
  46.246 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.247 -+        return (info_ptr->next_frame_x_offset);
  46.248 -+    return (0);
  46.249 -+}
  46.250 -+
  46.251 -+png_uint_32 PNGAPI
  46.252 -+png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
  46.253 -+{
  46.254 -+    png_debug(1, "in png_get_next_frame_y_offset()");
  46.255 -+
  46.256 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.257 -+        return (info_ptr->next_frame_y_offset);
  46.258 -+    return (0);
  46.259 -+}
  46.260 -+
  46.261 -+png_uint_16 PNGAPI
  46.262 -+png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
  46.263 -+{
  46.264 -+    png_debug(1, "in png_get_next_frame_delay_num()");
  46.265 -+
  46.266 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.267 -+        return (info_ptr->next_frame_delay_num);
  46.268 -+    return (0);
  46.269 -+}
  46.270 -+
  46.271 -+png_uint_16 PNGAPI
  46.272 -+png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
  46.273 -+{
  46.274 -+    png_debug(1, "in png_get_next_frame_delay_den()");
  46.275 -+
  46.276 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.277 -+        return (info_ptr->next_frame_delay_den);
  46.278 -+    return (0);
  46.279 -+}
  46.280 -+
  46.281 -+png_byte PNGAPI
  46.282 -+png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
  46.283 -+{
  46.284 -+    png_debug(1, "in png_get_next_frame_dispose_op()");
  46.285 -+
  46.286 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.287 -+        return (info_ptr->next_frame_dispose_op);
  46.288 -+    return (0);
  46.289 -+}
  46.290 -+
  46.291 -+png_byte PNGAPI
  46.292 -+png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
  46.293 -+{
  46.294 -+    png_debug(1, "in png_get_next_frame_blend_op()");
  46.295 -+
  46.296 -+    if (png_ptr != NULL && info_ptr != NULL)
  46.297 -+        return (info_ptr->next_frame_blend_op);
  46.298 -+    return (0);
  46.299 -+}
  46.300 -+
  46.301 -+png_byte PNGAPI
  46.302 -+png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
  46.303 -+{
  46.304 -+    png_debug(1, "in png_first_frame_is_hidden()");
  46.305 -+
  46.306 -+    if (png_ptr != NULL)
  46.307 -+       return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
  46.308 -+
  46.309 -+    PNG_UNUSED(info_ptr)
  46.310 -+
  46.311 -+    return 0;
  46.312 -+}
  46.313 -+#endif /* PNG_APNG_SUPPORTED */
  46.314 - #endif /* READ || WRITE */
  46.315 -diff -Naru libpng-1.6.34.org/pnginfo.h libpng-1.6.34/pnginfo.h
  46.316 ---- libpng-1.6.34.org/pnginfo.h	2017-09-29 18:53:22.698691668 +0900
  46.317 -+++ libpng-1.6.34/pnginfo.h	2017-09-29 18:56:30.286848380 +0900
  46.318 -@@ -263,5 +263,18 @@
  46.319 -    png_bytepp row_pointers;        /* the image bits */
  46.320 - #endif
  46.321 - 
  46.322 -+#ifdef PNG_APNG_SUPPORTED
  46.323 -+   png_uint_32 num_frames; /* including default image */
  46.324 -+   png_uint_32 num_plays;
  46.325 -+   png_uint_32 next_frame_width;
  46.326 -+   png_uint_32 next_frame_height;
  46.327 -+   png_uint_32 next_frame_x_offset;
  46.328 -+   png_uint_32 next_frame_y_offset;
  46.329 -+   png_uint_16 next_frame_delay_num;
  46.330 -+   png_uint_16 next_frame_delay_den;
  46.331 -+   png_byte next_frame_dispose_op;
  46.332 -+   png_byte next_frame_blend_op;
  46.333 -+#endif
  46.334 -+
  46.335 - };
  46.336 - #endif /* PNGINFO_H */
  46.337 -diff -Naru libpng-1.6.34.org/pngpread.c libpng-1.6.34/pngpread.c
  46.338 ---- libpng-1.6.34.org/pngpread.c	2017-09-29 18:53:22.698691668 +0900
  46.339 -+++ libpng-1.6.34/pngpread.c	2017-09-29 18:56:30.286848380 +0900
  46.340 -@@ -195,6 +195,106 @@
  46.341 - 
  46.342 -    chunk_name = png_ptr->chunk_name;
  46.343 - 
  46.344 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.345 -+   if (png_ptr->num_frames_read > 0 &&
  46.346 -+       png_ptr->num_frames_read < info_ptr->num_frames)
  46.347 -+   {
  46.348 -+      if (chunk_name == png_IDAT)
  46.349 -+      {
  46.350 -+         /* Discard trailing IDATs for the first frame */
  46.351 -+         if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
  46.352 -+            png_error(png_ptr, "out of place IDAT");
  46.353 -+
  46.354 -+         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  46.355 -+         {
  46.356 -+            png_push_save_buffer(png_ptr);
  46.357 -+            return;
  46.358 -+         }
  46.359 -+
  46.360 -+         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  46.361 -+         return;
  46.362 -+      }
  46.363 -+      else if (chunk_name == png_fdAT)
  46.364 -+      {
  46.365 -+         if (png_ptr->buffer_size < 4)
  46.366 -+         {
  46.367 -+            png_push_save_buffer(png_ptr);
  46.368 -+            return;
  46.369 -+         }
  46.370 -+
  46.371 -+         png_ensure_sequence_number(png_ptr, 4);
  46.372 -+
  46.373 -+         if (!(png_ptr->mode & PNG_HAVE_fcTL))
  46.374 -+         {
  46.375 -+            /* Discard trailing fdATs for frames other than the first */
  46.376 -+            if (png_ptr->num_frames_read < 2)
  46.377 -+               png_error(png_ptr, "out of place fdAT");
  46.378 -+
  46.379 -+            if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  46.380 -+            {
  46.381 -+               png_push_save_buffer(png_ptr);
  46.382 -+               return;
  46.383 -+            }
  46.384 -+
  46.385 -+            png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  46.386 -+            return;
  46.387 -+         }
  46.388 -+
  46.389 -+         else
  46.390 -+         {
  46.391 -+            /* frame data follows */
  46.392 -+            png_ptr->idat_size = png_ptr->push_length - 4;
  46.393 -+            png_ptr->mode |= PNG_HAVE_IDAT;
  46.394 -+            png_ptr->process_mode = PNG_READ_IDAT_MODE;
  46.395 -+
  46.396 -+            return;
  46.397 -+         }
  46.398 -+      }
  46.399 -+
  46.400 -+      else if (chunk_name == png_fcTL)
  46.401 -+      {
  46.402 -+         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  46.403 -+         {
  46.404 -+            png_push_save_buffer(png_ptr);
  46.405 -+            return;
  46.406 -+         }
  46.407 -+
  46.408 -+         png_read_reset(png_ptr);
  46.409 -+         png_ptr->mode &= ~PNG_HAVE_fcTL;
  46.410 -+
  46.411 -+         png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
  46.412 -+
  46.413 -+         if (!(png_ptr->mode & PNG_HAVE_fcTL))
  46.414 -+            png_error(png_ptr, "missing required fcTL chunk");
  46.415 -+
  46.416 -+         png_read_reinit(png_ptr, info_ptr);
  46.417 -+         png_progressive_read_reset(png_ptr);
  46.418 -+
  46.419 -+         if (png_ptr->frame_info_fn != NULL)
  46.420 -+            (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
  46.421 -+
  46.422 -+         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  46.423 -+
  46.424 -+         return;
  46.425 -+      }
  46.426 -+
  46.427 -+      else
  46.428 -+      {
  46.429 -+         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  46.430 -+         {
  46.431 -+            png_push_save_buffer(png_ptr);
  46.432 -+            return;
  46.433 -+         }
  46.434 -+         png_warning(png_ptr, "Skipped (ignored) a chunk "
  46.435 -+                              "between APNG chunks");
  46.436 -+         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  46.437 -+         return;
  46.438 -+      }
  46.439 -+
  46.440 -+      return;
  46.441 -+   }
  46.442 -+#endif /* PNG_READ_APNG_SUPPORTED */
  46.443 -+
  46.444 -    if (chunk_name == png_IDAT)
  46.445 -    {
  46.446 -       if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
  46.447 -@@ -261,6 +361,9 @@
  46.448 - 
  46.449 -    else if (chunk_name == png_IDAT)
  46.450 -    {
  46.451 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.452 -+      png_have_info(png_ptr, info_ptr);
  46.453 -+#endif
  46.454 -       png_ptr->idat_size = png_ptr->push_length;
  46.455 -       png_ptr->process_mode = PNG_READ_IDAT_MODE;
  46.456 -       png_push_have_info(png_ptr, info_ptr);
  46.457 -@@ -406,6 +509,30 @@
  46.458 -       png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
  46.459 -    }
  46.460 - #endif
  46.461 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.462 -+   else if (chunk_name == png_acTL)
  46.463 -+   {
  46.464 -+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  46.465 -+      {
  46.466 -+         png_push_save_buffer(png_ptr);
  46.467 -+         return;
  46.468 -+      }
  46.469 -+
  46.470 -+      png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
  46.471 -+   }
  46.472 -+
  46.473 -+   else if (chunk_name == png_fcTL)
  46.474 -+   {
  46.475 -+      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  46.476 -+      {
  46.477 -+         png_push_save_buffer(png_ptr);
  46.478 -+         return;
  46.479 -+      }
  46.480 -+
  46.481 -+      png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
  46.482 -+   }
  46.483 -+
  46.484 -+#endif /* PNG_READ_APNG_SUPPORTED */
  46.485 - 
  46.486 -    else
  46.487 -    {
  46.488 -@@ -539,7 +666,11 @@
  46.489 -       png_byte chunk_tag[4];
  46.490 - 
  46.491 -       /* TODO: this code can be commoned up with the same code in push_read */
  46.492 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.493 -+      PNG_PUSH_SAVE_BUFFER_IF_LT(12)
  46.494 -+#else
  46.495 -       PNG_PUSH_SAVE_BUFFER_IF_LT(8)
  46.496 -+#endif
  46.497 -       png_push_fill_buffer(png_ptr, chunk_length, 4);
  46.498 -       png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
  46.499 -       png_reset_crc(png_ptr);
  46.500 -@@ -547,17 +678,64 @@
  46.501 -       png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
  46.502 -       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
  46.503 - 
  46.504 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.505 -+      if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
  46.506 -+      {
  46.507 -+          if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
  46.508 -+          {
  46.509 -+              png_ptr->process_mode = PNG_READ_CHUNK_MODE;
  46.510 -+              if (png_ptr->frame_end_fn != NULL)
  46.511 -+                 (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
  46.512 -+              png_ptr->num_frames_read++;
  46.513 -+              return;
  46.514 -+          }
  46.515 -+          else
  46.516 -+          {
  46.517 -+              if (png_ptr->chunk_name == png_IEND)
  46.518 -+                  png_error(png_ptr, "Not enough image data");
  46.519 -+              if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  46.520 -+              {
  46.521 -+                 png_push_save_buffer(png_ptr);
  46.522 -+                 return;
  46.523 -+              }
  46.524 -+              png_warning(png_ptr, "Skipping (ignoring) a chunk between "
  46.525 -+                                   "APNG chunks");
  46.526 -+              png_crc_finish(png_ptr, png_ptr->push_length);
  46.527 -+              png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  46.528 -+              return;
  46.529 -+          }
  46.530 -+      }
  46.531 -+      else
  46.532 -+#endif
  46.533 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.534 -+      if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
  46.535 -+#else
  46.536 -       if (png_ptr->chunk_name != png_IDAT)
  46.537 -+#endif
  46.538 -       {
  46.539 -          png_ptr->process_mode = PNG_READ_CHUNK_MODE;
  46.540 - 
  46.541 -          if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
  46.542 -             png_error(png_ptr, "Not enough compressed data");
  46.543 - 
  46.544 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.545 -+         if (png_ptr->frame_end_fn != NULL)
  46.546 -+            (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
  46.547 -+         png_ptr->num_frames_read++;
  46.548 -+#endif
  46.549 -+
  46.550 -          return;
  46.551 -       }
  46.552 - 
  46.553 -       png_ptr->idat_size = png_ptr->push_length;
  46.554 -+
  46.555 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.556 -+      if (png_ptr->num_frames_read > 0)
  46.557 -+      {
  46.558 -+         png_ensure_sequence_number(png_ptr, 4);
  46.559 -+         png_ptr->idat_size -= 4;
  46.560 -+      }
  46.561 -+#endif
  46.562 -    }
  46.563 - 
  46.564 -    if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
  46.565 -@@ -631,6 +809,15 @@
  46.566 -    if (!(buffer_length > 0) || buffer == NULL)
  46.567 -       png_error(png_ptr, "No IDAT data (internal error)");
  46.568 - 
  46.569 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.570 -+   /* If the app is not APNG-aware, decode only the first frame */
  46.571 -+   if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
  46.572 -+   {
  46.573 -+     png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
  46.574 -+     return;
  46.575 -+   }
  46.576 -+#endif
  46.577 -+
  46.578 -    /* This routine must process all the data it has been given
  46.579 -     * before returning, calling the row callback as required to
  46.580 -     * handle the uncompressed results.
  46.581 -@@ -1085,6 +1272,18 @@
  46.582 -    png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
  46.583 - }
  46.584 - 
  46.585 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.586 -+void PNGAPI
  46.587 -+png_set_progressive_frame_fn(png_structp png_ptr,
  46.588 -+   png_progressive_frame_ptr frame_info_fn,
  46.589 -+   png_progressive_frame_ptr frame_end_fn)
  46.590 -+{
  46.591 -+   png_ptr->frame_info_fn = frame_info_fn;
  46.592 -+   png_ptr->frame_end_fn = frame_end_fn;
  46.593 -+   png_ptr->apng_flags |= PNG_APNG_APP;
  46.594 -+}
  46.595 -+#endif
  46.596 -+
  46.597 - png_voidp PNGAPI
  46.598 - png_get_progressive_ptr(png_const_structrp png_ptr)
  46.599 - {
  46.600 -diff -Naru libpng-1.6.34.org/pngpriv.h libpng-1.6.34/pngpriv.h
  46.601 ---- libpng-1.6.34.org/pngpriv.h	2017-09-29 18:53:22.699691754 +0900
  46.602 -+++ libpng-1.6.34/pngpriv.h	2017-09-29 18:56:30.286848380 +0900
  46.603 -@@ -628,6 +628,10 @@
  46.604 - #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
  46.605 -                    /*             0x4000U (unused) */
  46.606 - #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
  46.607 -+#ifdef PNG_APNG_SUPPORTED
  46.608 -+#define PNG_HAVE_acTL            0x10000U
  46.609 -+#define PNG_HAVE_fcTL            0x20000U
  46.610 -+#endif
  46.611 - 
  46.612 - /* Flags for the transformations the PNG library does on the image data */
  46.613 - #define PNG_BGR                 0x0001U
  46.614 -@@ -864,6 +868,16 @@
  46.615 - #define png_tRNS PNG_U32(116,  82,  78,  83)
  46.616 - #define png_zTXt PNG_U32(122,  84,  88, 116)
  46.617 - 
  46.618 -+#ifdef PNG_APNG_SUPPORTED
  46.619 -+#define png_acTL PNG_U32( 97,  99,  84,  76)
  46.620 -+#define png_fcTL PNG_U32(102,  99,  84,  76)
  46.621 -+#define png_fdAT PNG_U32(102, 100,  65,  84)
  46.622 -+
  46.623 -+/* For png_struct.apng_flags: */
  46.624 -+#define PNG_FIRST_FRAME_HIDDEN       0x0001U
  46.625 -+#define PNG_APNG_APP                 0x0002U
  46.626 -+#endif
  46.627 -+
  46.628 - /* The following will work on (signed char*) strings, whereas the get_uint_32
  46.629 -  * macro will fail on top-bit-set values because of the sign extension.
  46.630 -  */
  46.631 -@@ -1635,6 +1649,47 @@
  46.632 -     */
  46.633 - #endif
  46.634 - 
  46.635 -+#ifdef PNG_APNG_SUPPORTED
  46.636 -+PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
  46.637 -+   png_uint_32 width, png_uint_32 height,
  46.638 -+   png_uint_32 x_offset, png_uint_32 y_offset,
  46.639 -+   png_uint_16 delay_num, png_uint_16 delay_den,
  46.640 -+   png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
  46.641 -+
  46.642 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.643 -+PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
  46.644 -+   png_uint_32 length),PNG_EMPTY);
  46.645 -+PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
  46.646 -+   png_uint_32 length),PNG_EMPTY);
  46.647 -+PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
  46.648 -+   png_uint_32 length),PNG_EMPTY);
  46.649 -+PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
  46.650 -+PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
  46.651 -+   png_uint_32 length),PNG_EMPTY);
  46.652 -+PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
  46.653 -+PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
  46.654 -+   png_infop info_ptr),PNG_EMPTY);
  46.655 -+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  46.656 -+PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
  46.657 -+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
  46.658 -+#endif /* PNG_READ_APNG_SUPPORTED */
  46.659 -+
  46.660 -+#ifdef PNG_WRITE_APNG_SUPPORTED
  46.661 -+PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
  46.662 -+   png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
  46.663 -+PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
  46.664 -+   png_uint_32 width, png_uint_32 height,
  46.665 -+   png_uint_32 x_offset, png_uint_32 y_offset,
  46.666 -+   png_uint_16 delay_num, png_uint_16 delay_den,
  46.667 -+   png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
  46.668 -+PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
  46.669 -+   png_const_bytep data, png_size_t length),PNG_EMPTY);
  46.670 -+PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
  46.671 -+PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
  46.672 -+   png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
  46.673 -+#endif /* PNG_WRITE_APNG_SUPPORTED */
  46.674 -+#endif /* PNG_APNG_SUPPORTED */
  46.675 -+
  46.676 - /* Added at libpng version 1.4.0 */
  46.677 - #ifdef PNG_COLORSPACE_SUPPORTED
  46.678 - /* These internal functions are for maintaining the colorspace structure within
  46.679 -diff -Naru libpng-1.6.34.org/pngread.c libpng-1.6.34/pngread.c
  46.680 ---- libpng-1.6.34.org/pngread.c	2017-09-29 18:53:22.699691754 +0900
  46.681 -+++ libpng-1.6.34/pngread.c	2017-09-29 18:56:30.286848380 +0900
  46.682 -@@ -161,6 +161,9 @@
  46.683 - 
  46.684 -       else if (chunk_name == png_IDAT)
  46.685 -       {
  46.686 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.687 -+         png_have_info(png_ptr, info_ptr);
  46.688 -+#endif
  46.689 -          png_ptr->idat_size = length;
  46.690 -          break;
  46.691 -       }
  46.692 -@@ -255,6 +258,17 @@
  46.693 -          png_handle_iTXt(png_ptr, info_ptr, length);
  46.694 - #endif
  46.695 - 
  46.696 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.697 -+      else if (chunk_name == png_acTL)
  46.698 -+         png_handle_acTL(png_ptr, info_ptr, length);
  46.699 -+
  46.700 -+      else if (chunk_name == png_fcTL)
  46.701 -+         png_handle_fcTL(png_ptr, info_ptr, length);
  46.702 -+
  46.703 -+      else if (chunk_name == png_fdAT)
  46.704 -+         png_handle_fdAT(png_ptr, info_ptr, length);
  46.705 -+#endif
  46.706 -+
  46.707 -       else
  46.708 -          png_handle_unknown(png_ptr, info_ptr, length,
  46.709 -              PNG_HANDLE_CHUNK_AS_DEFAULT);
  46.710 -@@ -262,6 +276,72 @@
  46.711 - }
  46.712 - #endif /* SEQUENTIAL_READ */
  46.713 - 
  46.714 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.715 -+void PNGAPI
  46.716 -+png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
  46.717 -+{
  46.718 -+    png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
  46.719 -+
  46.720 -+    png_debug(0, "Reading frame head");
  46.721 -+
  46.722 -+    if (!(png_ptr->mode & PNG_HAVE_acTL))
  46.723 -+        png_error(png_ptr, "attempt to png_read_frame_head() but "
  46.724 -+                           "no acTL present");
  46.725 -+
  46.726 -+    /* do nothing for the main IDAT */
  46.727 -+    if (png_ptr->num_frames_read == 0)
  46.728 -+        return;
  46.729 -+
  46.730 -+    png_read_reset(png_ptr);
  46.731 -+    png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
  46.732 -+    png_ptr->mode &= ~PNG_HAVE_fcTL;
  46.733 -+
  46.734 -+    have_chunk_after_DAT = 0;
  46.735 -+    for (;;)
  46.736 -+    {
  46.737 -+        png_uint_32 length = png_read_chunk_header(png_ptr);
  46.738 -+
  46.739 -+        if (png_ptr->chunk_name == png_IDAT)
  46.740 -+        {
  46.741 -+            /* discard trailing IDATs for the first frame */
  46.742 -+            if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
  46.743 -+                png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
  46.744 -+            png_crc_finish(png_ptr, length);
  46.745 -+        }
  46.746 -+
  46.747 -+        else if (png_ptr->chunk_name == png_fcTL)
  46.748 -+        {
  46.749 -+            png_handle_fcTL(png_ptr, info_ptr, length);
  46.750 -+            have_chunk_after_DAT = 1;
  46.751 -+        }
  46.752 -+
  46.753 -+        else if (png_ptr->chunk_name == png_fdAT)
  46.754 -+        {
  46.755 -+            png_ensure_sequence_number(png_ptr, length);
  46.756 -+
  46.757 -+            /* discard trailing fdATs for frames other than the first */
  46.758 -+            if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
  46.759 -+                png_crc_finish(png_ptr, length - 4);
  46.760 -+            else if(png_ptr->mode & PNG_HAVE_fcTL)
  46.761 -+            {
  46.762 -+                png_ptr->idat_size = length - 4;
  46.763 -+                png_ptr->mode |= PNG_HAVE_IDAT;
  46.764 -+
  46.765 -+                break;
  46.766 -+            }
  46.767 -+            else
  46.768 -+                png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
  46.769 -+        }
  46.770 -+        else
  46.771 -+        {
  46.772 -+            png_warning(png_ptr, "Skipped (ignored) a chunk "
  46.773 -+                                 "between APNG chunks");
  46.774 -+            png_crc_finish(png_ptr, length);
  46.775 -+        }
  46.776 -+    }
  46.777 -+}
  46.778 -+#endif /* PNG_READ_APNG_SUPPORTED */
  46.779 -+
  46.780 - /* Optional call to update the users info_ptr structure */
  46.781 - void PNGAPI
  46.782 - png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
  46.783 -diff -Naru libpng-1.6.34.org/pngrutil.c libpng-1.6.34/pngrutil.c
  46.784 ---- libpng-1.6.34.org/pngrutil.c	2017-09-29 18:53:22.701691926 +0900
  46.785 -+++ libpng-1.6.34/pngrutil.c	2017-09-29 18:56:30.287848466 +0900
  46.786 -@@ -865,6 +865,11 @@
  46.787 -    filter_type = buf[11];
  46.788 -    interlace_type = buf[12];
  46.789 - 
  46.790 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.791 -+   png_ptr->first_frame_width = width;
  46.792 -+   png_ptr->first_frame_height = height;
  46.793 -+#endif
  46.794 -+
  46.795 -    /* Set internal variables */
  46.796 -    png_ptr->width = width;
  46.797 -    png_ptr->height = height;
  46.798 -@@ -2840,6 +2845,179 @@
  46.799 - }
  46.800 - #endif
  46.801 - 
  46.802 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.803 -+void /* PRIVATE */
  46.804 -+png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  46.805 -+{
  46.806 -+    png_byte data[8];
  46.807 -+    png_uint_32 num_frames;
  46.808 -+    png_uint_32 num_plays;
  46.809 -+    png_uint_32 didSet;
  46.810 -+
  46.811 -+    png_debug(1, "in png_handle_acTL");
  46.812 -+
  46.813 -+    if (!(png_ptr->mode & PNG_HAVE_IHDR))
  46.814 -+    {
  46.815 -+        png_error(png_ptr, "Missing IHDR before acTL");
  46.816 -+    }
  46.817 -+    else if (png_ptr->mode & PNG_HAVE_IDAT)
  46.818 -+    {
  46.819 -+        png_warning(png_ptr, "Invalid acTL after IDAT skipped");
  46.820 -+        png_crc_finish(png_ptr, length);
  46.821 -+        return;
  46.822 -+    }
  46.823 -+    else if (png_ptr->mode & PNG_HAVE_acTL)
  46.824 -+    {
  46.825 -+        png_warning(png_ptr, "Duplicate acTL skipped");
  46.826 -+        png_crc_finish(png_ptr, length);
  46.827 -+        return;
  46.828 -+    }
  46.829 -+    else if (length != 8)
  46.830 -+    {
  46.831 -+        png_warning(png_ptr, "acTL with invalid length skipped");
  46.832 -+        png_crc_finish(png_ptr, length);
  46.833 -+        return;
  46.834 -+    }
  46.835 -+
  46.836 -+    png_crc_read(png_ptr, data, 8);
  46.837 -+    png_crc_finish(png_ptr, 0);
  46.838 -+
  46.839 -+    num_frames = png_get_uint_31(png_ptr, data);
  46.840 -+    num_plays = png_get_uint_31(png_ptr, data + 4);
  46.841 -+
  46.842 -+    /* the set function will do error checking on num_frames */
  46.843 -+    didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
  46.844 -+    if(didSet)
  46.845 -+        png_ptr->mode |= PNG_HAVE_acTL;
  46.846 -+}
  46.847 -+
  46.848 -+void /* PRIVATE */
  46.849 -+png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  46.850 -+{
  46.851 -+    png_byte data[22];
  46.852 -+    png_uint_32 width;
  46.853 -+    png_uint_32 height;
  46.854 -+    png_uint_32 x_offset;
  46.855 -+    png_uint_32 y_offset;
  46.856 -+    png_uint_16 delay_num;
  46.857 -+    png_uint_16 delay_den;
  46.858 -+    png_byte dispose_op;
  46.859 -+    png_byte blend_op;
  46.860 -+
  46.861 -+    png_debug(1, "in png_handle_fcTL");
  46.862 -+
  46.863 -+    png_ensure_sequence_number(png_ptr, length);
  46.864 -+
  46.865 -+    if (!(png_ptr->mode & PNG_HAVE_IHDR))
  46.866 -+    {
  46.867 -+        png_error(png_ptr, "Missing IHDR before fcTL");
  46.868 -+    }
  46.869 -+    else if (png_ptr->mode & PNG_HAVE_IDAT)
  46.870 -+    {
  46.871 -+        /* for any frames other then the first this message may be misleading,
  46.872 -+        * but correct. PNG_HAVE_IDAT is unset before the frame head is read
  46.873 -+        * i can't think of a better message */
  46.874 -+        png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
  46.875 -+        png_crc_finish(png_ptr, length-4);
  46.876 -+        return;
  46.877 -+    }
  46.878 -+    else if (png_ptr->mode & PNG_HAVE_fcTL)
  46.879 -+    {
  46.880 -+        png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
  46.881 -+        png_crc_finish(png_ptr, length-4);
  46.882 -+        return;
  46.883 -+    }
  46.884 -+    else if (length != 26)
  46.885 -+    {
  46.886 -+        png_warning(png_ptr, "fcTL with invalid length skipped");
  46.887 -+        png_crc_finish(png_ptr, length-4);
  46.888 -+        return;
  46.889 -+    }
  46.890 -+
  46.891 -+    png_crc_read(png_ptr, data, 22);
  46.892 -+    png_crc_finish(png_ptr, 0);
  46.893 -+
  46.894 -+    width = png_get_uint_31(png_ptr, data);
  46.895 -+    height = png_get_uint_31(png_ptr, data + 4);
  46.896 -+    x_offset = png_get_uint_31(png_ptr, data + 8);
  46.897 -+    y_offset = png_get_uint_31(png_ptr, data + 12);
  46.898 -+    delay_num = png_get_uint_16(data + 16);
  46.899 -+    delay_den = png_get_uint_16(data + 18);
  46.900 -+    dispose_op = data[20];
  46.901 -+    blend_op = data[21];
  46.902 -+
  46.903 -+    if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
  46.904 -+    {
  46.905 -+        png_warning(png_ptr, "fcTL for the first frame must have zero offset");
  46.906 -+        return;
  46.907 -+    }
  46.908 -+
  46.909 -+    if (info_ptr != NULL)
  46.910 -+    {
  46.911 -+        if (png_ptr->num_frames_read == 0 &&
  46.912 -+            (width != info_ptr->width || height != info_ptr->height))
  46.913 -+        {
  46.914 -+            png_warning(png_ptr, "size in first frame's fcTL must match "
  46.915 -+                               "the size in IHDR");
  46.916 -+            return;
  46.917 -+        }
  46.918 -+
  46.919 -+        /* The set function will do more error checking */
  46.920 -+        png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
  46.921 -+                                x_offset, y_offset, delay_num, delay_den,
  46.922 -+                                dispose_op, blend_op);
  46.923 -+
  46.924 -+        png_read_reinit(png_ptr, info_ptr);
  46.925 -+
  46.926 -+        png_ptr->mode |= PNG_HAVE_fcTL;
  46.927 -+    }
  46.928 -+}
  46.929 -+
  46.930 -+void /* PRIVATE */
  46.931 -+png_have_info(png_structp png_ptr, png_infop info_ptr)
  46.932 -+{
  46.933 -+    if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
  46.934 -+    {
  46.935 -+        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
  46.936 -+        info_ptr->num_frames++;
  46.937 -+    }
  46.938 -+}
  46.939 -+
  46.940 -+void /* PRIVATE */
  46.941 -+png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  46.942 -+{
  46.943 -+    png_ensure_sequence_number(png_ptr, length);
  46.944 -+
  46.945 -+    /* This function is only called from png_read_end(), png_read_info(),
  46.946 -+    * and png_push_read_chunk() which means that:
  46.947 -+    * - the user doesn't want to read this frame
  46.948 -+    * - or this is an out-of-place fdAT
  46.949 -+    * in either case it is safe to ignore the chunk with a warning */
  46.950 -+    png_warning(png_ptr, "ignoring fdAT chunk");
  46.951 -+    png_crc_finish(png_ptr, length - 4);
  46.952 -+    PNG_UNUSED(info_ptr)
  46.953 -+}
  46.954 -+
  46.955 -+void /* PRIVATE */
  46.956 -+png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
  46.957 -+{
  46.958 -+    png_byte data[4];
  46.959 -+    png_uint_32 sequence_number;
  46.960 -+
  46.961 -+    if (length < 4)
  46.962 -+        png_error(png_ptr, "invalid fcTL or fdAT chunk found");
  46.963 -+
  46.964 -+    png_crc_read(png_ptr, data, 4);
  46.965 -+    sequence_number = png_get_uint_31(png_ptr, data);
  46.966 -+
  46.967 -+    if (sequence_number != png_ptr->next_seq_num)
  46.968 -+        png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
  46.969 -+                           "number found");
  46.970 -+
  46.971 -+    png_ptr->next_seq_num++;
  46.972 -+}
  46.973 -+#endif /* PNG_READ_APNG_SUPPORTED */
  46.974 -+
  46.975 - #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
  46.976 - /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
  46.977 - static int
  46.978 -@@ -4145,7 +4323,38 @@
  46.979 -       {
  46.980 -          uInt avail_in;
  46.981 -          png_bytep buffer;
  46.982 -+#ifdef PNG_READ_APNG_SUPPORTED
  46.983 -+         png_uint_32 bytes_to_skip = 0;
  46.984 -+
  46.985 -+         while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
  46.986 -+         {
  46.987 -+            png_crc_finish(png_ptr, bytes_to_skip);
  46.988 -+            bytes_to_skip = 0;
  46.989 -+
  46.990 -+            png_ptr->idat_size = png_read_chunk_header(png_ptr);
  46.991 -+            if (png_ptr->num_frames_read == 0)
  46.992 -+            {
  46.993 -+               if (png_ptr->chunk_name != png_IDAT)
  46.994 -+                  png_error(png_ptr, "Not enough image data");
  46.995 -+            }
  46.996 -+            else
  46.997 -+            {
  46.998 -+               if (png_ptr->chunk_name == png_IEND)
  46.999 -+                  png_error(png_ptr, "Not enough image data");
 46.1000 -+               if (png_ptr->chunk_name != png_fdAT)
 46.1001 -+               {
 46.1002 -+                  png_warning(png_ptr, "Skipped (ignored) a chunk "
 46.1003 -+                                       "between APNG chunks");
 46.1004 -+                  bytes_to_skip = png_ptr->idat_size;
 46.1005 -+                  continue;
 46.1006 -+               }
 46.1007 - 
 46.1008 -+               png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
 46.1009 -+
 46.1010 -+               png_ptr->idat_size -= 4;
 46.1011 -+            }
 46.1012 -+         }
 46.1013 -+#else
 46.1014 -          while (png_ptr->idat_size == 0)
 46.1015 -          {
 46.1016 -             png_crc_finish(png_ptr, 0);
 46.1017 -@@ -4157,7 +4366,7 @@
 46.1018 -             if (png_ptr->chunk_name != png_IDAT)
 46.1019 -                png_error(png_ptr, "Not enough image data");
 46.1020 -          }
 46.1021 --
 46.1022 -+#endif /* PNG_READ_APNG_SUPPORTED */
 46.1023 -          avail_in = png_ptr->IDAT_read_size;
 46.1024 - 
 46.1025 -          if (avail_in > png_ptr->idat_size)
 46.1026 -@@ -4220,6 +4429,9 @@
 46.1027 - 
 46.1028 -          png_ptr->mode |= PNG_AFTER_IDAT;
 46.1029 -          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
 46.1030 -+#ifdef PNG_READ_APNG_SUPPORTED
 46.1031 -+         png_ptr->num_frames_read++;
 46.1032 -+#endif
 46.1033 - 
 46.1034 -          if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
 46.1035 -             png_chunk_benign_error(png_ptr, "Extra compressed data");
 46.1036 -@@ -4658,4 +4870,80 @@
 46.1037 - 
 46.1038 -    png_ptr->flags |= PNG_FLAG_ROW_INIT;
 46.1039 - }
 46.1040 -+
 46.1041 -+#ifdef PNG_READ_APNG_SUPPORTED
 46.1042 -+/* This function is to be called after the main IDAT set has been read and
 46.1043 -+ * before a new IDAT is read. It resets some parts of png_ptr
 46.1044 -+ * to make them usable by the read functions again */
 46.1045 -+void /* PRIVATE */
 46.1046 -+png_read_reset(png_structp png_ptr)
 46.1047 -+{
 46.1048 -+    png_ptr->mode &= ~PNG_HAVE_IDAT;
 46.1049 -+    png_ptr->mode &= ~PNG_AFTER_IDAT;
 46.1050 -+    png_ptr->row_number = 0;
 46.1051 -+    png_ptr->pass = 0;
 46.1052 -+}
 46.1053 -+
 46.1054 -+void /* PRIVATE */
 46.1055 -+png_read_reinit(png_structp png_ptr, png_infop info_ptr)
 46.1056 -+{
 46.1057 -+    png_ptr->width = info_ptr->next_frame_width;
 46.1058 -+    png_ptr->height = info_ptr->next_frame_height;
 46.1059 -+    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
 46.1060 -+    png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
 46.1061 -+        png_ptr->width);
 46.1062 -+    if (png_ptr->prev_row)
 46.1063 -+        memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
 46.1064 -+}
 46.1065 -+
 46.1066 -+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 46.1067 -+/* same as png_read_reset() but for the progressive reader */
 46.1068 -+void /* PRIVATE */
 46.1069 -+png_progressive_read_reset(png_structp png_ptr)
 46.1070 -+{
 46.1071 -+#ifdef PNG_READ_INTERLACING_SUPPORTED
 46.1072 -+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
 46.1073 -+
 46.1074 -+   /* Start of interlace block */
 46.1075 -+    const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
 46.1076 -+
 46.1077 -+    /* Offset to next interlace block */
 46.1078 -+    const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
 46.1079 -+
 46.1080 -+    /* Start of interlace block in the y direction */
 46.1081 -+    const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
 46.1082 -+
 46.1083 -+    /* Offset to next interlace block in the y direction */
 46.1084 -+    const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
 46.1085 -+
 46.1086 -+    if (png_ptr->interlaced)
 46.1087 -+    {
 46.1088 -+        if (!(png_ptr->transformations & PNG_INTERLACE))
 46.1089 -+            png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
 46.1090 -+                                png_pass_ystart[0]) / png_pass_yinc[0];
 46.1091 -+        else
 46.1092 -+            png_ptr->num_rows = png_ptr->height;
 46.1093 -+
 46.1094 -+        png_ptr->iwidth = (png_ptr->width +
 46.1095 -+                           png_pass_inc[png_ptr->pass] - 1 -
 46.1096 -+                           png_pass_start[png_ptr->pass]) /
 46.1097 -+                           png_pass_inc[png_ptr->pass];
 46.1098 -+    }
 46.1099 -+    else
 46.1100 -+#endif /* PNG_READ_INTERLACING_SUPPORTED */
 46.1101 -+    {
 46.1102 -+        png_ptr->num_rows = png_ptr->height;
 46.1103 -+        png_ptr->iwidth = png_ptr->width;
 46.1104 -+    }
 46.1105 -+    png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
 46.1106 -+    if (inflateReset(&(png_ptr->zstream)) != Z_OK)
 46.1107 -+        png_error(png_ptr, "inflateReset failed");
 46.1108 -+    png_ptr->zstream.avail_in = 0;
 46.1109 -+    png_ptr->zstream.next_in = 0;
 46.1110 -+    png_ptr->zstream.next_out = png_ptr->row_buf;
 46.1111 -+    png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
 46.1112 -+        png_ptr->iwidth) + 1;
 46.1113 -+}
 46.1114 -+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 46.1115 -+#endif /* PNG_READ_APNG_SUPPORTED */
 46.1116 - #endif /* READ */
 46.1117 -diff -Naru libpng-1.6.34.org/pngset.c libpng-1.6.34/pngset.c
 46.1118 ---- libpng-1.6.34.org/pngset.c	2017-09-29 18:53:22.701691926 +0900
 46.1119 -+++ libpng-1.6.34/pngset.c	2017-09-29 18:56:30.292848897 +0900
 46.1120 -@@ -288,6 +288,11 @@
 46.1121 -    info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
 46.1122 - 
 46.1123 -    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
 46.1124 -+
 46.1125 -+#ifdef PNG_APNG_SUPPORTED
 46.1126 -+   /* for non-animated png. this may be overwritten from an acTL chunk later */
 46.1127 -+   info_ptr->num_frames = 1;
 46.1128 -+#endif
 46.1129 - }
 46.1130 - 
 46.1131 - #ifdef PNG_oFFs_SUPPORTED
 46.1132 -@@ -1158,6 +1163,147 @@
 46.1133 - }
 46.1134 - #endif /* sPLT */
 46.1135 - 
 46.1136 -+#ifdef PNG_APNG_SUPPORTED
 46.1137 -+png_uint_32 PNGAPI
 46.1138 -+png_set_acTL(png_structp png_ptr, png_infop info_ptr,
 46.1139 -+    png_uint_32 num_frames, png_uint_32 num_plays)
 46.1140 -+{
 46.1141 -+    png_debug1(1, "in %s storage function", "acTL");
 46.1142 -+
 46.1143 -+    if (png_ptr == NULL || info_ptr == NULL)
 46.1144 -+    {
 46.1145 -+        png_warning(png_ptr,
 46.1146 -+                    "Call to png_set_acTL() with NULL png_ptr "
 46.1147 -+                    "or info_ptr ignored");
 46.1148 -+        return (0);
 46.1149 -+    }
 46.1150 -+    if (num_frames == 0)
 46.1151 -+    {
 46.1152 -+        png_warning(png_ptr,
 46.1153 -+                    "Ignoring attempt to set acTL with num_frames zero");
 46.1154 -+        return (0);
 46.1155 -+    }
 46.1156 -+    if (num_frames > PNG_UINT_31_MAX)
 46.1157 -+    {
 46.1158 -+        png_warning(png_ptr,
 46.1159 -+                    "Ignoring attempt to set acTL with num_frames > 2^31-1");
 46.1160 -+        return (0);
 46.1161 -+    }
 46.1162 -+    if (num_plays > PNG_UINT_31_MAX)
 46.1163 -+    {
 46.1164 -+        png_warning(png_ptr,
 46.1165 -+                    "Ignoring attempt to set acTL with num_plays "
 46.1166 -+                    "> 2^31-1");
 46.1167 -+        return (0);
 46.1168 -+    }
 46.1169 -+
 46.1170 -+    info_ptr->num_frames = num_frames;
 46.1171 -+    info_ptr->num_plays = num_plays;
 46.1172 -+
 46.1173 -+    info_ptr->valid |= PNG_INFO_acTL;
 46.1174 -+
 46.1175 -+    return (1);
 46.1176 -+}
 46.1177 -+
 46.1178 -+/* delay_num and delay_den can hold any 16-bit values including zero */
 46.1179 -+png_uint_32 PNGAPI
 46.1180 -+png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
 46.1181 -+    png_uint_32 width, png_uint_32 height,
 46.1182 -+    png_uint_32 x_offset, png_uint_32 y_offset,
 46.1183 -+    png_uint_16 delay_num, png_uint_16 delay_den,
 46.1184 -+    png_byte dispose_op, png_byte blend_op)
 46.1185 -+{
 46.1186 -+    png_debug1(1, "in %s storage function", "fcTL");
 46.1187 -+
 46.1188 -+    if (png_ptr == NULL || info_ptr == NULL)
 46.1189 -+    {
 46.1190 -+        png_warning(png_ptr,
 46.1191 -+                    "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
 46.1192 -+                    "ignored");
 46.1193 -+        return (0);
 46.1194 -+    }
 46.1195 -+
 46.1196 -+    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
 46.1197 -+                             delay_num, delay_den, dispose_op, blend_op);
 46.1198 -+
 46.1199 -+    if (blend_op == PNG_BLEND_OP_OVER)
 46.1200 -+    {
 46.1201 -+        if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
 46.1202 -+            !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
 46.1203 -+        {
 46.1204 -+          png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
 46.1205 -+                               "and wasteful for opaque images, ignored");
 46.1206 -+          blend_op = PNG_BLEND_OP_SOURCE;
 46.1207 -+        }
 46.1208 -+    }
 46.1209 -+
 46.1210 -+    info_ptr->next_frame_width = width;
 46.1211 -+    info_ptr->next_frame_height = height;
 46.1212 -+    info_ptr->next_frame_x_offset = x_offset;
 46.1213 -+    info_ptr->next_frame_y_offset = y_offset;
 46.1214 -+    info_ptr->next_frame_delay_num = delay_num;
 46.1215 -+    info_ptr->next_frame_delay_den = delay_den;
 46.1216 -+    info_ptr->next_frame_dispose_op = dispose_op;
 46.1217 -+    info_ptr->next_frame_blend_op = blend_op;
 46.1218 -+
 46.1219 -+    info_ptr->valid |= PNG_INFO_fcTL;
 46.1220 -+
 46.1221 -+    return (1);
 46.1222 -+}
 46.1223 -+
 46.1224 -+void /* PRIVATE */
 46.1225 -+png_ensure_fcTL_is_valid(png_structp png_ptr,
 46.1226 -+    png_uint_32 width, png_uint_32 height,
 46.1227 -+    png_uint_32 x_offset, png_uint_32 y_offset,
 46.1228 -+    png_uint_16 delay_num, png_uint_16 delay_den,
 46.1229 -+    png_byte dispose_op, png_byte blend_op)
 46.1230 -+{
 46.1231 -+    if (width == 0 || width > PNG_UINT_31_MAX)
 46.1232 -+        png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
 46.1233 -+    if (height == 0 || height > PNG_UINT_31_MAX)
 46.1234 -+        png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
 46.1235 -+    if (x_offset > PNG_UINT_31_MAX)
 46.1236 -+        png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
 46.1237 -+    if (y_offset > PNG_UINT_31_MAX)
 46.1238 -+        png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
 46.1239 -+    if (width + x_offset > png_ptr->first_frame_width ||
 46.1240 -+        height + y_offset > png_ptr->first_frame_height)
 46.1241 -+        png_error(png_ptr, "dimensions of a frame are greater than"
 46.1242 -+                           "the ones in IHDR");
 46.1243 -+
 46.1244 -+    if (dispose_op != PNG_DISPOSE_OP_NONE &&
 46.1245 -+        dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
 46.1246 -+        dispose_op != PNG_DISPOSE_OP_PREVIOUS)
 46.1247 -+        png_error(png_ptr, "invalid dispose_op in fcTL");
 46.1248 -+
 46.1249 -+    if (blend_op != PNG_BLEND_OP_SOURCE &&
 46.1250 -+        blend_op != PNG_BLEND_OP_OVER)
 46.1251 -+        png_error(png_ptr, "invalid blend_op in fcTL");
 46.1252 -+
 46.1253 -+    PNG_UNUSED(delay_num)
 46.1254 -+    PNG_UNUSED(delay_den)
 46.1255 -+}
 46.1256 -+
 46.1257 -+png_uint_32 PNGAPI
 46.1258 -+png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
 46.1259 -+                              png_byte is_hidden)
 46.1260 -+{
 46.1261 -+    png_debug(1, "in png_first_frame_is_hidden()");
 46.1262 -+
 46.1263 -+    if (png_ptr == NULL)
 46.1264 -+        return 0;
 46.1265 -+
 46.1266 -+    if (is_hidden)
 46.1267 -+        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
 46.1268 -+    else
 46.1269 -+        png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
 46.1270 -+
 46.1271 -+    PNG_UNUSED(info_ptr)
 46.1272 -+
 46.1273 -+    return 1;
 46.1274 -+}
 46.1275 -+#endif /* PNG_APNG_SUPPORTED */
 46.1276 -+
 46.1277 - #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
 46.1278 - static png_byte
 46.1279 - check_location(png_const_structrp png_ptr, int location)
 46.1280 -diff -Naru libpng-1.6.34.org/pngstruct.h libpng-1.6.34/pngstruct.h
 46.1281 ---- libpng-1.6.34.org/pngstruct.h	2017-09-29 18:53:22.701691926 +0900
 46.1282 -+++ libpng-1.6.34/pngstruct.h	2017-09-29 18:56:30.287848466 +0900
 46.1283 -@@ -403,6 +403,27 @@
 46.1284 -    png_byte filter_type;
 46.1285 - #endif
 46.1286 - 
 46.1287 -+#ifdef PNG_APNG_SUPPORTED
 46.1288 -+   png_uint_32 apng_flags;
 46.1289 -+   png_uint_32 next_seq_num;         /* next fcTL/fdAT chunk sequence number */
 46.1290 -+   png_uint_32 first_frame_width;
 46.1291 -+   png_uint_32 first_frame_height;
 46.1292 -+
 46.1293 -+#ifdef PNG_READ_APNG_SUPPORTED
 46.1294 -+   png_uint_32 num_frames_read;      /* incremented after all image data of */
 46.1295 -+                                     /* a frame is read */
 46.1296 -+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 46.1297 -+   png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
 46.1298 -+   png_progressive_frame_ptr frame_end_fn;  /* frame data read callback */
 46.1299 -+#endif
 46.1300 -+#endif
 46.1301 -+
 46.1302 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1303 -+   png_uint_32 num_frames_to_write;
 46.1304 -+   png_uint_32 num_frames_written;
 46.1305 -+#endif
 46.1306 -+#endif /* PNG_APNG_SUPPORTED */
 46.1307 -+
 46.1308 - /* New members added in libpng-1.2.0 */
 46.1309 - 
 46.1310 - /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
 46.1311 -diff -Naru libpng-1.6.34.org/pngtest.c libpng-1.6.34/pngtest.c
 46.1312 ---- libpng-1.6.34.org/pngtest.c	2017-09-29 18:55:30.654712085 +0900
 46.1313 -+++ libpng-1.6.34/pngtest.c	2017-09-29 18:56:30.287848466 +0900
 46.1314 -@@ -875,6 +875,10 @@
 46.1315 -    volatile int num_passes;
 46.1316 -    int pass;
 46.1317 -    int bit_depth, color_type;
 46.1318 -+#ifdef PNG_APNG_SUPPORTED
 46.1319 -+   png_uint_32 num_frames;
 46.1320 -+   png_uint_32 num_plays;
 46.1321 -+#endif
 46.1322 - 
 46.1323 -    row_buf = NULL;
 46.1324 -    error_parameters.file_name = inname;
 46.1325 -@@ -1381,6 +1385,22 @@
 46.1326 -       }
 46.1327 -    }
 46.1328 - #endif
 46.1329 -+
 46.1330 -+#ifdef PNG_APNG_SUPPORTED
 46.1331 -+   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
 46.1332 -+   {
 46.1333 -+      if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
 46.1334 -+      {
 46.1335 -+         png_byte is_hidden;
 46.1336 -+         pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
 46.1337 -+                    num_frames, num_plays);
 46.1338 -+         png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
 46.1339 -+         is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
 46.1340 -+         png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
 46.1341 -+      }
 46.1342 -+   }
 46.1343 -+#endif
 46.1344 -+
 46.1345 - #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
 46.1346 -    {
 46.1347 -       png_unknown_chunkp unknowns;
 46.1348 -@@ -1461,6 +1481,110 @@
 46.1349 -    t_misc += (t_stop - t_start);
 46.1350 -    t_start = t_stop;
 46.1351 - #endif
 46.1352 -+#ifdef PNG_APNG_SUPPORTED
 46.1353 -+   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
 46.1354 -+   {
 46.1355 -+      png_uint_32 frame;
 46.1356 -+      for (frame = 0; frame < num_frames; frame++)
 46.1357 -+      {
 46.1358 -+         png_uint_32 frame_width;
 46.1359 -+         png_uint_32 frame_height;
 46.1360 -+         png_uint_32 x_offset;
 46.1361 -+         png_uint_32 y_offset;
 46.1362 -+         png_uint_16 delay_num;
 46.1363 -+         png_uint_16 delay_den;
 46.1364 -+         png_byte dispose_op;
 46.1365 -+         png_byte blend_op;
 46.1366 -+         png_read_frame_head(read_ptr, read_info_ptr);
 46.1367 -+         if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
 46.1368 -+         {
 46.1369 -+            png_get_next_frame_fcTL(read_ptr, read_info_ptr,
 46.1370 -+                                    &frame_width, &frame_height,
 46.1371 -+                                    &x_offset, &y_offset,
 46.1372 -+                                    &delay_num, &delay_den,
 46.1373 -+                                    &dispose_op, &blend_op);
 46.1374 -+         }
 46.1375 -+         else
 46.1376 -+         {
 46.1377 -+            frame_width = width;
 46.1378 -+            frame_height = height;
 46.1379 -+            x_offset = 0;
 46.1380 -+            y_offset = 0;
 46.1381 -+            delay_num = 1;
 46.1382 -+            delay_den = 1;
 46.1383 -+            dispose_op = PNG_DISPOSE_OP_NONE;
 46.1384 -+            blend_op = PNG_BLEND_OP_SOURCE;
 46.1385 -+         }
 46.1386 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1387 -+         png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
 46.1388 -+                              frame_width, frame_height,
 46.1389 -+                              x_offset, y_offset,
 46.1390 -+                              delay_num, delay_den,
 46.1391 -+                              dispose_op, blend_op);
 46.1392 -+#endif
 46.1393 -+         for (pass = 0; pass < num_passes; pass++)
 46.1394 -+         {
 46.1395 -+#           ifdef calc_pass_height
 46.1396 -+               png_uint_32 pass_height;
 46.1397 -+
 46.1398 -+               if (num_passes == 7) /* interlaced */
 46.1399 -+               {
 46.1400 -+                  if (PNG_PASS_COLS(frame_width, pass) > 0)
 46.1401 -+                     pass_height = PNG_PASS_ROWS(frame_height, pass);
 46.1402 -+
 46.1403 -+                  else
 46.1404 -+                     pass_height = 0;
 46.1405 -+               }
 46.1406 -+
 46.1407 -+               else /* not interlaced */
 46.1408 -+                  pass_height = frame_height;
 46.1409 -+#           else
 46.1410 -+#              define pass_height frame_height
 46.1411 -+#           endif
 46.1412 -+
 46.1413 -+            pngtest_debug1("Writing row data for pass %d", pass);
 46.1414 -+            for (y = 0; y < pass_height; y++)
 46.1415 -+            {
 46.1416 -+#ifndef SINGLE_ROWBUF_ALLOC
 46.1417 -+               pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
 46.1418 -+
 46.1419 -+               row_buf = (png_bytep)png_malloc(read_ptr,
 46.1420 -+                  png_get_rowbytes(read_ptr, read_info_ptr));
 46.1421 -+
 46.1422 -+               pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
 46.1423 -+                  (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
 46.1424 -+
 46.1425 -+#endif /* !SINGLE_ROWBUF_ALLOC */
 46.1426 -+               png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
 46.1427 -+
 46.1428 -+#ifdef PNG_WRITE_SUPPORTED
 46.1429 -+#ifdef PNGTEST_TIMING
 46.1430 -+               t_stop = (float)clock();
 46.1431 -+               t_decode += (t_stop - t_start);
 46.1432 -+               t_start = t_stop;
 46.1433 -+#endif
 46.1434 -+               png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
 46.1435 -+#ifdef PNGTEST_TIMING
 46.1436 -+               t_stop = (float)clock();
 46.1437 -+               t_encode += (t_stop - t_start);
 46.1438 -+               t_start = t_stop;
 46.1439 -+#endif
 46.1440 -+#endif /* PNG_WRITE_SUPPORTED */
 46.1441 -+
 46.1442 -+#ifndef SINGLE_ROWBUF_ALLOC
 46.1443 -+               pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
 46.1444 -+               png_free(read_ptr, row_buf);
 46.1445 -+               row_buf = NULL;
 46.1446 -+#endif /* !SINGLE_ROWBUF_ALLOC */
 46.1447 -+            }
 46.1448 -+         }
 46.1449 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1450 -+         png_write_frame_tail(write_ptr, write_info_ptr);
 46.1451 -+#endif
 46.1452 -+      }
 46.1453 -+   }
 46.1454 -+   else
 46.1455 -+#endif
 46.1456 -    for (pass = 0; pass < num_passes; pass++)
 46.1457 -    {
 46.1458 - #     ifdef calc_pass_height
 46.1459 -diff -Naru libpng-1.6.34.org/pngwrite.c libpng-1.6.34/pngwrite.c
 46.1460 ---- libpng-1.6.34.org/pngwrite.c	2017-09-29 18:53:22.702692013 +0900
 46.1461 -+++ libpng-1.6.34/pngwrite.c	2017-09-29 18:56:30.288848552 +0900
 46.1462 -@@ -128,6 +128,10 @@
 46.1463 -        * the application continues writing the PNG.  So check the 'invalid'
 46.1464 -        * flag here too.
 46.1465 -        */
 46.1466 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1467 -+      if (info_ptr->valid & PNG_INFO_acTL)
 46.1468 -+         png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
 46.1469 -+#endif
 46.1470 - #ifdef PNG_GAMMA_SUPPORTED
 46.1471 - #  ifdef PNG_WRITE_gAMA_SUPPORTED
 46.1472 -       if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
 46.1473 -@@ -370,6 +374,11 @@
 46.1474 -       png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
 46.1475 - #endif
 46.1476 - 
 46.1477 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1478 -+   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
 46.1479 -+      png_error(png_ptr, "Not enough frames written");
 46.1480 -+#endif
 46.1481 -+
 46.1482 -    /* See if user wants us to write information chunks */
 46.1483 -    if (info_ptr != NULL)
 46.1484 -    {
 46.1485 -@@ -1461,6 +1470,43 @@
 46.1486 - }
 46.1487 - #endif
 46.1488 - 
 46.1489 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1490 -+void PNGAPI
 46.1491 -+png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
 46.1492 -+    png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
 46.1493 -+    png_uint_32 x_offset, png_uint_32 y_offset,
 46.1494 -+    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
 46.1495 -+    png_byte blend_op)
 46.1496 -+{
 46.1497 -+    png_debug(1, "in png_write_frame_head");
 46.1498 -+
 46.1499 -+    /* there is a chance this has been set after png_write_info was called,
 46.1500 -+    * so it would be set but not written. is there a way to be sure? */
 46.1501 -+    if (!(info_ptr->valid & PNG_INFO_acTL))
 46.1502 -+        png_error(png_ptr, "png_write_frame_head(): acTL not set");
 46.1503 -+
 46.1504 -+    png_write_reset(png_ptr);
 46.1505 -+
 46.1506 -+    png_write_reinit(png_ptr, info_ptr, width, height);
 46.1507 -+
 46.1508 -+    if ( !(png_ptr->num_frames_written == 0 &&
 46.1509 -+           (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
 46.1510 -+        png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
 46.1511 -+                       delay_num, delay_den, dispose_op, blend_op);
 46.1512 -+
 46.1513 -+    PNG_UNUSED(row_pointers)
 46.1514 -+}
 46.1515 -+
 46.1516 -+void PNGAPI
 46.1517 -+png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
 46.1518 -+{
 46.1519 -+    png_debug(1, "in png_write_frame_tail");
 46.1520 -+
 46.1521 -+    png_ptr->num_frames_written++;
 46.1522 -+
 46.1523 -+    PNG_UNUSED(info_ptr)
 46.1524 -+}
 46.1525 -+#endif /* PNG_WRITE_APNG_SUPPORTED */
 46.1526 - 
 46.1527 - #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
 46.1528 - /* Initialize the write structure - general purpose utility. */
 46.1529 -diff -Naru libpng-1.6.34.org/pngwutil.c libpng-1.6.34/pngwutil.c
 46.1530 ---- libpng-1.6.34.org/pngwutil.c	2017-09-29 18:53:22.703692099 +0900
 46.1531 -+++ libpng-1.6.34/pngwutil.c	2017-09-29 18:56:30.302849758 +0900
 46.1532 -@@ -822,6 +822,11 @@
 46.1533 -    /* Write the chunk */
 46.1534 -    png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
 46.1535 - 
 46.1536 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1537 -+   png_ptr->first_frame_width = width;
 46.1538 -+   png_ptr->first_frame_height = height;
 46.1539 -+#endif
 46.1540 -+
 46.1541 -    if ((png_ptr->do_filter) == PNG_NO_FILTERS)
 46.1542 -    {
 46.1543 -       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
 46.1544 -@@ -1003,8 +1008,17 @@
 46.1545 -                optimize_cmf(data, png_image_size(png_ptr));
 46.1546 - #endif
 46.1547 - 
 46.1548 --         if (size > 0)
 46.1549 --            png_write_complete_chunk(png_ptr, png_IDAT, data, size);
 46.1550 -+            if (size > 0)
 46.1551 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1552 -+            {
 46.1553 -+               if (png_ptr->num_frames_written == 0)
 46.1554 -+#endif
 46.1555 -+               png_write_complete_chunk(png_ptr, png_IDAT, data, size);
 46.1556 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1557 -+               else
 46.1558 -+                  png_write_fdAT(png_ptr, data, size);
 46.1559 -+            }
 46.1560 -+#endif /* PNG_WRITE_APNG_SUPPORTED */
 46.1561 -          png_ptr->mode |= PNG_HAVE_IDAT;
 46.1562 - 
 46.1563 -          png_ptr->zstream.next_out = data;
 46.1564 -@@ -1051,7 +1065,17 @@
 46.1565 - #endif
 46.1566 - 
 46.1567 -          if (size > 0)
 46.1568 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1569 -+         {
 46.1570 -+            if (png_ptr->num_frames_written == 0)
 46.1571 -+#endif
 46.1572 -             png_write_complete_chunk(png_ptr, png_IDAT, data, size);
 46.1573 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1574 -+            else
 46.1575 -+               png_write_fdAT(png_ptr, data, size);
 46.1576 -+         }
 46.1577 -+#endif /* PNG_WRITE_APNG_SUPPORTED */
 46.1578 -+
 46.1579 -          png_ptr->zstream.avail_out = 0;
 46.1580 -          png_ptr->zstream.next_out = NULL;
 46.1581 -          png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
 46.1582 -@@ -1887,6 +1911,82 @@
 46.1583 - }
 46.1584 - #endif
 46.1585 - 
 46.1586 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1587 -+void /* PRIVATE */
 46.1588 -+png_write_acTL(png_structp png_ptr,
 46.1589 -+    png_uint_32 num_frames, png_uint_32 num_plays)
 46.1590 -+{
 46.1591 -+    png_byte buf[8];
 46.1592 -+
 46.1593 -+    png_debug(1, "in png_write_acTL");
 46.1594 -+
 46.1595 -+    png_ptr->num_frames_to_write = num_frames;
 46.1596 -+
 46.1597 -+    if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
 46.1598 -+        num_frames--;
 46.1599 -+
 46.1600 -+    png_save_uint_32(buf, num_frames);
 46.1601 -+    png_save_uint_32(buf + 4, num_plays);
 46.1602 -+
 46.1603 -+    png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
 46.1604 -+}
 46.1605 -+
 46.1606 -+void /* PRIVATE */
 46.1607 -+png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
 46.1608 -+    png_uint_32 x_offset, png_uint_32 y_offset,
 46.1609 -+    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
 46.1610 -+    png_byte blend_op)
 46.1611 -+{
 46.1612 -+    png_byte buf[26];
 46.1613 -+
 46.1614 -+    png_debug(1, "in png_write_fcTL");
 46.1615 -+
 46.1616 -+    if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
 46.1617 -+        png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
 46.1618 -+    if (png_ptr->num_frames_written == 0 &&
 46.1619 -+        (width != png_ptr->first_frame_width ||
 46.1620 -+         height != png_ptr->first_frame_height))
 46.1621 -+        png_error(png_ptr, "width and/or height in the first frame's fcTL "
 46.1622 -+                           "don't match the ones in IHDR");
 46.1623 -+
 46.1624 -+    /* more error checking */
 46.1625 -+    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
 46.1626 -+                             delay_num, delay_den, dispose_op, blend_op);
 46.1627 -+
 46.1628 -+    png_save_uint_32(buf, png_ptr->next_seq_num);
 46.1629 -+    png_save_uint_32(buf + 4, width);
 46.1630 -+    png_save_uint_32(buf + 8, height);
 46.1631 -+    png_save_uint_32(buf + 12, x_offset);
 46.1632 -+    png_save_uint_32(buf + 16, y_offset);
 46.1633 -+    png_save_uint_16(buf + 20, delay_num);
 46.1634 -+    png_save_uint_16(buf + 22, delay_den);
 46.1635 -+    buf[24] = dispose_op;
 46.1636 -+    buf[25] = blend_op;
 46.1637 -+
 46.1638 -+    png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
 46.1639 -+
 46.1640 -+    png_ptr->next_seq_num++;
 46.1641 -+}
 46.1642 -+
 46.1643 -+void /* PRIVATE */
 46.1644 -+png_write_fdAT(png_structp png_ptr,
 46.1645 -+    png_const_bytep data, png_size_t length)
 46.1646 -+{
 46.1647 -+    png_byte buf[4];
 46.1648 -+
 46.1649 -+    png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
 46.1650 -+
 46.1651 -+    png_save_uint_32(buf, png_ptr->next_seq_num);
 46.1652 -+    png_write_chunk_data(png_ptr, buf, 4);
 46.1653 -+
 46.1654 -+    png_write_chunk_data(png_ptr, data, length);
 46.1655 -+
 46.1656 -+    png_write_chunk_end(png_ptr);
 46.1657 -+
 46.1658 -+    png_ptr->next_seq_num++;
 46.1659 -+}
 46.1660 -+#endif /* PNG_WRITE_APNG_SUPPORTED */
 46.1661 -+
 46.1662 - /* Initializes the row writing capability of libpng */
 46.1663 - void /* PRIVATE */
 46.1664 - png_write_start_row(png_structrp png_ptr)
 46.1665 -@@ -2781,4 +2881,39 @@
 46.1666 -    }
 46.1667 - #endif /* WRITE_FLUSH */
 46.1668 - }
 46.1669 -+
 46.1670 -+#ifdef PNG_WRITE_APNG_SUPPORTED
 46.1671 -+void /* PRIVATE */
 46.1672 -+png_write_reset(png_structp png_ptr)
 46.1673 -+{
 46.1674 -+    png_ptr->row_number = 0;
 46.1675 -+    png_ptr->pass = 0;
 46.1676 -+    png_ptr->mode &= ~PNG_HAVE_IDAT;
 46.1677 -+}
 46.1678 -+
 46.1679 -+void /* PRIVATE */
 46.1680 -+png_write_reinit(png_structp png_ptr, png_infop info_ptr,
 46.1681 -+                 png_uint_32 width, png_uint_32 height)
 46.1682 -+{
 46.1683 -+    if (png_ptr->num_frames_written == 0 &&
 46.1684 -+        (width != png_ptr->first_frame_width ||
 46.1685 -+         height != png_ptr->first_frame_height))
 46.1686 -+        png_error(png_ptr, "width and/or height in the first frame's fcTL "
 46.1687 -+                           "don't match the ones in IHDR");
 46.1688 -+    if (width > png_ptr->first_frame_width ||
 46.1689 -+        height > png_ptr->first_frame_height)
 46.1690 -+        png_error(png_ptr, "width and/or height for a frame greater than"
 46.1691 -+                           "the ones in IHDR");
 46.1692 -+
 46.1693 -+    png_set_IHDR(png_ptr, info_ptr, width, height,
 46.1694 -+                 info_ptr->bit_depth, info_ptr->color_type,
 46.1695 -+                 info_ptr->interlace_type, info_ptr->compression_type,
 46.1696 -+                 info_ptr->filter_type);
 46.1697 -+
 46.1698 -+    png_ptr->width = width;
 46.1699 -+    png_ptr->height = height;
 46.1700 -+    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
 46.1701 -+    png_ptr->usr_width = png_ptr->width;
 46.1702 -+}
 46.1703 -+#endif /* PNG_WRITE_APNG_SUPPORTED */
 46.1704 - #endif /* WRITE */
 46.1705 -diff -Naru libpng-1.6.34.org/scripts/symbols.def libpng-1.6.34/scripts/symbols.def
 46.1706 ---- libpng-1.6.34.org/scripts/symbols.def	2017-09-29 18:55:30.655712171 +0900
 46.1707 -+++ libpng-1.6.34/scripts/symbols.def	2017-09-29 18:56:30.289848638 +0900
 46.1708 -@@ -254,3 +254,23 @@
 46.1709 -  png_set_eXIf @247
 46.1710 -  png_get_eXIf_1 @248
 46.1711 -  png_set_eXIf_1 @249
 46.1712 -+ png_get_acTL @250
 46.1713 -+ png_set_acTL @251
 46.1714 -+ png_get_num_frames @252
 46.1715 -+ png_get_num_plays @253
 46.1716 -+ png_get_next_frame_fcTL @254
 46.1717 -+ png_set_next_frame_fcTL @255
 46.1718 -+ png_get_next_frame_width @256
 46.1719 -+ png_get_next_frame_height @257
 46.1720 -+ png_get_next_frame_x_offset @258
 46.1721 -+ png_get_next_frame_y_offset @259
 46.1722 -+ png_get_next_frame_delay_num @260
 46.1723 -+ png_get_next_frame_delay_den @261
 46.1724 -+ png_get_next_frame_dispose_op @262
 46.1725 -+ png_get_next_frame_blend_op @263
 46.1726 -+ png_get_first_frame_is_hidden @264
 46.1727 -+ png_set_first_frame_is_hidden @265
 46.1728 -+ png_read_frame_head @266
 46.1729 -+ png_set_progressive_frame_fn @267
 46.1730 -+ png_write_frame_head @268
 46.1731 -+ png_write_frame_tail @269
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/libpng16/stuff/patches/libpng-1.6.35-apng.patch	Tue Aug 07 00:30:45 2018 +0300
    47.3 @@ -0,0 +1,1728 @@
    47.4 +diff -Naru libpng-1.6.35.org/png.h libpng-1.6.35/png.h
    47.5 +--- libpng-1.6.35.org/png.h	2018-07-21 19:16:37.185142931 +0900
    47.6 ++++ libpng-1.6.35/png.h	2018-07-21 19:16:16.327364638 +0900
    47.7 +@@ -361,6 +361,10 @@
    47.8 + #   include "pnglibconf.h"
    47.9 + #endif
   47.10 + 
   47.11 ++#define PNG_APNG_SUPPORTED
   47.12 ++#define PNG_READ_APNG_SUPPORTED
   47.13 ++#define PNG_WRITE_APNG_SUPPORTED
   47.14 ++
   47.15 + #ifndef PNG_VERSION_INFO_ONLY
   47.16 + /* Machine specific configuration. */
   47.17 + #  include "pngconf.h"
   47.18 +@@ -456,6 +460,17 @@
   47.19 +  * See pngconf.h for base types that vary by machine/system
   47.20 +  */
   47.21 + 
   47.22 ++#ifdef PNG_APNG_SUPPORTED
   47.23 ++/* dispose_op flags from inside fcTL */
   47.24 ++#define PNG_DISPOSE_OP_NONE        0x00U
   47.25 ++#define PNG_DISPOSE_OP_BACKGROUND  0x01U
   47.26 ++#define PNG_DISPOSE_OP_PREVIOUS    0x02U
   47.27 ++
   47.28 ++/* blend_op flags from inside fcTL */
   47.29 ++#define PNG_BLEND_OP_SOURCE        0x00U
   47.30 ++#define PNG_BLEND_OP_OVER          0x01U
   47.31 ++#endif /* PNG_APNG_SUPPORTED */
   47.32 ++
   47.33 + /* This triggers a compiler error in png.c, if png.c and png.h
   47.34 +  * do not agree upon the version number.
   47.35 +  */
   47.36 +@@ -777,6 +792,10 @@
   47.37 + #define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */
   47.38 + #define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */
   47.39 + #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
   47.40 ++#ifdef PNG_APNG_SUPPORTED
   47.41 ++#define PNG_INFO_acTL 0x20000U
   47.42 ++#define PNG_INFO_fcTL 0x40000U
   47.43 ++#endif
   47.44 + 
   47.45 + /* This is used for the transformation routines, as some of them
   47.46 +  * change these values for the row.  It also should enable using
   47.47 +@@ -814,6 +833,10 @@
   47.48 + #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
   47.49 + typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
   47.50 + typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
   47.51 ++#ifdef PNG_APNG_SUPPORTED
   47.52 ++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
   47.53 ++    png_uint_32));
   47.54 ++#endif
   47.55 + 
   47.56 + /* The following callback receives png_uint_32 row_number, int pass for the
   47.57 +  * png_bytep data of the row.  When transforming an interlaced image the
   47.58 +@@ -3257,6 +3280,74 @@
   47.59 + /*******************************************************************************
   47.60 +  *  END OF HARDWARE AND SOFTWARE OPTIONS
   47.61 +  ******************************************************************************/
   47.62 ++#ifdef PNG_APNG_SUPPORTED
   47.63 ++PNG_EXPORT(250, png_uint_32, png_get_acTL, (png_structp png_ptr,
   47.64 ++   png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
   47.65 ++
   47.66 ++PNG_EXPORT(251, png_uint_32, png_set_acTL, (png_structp png_ptr,
   47.67 ++   png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
   47.68 ++
   47.69 ++PNG_EXPORT(252, png_uint_32, png_get_num_frames, (png_structp png_ptr,
   47.70 ++   png_infop info_ptr));
   47.71 ++
   47.72 ++PNG_EXPORT(253, png_uint_32, png_get_num_plays, (png_structp png_ptr,
   47.73 ++   png_infop info_ptr));
   47.74 ++
   47.75 ++PNG_EXPORT(254, png_uint_32, png_get_next_frame_fcTL,
   47.76 ++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
   47.77 ++   png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
   47.78 ++   png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
   47.79 ++   png_byte *blend_op));
   47.80 ++
   47.81 ++PNG_EXPORT(255, png_uint_32, png_set_next_frame_fcTL,
   47.82 ++   (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
   47.83 ++   png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
   47.84 ++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
   47.85 ++   png_byte blend_op));
   47.86 ++
   47.87 ++PNG_EXPORT(256, png_uint_32, png_get_next_frame_width,
   47.88 ++   (png_structp png_ptr, png_infop info_ptr));
   47.89 ++PNG_EXPORT(257, png_uint_32, png_get_next_frame_height,
   47.90 ++   (png_structp png_ptr, png_infop info_ptr));
   47.91 ++PNG_EXPORT(258, png_uint_32, png_get_next_frame_x_offset,
   47.92 ++   (png_structp png_ptr, png_infop info_ptr));
   47.93 ++PNG_EXPORT(259, png_uint_32, png_get_next_frame_y_offset,
   47.94 ++   (png_structp png_ptr, png_infop info_ptr));
   47.95 ++PNG_EXPORT(260, png_uint_16, png_get_next_frame_delay_num,
   47.96 ++   (png_structp png_ptr, png_infop info_ptr));
   47.97 ++PNG_EXPORT(261, png_uint_16, png_get_next_frame_delay_den,
   47.98 ++   (png_structp png_ptr, png_infop info_ptr));
   47.99 ++PNG_EXPORT(262, png_byte, png_get_next_frame_dispose_op,
  47.100 ++   (png_structp png_ptr, png_infop info_ptr));
  47.101 ++PNG_EXPORT(263, png_byte, png_get_next_frame_blend_op,
  47.102 ++   (png_structp png_ptr, png_infop info_ptr));
  47.103 ++PNG_EXPORT(264, png_byte, png_get_first_frame_is_hidden,
  47.104 ++   (png_structp png_ptr, png_infop info_ptr));
  47.105 ++PNG_EXPORT(265, png_uint_32, png_set_first_frame_is_hidden,
  47.106 ++   (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
  47.107 ++
  47.108 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.109 ++PNG_EXPORT(266, void, png_read_frame_head, (png_structp png_ptr,
  47.110 ++   png_infop info_ptr));
  47.111 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  47.112 ++PNG_EXPORT(267, void, png_set_progressive_frame_fn, (png_structp png_ptr,
  47.113 ++   png_progressive_frame_ptr frame_info_fn,
  47.114 ++   png_progressive_frame_ptr frame_end_fn));
  47.115 ++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
  47.116 ++#endif /* PNG_READ_APNG_SUPPORTED */
  47.117 ++
  47.118 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  47.119 ++PNG_EXPORT(268, void, png_write_frame_head, (png_structp png_ptr,
  47.120 ++   png_infop info_ptr, png_bytepp row_pointers,
  47.121 ++   png_uint_32 width, png_uint_32 height,
  47.122 ++   png_uint_32 x_offset, png_uint_32 y_offset,
  47.123 ++   png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
  47.124 ++   png_byte blend_op));
  47.125 ++
  47.126 ++PNG_EXPORT(269, void, png_write_frame_tail, (png_structp png_ptr,
  47.127 ++   png_infop info_ptr));
  47.128 ++#endif /* PNG_WRITE_APNG_SUPPORTED */
  47.129 ++#endif /* PNG_APNG_SUPPORTED */
  47.130 + 
  47.131 + /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
  47.132 +  * defs, and in scripts/symbols.def.
  47.133 +@@ -3266,7 +3357,11 @@
  47.134 +  * one to use is one more than this.)
  47.135 +  */
  47.136 + #ifdef PNG_EXPORT_LAST_ORDINAL
  47.137 ++#ifdef PNG_APNG_SUPPORTED
  47.138 ++  PNG_EXPORT_LAST_ORDINAL(269);
  47.139 ++#else
  47.140 +   PNG_EXPORT_LAST_ORDINAL(249);
  47.141 ++#endif /* PNG_APNG_SUPPORTED */
  47.142 + #endif
  47.143 + 
  47.144 + #ifdef __cplusplus
  47.145 +diff -Naru libpng-1.6.35.org/pngget.c libpng-1.6.35/pngget.c
  47.146 +--- libpng-1.6.35.org/pngget.c	2018-07-21 19:16:37.185142931 +0900
  47.147 ++++ libpng-1.6.35/pngget.c	2018-07-21 19:16:16.229356281 +0900
  47.148 +@@ -1246,4 +1246,166 @@
  47.149 + #  endif
  47.150 + #endif
  47.151 + 
  47.152 ++#ifdef PNG_APNG_SUPPORTED
  47.153 ++png_uint_32 PNGAPI
  47.154 ++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
  47.155 ++             png_uint_32 *num_frames, png_uint_32 *num_plays)
  47.156 ++{
  47.157 ++    png_debug1(1, "in %s retrieval function", "acTL");
  47.158 ++
  47.159 ++    if (png_ptr != NULL && info_ptr != NULL &&
  47.160 ++        (info_ptr->valid & PNG_INFO_acTL) &&
  47.161 ++        num_frames != NULL && num_plays != NULL)
  47.162 ++    {
  47.163 ++        *num_frames = info_ptr->num_frames;
  47.164 ++        *num_plays = info_ptr->num_plays;
  47.165 ++        return (1);
  47.166 ++    }
  47.167 ++
  47.168 ++    return (0);
  47.169 ++}
  47.170 ++
  47.171 ++png_uint_32 PNGAPI
  47.172 ++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
  47.173 ++{
  47.174 ++    png_debug(1, "in png_get_num_frames()");
  47.175 ++
  47.176 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.177 ++        return (info_ptr->num_frames);
  47.178 ++    return (0);
  47.179 ++}
  47.180 ++
  47.181 ++png_uint_32 PNGAPI
  47.182 ++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
  47.183 ++{
  47.184 ++    png_debug(1, "in png_get_num_plays()");
  47.185 ++
  47.186 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.187 ++        return (info_ptr->num_plays);
  47.188 ++    return (0);
  47.189 ++}
  47.190 ++
  47.191 ++png_uint_32 PNGAPI
  47.192 ++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
  47.193 ++             png_uint_32 *width, png_uint_32 *height,
  47.194 ++             png_uint_32 *x_offset, png_uint_32 *y_offset,
  47.195 ++             png_uint_16 *delay_num, png_uint_16 *delay_den,
  47.196 ++             png_byte *dispose_op, png_byte *blend_op)
  47.197 ++{
  47.198 ++    png_debug1(1, "in %s retrieval function", "fcTL");
  47.199 ++
  47.200 ++    if (png_ptr != NULL && info_ptr != NULL &&
  47.201 ++        (info_ptr->valid & PNG_INFO_fcTL) &&
  47.202 ++        width != NULL && height != NULL &&
  47.203 ++        x_offset != NULL && y_offset != NULL &&
  47.204 ++        delay_num != NULL && delay_den != NULL &&
  47.205 ++        dispose_op != NULL && blend_op != NULL)
  47.206 ++    {
  47.207 ++        *width = info_ptr->next_frame_width;
  47.208 ++        *height = info_ptr->next_frame_height;
  47.209 ++        *x_offset = info_ptr->next_frame_x_offset;
  47.210 ++        *y_offset = info_ptr->next_frame_y_offset;
  47.211 ++        *delay_num = info_ptr->next_frame_delay_num;
  47.212 ++        *delay_den = info_ptr->next_frame_delay_den;
  47.213 ++        *dispose_op = info_ptr->next_frame_dispose_op;
  47.214 ++        *blend_op = info_ptr->next_frame_blend_op;
  47.215 ++        return (1);
  47.216 ++    }
  47.217 ++
  47.218 ++    return (0);
  47.219 ++}
  47.220 ++
  47.221 ++png_uint_32 PNGAPI
  47.222 ++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
  47.223 ++{
  47.224 ++    png_debug(1, "in png_get_next_frame_width()");
  47.225 ++
  47.226 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.227 ++        return (info_ptr->next_frame_width);
  47.228 ++    return (0);
  47.229 ++}
  47.230 ++
  47.231 ++png_uint_32 PNGAPI
  47.232 ++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
  47.233 ++{
  47.234 ++    png_debug(1, "in png_get_next_frame_height()");
  47.235 ++
  47.236 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.237 ++        return (info_ptr->next_frame_height);
  47.238 ++    return (0);
  47.239 ++}
  47.240 ++
  47.241 ++png_uint_32 PNGAPI
  47.242 ++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
  47.243 ++{
  47.244 ++    png_debug(1, "in png_get_next_frame_x_offset()");
  47.245 ++
  47.246 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.247 ++        return (info_ptr->next_frame_x_offset);
  47.248 ++    return (0);
  47.249 ++}
  47.250 ++
  47.251 ++png_uint_32 PNGAPI
  47.252 ++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
  47.253 ++{
  47.254 ++    png_debug(1, "in png_get_next_frame_y_offset()");
  47.255 ++
  47.256 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.257 ++        return (info_ptr->next_frame_y_offset);
  47.258 ++    return (0);
  47.259 ++}
  47.260 ++
  47.261 ++png_uint_16 PNGAPI
  47.262 ++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
  47.263 ++{
  47.264 ++    png_debug(1, "in png_get_next_frame_delay_num()");
  47.265 ++
  47.266 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.267 ++        return (info_ptr->next_frame_delay_num);
  47.268 ++    return (0);
  47.269 ++}
  47.270 ++
  47.271 ++png_uint_16 PNGAPI
  47.272 ++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
  47.273 ++{
  47.274 ++    png_debug(1, "in png_get_next_frame_delay_den()");
  47.275 ++
  47.276 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.277 ++        return (info_ptr->next_frame_delay_den);
  47.278 ++    return (0);
  47.279 ++}
  47.280 ++
  47.281 ++png_byte PNGAPI
  47.282 ++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
  47.283 ++{
  47.284 ++    png_debug(1, "in png_get_next_frame_dispose_op()");
  47.285 ++
  47.286 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.287 ++        return (info_ptr->next_frame_dispose_op);
  47.288 ++    return (0);
  47.289 ++}
  47.290 ++
  47.291 ++png_byte PNGAPI
  47.292 ++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
  47.293 ++{
  47.294 ++    png_debug(1, "in png_get_next_frame_blend_op()");
  47.295 ++
  47.296 ++    if (png_ptr != NULL && info_ptr != NULL)
  47.297 ++        return (info_ptr->next_frame_blend_op);
  47.298 ++    return (0);
  47.299 ++}
  47.300 ++
  47.301 ++png_byte PNGAPI
  47.302 ++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
  47.303 ++{
  47.304 ++    png_debug(1, "in png_first_frame_is_hidden()");
  47.305 ++
  47.306 ++    if (png_ptr != NULL)
  47.307 ++       return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
  47.308 ++
  47.309 ++    PNG_UNUSED(info_ptr)
  47.310 ++
  47.311 ++    return 0;
  47.312 ++}
  47.313 ++#endif /* PNG_APNG_SUPPORTED */
  47.314 + #endif /* READ || WRITE */
  47.315 +diff -Naru libpng-1.6.35.org/pnginfo.h libpng-1.6.35/pnginfo.h
  47.316 +--- libpng-1.6.35.org/pnginfo.h	2018-07-21 19:16:37.185142931 +0900
  47.317 ++++ libpng-1.6.35/pnginfo.h	2018-07-21 19:16:16.228356197 +0900
  47.318 +@@ -263,5 +263,18 @@
  47.319 +    png_bytepp row_pointers;        /* the image bits */
  47.320 + #endif
  47.321 + 
  47.322 ++#ifdef PNG_APNG_SUPPORTED
  47.323 ++   png_uint_32 num_frames; /* including default image */
  47.324 ++   png_uint_32 num_plays;
  47.325 ++   png_uint_32 next_frame_width;
  47.326 ++   png_uint_32 next_frame_height;
  47.327 ++   png_uint_32 next_frame_x_offset;
  47.328 ++   png_uint_32 next_frame_y_offset;
  47.329 ++   png_uint_16 next_frame_delay_num;
  47.330 ++   png_uint_16 next_frame_delay_den;
  47.331 ++   png_byte next_frame_dispose_op;
  47.332 ++   png_byte next_frame_blend_op;
  47.333 ++#endif
  47.334 ++
  47.335 + };
  47.336 + #endif /* PNGINFO_H */
  47.337 +diff -Naru libpng-1.6.35.org/pngpread.c libpng-1.6.35/pngpread.c
  47.338 +--- libpng-1.6.35.org/pngpread.c	2018-07-21 19:16:37.185142931 +0900
  47.339 ++++ libpng-1.6.35/pngpread.c	2018-07-21 19:16:16.228356197 +0900
  47.340 +@@ -195,6 +195,106 @@
  47.341 + 
  47.342 +    chunk_name = png_ptr->chunk_name;
  47.343 + 
  47.344 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.345 ++   if (png_ptr->num_frames_read > 0 &&
  47.346 ++       png_ptr->num_frames_read < info_ptr->num_frames)
  47.347 ++   {
  47.348 ++      if (chunk_name == png_IDAT)
  47.349 ++      {
  47.350 ++         /* Discard trailing IDATs for the first frame */
  47.351 ++         if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
  47.352 ++            png_error(png_ptr, "out of place IDAT");
  47.353 ++
  47.354 ++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  47.355 ++         {
  47.356 ++            png_push_save_buffer(png_ptr);
  47.357 ++            return;
  47.358 ++         }
  47.359 ++
  47.360 ++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  47.361 ++         return;
  47.362 ++      }
  47.363 ++      else if (chunk_name == png_fdAT)
  47.364 ++      {
  47.365 ++         if (png_ptr->buffer_size < 4)
  47.366 ++         {
  47.367 ++            png_push_save_buffer(png_ptr);
  47.368 ++            return;
  47.369 ++         }
  47.370 ++
  47.371 ++         png_ensure_sequence_number(png_ptr, 4);
  47.372 ++
  47.373 ++         if (!(png_ptr->mode & PNG_HAVE_fcTL))
  47.374 ++         {
  47.375 ++            /* Discard trailing fdATs for frames other than the first */
  47.376 ++            if (png_ptr->num_frames_read < 2)
  47.377 ++               png_error(png_ptr, "out of place fdAT");
  47.378 ++
  47.379 ++            if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  47.380 ++            {
  47.381 ++               png_push_save_buffer(png_ptr);
  47.382 ++               return;
  47.383 ++            }
  47.384 ++
  47.385 ++            png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  47.386 ++            return;
  47.387 ++         }
  47.388 ++
  47.389 ++         else
  47.390 ++         {
  47.391 ++            /* frame data follows */
  47.392 ++            png_ptr->idat_size = png_ptr->push_length - 4;
  47.393 ++            png_ptr->mode |= PNG_HAVE_IDAT;
  47.394 ++            png_ptr->process_mode = PNG_READ_IDAT_MODE;
  47.395 ++
  47.396 ++            return;
  47.397 ++         }
  47.398 ++      }
  47.399 ++
  47.400 ++      else if (chunk_name == png_fcTL)
  47.401 ++      {
  47.402 ++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  47.403 ++         {
  47.404 ++            png_push_save_buffer(png_ptr);
  47.405 ++            return;
  47.406 ++         }
  47.407 ++
  47.408 ++         png_read_reset(png_ptr);
  47.409 ++         png_ptr->mode &= ~PNG_HAVE_fcTL;
  47.410 ++
  47.411 ++         png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
  47.412 ++
  47.413 ++         if (!(png_ptr->mode & PNG_HAVE_fcTL))
  47.414 ++            png_error(png_ptr, "missing required fcTL chunk");
  47.415 ++
  47.416 ++         png_read_reinit(png_ptr, info_ptr);
  47.417 ++         png_progressive_read_reset(png_ptr);
  47.418 ++
  47.419 ++         if (png_ptr->frame_info_fn != NULL)
  47.420 ++            (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
  47.421 ++
  47.422 ++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  47.423 ++
  47.424 ++         return;
  47.425 ++      }
  47.426 ++
  47.427 ++      else
  47.428 ++      {
  47.429 ++         if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  47.430 ++         {
  47.431 ++            png_push_save_buffer(png_ptr);
  47.432 ++            return;
  47.433 ++         }
  47.434 ++         png_warning(png_ptr, "Skipped (ignored) a chunk "
  47.435 ++                              "between APNG chunks");
  47.436 ++         png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  47.437 ++         return;
  47.438 ++      }
  47.439 ++
  47.440 ++      return;
  47.441 ++   }
  47.442 ++#endif /* PNG_READ_APNG_SUPPORTED */
  47.443 ++
  47.444 +    if (chunk_name == png_IDAT)
  47.445 +    {
  47.446 +       if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
  47.447 +@@ -261,6 +361,9 @@
  47.448 + 
  47.449 +    else if (chunk_name == png_IDAT)
  47.450 +    {
  47.451 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.452 ++      png_have_info(png_ptr, info_ptr);
  47.453 ++#endif
  47.454 +       png_ptr->idat_size = png_ptr->push_length;
  47.455 +       png_ptr->process_mode = PNG_READ_IDAT_MODE;
  47.456 +       png_push_have_info(png_ptr, info_ptr);
  47.457 +@@ -406,6 +509,30 @@
  47.458 +       png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
  47.459 +    }
  47.460 + #endif
  47.461 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.462 ++   else if (chunk_name == png_acTL)
  47.463 ++   {
  47.464 ++      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  47.465 ++      {
  47.466 ++         png_push_save_buffer(png_ptr);
  47.467 ++         return;
  47.468 ++      }
  47.469 ++
  47.470 ++      png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
  47.471 ++   }
  47.472 ++
  47.473 ++   else if (chunk_name == png_fcTL)
  47.474 ++   {
  47.475 ++      if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  47.476 ++      {
  47.477 ++         png_push_save_buffer(png_ptr);
  47.478 ++         return;
  47.479 ++      }
  47.480 ++
  47.481 ++      png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
  47.482 ++   }
  47.483 ++
  47.484 ++#endif /* PNG_READ_APNG_SUPPORTED */
  47.485 + 
  47.486 +    else
  47.487 +    {
  47.488 +@@ -539,7 +666,11 @@
  47.489 +       png_byte chunk_tag[4];
  47.490 + 
  47.491 +       /* TODO: this code can be commoned up with the same code in push_read */
  47.492 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.493 ++      PNG_PUSH_SAVE_BUFFER_IF_LT(12)
  47.494 ++#else
  47.495 +       PNG_PUSH_SAVE_BUFFER_IF_LT(8)
  47.496 ++#endif
  47.497 +       png_push_fill_buffer(png_ptr, chunk_length, 4);
  47.498 +       png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
  47.499 +       png_reset_crc(png_ptr);
  47.500 +@@ -547,17 +678,64 @@
  47.501 +       png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
  47.502 +       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
  47.503 + 
  47.504 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.505 ++      if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
  47.506 ++      {
  47.507 ++          if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
  47.508 ++          {
  47.509 ++              png_ptr->process_mode = PNG_READ_CHUNK_MODE;
  47.510 ++              if (png_ptr->frame_end_fn != NULL)
  47.511 ++                 (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
  47.512 ++              png_ptr->num_frames_read++;
  47.513 ++              return;
  47.514 ++          }
  47.515 ++          else
  47.516 ++          {
  47.517 ++              if (png_ptr->chunk_name == png_IEND)
  47.518 ++                  png_error(png_ptr, "Not enough image data");
  47.519 ++              if (png_ptr->push_length + 4 > png_ptr->buffer_size)
  47.520 ++              {
  47.521 ++                 png_push_save_buffer(png_ptr);
  47.522 ++                 return;
  47.523 ++              }
  47.524 ++              png_warning(png_ptr, "Skipping (ignoring) a chunk between "
  47.525 ++                                   "APNG chunks");
  47.526 ++              png_crc_finish(png_ptr, png_ptr->push_length);
  47.527 ++              png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
  47.528 ++              return;
  47.529 ++          }
  47.530 ++      }
  47.531 ++      else
  47.532 ++#endif
  47.533 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.534 ++      if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
  47.535 ++#else
  47.536 +       if (png_ptr->chunk_name != png_IDAT)
  47.537 ++#endif
  47.538 +       {
  47.539 +          png_ptr->process_mode = PNG_READ_CHUNK_MODE;
  47.540 + 
  47.541 +          if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
  47.542 +             png_error(png_ptr, "Not enough compressed data");
  47.543 + 
  47.544 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.545 ++         if (png_ptr->frame_end_fn != NULL)
  47.546 ++            (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
  47.547 ++         png_ptr->num_frames_read++;
  47.548 ++#endif
  47.549 ++
  47.550 +          return;
  47.551 +       }
  47.552 + 
  47.553 +       png_ptr->idat_size = png_ptr->push_length;
  47.554 ++
  47.555 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.556 ++      if (png_ptr->num_frames_read > 0)
  47.557 ++      {
  47.558 ++         png_ensure_sequence_number(png_ptr, 4);
  47.559 ++         png_ptr->idat_size -= 4;
  47.560 ++      }
  47.561 ++#endif
  47.562 +    }
  47.563 + 
  47.564 +    if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
  47.565 +@@ -631,6 +809,15 @@
  47.566 +    if (!(buffer_length > 0) || buffer == NULL)
  47.567 +       png_error(png_ptr, "No IDAT data (internal error)");
  47.568 + 
  47.569 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.570 ++   /* If the app is not APNG-aware, decode only the first frame */
  47.571 ++   if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
  47.572 ++   {
  47.573 ++     png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
  47.574 ++     return;
  47.575 ++   }
  47.576 ++#endif
  47.577 ++
  47.578 +    /* This routine must process all the data it has been given
  47.579 +     * before returning, calling the row callback as required to
  47.580 +     * handle the uncompressed results.
  47.581 +@@ -1085,6 +1272,18 @@
  47.582 +    png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
  47.583 + }
  47.584 + 
  47.585 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.586 ++void PNGAPI
  47.587 ++png_set_progressive_frame_fn(png_structp png_ptr,
  47.588 ++   png_progressive_frame_ptr frame_info_fn,
  47.589 ++   png_progressive_frame_ptr frame_end_fn)
  47.590 ++{
  47.591 ++   png_ptr->frame_info_fn = frame_info_fn;
  47.592 ++   png_ptr->frame_end_fn = frame_end_fn;
  47.593 ++   png_ptr->apng_flags |= PNG_APNG_APP;
  47.594 ++}
  47.595 ++#endif
  47.596 ++
  47.597 + png_voidp PNGAPI
  47.598 + png_get_progressive_ptr(png_const_structrp png_ptr)
  47.599 + {
  47.600 +diff -Naru libpng-1.6.35.org/pngpriv.h libpng-1.6.35/pngpriv.h
  47.601 +--- libpng-1.6.35.org/pngpriv.h	2018-07-21 19:16:37.185142931 +0900
  47.602 ++++ libpng-1.6.35/pngpriv.h	2018-07-21 19:16:16.226356026 +0900
  47.603 +@@ -634,6 +634,10 @@
  47.604 + #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
  47.605 +                    /*             0x4000U (unused) */
  47.606 + #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
  47.607 ++#ifdef PNG_APNG_SUPPORTED
  47.608 ++#define PNG_HAVE_acTL            0x10000U
  47.609 ++#define PNG_HAVE_fcTL            0x20000U
  47.610 ++#endif
  47.611 + 
  47.612 + /* Flags for the transformations the PNG library does on the image data */
  47.613 + #define PNG_BGR                 0x0001U
  47.614 +@@ -870,6 +874,16 @@
  47.615 + #define png_tRNS PNG_U32(116,  82,  78,  83)
  47.616 + #define png_zTXt PNG_U32(122,  84,  88, 116)
  47.617 + 
  47.618 ++#ifdef PNG_APNG_SUPPORTED
  47.619 ++#define png_acTL PNG_U32( 97,  99,  84,  76)
  47.620 ++#define png_fcTL PNG_U32(102,  99,  84,  76)
  47.621 ++#define png_fdAT PNG_U32(102, 100,  65,  84)
  47.622 ++
  47.623 ++/* For png_struct.apng_flags: */
  47.624 ++#define PNG_FIRST_FRAME_HIDDEN       0x0001U
  47.625 ++#define PNG_APNG_APP                 0x0002U
  47.626 ++#endif
  47.627 ++
  47.628 + /* The following will work on (signed char*) strings, whereas the get_uint_32
  47.629 +  * macro will fail on top-bit-set values because of the sign extension.
  47.630 +  */
  47.631 +@@ -1641,6 +1655,47 @@
  47.632 +     */
  47.633 + #endif
  47.634 + 
  47.635 ++#ifdef PNG_APNG_SUPPORTED
  47.636 ++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
  47.637 ++   png_uint_32 width, png_uint_32 height,
  47.638 ++   png_uint_32 x_offset, png_uint_32 y_offset,
  47.639 ++   png_uint_16 delay_num, png_uint_16 delay_den,
  47.640 ++   png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
  47.641 ++
  47.642 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.643 ++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
  47.644 ++   png_uint_32 length),PNG_EMPTY);
  47.645 ++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
  47.646 ++   png_uint_32 length),PNG_EMPTY);
  47.647 ++PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
  47.648 ++   png_uint_32 length),PNG_EMPTY);
  47.649 ++PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
  47.650 ++PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
  47.651 ++   png_uint_32 length),PNG_EMPTY);
  47.652 ++PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
  47.653 ++PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
  47.654 ++   png_infop info_ptr),PNG_EMPTY);
  47.655 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
  47.656 ++PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
  47.657 ++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
  47.658 ++#endif /* PNG_READ_APNG_SUPPORTED */
  47.659 ++
  47.660 ++#ifdef PNG_WRITE_APNG_SUPPORTED
  47.661 ++PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
  47.662 ++   png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
  47.663 ++PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
  47.664 ++   png_uint_32 width, png_uint_32 height,
  47.665 ++   png_uint_32 x_offset, png_uint_32 y_offset,
  47.666 ++   png_uint_16 delay_num, png_uint_16 delay_den,
  47.667 ++   png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
  47.668 ++PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
  47.669 ++   png_const_bytep data, png_size_t length),PNG_EMPTY);
  47.670 ++PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
  47.671 ++PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
  47.672 ++   png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
  47.673 ++#endif /* PNG_WRITE_APNG_SUPPORTED */
  47.674 ++#endif /* PNG_APNG_SUPPORTED */
  47.675 ++
  47.676 + /* Added at libpng version 1.4.0 */
  47.677 + #ifdef PNG_COLORSPACE_SUPPORTED
  47.678 + /* These internal functions are for maintaining the colorspace structure within
  47.679 +diff -Naru libpng-1.6.35.org/pngread.c libpng-1.6.35/pngread.c
  47.680 +--- libpng-1.6.35.org/pngread.c	2018-07-21 19:16:37.186143016 +0900
  47.681 ++++ libpng-1.6.35/pngread.c	2018-07-21 19:16:16.224355855 +0900
  47.682 +@@ -161,6 +161,9 @@
  47.683 + 
  47.684 +       else if (chunk_name == png_IDAT)
  47.685 +       {
  47.686 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.687 ++         png_have_info(png_ptr, info_ptr);
  47.688 ++#endif
  47.689 +          png_ptr->idat_size = length;
  47.690 +          break;
  47.691 +       }
  47.692 +@@ -255,6 +258,17 @@
  47.693 +          png_handle_iTXt(png_ptr, info_ptr, length);
  47.694 + #endif
  47.695 + 
  47.696 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.697 ++      else if (chunk_name == png_acTL)
  47.698 ++         png_handle_acTL(png_ptr, info_ptr, length);
  47.699 ++
  47.700 ++      else if (chunk_name == png_fcTL)
  47.701 ++         png_handle_fcTL(png_ptr, info_ptr, length);
  47.702 ++
  47.703 ++      else if (chunk_name == png_fdAT)
  47.704 ++         png_handle_fdAT(png_ptr, info_ptr, length);
  47.705 ++#endif
  47.706 ++
  47.707 +       else
  47.708 +          png_handle_unknown(png_ptr, info_ptr, length,
  47.709 +              PNG_HANDLE_CHUNK_AS_DEFAULT);
  47.710 +@@ -262,6 +276,72 @@
  47.711 + }
  47.712 + #endif /* SEQUENTIAL_READ */
  47.713 + 
  47.714 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.715 ++void PNGAPI
  47.716 ++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
  47.717 ++{
  47.718 ++    png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
  47.719 ++
  47.720 ++    png_debug(0, "Reading frame head");
  47.721 ++
  47.722 ++    if (!(png_ptr->mode & PNG_HAVE_acTL))
  47.723 ++        png_error(png_ptr, "attempt to png_read_frame_head() but "
  47.724 ++                           "no acTL present");
  47.725 ++
  47.726 ++    /* do nothing for the main IDAT */
  47.727 ++    if (png_ptr->num_frames_read == 0)
  47.728 ++        return;
  47.729 ++
  47.730 ++    png_read_reset(png_ptr);
  47.731 ++    png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
  47.732 ++    png_ptr->mode &= ~PNG_HAVE_fcTL;
  47.733 ++
  47.734 ++    have_chunk_after_DAT = 0;
  47.735 ++    for (;;)
  47.736 ++    {
  47.737 ++        png_uint_32 length = png_read_chunk_header(png_ptr);
  47.738 ++
  47.739 ++        if (png_ptr->chunk_name == png_IDAT)
  47.740 ++        {
  47.741 ++            /* discard trailing IDATs for the first frame */
  47.742 ++            if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
  47.743 ++                png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
  47.744 ++            png_crc_finish(png_ptr, length);
  47.745 ++        }
  47.746 ++
  47.747 ++        else if (png_ptr->chunk_name == png_fcTL)
  47.748 ++        {
  47.749 ++            png_handle_fcTL(png_ptr, info_ptr, length);
  47.750 ++            have_chunk_after_DAT = 1;
  47.751 ++        }
  47.752 ++
  47.753 ++        else if (png_ptr->chunk_name == png_fdAT)
  47.754 ++        {
  47.755 ++            png_ensure_sequence_number(png_ptr, length);
  47.756 ++
  47.757 ++            /* discard trailing fdATs for frames other than the first */
  47.758 ++            if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
  47.759 ++                png_crc_finish(png_ptr, length - 4);
  47.760 ++            else if(png_ptr->mode & PNG_HAVE_fcTL)
  47.761 ++            {
  47.762 ++                png_ptr->idat_size = length - 4;
  47.763 ++                png_ptr->mode |= PNG_HAVE_IDAT;
  47.764 ++
  47.765 ++                break;
  47.766 ++            }
  47.767 ++            else
  47.768 ++                png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
  47.769 ++        }
  47.770 ++        else
  47.771 ++        {
  47.772 ++            png_warning(png_ptr, "Skipped (ignored) a chunk "
  47.773 ++                                 "between APNG chunks");
  47.774 ++            png_crc_finish(png_ptr, length);
  47.775 ++        }
  47.776 ++    }
  47.777 ++}
  47.778 ++#endif /* PNG_READ_APNG_SUPPORTED */
  47.779 ++
  47.780 + /* Optional call to update the users info_ptr structure */
  47.781 + void PNGAPI
  47.782 + png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
  47.783 +diff -Naru libpng-1.6.35.org/pngrutil.c libpng-1.6.35/pngrutil.c
  47.784 +--- libpng-1.6.35.org/pngrutil.c	2018-07-21 19:16:37.187143101 +0900
  47.785 ++++ libpng-1.6.35/pngrutil.c	2018-07-21 19:16:16.220355514 +0900
  47.786 +@@ -865,6 +865,11 @@
  47.787 +    filter_type = buf[11];
  47.788 +    interlace_type = buf[12];
  47.789 + 
  47.790 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.791 ++   png_ptr->first_frame_width = width;
  47.792 ++   png_ptr->first_frame_height = height;
  47.793 ++#endif
  47.794 ++
  47.795 +    /* Set internal variables */
  47.796 +    png_ptr->width = width;
  47.797 +    png_ptr->height = height;
  47.798 +@@ -2858,6 +2863,179 @@
  47.799 + }
  47.800 + #endif
  47.801 + 
  47.802 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.803 ++void /* PRIVATE */
  47.804 ++png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  47.805 ++{
  47.806 ++    png_byte data[8];
  47.807 ++    png_uint_32 num_frames;
  47.808 ++    png_uint_32 num_plays;
  47.809 ++    png_uint_32 didSet;
  47.810 ++
  47.811 ++    png_debug(1, "in png_handle_acTL");
  47.812 ++
  47.813 ++    if (!(png_ptr->mode & PNG_HAVE_IHDR))
  47.814 ++    {
  47.815 ++        png_error(png_ptr, "Missing IHDR before acTL");
  47.816 ++    }
  47.817 ++    else if (png_ptr->mode & PNG_HAVE_IDAT)
  47.818 ++    {
  47.819 ++        png_warning(png_ptr, "Invalid acTL after IDAT skipped");
  47.820 ++        png_crc_finish(png_ptr, length);
  47.821 ++        return;
  47.822 ++    }
  47.823 ++    else if (png_ptr->mode & PNG_HAVE_acTL)
  47.824 ++    {
  47.825 ++        png_warning(png_ptr, "Duplicate acTL skipped");
  47.826 ++        png_crc_finish(png_ptr, length);
  47.827 ++        return;
  47.828 ++    }
  47.829 ++    else if (length != 8)
  47.830 ++    {
  47.831 ++        png_warning(png_ptr, "acTL with invalid length skipped");
  47.832 ++        png_crc_finish(png_ptr, length);
  47.833 ++        return;
  47.834 ++    }
  47.835 ++
  47.836 ++    png_crc_read(png_ptr, data, 8);
  47.837 ++    png_crc_finish(png_ptr, 0);
  47.838 ++
  47.839 ++    num_frames = png_get_uint_31(png_ptr, data);
  47.840 ++    num_plays = png_get_uint_31(png_ptr, data + 4);
  47.841 ++
  47.842 ++    /* the set function will do error checking on num_frames */
  47.843 ++    didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
  47.844 ++    if(didSet)
  47.845 ++        png_ptr->mode |= PNG_HAVE_acTL;
  47.846 ++}
  47.847 ++
  47.848 ++void /* PRIVATE */
  47.849 ++png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  47.850 ++{
  47.851 ++    png_byte data[22];
  47.852 ++    png_uint_32 width;
  47.853 ++    png_uint_32 height;
  47.854 ++    png_uint_32 x_offset;
  47.855 ++    png_uint_32 y_offset;
  47.856 ++    png_uint_16 delay_num;
  47.857 ++    png_uint_16 delay_den;
  47.858 ++    png_byte dispose_op;
  47.859 ++    png_byte blend_op;
  47.860 ++
  47.861 ++    png_debug(1, "in png_handle_fcTL");
  47.862 ++
  47.863 ++    png_ensure_sequence_number(png_ptr, length);
  47.864 ++
  47.865 ++    if (!(png_ptr->mode & PNG_HAVE_IHDR))
  47.866 ++    {
  47.867 ++        png_error(png_ptr, "Missing IHDR before fcTL");
  47.868 ++    }
  47.869 ++    else if (png_ptr->mode & PNG_HAVE_IDAT)
  47.870 ++    {
  47.871 ++        /* for any frames other then the first this message may be misleading,
  47.872 ++        * but correct. PNG_HAVE_IDAT is unset before the frame head is read
  47.873 ++        * i can't think of a better message */
  47.874 ++        png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
  47.875 ++        png_crc_finish(png_ptr, length-4);
  47.876 ++        return;
  47.877 ++    }
  47.878 ++    else if (png_ptr->mode & PNG_HAVE_fcTL)
  47.879 ++    {
  47.880 ++        png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
  47.881 ++        png_crc_finish(png_ptr, length-4);
  47.882 ++        return;
  47.883 ++    }
  47.884 ++    else if (length != 26)
  47.885 ++    {
  47.886 ++        png_warning(png_ptr, "fcTL with invalid length skipped");
  47.887 ++        png_crc_finish(png_ptr, length-4);
  47.888 ++        return;
  47.889 ++    }
  47.890 ++
  47.891 ++    png_crc_read(png_ptr, data, 22);
  47.892 ++    png_crc_finish(png_ptr, 0);
  47.893 ++
  47.894 ++    width = png_get_uint_31(png_ptr, data);
  47.895 ++    height = png_get_uint_31(png_ptr, data + 4);
  47.896 ++    x_offset = png_get_uint_31(png_ptr, data + 8);
  47.897 ++    y_offset = png_get_uint_31(png_ptr, data + 12);
  47.898 ++    delay_num = png_get_uint_16(data + 16);
  47.899 ++    delay_den = png_get_uint_16(data + 18);
  47.900 ++    dispose_op = data[20];
  47.901 ++    blend_op = data[21];
  47.902 ++
  47.903 ++    if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
  47.904 ++    {
  47.905 ++        png_warning(png_ptr, "fcTL for the first frame must have zero offset");
  47.906 ++        return;
  47.907 ++    }
  47.908 ++
  47.909 ++    if (info_ptr != NULL)
  47.910 ++    {
  47.911 ++        if (png_ptr->num_frames_read == 0 &&
  47.912 ++            (width != info_ptr->width || height != info_ptr->height))
  47.913 ++        {
  47.914 ++            png_warning(png_ptr, "size in first frame's fcTL must match "
  47.915 ++                               "the size in IHDR");
  47.916 ++            return;
  47.917 ++        }
  47.918 ++
  47.919 ++        /* The set function will do more error checking */
  47.920 ++        png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
  47.921 ++                                x_offset, y_offset, delay_num, delay_den,
  47.922 ++                                dispose_op, blend_op);
  47.923 ++
  47.924 ++        png_read_reinit(png_ptr, info_ptr);
  47.925 ++
  47.926 ++        png_ptr->mode |= PNG_HAVE_fcTL;
  47.927 ++    }
  47.928 ++}
  47.929 ++
  47.930 ++void /* PRIVATE */
  47.931 ++png_have_info(png_structp png_ptr, png_infop info_ptr)
  47.932 ++{
  47.933 ++    if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
  47.934 ++    {
  47.935 ++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
  47.936 ++        info_ptr->num_frames++;
  47.937 ++    }
  47.938 ++}
  47.939 ++
  47.940 ++void /* PRIVATE */
  47.941 ++png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  47.942 ++{
  47.943 ++    png_ensure_sequence_number(png_ptr, length);
  47.944 ++
  47.945 ++    /* This function is only called from png_read_end(), png_read_info(),
  47.946 ++    * and png_push_read_chunk() which means that:
  47.947 ++    * - the user doesn't want to read this frame
  47.948 ++    * - or this is an out-of-place fdAT
  47.949 ++    * in either case it is safe to ignore the chunk with a warning */
  47.950 ++    png_warning(png_ptr, "ignoring fdAT chunk");
  47.951 ++    png_crc_finish(png_ptr, length - 4);
  47.952 ++    PNG_UNUSED(info_ptr)
  47.953 ++}
  47.954 ++
  47.955 ++void /* PRIVATE */
  47.956 ++png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
  47.957 ++{
  47.958 ++    png_byte data[4];
  47.959 ++    png_uint_32 sequence_number;
  47.960 ++
  47.961 ++    if (length < 4)
  47.962 ++        png_error(png_ptr, "invalid fcTL or fdAT chunk found");
  47.963 ++
  47.964 ++    png_crc_read(png_ptr, data, 4);
  47.965 ++    sequence_number = png_get_uint_31(png_ptr, data);
  47.966 ++
  47.967 ++    if (sequence_number != png_ptr->next_seq_num)
  47.968 ++        png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
  47.969 ++                           "number found");
  47.970 ++
  47.971 ++    png_ptr->next_seq_num++;
  47.972 ++}
  47.973 ++#endif /* PNG_READ_APNG_SUPPORTED */
  47.974 ++
  47.975 + #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
  47.976 + /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
  47.977 + static int
  47.978 +@@ -4166,7 +4344,38 @@
  47.979 +       {
  47.980 +          uInt avail_in;
  47.981 +          png_bytep buffer;
  47.982 ++#ifdef PNG_READ_APNG_SUPPORTED
  47.983 ++         png_uint_32 bytes_to_skip = 0;
  47.984 ++
  47.985 ++         while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
  47.986 ++         {
  47.987 ++            png_crc_finish(png_ptr, bytes_to_skip);
  47.988 ++            bytes_to_skip = 0;
  47.989 + 
  47.990 ++            png_ptr->idat_size = png_read_chunk_header(png_ptr);
  47.991 ++            if (png_ptr->num_frames_read == 0)
  47.992 ++            {
  47.993 ++               if (png_ptr->chunk_name != png_IDAT)
  47.994 ++                  png_error(png_ptr, "Not enough image data");
  47.995 ++            }
  47.996 ++            else
  47.997 ++            {
  47.998 ++               if (png_ptr->chunk_name == png_IEND)
  47.999 ++                  png_error(png_ptr, "Not enough image data");
 47.1000 ++               if (png_ptr->chunk_name != png_fdAT)
 47.1001 ++               {
 47.1002 ++                  png_warning(png_ptr, "Skipped (ignored) a chunk "
 47.1003 ++                                       "between APNG chunks");
 47.1004 ++                  bytes_to_skip = png_ptr->idat_size;
 47.1005 ++                  continue;
 47.1006 ++               }
 47.1007 ++
 47.1008 ++               png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
 47.1009 ++
 47.1010 ++               png_ptr->idat_size -= 4;
 47.1011 ++            }
 47.1012 ++         }
 47.1013 ++#else
 47.1014 +          while (png_ptr->idat_size == 0)
 47.1015 +          {
 47.1016 +             png_crc_finish(png_ptr, 0);
 47.1017 +@@ -4178,7 +4387,7 @@
 47.1018 +             if (png_ptr->chunk_name != png_IDAT)
 47.1019 +                png_error(png_ptr, "Not enough image data");
 47.1020 +          }
 47.1021 +-
 47.1022 ++#endif /* PNG_READ_APNG_SUPPORTED */
 47.1023 +          avail_in = png_ptr->IDAT_read_size;
 47.1024 + 
 47.1025 +          if (avail_in > png_ptr->idat_size)
 47.1026 +@@ -4241,6 +4450,9 @@
 47.1027 + 
 47.1028 +          png_ptr->mode |= PNG_AFTER_IDAT;
 47.1029 +          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
 47.1030 ++#ifdef PNG_READ_APNG_SUPPORTED
 47.1031 ++         png_ptr->num_frames_read++;
 47.1032 ++#endif
 47.1033 + 
 47.1034 +          if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
 47.1035 +             png_chunk_benign_error(png_ptr, "Extra compressed data");
 47.1036 +@@ -4679,4 +4891,80 @@
 47.1037 + 
 47.1038 +    png_ptr->flags |= PNG_FLAG_ROW_INIT;
 47.1039 + }
 47.1040 ++
 47.1041 ++#ifdef PNG_READ_APNG_SUPPORTED
 47.1042 ++/* This function is to be called after the main IDAT set has been read and
 47.1043 ++ * before a new IDAT is read. It resets some parts of png_ptr
 47.1044 ++ * to make them usable by the read functions again */
 47.1045 ++void /* PRIVATE */
 47.1046 ++png_read_reset(png_structp png_ptr)
 47.1047 ++{
 47.1048 ++    png_ptr->mode &= ~PNG_HAVE_IDAT;
 47.1049 ++    png_ptr->mode &= ~PNG_AFTER_IDAT;
 47.1050 ++    png_ptr->row_number = 0;
 47.1051 ++    png_ptr->pass = 0;
 47.1052 ++}
 47.1053 ++
 47.1054 ++void /* PRIVATE */
 47.1055 ++png_read_reinit(png_structp png_ptr, png_infop info_ptr)
 47.1056 ++{
 47.1057 ++    png_ptr->width = info_ptr->next_frame_width;
 47.1058 ++    png_ptr->height = info_ptr->next_frame_height;
 47.1059 ++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
 47.1060 ++    png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
 47.1061 ++        png_ptr->width);
 47.1062 ++    if (png_ptr->prev_row)
 47.1063 ++        memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
 47.1064 ++}
 47.1065 ++
 47.1066 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 47.1067 ++/* same as png_read_reset() but for the progressive reader */
 47.1068 ++void /* PRIVATE */
 47.1069 ++png_progressive_read_reset(png_structp png_ptr)
 47.1070 ++{
 47.1071 ++#ifdef PNG_READ_INTERLACING_SUPPORTED
 47.1072 ++   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
 47.1073 ++
 47.1074 ++   /* Start of interlace block */
 47.1075 ++    const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
 47.1076 ++
 47.1077 ++    /* Offset to next interlace block */
 47.1078 ++    const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
 47.1079 ++
 47.1080 ++    /* Start of interlace block in the y direction */
 47.1081 ++    const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
 47.1082 ++
 47.1083 ++    /* Offset to next interlace block in the y direction */
 47.1084 ++    const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
 47.1085 ++
 47.1086 ++    if (png_ptr->interlaced)
 47.1087 ++    {
 47.1088 ++        if (!(png_ptr->transformations & PNG_INTERLACE))
 47.1089 ++            png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
 47.1090 ++                                png_pass_ystart[0]) / png_pass_yinc[0];
 47.1091 ++        else
 47.1092 ++            png_ptr->num_rows = png_ptr->height;
 47.1093 ++
 47.1094 ++        png_ptr->iwidth = (png_ptr->width +
 47.1095 ++                           png_pass_inc[png_ptr->pass] - 1 -
 47.1096 ++                           png_pass_start[png_ptr->pass]) /
 47.1097 ++                           png_pass_inc[png_ptr->pass];
 47.1098 ++    }
 47.1099 ++    else
 47.1100 ++#endif /* PNG_READ_INTERLACING_SUPPORTED */
 47.1101 ++    {
 47.1102 ++        png_ptr->num_rows = png_ptr->height;
 47.1103 ++        png_ptr->iwidth = png_ptr->width;
 47.1104 ++    }
 47.1105 ++    png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
 47.1106 ++    if (inflateReset(&(png_ptr->zstream)) != Z_OK)
 47.1107 ++        png_error(png_ptr, "inflateReset failed");
 47.1108 ++    png_ptr->zstream.avail_in = 0;
 47.1109 ++    png_ptr->zstream.next_in = 0;
 47.1110 ++    png_ptr->zstream.next_out = png_ptr->row_buf;
 47.1111 ++    png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
 47.1112 ++        png_ptr->iwidth) + 1;
 47.1113 ++}
 47.1114 ++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 47.1115 ++#endif /* PNG_READ_APNG_SUPPORTED */
 47.1116 + #endif /* READ */
 47.1117 +diff -Naru libpng-1.6.35.org/pngset.c libpng-1.6.35/pngset.c
 47.1118 +--- libpng-1.6.35.org/pngset.c	2018-07-21 19:16:37.188143186 +0900
 47.1119 ++++ libpng-1.6.35/pngset.c	2018-07-21 19:16:16.256358584 +0900
 47.1120 +@@ -288,6 +288,11 @@
 47.1121 +    info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
 47.1122 + 
 47.1123 +    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
 47.1124 ++
 47.1125 ++#ifdef PNG_APNG_SUPPORTED
 47.1126 ++   /* for non-animated png. this may be overwritten from an acTL chunk later */
 47.1127 ++   info_ptr->num_frames = 1;
 47.1128 ++#endif
 47.1129 + }
 47.1130 + 
 47.1131 + #ifdef PNG_oFFs_SUPPORTED
 47.1132 +@@ -1158,6 +1163,147 @@
 47.1133 + }
 47.1134 + #endif /* sPLT */
 47.1135 + 
 47.1136 ++#ifdef PNG_APNG_SUPPORTED
 47.1137 ++png_uint_32 PNGAPI
 47.1138 ++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
 47.1139 ++    png_uint_32 num_frames, png_uint_32 num_plays)
 47.1140 ++{
 47.1141 ++    png_debug1(1, "in %s storage function", "acTL");
 47.1142 ++
 47.1143 ++    if (png_ptr == NULL || info_ptr == NULL)
 47.1144 ++    {
 47.1145 ++        png_warning(png_ptr,
 47.1146 ++                    "Call to png_set_acTL() with NULL png_ptr "
 47.1147 ++                    "or info_ptr ignored");
 47.1148 ++        return (0);
 47.1149 ++    }
 47.1150 ++    if (num_frames == 0)
 47.1151 ++    {
 47.1152 ++        png_warning(png_ptr,
 47.1153 ++                    "Ignoring attempt to set acTL with num_frames zero");
 47.1154 ++        return (0);
 47.1155 ++    }
 47.1156 ++    if (num_frames > PNG_UINT_31_MAX)
 47.1157 ++    {
 47.1158 ++        png_warning(png_ptr,
 47.1159 ++                    "Ignoring attempt to set acTL with num_frames > 2^31-1");
 47.1160 ++        return (0);
 47.1161 ++    }
 47.1162 ++    if (num_plays > PNG_UINT_31_MAX)
 47.1163 ++    {
 47.1164 ++        png_warning(png_ptr,
 47.1165 ++                    "Ignoring attempt to set acTL with num_plays "
 47.1166 ++                    "> 2^31-1");
 47.1167 ++        return (0);
 47.1168 ++    }
 47.1169 ++
 47.1170 ++    info_ptr->num_frames = num_frames;
 47.1171 ++    info_ptr->num_plays = num_plays;
 47.1172 ++
 47.1173 ++    info_ptr->valid |= PNG_INFO_acTL;
 47.1174 ++
 47.1175 ++    return (1);
 47.1176 ++}
 47.1177 ++
 47.1178 ++/* delay_num and delay_den can hold any 16-bit values including zero */
 47.1179 ++png_uint_32 PNGAPI
 47.1180 ++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
 47.1181 ++    png_uint_32 width, png_uint_32 height,
 47.1182 ++    png_uint_32 x_offset, png_uint_32 y_offset,
 47.1183 ++    png_uint_16 delay_num, png_uint_16 delay_den,
 47.1184 ++    png_byte dispose_op, png_byte blend_op)
 47.1185 ++{
 47.1186 ++    png_debug1(1, "in %s storage function", "fcTL");
 47.1187 ++
 47.1188 ++    if (png_ptr == NULL || info_ptr == NULL)
 47.1189 ++    {
 47.1190 ++        png_warning(png_ptr,
 47.1191 ++                    "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
 47.1192 ++                    "ignored");
 47.1193 ++        return (0);
 47.1194 ++    }
 47.1195 ++
 47.1196 ++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
 47.1197 ++                             delay_num, delay_den, dispose_op, blend_op);
 47.1198 ++
 47.1199 ++    if (blend_op == PNG_BLEND_OP_OVER)
 47.1200 ++    {
 47.1201 ++        if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
 47.1202 ++            !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
 47.1203 ++        {
 47.1204 ++          png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
 47.1205 ++                               "and wasteful for opaque images, ignored");
 47.1206 ++          blend_op = PNG_BLEND_OP_SOURCE;
 47.1207 ++        }
 47.1208 ++    }
 47.1209 ++
 47.1210 ++    info_ptr->next_frame_width = width;
 47.1211 ++    info_ptr->next_frame_height = height;
 47.1212 ++    info_ptr->next_frame_x_offset = x_offset;
 47.1213 ++    info_ptr->next_frame_y_offset = y_offset;
 47.1214 ++    info_ptr->next_frame_delay_num = delay_num;
 47.1215 ++    info_ptr->next_frame_delay_den = delay_den;
 47.1216 ++    info_ptr->next_frame_dispose_op = dispose_op;
 47.1217 ++    info_ptr->next_frame_blend_op = blend_op;
 47.1218 ++
 47.1219 ++    info_ptr->valid |= PNG_INFO_fcTL;
 47.1220 ++
 47.1221 ++    return (1);
 47.1222 ++}
 47.1223 ++
 47.1224 ++void /* PRIVATE */
 47.1225 ++png_ensure_fcTL_is_valid(png_structp png_ptr,
 47.1226 ++    png_uint_32 width, png_uint_32 height,
 47.1227 ++    png_uint_32 x_offset, png_uint_32 y_offset,
 47.1228 ++    png_uint_16 delay_num, png_uint_16 delay_den,
 47.1229 ++    png_byte dispose_op, png_byte blend_op)
 47.1230 ++{
 47.1231 ++    if (width == 0 || width > PNG_UINT_31_MAX)
 47.1232 ++        png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
 47.1233 ++    if (height == 0 || height > PNG_UINT_31_MAX)
 47.1234 ++        png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
 47.1235 ++    if (x_offset > PNG_UINT_31_MAX)
 47.1236 ++        png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
 47.1237 ++    if (y_offset > PNG_UINT_31_MAX)
 47.1238 ++        png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
 47.1239 ++    if (width + x_offset > png_ptr->first_frame_width ||
 47.1240 ++        height + y_offset > png_ptr->first_frame_height)
 47.1241 ++        png_error(png_ptr, "dimensions of a frame are greater than"
 47.1242 ++                           "the ones in IHDR");
 47.1243 ++
 47.1244 ++    if (dispose_op != PNG_DISPOSE_OP_NONE &&
 47.1245 ++        dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
 47.1246 ++        dispose_op != PNG_DISPOSE_OP_PREVIOUS)
 47.1247 ++        png_error(png_ptr, "invalid dispose_op in fcTL");
 47.1248 ++
 47.1249 ++    if (blend_op != PNG_BLEND_OP_SOURCE &&
 47.1250 ++        blend_op != PNG_BLEND_OP_OVER)
 47.1251 ++        png_error(png_ptr, "invalid blend_op in fcTL");
 47.1252 ++
 47.1253 ++    PNG_UNUSED(delay_num)
 47.1254 ++    PNG_UNUSED(delay_den)
 47.1255 ++}
 47.1256 ++
 47.1257 ++png_uint_32 PNGAPI
 47.1258 ++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
 47.1259 ++                              png_byte is_hidden)
 47.1260 ++{
 47.1261 ++    png_debug(1, "in png_first_frame_is_hidden()");
 47.1262 ++
 47.1263 ++    if (png_ptr == NULL)
 47.1264 ++        return 0;
 47.1265 ++
 47.1266 ++    if (is_hidden)
 47.1267 ++        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
 47.1268 ++    else
 47.1269 ++        png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
 47.1270 ++
 47.1271 ++    PNG_UNUSED(info_ptr)
 47.1272 ++
 47.1273 ++    return 1;
 47.1274 ++}
 47.1275 ++#endif /* PNG_APNG_SUPPORTED */
 47.1276 ++
 47.1277 + #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
 47.1278 + static png_byte
 47.1279 + check_location(png_const_structrp png_ptr, int location)
 47.1280 +diff -Naru libpng-1.6.35.org/pngstruct.h libpng-1.6.35/pngstruct.h
 47.1281 +--- libpng-1.6.35.org/pngstruct.h	2018-07-21 19:16:37.188143186 +0900
 47.1282 ++++ libpng-1.6.35/pngstruct.h	2018-07-21 19:16:16.214355003 +0900
 47.1283 +@@ -403,6 +403,27 @@
 47.1284 +    png_byte filter_type;
 47.1285 + #endif
 47.1286 + 
 47.1287 ++#ifdef PNG_APNG_SUPPORTED
 47.1288 ++   png_uint_32 apng_flags;
 47.1289 ++   png_uint_32 next_seq_num;         /* next fcTL/fdAT chunk sequence number */
 47.1290 ++   png_uint_32 first_frame_width;
 47.1291 ++   png_uint_32 first_frame_height;
 47.1292 ++
 47.1293 ++#ifdef PNG_READ_APNG_SUPPORTED
 47.1294 ++   png_uint_32 num_frames_read;      /* incremented after all image data of */
 47.1295 ++                                     /* a frame is read */
 47.1296 ++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 47.1297 ++   png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
 47.1298 ++   png_progressive_frame_ptr frame_end_fn;  /* frame data read callback */
 47.1299 ++#endif
 47.1300 ++#endif
 47.1301 ++
 47.1302 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1303 ++   png_uint_32 num_frames_to_write;
 47.1304 ++   png_uint_32 num_frames_written;
 47.1305 ++#endif
 47.1306 ++#endif /* PNG_APNG_SUPPORTED */
 47.1307 ++
 47.1308 + /* New members added in libpng-1.2.0 */
 47.1309 + 
 47.1310 + /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
 47.1311 +diff -Naru libpng-1.6.35.org/pngtest.c libpng-1.6.35/pngtest.c
 47.1312 +--- libpng-1.6.35.org/pngtest.c	2018-07-21 19:16:37.188143186 +0900
 47.1313 ++++ libpng-1.6.35/pngtest.c	2018-07-21 19:16:16.213354917 +0900
 47.1314 +@@ -875,6 +875,10 @@
 47.1315 +    volatile int num_passes;
 47.1316 +    int pass;
 47.1317 +    int bit_depth, color_type;
 47.1318 ++#ifdef PNG_APNG_SUPPORTED
 47.1319 ++   png_uint_32 num_frames;
 47.1320 ++   png_uint_32 num_plays;
 47.1321 ++#endif
 47.1322 + 
 47.1323 +    row_buf = NULL;
 47.1324 +    error_parameters.file_name = inname;
 47.1325 +@@ -1381,6 +1385,22 @@
 47.1326 +       }
 47.1327 +    }
 47.1328 + #endif
 47.1329 ++
 47.1330 ++#ifdef PNG_APNG_SUPPORTED
 47.1331 ++   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
 47.1332 ++   {
 47.1333 ++      if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
 47.1334 ++      {
 47.1335 ++         png_byte is_hidden;
 47.1336 ++         pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
 47.1337 ++                    num_frames, num_plays);
 47.1338 ++         png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
 47.1339 ++         is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
 47.1340 ++         png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
 47.1341 ++      }
 47.1342 ++   }
 47.1343 ++#endif
 47.1344 ++
 47.1345 + #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
 47.1346 +    {
 47.1347 +       png_unknown_chunkp unknowns;
 47.1348 +@@ -1461,6 +1481,110 @@
 47.1349 +    t_misc += (t_stop - t_start);
 47.1350 +    t_start = t_stop;
 47.1351 + #endif
 47.1352 ++#ifdef PNG_APNG_SUPPORTED
 47.1353 ++   if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
 47.1354 ++   {
 47.1355 ++      png_uint_32 frame;
 47.1356 ++      for (frame = 0; frame < num_frames; frame++)
 47.1357 ++      {
 47.1358 ++         png_uint_32 frame_width;
 47.1359 ++         png_uint_32 frame_height;
 47.1360 ++         png_uint_32 x_offset;
 47.1361 ++         png_uint_32 y_offset;
 47.1362 ++         png_uint_16 delay_num;
 47.1363 ++         png_uint_16 delay_den;
 47.1364 ++         png_byte dispose_op;
 47.1365 ++         png_byte blend_op;
 47.1366 ++         png_read_frame_head(read_ptr, read_info_ptr);
 47.1367 ++         if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
 47.1368 ++         {
 47.1369 ++            png_get_next_frame_fcTL(read_ptr, read_info_ptr,
 47.1370 ++                                    &frame_width, &frame_height,
 47.1371 ++                                    &x_offset, &y_offset,
 47.1372 ++                                    &delay_num, &delay_den,
 47.1373 ++                                    &dispose_op, &blend_op);
 47.1374 ++         }
 47.1375 ++         else
 47.1376 ++         {
 47.1377 ++            frame_width = width;
 47.1378 ++            frame_height = height;
 47.1379 ++            x_offset = 0;
 47.1380 ++            y_offset = 0;
 47.1381 ++            delay_num = 1;
 47.1382 ++            delay_den = 1;
 47.1383 ++            dispose_op = PNG_DISPOSE_OP_NONE;
 47.1384 ++            blend_op = PNG_BLEND_OP_SOURCE;
 47.1385 ++         }
 47.1386 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1387 ++         png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
 47.1388 ++                              frame_width, frame_height,
 47.1389 ++                              x_offset, y_offset,
 47.1390 ++                              delay_num, delay_den,
 47.1391 ++                              dispose_op, blend_op);
 47.1392 ++#endif
 47.1393 ++         for (pass = 0; pass < num_passes; pass++)
 47.1394 ++         {
 47.1395 ++#           ifdef calc_pass_height
 47.1396 ++               png_uint_32 pass_height;
 47.1397 ++
 47.1398 ++               if (num_passes == 7) /* interlaced */
 47.1399 ++               {
 47.1400 ++                  if (PNG_PASS_COLS(frame_width, pass) > 0)
 47.1401 ++                     pass_height = PNG_PASS_ROWS(frame_height, pass);
 47.1402 ++
 47.1403 ++                  else
 47.1404 ++                     pass_height = 0;
 47.1405 ++               }
 47.1406 ++
 47.1407 ++               else /* not interlaced */
 47.1408 ++                  pass_height = frame_height;
 47.1409 ++#           else
 47.1410 ++#              define pass_height frame_height
 47.1411 ++#           endif
 47.1412 ++
 47.1413 ++            pngtest_debug1("Writing row data for pass %d", pass);
 47.1414 ++            for (y = 0; y < pass_height; y++)
 47.1415 ++            {
 47.1416 ++#ifndef SINGLE_ROWBUF_ALLOC
 47.1417 ++               pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
 47.1418 ++
 47.1419 ++               row_buf = (png_bytep)png_malloc(read_ptr,
 47.1420 ++                  png_get_rowbytes(read_ptr, read_info_ptr));
 47.1421 ++
 47.1422 ++               pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
 47.1423 ++                  (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
 47.1424 ++
 47.1425 ++#endif /* !SINGLE_ROWBUF_ALLOC */
 47.1426 ++               png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
 47.1427 ++
 47.1428 ++#ifdef PNG_WRITE_SUPPORTED
 47.1429 ++#ifdef PNGTEST_TIMING
 47.1430 ++               t_stop = (float)clock();
 47.1431 ++               t_decode += (t_stop - t_start);
 47.1432 ++               t_start = t_stop;
 47.1433 ++#endif
 47.1434 ++               png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
 47.1435 ++#ifdef PNGTEST_TIMING
 47.1436 ++               t_stop = (float)clock();
 47.1437 ++               t_encode += (t_stop - t_start);
 47.1438 ++               t_start = t_stop;
 47.1439 ++#endif
 47.1440 ++#endif /* PNG_WRITE_SUPPORTED */
 47.1441 ++
 47.1442 ++#ifndef SINGLE_ROWBUF_ALLOC
 47.1443 ++               pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
 47.1444 ++               png_free(read_ptr, row_buf);
 47.1445 ++               row_buf = NULL;
 47.1446 ++#endif /* !SINGLE_ROWBUF_ALLOC */
 47.1447 ++            }
 47.1448 ++         }
 47.1449 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1450 ++         png_write_frame_tail(write_ptr, write_info_ptr);
 47.1451 ++#endif
 47.1452 ++      }
 47.1453 ++   }
 47.1454 ++   else
 47.1455 ++#endif
 47.1456 +    for (pass = 0; pass < num_passes; pass++)
 47.1457 +    {
 47.1458 + #     ifdef calc_pass_height
 47.1459 +diff -Naru libpng-1.6.35.org/pngwrite.c libpng-1.6.35/pngwrite.c
 47.1460 +--- libpng-1.6.35.org/pngwrite.c	2018-07-21 19:16:37.188143186 +0900
 47.1461 ++++ libpng-1.6.35/pngwrite.c	2018-07-21 19:16:16.211354747 +0900
 47.1462 +@@ -128,6 +128,10 @@
 47.1463 +        * the application continues writing the PNG.  So check the 'invalid'
 47.1464 +        * flag here too.
 47.1465 +        */
 47.1466 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1467 ++      if (info_ptr->valid & PNG_INFO_acTL)
 47.1468 ++         png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
 47.1469 ++#endif
 47.1470 + #ifdef PNG_GAMMA_SUPPORTED
 47.1471 + #  ifdef PNG_WRITE_gAMA_SUPPORTED
 47.1472 +       if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
 47.1473 +@@ -370,6 +374,11 @@
 47.1474 +       png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
 47.1475 + #endif
 47.1476 + 
 47.1477 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1478 ++   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
 47.1479 ++      png_error(png_ptr, "Not enough frames written");
 47.1480 ++#endif
 47.1481 ++
 47.1482 +    /* See if user wants us to write information chunks */
 47.1483 +    if (info_ptr != NULL)
 47.1484 +    {
 47.1485 +@@ -1461,6 +1470,43 @@
 47.1486 + }
 47.1487 + #endif
 47.1488 + 
 47.1489 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1490 ++void PNGAPI
 47.1491 ++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
 47.1492 ++    png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
 47.1493 ++    png_uint_32 x_offset, png_uint_32 y_offset,
 47.1494 ++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
 47.1495 ++    png_byte blend_op)
 47.1496 ++{
 47.1497 ++    png_debug(1, "in png_write_frame_head");
 47.1498 ++
 47.1499 ++    /* there is a chance this has been set after png_write_info was called,
 47.1500 ++    * so it would be set but not written. is there a way to be sure? */
 47.1501 ++    if (!(info_ptr->valid & PNG_INFO_acTL))
 47.1502 ++        png_error(png_ptr, "png_write_frame_head(): acTL not set");
 47.1503 ++
 47.1504 ++    png_write_reset(png_ptr);
 47.1505 ++
 47.1506 ++    png_write_reinit(png_ptr, info_ptr, width, height);
 47.1507 ++
 47.1508 ++    if ( !(png_ptr->num_frames_written == 0 &&
 47.1509 ++           (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
 47.1510 ++        png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
 47.1511 ++                       delay_num, delay_den, dispose_op, blend_op);
 47.1512 ++
 47.1513 ++    PNG_UNUSED(row_pointers)
 47.1514 ++}
 47.1515 ++
 47.1516 ++void PNGAPI
 47.1517 ++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
 47.1518 ++{
 47.1519 ++    png_debug(1, "in png_write_frame_tail");
 47.1520 ++
 47.1521 ++    png_ptr->num_frames_written++;
 47.1522 ++
 47.1523 ++    PNG_UNUSED(info_ptr)
 47.1524 ++}
 47.1525 ++#endif /* PNG_WRITE_APNG_SUPPORTED */
 47.1526 + 
 47.1527 + #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
 47.1528 + /* Initialize the write structure - general purpose utility. */
 47.1529 +diff -Naru libpng-1.6.35.org/pngwutil.c libpng-1.6.35/pngwutil.c
 47.1530 +--- libpng-1.6.35.org/pngwutil.c	2018-07-21 19:16:37.189143271 +0900
 47.1531 ++++ libpng-1.6.35/pngwutil.c	2018-07-21 19:16:16.303362592 +0900
 47.1532 +@@ -821,6 +821,11 @@
 47.1533 +    /* Write the chunk */
 47.1534 +    png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
 47.1535 + 
 47.1536 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1537 ++   png_ptr->first_frame_width = width;
 47.1538 ++   png_ptr->first_frame_height = height;
 47.1539 ++#endif
 47.1540 ++
 47.1541 +    if ((png_ptr->do_filter) == PNG_NO_FILTERS)
 47.1542 +    {
 47.1543 +       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
 47.1544 +@@ -1002,8 +1007,17 @@
 47.1545 +                optimize_cmf(data, png_image_size(png_ptr));
 47.1546 + #endif
 47.1547 + 
 47.1548 +-         if (size > 0)
 47.1549 +-            png_write_complete_chunk(png_ptr, png_IDAT, data, size);
 47.1550 ++            if (size > 0)
 47.1551 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1552 ++            {
 47.1553 ++               if (png_ptr->num_frames_written == 0)
 47.1554 ++#endif
 47.1555 ++               png_write_complete_chunk(png_ptr, png_IDAT, data, size);
 47.1556 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1557 ++               else
 47.1558 ++                  png_write_fdAT(png_ptr, data, size);
 47.1559 ++            }
 47.1560 ++#endif /* PNG_WRITE_APNG_SUPPORTED */
 47.1561 +          png_ptr->mode |= PNG_HAVE_IDAT;
 47.1562 + 
 47.1563 +          png_ptr->zstream.next_out = data;
 47.1564 +@@ -1050,7 +1064,17 @@
 47.1565 + #endif
 47.1566 + 
 47.1567 +          if (size > 0)
 47.1568 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1569 ++         {
 47.1570 ++            if (png_ptr->num_frames_written == 0)
 47.1571 ++#endif
 47.1572 +             png_write_complete_chunk(png_ptr, png_IDAT, data, size);
 47.1573 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1574 ++            else
 47.1575 ++               png_write_fdAT(png_ptr, data, size);
 47.1576 ++         }
 47.1577 ++#endif /* PNG_WRITE_APNG_SUPPORTED */
 47.1578 ++
 47.1579 +          png_ptr->zstream.avail_out = 0;
 47.1580 +          png_ptr->zstream.next_out = NULL;
 47.1581 +          png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
 47.1582 +@@ -1885,6 +1909,82 @@
 47.1583 + }
 47.1584 + #endif
 47.1585 + 
 47.1586 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1587 ++void /* PRIVATE */
 47.1588 ++png_write_acTL(png_structp png_ptr,
 47.1589 ++    png_uint_32 num_frames, png_uint_32 num_plays)
 47.1590 ++{
 47.1591 ++    png_byte buf[8];
 47.1592 ++
 47.1593 ++    png_debug(1, "in png_write_acTL");
 47.1594 ++
 47.1595 ++    png_ptr->num_frames_to_write = num_frames;
 47.1596 ++
 47.1597 ++    if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
 47.1598 ++        num_frames--;
 47.1599 ++
 47.1600 ++    png_save_uint_32(buf, num_frames);
 47.1601 ++    png_save_uint_32(buf + 4, num_plays);
 47.1602 ++
 47.1603 ++    png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
 47.1604 ++}
 47.1605 ++
 47.1606 ++void /* PRIVATE */
 47.1607 ++png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
 47.1608 ++    png_uint_32 x_offset, png_uint_32 y_offset,
 47.1609 ++    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
 47.1610 ++    png_byte blend_op)
 47.1611 ++{
 47.1612 ++    png_byte buf[26];
 47.1613 ++
 47.1614 ++    png_debug(1, "in png_write_fcTL");
 47.1615 ++
 47.1616 ++    if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
 47.1617 ++        png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
 47.1618 ++    if (png_ptr->num_frames_written == 0 &&
 47.1619 ++        (width != png_ptr->first_frame_width ||
 47.1620 ++         height != png_ptr->first_frame_height))
 47.1621 ++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
 47.1622 ++                           "don't match the ones in IHDR");
 47.1623 ++
 47.1624 ++    /* more error checking */
 47.1625 ++    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
 47.1626 ++                             delay_num, delay_den, dispose_op, blend_op);
 47.1627 ++
 47.1628 ++    png_save_uint_32(buf, png_ptr->next_seq_num);
 47.1629 ++    png_save_uint_32(buf + 4, width);
 47.1630 ++    png_save_uint_32(buf + 8, height);
 47.1631 ++    png_save_uint_32(buf + 12, x_offset);
 47.1632 ++    png_save_uint_32(buf + 16, y_offset);
 47.1633 ++    png_save_uint_16(buf + 20, delay_num);
 47.1634 ++    png_save_uint_16(buf + 22, delay_den);
 47.1635 ++    buf[24] = dispose_op;
 47.1636 ++    buf[25] = blend_op;
 47.1637 ++
 47.1638 ++    png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
 47.1639 ++
 47.1640 ++    png_ptr->next_seq_num++;
 47.1641 ++}
 47.1642 ++
 47.1643 ++void /* PRIVATE */
 47.1644 ++png_write_fdAT(png_structp png_ptr,
 47.1645 ++    png_const_bytep data, png_size_t length)
 47.1646 ++{
 47.1647 ++    png_byte buf[4];
 47.1648 ++
 47.1649 ++    png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
 47.1650 ++
 47.1651 ++    png_save_uint_32(buf, png_ptr->next_seq_num);
 47.1652 ++    png_write_chunk_data(png_ptr, buf, 4);
 47.1653 ++
 47.1654 ++    png_write_chunk_data(png_ptr, data, length);
 47.1655 ++
 47.1656 ++    png_write_chunk_end(png_ptr);
 47.1657 ++
 47.1658 ++    png_ptr->next_seq_num++;
 47.1659 ++}
 47.1660 ++#endif /* PNG_WRITE_APNG_SUPPORTED */
 47.1661 ++
 47.1662 + /* Initializes the row writing capability of libpng */
 47.1663 + void /* PRIVATE */
 47.1664 + png_write_start_row(png_structrp png_ptr)
 47.1665 +@@ -2778,4 +2878,39 @@
 47.1666 +    }
 47.1667 + #endif /* WRITE_FLUSH */
 47.1668 + }
 47.1669 ++
 47.1670 ++#ifdef PNG_WRITE_APNG_SUPPORTED
 47.1671 ++void /* PRIVATE */
 47.1672 ++png_write_reset(png_structp png_ptr)
 47.1673 ++{
 47.1674 ++    png_ptr->row_number = 0;
 47.1675 ++    png_ptr->pass = 0;
 47.1676 ++    png_ptr->mode &= ~PNG_HAVE_IDAT;
 47.1677 ++}
 47.1678 ++
 47.1679 ++void /* PRIVATE */
 47.1680 ++png_write_reinit(png_structp png_ptr, png_infop info_ptr,
 47.1681 ++                 png_uint_32 width, png_uint_32 height)
 47.1682 ++{
 47.1683 ++    if (png_ptr->num_frames_written == 0 &&
 47.1684 ++        (width != png_ptr->first_frame_width ||
 47.1685 ++         height != png_ptr->first_frame_height))
 47.1686 ++        png_error(png_ptr, "width and/or height in the first frame's fcTL "
 47.1687 ++                           "don't match the ones in IHDR");
 47.1688 ++    if (width > png_ptr->first_frame_width ||
 47.1689 ++        height > png_ptr->first_frame_height)
 47.1690 ++        png_error(png_ptr, "width and/or height for a frame greater than"
 47.1691 ++                           "the ones in IHDR");
 47.1692 ++
 47.1693 ++    png_set_IHDR(png_ptr, info_ptr, width, height,
 47.1694 ++                 info_ptr->bit_depth, info_ptr->color_type,
 47.1695 ++                 info_ptr->interlace_type, info_ptr->compression_type,
 47.1696 ++                 info_ptr->filter_type);
 47.1697 ++
 47.1698 ++    png_ptr->width = width;
 47.1699 ++    png_ptr->height = height;
 47.1700 ++    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
 47.1701 ++    png_ptr->usr_width = png_ptr->width;
 47.1702 ++}
 47.1703 ++#endif /* PNG_WRITE_APNG_SUPPORTED */
 47.1704 + #endif /* WRITE */
 47.1705 +diff -Naru libpng-1.6.35.org/scripts/symbols.def libpng-1.6.35/scripts/symbols.def
 47.1706 +--- libpng-1.6.35.org/scripts/symbols.def	2018-07-21 19:16:37.192143527 +0900
 47.1707 ++++ libpng-1.6.35/scripts/symbols.def	2018-07-21 19:16:16.206354321 +0900
 47.1708 +@@ -254,3 +254,23 @@
 47.1709 +  png_set_eXIf @247
 47.1710 +  png_get_eXIf_1 @248
 47.1711 +  png_set_eXIf_1 @249
 47.1712 ++ png_get_acTL @250
 47.1713 ++ png_set_acTL @251
 47.1714 ++ png_get_num_frames @252
 47.1715 ++ png_get_num_plays @253
 47.1716 ++ png_get_next_frame_fcTL @254
 47.1717 ++ png_set_next_frame_fcTL @255
 47.1718 ++ png_get_next_frame_width @256
 47.1719 ++ png_get_next_frame_height @257
 47.1720 ++ png_get_next_frame_x_offset @258
 47.1721 ++ png_get_next_frame_y_offset @259
 47.1722 ++ png_get_next_frame_delay_num @260
 47.1723 ++ png_get_next_frame_delay_den @261
 47.1724 ++ png_get_next_frame_dispose_op @262
 47.1725 ++ png_get_next_frame_blend_op @263
 47.1726 ++ png_get_first_frame_is_hidden @264
 47.1727 ++ png_set_first_frame_is_hidden @265
 47.1728 ++ png_read_frame_head @266
 47.1729 ++ png_set_progressive_frame_fn @267
 47.1730 ++ png_write_frame_head @268
 47.1731 ++ png_write_frame_tail @269
    48.1 --- a/libpng16/stuff/patches/series	Mon Jul 30 23:44:42 2018 +0300
    48.2 +++ b/libpng16/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
    48.3 @@ -1,5 +1,5 @@
    48.4  # This patch listed in the BLFS page, was downloaded using following address and
    48.5  # unzipped:
    48.6 -# https://downloads.sourceforge.net/sourceforge/libpng-apng/libpng-1.6.34-apng.patch.gz
    48.7 +# https://downloads.sourceforge.net/sourceforge/libpng-apng/libpng-1.6.35-apng.patch.gz
    48.8  
    48.9 --p1|libpng-1.6.34-apng.patch
   48.10 +-p1|libpng-1.6.35-apng.patch
    49.1 --- a/libsoup/receipt	Mon Jul 30 23:44:42 2018 +0300
    49.2 +++ b/libsoup/receipt	Tue Aug 07 00:30:45 2018 +0300
    49.3 @@ -1,13 +1,13 @@
    49.4  # SliTaz package receipt v2.
    49.5  
    49.6  PACKAGE="libsoup"
    49.7 -VERSION="2.60.3"
    49.8 +VERSION="2.62.2"
    49.9  CATEGORY="network"
   49.10  SHORT_DESC="HTTP client/server library for GNOME"
   49.11  MAINTAINER="pankso@slitaz.org"
   49.12  LICENSE="LGPL2"
   49.13  WEB_SITE="https://wiki.gnome.org/Projects/libsoup"
   49.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/basicnet/libsoup.html"
   49.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/basicnet/libsoup.html"
   49.16  
   49.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   49.18  WGET_URL="$GNOME_MIRROR/$PACKAGE/${VERSION%.*}/$TARBALL"
   49.19 @@ -15,7 +15,7 @@
   49.20  BUILD_DEPENDS_arm="glib-networking glib-dev libxml2-dev libgcrypt-dev \
   49.21  libtasn1-dev gnutls-dev zlib-dev libgnome-keyring-dev sqlite3-dev dbus-dev"
   49.22  BUILD_DEPENDS="glib-dev libxml2-dev sqlite3-dev intltool gtk-doc \
   49.23 -gobject-introspection-dev vala glib-networking"
   49.24 +gobject-introspection-dev vala glib-networking python3"
   49.25  SPLIT="libsoup-gnome libsoup-dev"
   49.26  
   49.27  compile_rules() {
   49.28 @@ -36,7 +36,7 @@
   49.29  		libsoup-gnome)
   49.30  			copy libsoup-gnome*.so*
   49.31  			CAT="x-window|GNOME specific library"
   49.32 -			DEPENDS="libsoup glib"
   49.33 +			DEPENDS="glib libsoup"
   49.34  			;;
   49.35  		*-dev)
   49.36  			copy @dev
    50.1 --- a/libtirpc/receipt	Mon Jul 30 23:44:42 2018 +0300
    50.2 +++ b/libtirpc/receipt	Tue Aug 07 00:30:45 2018 +0300
    50.3 @@ -1,13 +1,13 @@
    50.4  # SliTaz package receipt v2.
    50.5  
    50.6  PACKAGE="libtirpc"
    50.7 -VERSION="1.0.2"
    50.8 +VERSION="1.0.3"
    50.9  CATEGORY="system-tools"
   50.10  SHORT_DESC="Transport-Independent RPC library"
   50.11  MAINTAINER="pascal.bellard@slitaz.org"
   50.12  LICENSE="BSD"
   50.13  WEB_SITE="http://libtirpc.sourceforge.net/"
   50.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/basicnet/libtirpc.html"
   50.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/basicnet/libtirpc.html"
   50.16  
   50.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   50.18  WGET_URL="$SF_MIRROR/$PACKAGE/$TARBALL"
   50.19 @@ -15,19 +15,12 @@
   50.20  SPLIT="libtirpc-dev"
   50.21  
   50.22  compile_rules() {
   50.23 -	# Fix a build issue with glibc-2.26:
   50.24 -	sed -i '/stdlib.h/a#include <stdint.h>' src/xdr_sizeof.c
   50.25 -
   50.26 -	# Fix a symbol name needed by NIS libraries:
   50.27 -	sed -i '/key_secret_is/s|secret|secretkey|' src/libtirpc.map
   50.28 -
   50.29  	./configure \
   50.30 +		--sysconfdir=/etc \
   50.31  		--disable-static \
   50.32  		--disable-gssapi \
   50.33  		$CONFIGURE_ARGS &&
   50.34 -	fix libtool &&
   50.35 -	make &&
   50.36 -	make install || return 1
   50.37 +	make && make install || return 1
   50.38  
   50.39  	mkdir -p $install/lib
   50.40  	mv -v $install/usr/lib/libtirpc.so.* $install/lib
    51.1 --- a/libunistring/receipt	Mon Jul 30 23:44:42 2018 +0300
    51.2 +++ b/libunistring/receipt	Tue Aug 07 00:30:45 2018 +0300
    51.3 @@ -1,13 +1,13 @@
    51.4  # SliTaz package receipt v2.
    51.5  
    51.6  PACKAGE="libunistring"
    51.7 -VERSION="0.9.8"
    51.8 +VERSION="0.9.10"
    51.9  CATEGORY="libdevel"
   51.10  SHORT_DESC="Unicode string library"
   51.11  MAINTAINER="al.bobylev@gmail.com"
   51.12  LICENSE="GPL3 LGPL3 FDL"
   51.13  WEB_SITE="https://www.gnu.org/software/libunistring/"
   51.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libunistring.html"
   51.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libunistring.html"
   51.16  
   51.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   51.18  WGET_URL="$GNU_MIRROR/$PACKAGE/$TARBALL"
    52.1 --- a/libusb/receipt	Mon Jul 30 23:44:42 2018 +0300
    52.2 +++ b/libusb/receipt	Tue Aug 07 00:30:45 2018 +0300
    52.3 @@ -1,13 +1,13 @@
    52.4  # SliTaz package receipt v2.
    52.5  
    52.6  PACKAGE="libusb"
    52.7 -VERSION="1.0.21"
    52.8 +VERSION="1.0.22"
    52.9  CATEGORY="system-tools"
   52.10  SHORT_DESC="Library used by some applications for USB device access"
   52.11  MAINTAINER="pankso@slitaz.org"
   52.12  LICENSE="LGPL2.1"
   52.13  WEB_SITE="http://libusb.info/"
   52.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libusb.html"
   52.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libusb.html"
   52.16  
   52.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   52.18  WGET_URL="https://github.com/libusb/libusb/releases/download/v$VERSION/$TARBALL"
   52.19 @@ -16,7 +16,7 @@
   52.20  SPLIT="libusb-dev"
   52.21  
   52.22  compile_rules() {
   52.23 -	sed -i "s/^PROJECT_LOGO/#&/" doc/doxygen.cfg.in
   52.24 +	sed -i 's|^PROJECT_LOGO|#&|' doc/doxygen.cfg.in
   52.25  
   52.26  	# Results are unstable, please keep `make -j1`
   52.27  	./configure \
    53.1 --- a/libvorbis/receipt	Mon Jul 30 23:44:42 2018 +0300
    53.2 +++ b/libvorbis/receipt	Tue Aug 07 00:30:45 2018 +0300
    53.3 @@ -1,7 +1,7 @@
    53.4  # SliTaz package receipt v2.
    53.5  
    53.6  PACKAGE="libvorbis"
    53.7 -VERSION="1.3.5"
    53.8 +VERSION="1.3.6"
    53.9  CATEGORY="multimedia"
   53.10  SHORT_DESC="Vorbis base library"
   53.11  MAINTAINER="pankso@slitaz.org"
   53.12 @@ -23,7 +23,13 @@
   53.13  
   53.14  genpkg_rules() {
   53.15  	case $PACKAGE in
   53.16 -		libvorbis) copy @std; DEPENDS="libogg";;
   53.17 -		*-dev)     copy @dev; DEPENDS="libvorbis libogg-dev";;
   53.18 +		libvorbis)
   53.19 +			copy @std
   53.20 +			DEPENDS="libogg"
   53.21 +			;;
   53.22 +		*-dev)
   53.23 +			copy @dev
   53.24 +			DEPENDS="libvorbis libogg-dev"
   53.25 +			;;
   53.26  	esac
   53.27  }
    54.1 --- a/libwnck2/receipt	Mon Jul 30 23:44:42 2018 +0300
    54.2 +++ b/libwnck2/receipt	Tue Aug 07 00:30:45 2018 +0300
    54.3 @@ -1,14 +1,14 @@
    54.4  # SliTaz package receipt v2.
    54.5  
    54.6  PACKAGE="libwnck2"
    54.7 -VERSION="2.30.7"
    54.8 +VERSION="2.31.0"
    54.9  CATEGORY="x-window"
   54.10  SHORT_DESC="Window Navigator Construction Kit"
   54.11  MAINTAINER="pankso@slitaz.org"
   54.12  LICENSE="LGPL2"
   54.13  WEB_SITE="https://developer.gnome.org/libwnck/"
   54.14  
   54.15 -TARBALL="libwnck-$VERSION.tar.bz2"
   54.16 +TARBALL="libwnck-$VERSION.tar.xz"
   54.17  WGET_URL="$GNOME_MIRROR/libwnck/${VERSION%.*}/$TARBALL"
   54.18  
   54.19  BUILD_DEPENDS="intltool startup-notification-dev xorg-libX11-dev gtk+-dev \
    55.1 --- a/libxml2/receipt	Mon Jul 30 23:44:42 2018 +0300
    55.2 +++ b/libxml2/receipt	Tue Aug 07 00:30:45 2018 +0300
    55.3 @@ -1,20 +1,20 @@
    55.4  # SliTaz package receipt v2.
    55.5  
    55.6  PACKAGE="libxml2"
    55.7 -VERSION="2.9.4"
    55.8 +VERSION="2.9.8"
    55.9  CATEGORY="system-tools"
   55.10  SHORT_DESC="XML C parser and toolkit"
   55.11  MAINTAINER="pankso@slitaz.org"
   55.12  LICENSE="MIT"
   55.13  WEB_SITE="http://xmlsoft.org/"
   55.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/libxml2.html"
   55.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/libxml2.html"
   55.16  
   55.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   55.18  WGET_URL="ftp://xmlsoft.org/libxml2/$TARBALL"
   55.19  
   55.20  BUILD_DEPENDS_arm=" "
   55.21  BUILD_DEPENDS="zlib-dev xz-dev python-dev ncurses-dev readline-dev"
   55.22 -SPLIT="libxml2-tools libxml2-python libxml2-dev"
   55.23 +SPLIT="libxml2-tools libxml2-python libxml2-dev libxml2-min:min"
   55.24  
   55.25  # Note: libxml2 can be build using option --with-minimum
   55.26  # and binaries are splited into libxml2-tools
   55.27 @@ -26,13 +26,17 @@
   55.28  		arm) ARCH_ARGS="--without-lzma" ;;
   55.29  	esac
   55.30  
   55.31 +	case $SET in
   55.32 +		min) SET_ARGS='--with-minimum';;
   55.33 +	esac
   55.34 +
   55.35  	#	autoreconf -fi
   55.36  	./configure \
   55.37  		--disable-static \
   55.38  		--with-html-dir=/usr/share/doc \
   55.39  		--with-threads \
   55.40  		--with-history \
   55.41 -	$CONFIGURE_ARGS $ARCH_ARGS &&
   55.42 +		$CONFIGURE_ARGS $ARCH_ARGS $SET_ARGS &&
   55.43  	fix libtool &&
   55.44  	make &&
   55.45  	make DESTDIR=$DESTDIR install || return 1
   55.46 @@ -52,16 +56,21 @@
   55.47  		libxml2-tools)
   55.48  			copy xmllint xmlcatalog
   55.49  			CAT="system-tools|xmllint tester and xmlcatalog parser utility"
   55.50 -			DEPENDS="liblzma libxml2 ncurses readline zlib"
   55.51 +			DEPENDS="libxml2 readline"
   55.52  			;;
   55.53  		libxml2-python)
   55.54  			copy python2.7/; find $fs -name '*.la' -delete
   55.55  			CAT="development|adapter for the Python"
   55.56 -			DEPENDS="liblzma libxml2 python zlib   libxslt"
   55.57 +			DEPENDS="libxml2 python" # libxslt
   55.58  			;;
   55.59  		libxml2-dev)
   55.60  			copy @dev *.sh
   55.61  			DEPENDS="xz-dev zlib-dev   libxml2-tools"
   55.62  			;;
   55.63 +		libxml2-min)
   55.64 +			copy libxml2.so*
   55.65 +			CAT="system-tools|minimally sized library"
   55.66 +			DEPENDS="liblzma"
   55.67 +			;;
   55.68  	esac
   55.69  }
    56.1 --- a/lvm2/receipt	Mon Jul 30 23:44:42 2018 +0300
    56.2 +++ b/lvm2/receipt	Tue Aug 07 00:30:45 2018 +0300
    56.3 @@ -1,18 +1,19 @@
    56.4  # SliTaz package receipt v2.
    56.5  
    56.6  PACKAGE="lvm2"
    56.7 -VERSION="2.02.177"
    56.8 +VERSION="2.02.180"
    56.9  CATEGORY="system-tools"
   56.10  SHORT_DESC="Linux Logical Volume Manager"
   56.11  MAINTAINER="guillaume.michon@laposte.net"
   56.12  LICENSE="GPL2"
   56.13  WEB_SITE="http://sourceware.org/lvm2/"
   56.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/postlfs/lvm2.html"
   56.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/postlfs/lvm2.html"
   56.16  
   56.17  TARBALL="LVM2.$VERSION.tgz"
   56.18  WGET_URL="ftp://sources.redhat.com/pub/lvm2/$TARBALL"
   56.19  
   56.20 -BUILD_DEPENDS="readline-dev eudev-dev ncurses-dev coreutils-file-format"
   56.21 +BUILD_DEPENDS="libaio-dev util-linux-blkid-dev eudev-dev ncurses-dev \
   56.22 +readline-dev coreutils-file-format"
   56.23  SPLIT="dmsetup libdevmapper libdevmapper-dev lvm2 lvm2-dev"
   56.24  
   56.25  compile_rules() {
   56.26 @@ -28,9 +29,9 @@
   56.27  		--with-thin-check=   --with-thin-dump=     --with-thin-repair= \
   56.28  		--with-thin-restore= --with-cache-check=   --with-cache-dump= \
   56.29  		--with-cache-repair= --with-cache-restore= \
   56.30 +		--enable-write-install \
   56.31  		MKDIR_P='mkdir -p' \
   56.32  		$CONFIGURE_ARGS &&
   56.33 -	title "make" &&
   56.34  	make &&
   56.35  	make -C tools install_dmsetup_dynamic &&
   56.36  	make -C udev  install &&
   56.37 @@ -48,7 +49,7 @@
   56.38  		libdevmapper)
   56.39  			# to satisfy package ldd-dependencies: add liblvm2cmd.so*
   56.40  			copy *.rules libdevmapper*.so* liblvm2cmd.so*
   56.41 -			DEPENDS="eudev"
   56.42 +			DEPENDS="eudev libaio util-linux-blkid"
   56.43  			CAT="system-tools|Linux device mapper library"
   56.44  			;;
   56.45  		libdevmapper-dev)
   56.46 @@ -59,11 +60,12 @@
   56.47  			;;
   56.48  		lvm2)
   56.49  			copy @std @rm
   56.50 -			DEPENDS="eudev libdevmapper ncurses readline   linux-md"
   56.51 +			DEPENDS="eudev libaio libdevmapper readline util-linux-blkid \
   56.52 +			   linux-md"
   56.53  			;;
   56.54  		lvm2-dev)
   56.55  			copy lvm2app.h lvm2app.pc
   56.56 -			DEPENDS="lvm2 libdevmapper-dev"
   56.57 +			DEPENDS="lvm2 libdevmapper-dev util-linux-blkid-dev"
   56.58  			;;
   56.59  	esac
   56.60  }
    57.1 --- a/lxpanel/receipt	Mon Jul 30 23:44:42 2018 +0300
    57.2 +++ b/lxpanel/receipt	Tue Aug 07 00:30:45 2018 +0300
    57.3 @@ -16,7 +16,7 @@
    57.4  libxml2-dev lxmenu-data"
    57.5  BUILD_DEPENDS="automake libtool intltool gtk+-dev menu-cache-dev alsa-lib-dev \
    57.6  wireless_tools-dev libxml2-dev lxmenu-data libwnck2-dev libfm-dev \
    57.7 -libkeybinder-dev"
    57.8 +keybinder-dev"
    57.9  SPLIT="lxpanel-extra lxpanel lxpanel-dev"
   57.10  
   57.11  compile_rules() {
   57.12 @@ -52,7 +52,7 @@
   57.13  		lxpanel)
   57.14  			copy @std @rm
   57.15  			DEPENDS="alsa-lib cairo gdk-pixbuf glib gtk+ libfm libfm-gtk \
   57.16 -			libkeybinder libwnck2 libxml2 menu-cache pango wireless_tools \
   57.17 +			keybinder libwnck2 libxml2 menu-cache pango wireless_tools \
   57.18  			xorg-libX11    slitaz-menus"
   57.19  			#CONFIG_FILES="/etc/xdg/lxpanel/default/"
   57.20  			TAGS="LXDE gtk2 panel"
    58.1 --- a/lzma/receipt	Mon Jul 30 23:44:42 2018 +0300
    58.2 +++ b/lzma/receipt	Tue Aug 07 00:30:45 2018 +0300
    58.3 @@ -6,7 +6,7 @@
    58.4  SHORT_DESC="Compressor with a high compression ratio"
    58.5  MAINTAINER="pascal.bellard@slitaz.org"
    58.6  LICENSE="LGPL2.1"
    58.7 -WEB_SITE="http://sourceforge.net/projects/sevenzip/"
    58.8 +WEB_SITE="https://tukaani.org/lzma/"
    58.9  
   58.10  TARBALL="lzma$(echo $VERSION | sed 's/\.//').tar.bz2"
   58.11  WGET_URL="$SF_MIRROR/sevenzip/$TARBALL"
    59.1 --- a/man-db/receipt	Mon Jul 30 23:44:42 2018 +0300
    59.2 +++ b/man-db/receipt	Tue Aug 07 00:30:45 2018 +0300
    59.3 @@ -1,13 +1,13 @@
    59.4  # SliTaz package receipt v2.
    59.5  
    59.6  PACKAGE="man-db"
    59.7 -VERSION="2.7.6.1"
    59.8 +VERSION="2.8.3"
    59.9  CATEGORY="system-tools"
   59.10  SHORT_DESC="The on-line manual database"
   59.11  MAINTAINER="al.bobylev@gmail.com"
   59.12  LICENSE="GPL2"
   59.13  WEB_SITE="http://www.nongnu.org/man-db/"
   59.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/man-db.html"
   59.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/man-db.html"
   59.16  
   59.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   59.18  WGET_URL="http://download.savannah.gnu.org/releases/man-db/$TARBALL"
    60.1 --- a/mate-notification-daemon-gtk2/receipt	Mon Jul 30 23:44:42 2018 +0300
    60.2 +++ b/mate-notification-daemon-gtk2/receipt	Tue Aug 07 00:30:45 2018 +0300
    60.3 @@ -1,12 +1,14 @@
    60.4  # SliTaz package receipt v2.
    60.5  
    60.6  PACKAGE="mate-notification-daemon-gtk2"
    60.7 -VERSION="1.14.0" # deprecated version, to use with gtk2
    60.8 +LEGACY_OF="mate-notification-daemon"
    60.9 +VERSION="1.14.1" # old version, to use with gtk2
   60.10  CATEGORY="x-window"
   60.11  SHORT_DESC="Fork of gnome-notification-daemon"
   60.12  MAINTAINER="al.bobylev@gmail.com"
   60.13  LICENSE="GPL2"
   60.14  WEB_SITE="https://github.com/mate-desktop/mate-notification-daemon/"
   60.15 +REPOLOGY="mate-notification-daemon"
   60.16  
   60.17  TARBALL="mate-notification-daemon-$VERSION.tar.gz"
   60.18  WGET_URL="${WEB_SITE}archive/v$VERSION.tar.gz"
    61.1 --- a/mc/receipt	Mon Jul 30 23:44:42 2018 +0300
    61.2 +++ b/mc/receipt	Tue Aug 07 00:30:45 2018 +0300
    61.3 @@ -1,13 +1,13 @@
    61.4  # SliTaz package receipt v2.
    61.5  
    61.6  PACKAGE="mc"
    61.7 -VERSION="4.8.20"
    61.8 +VERSION="4.8.21"
    61.9  CATEGORY="system-tools"
   61.10  SHORT_DESC="Midnight Commander - ncurses based file manager"
   61.11  MAINTAINER="erjo@slitaz.org"
   61.12  LICENSE="GPL3"
   61.13  WEB_SITE="http://midnight-commander.org/"
   61.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/mc.html"
   61.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/mc.html"
   61.16  
   61.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   61.18  WGET_URL="http://ftp.midnight-commander.org/$TARBALL"
    62.1 --- a/mc/stuff/patches/mc-slitaz.patch	Mon Jul 30 23:44:42 2018 +0300
    62.2 +++ b/mc/stuff/patches/mc-slitaz.patch	Tue Aug 07 00:30:45 2018 +0300
    62.3 @@ -1,6 +1,6 @@
    62.4  --- a/src/editor/edit.c
    62.5  +++ b/src/editor/edit.c
    62.6 -@@ -128,7 +128,7 @@
    62.7 +@@ -129,7 +129,7 @@
    62.8       { "xz -cd %s 2>&1", "xz > %s", ".xz"},
    62.9       { "lz4 -cd %s 2>&1", "lz4 > %s", ".lz4" },
   62.10       { "lzip -cd %s 2>&1", "lzip > %s", ".lz"},
    63.1 --- a/mpc-library/receipt	Mon Jul 30 23:44:42 2018 +0300
    63.2 +++ b/mpc-library/receipt	Tue Aug 07 00:30:45 2018 +0300
    63.3 @@ -1,17 +1,17 @@
    63.4  # SliTaz package receipt v2.
    63.5  
    63.6  PACKAGE="mpc-library"
    63.7 -VERSION="1.0.3"
    63.8 +VERSION="1.1.0"
    63.9  CATEGORY="development"
   63.10  SHORT_DESC="MPC library: complex numbers arithmetic"
   63.11  MAINTAINER="pankso@slitaz.org"
   63.12  LICENSE="GPL2"
   63.13  WEB_SITE="http://www.multiprecision.org/"
   63.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/mpc.html"
   63.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/mpc.html"
   63.16  REPOLOGY="gnumpc"
   63.17  
   63.18  TARBALL="mpc-$VERSION.tar.gz"
   63.19 -WGET_URL="${WEB_SITE}mpc/download/$TARBALL"
   63.20 +WGET_URL="$GNU_MIRROR/mpc/$TARBALL"
   63.21  
   63.22  BUILD_DEPENDS="mpfr-dev gmp-dev texinfo"
   63.23  SPLIT="mpc-library-dev"
    64.1 --- a/mpfr/receipt	Mon Jul 30 23:44:42 2018 +0300
    64.2 +++ b/mpfr/receipt	Tue Aug 07 00:30:45 2018 +0300
    64.3 @@ -1,18 +1,18 @@
    64.4  # SliTaz package receipt v2.
    64.5  
    64.6  PACKAGE="mpfr"
    64.7 -VERSION="3.1.5"
    64.8 +VERSION="4.0.1"
    64.9  CATEGORY="libdevel"
   64.10  SHORT_DESC="Multiple-precision floating-point computations"
   64.11  MAINTAINER="pankso@slitaz.org"
   64.12  LICENSE="GPL3"
   64.13  WEB_SITE="http://www.mpfr.org/"
   64.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/mpfr.html"
   64.15 +LFS="http://www.linuxfromscratch.org/lfs/view/svn/chapter06/mpfr.html"
   64.16  
   64.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   64.18  WGET_URL="http://www.mpfr.org/$PACKAGE-$VERSION/$TARBALL"
   64.19  
   64.20 -BUILD_DEPENDS="gmp-dev texinfo"
   64.21 +BUILD_DEPENDS="gmp-dev texinfo gcc-lib-math"
   64.22  SPLIT="mpfr-dev"
   64.23  
   64.24  compile_rules() {
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/mpfr4/receipt	Tue Aug 07 00:30:45 2018 +0300
    65.3 @@ -0,0 +1,42 @@
    65.4 +# SliTaz package receipt v2.
    65.5 +
    65.6 +PACKAGE="mpfr4"
    65.7 +LEGACY_OF="mpfr"
    65.8 +VERSION="3.1.5"
    65.9 +CATEGORY="libdevel"
   65.10 +SHORT_DESC="Multiple-precision floating-point computations"
   65.11 +MAINTAINER="pankso@slitaz.org"
   65.12 +LICENSE="GPL3"
   65.13 +WEB_SITE="http://www.mpfr.org/"
   65.14 +LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/mpfr.html"
   65.15 +REPOLOGY="mpfr"
   65.16 +
   65.17 +TARBALL="mpfr-$VERSION.tar.xz"
   65.18 +WGET_URL="http://www.mpfr.org/mpfr-$VERSION/$TARBALL"
   65.19 +
   65.20 +BUILD_DEPENDS="gmp-dev texinfo"
   65.21 +
   65.22 +compile_rules() {
   65.23 +	./configure \
   65.24 +		--disable-static \
   65.25 +		--enable-thread-safe \
   65.26 +		$CONFIGURE_ARGS &&
   65.27 +	fix libtool &&
   65.28 +	make &&
   65.29 +	make html &&
   65.30 +	make install &&
   65.31 +	make install-html
   65.32 +}
   65.33 +
   65.34 +testsuite() {
   65.35 +	case "$ARCH" in
   65.36 +		arm*) ;;
   65.37 +		*) make check;;
   65.38 +	esac
   65.39 +}
   65.40 +
   65.41 +genpkg_rules() {
   65.42 +	copy libmpfr.so.4*
   65.43 +	DEPENDS="gmp"
   65.44 +	TAGS="LFS"
   65.45 +}
    66.1 --- a/nano/receipt	Mon Jul 30 23:44:42 2018 +0300
    66.2 +++ b/nano/receipt	Tue Aug 07 00:30:45 2018 +0300
    66.3 @@ -1,7 +1,7 @@
    66.4  # SliTaz package receipt v2.
    66.5  
    66.6  PACKAGE="nano"
    66.7 -VERSION="2.6.3"
    66.8 +VERSION="2.9.8"
    66.9  CATEGORY="utilities"
   66.10  SHORT_DESC="Nano Text Editor"
   66.11  MAINTAINER="pankso@slitaz.org"
   66.12 @@ -19,16 +19,15 @@
   66.13  		--disable-wrapping-as-root \
   66.14  		--enable-utf8 \
   66.15  		$CONFIGURE_ARGS &&
   66.16 -	make && make install || exit 1
   66.17 +	make &&
   66.18 +	make install || exit 1
   66.19  
   66.20 -	# Config file.
   66.21 -	install -Dm644 $src/doc/nanorc.sample $install/etc/nanorc
   66.22 -
   66.23 -	cook_pick_docs doc/texinfo/nano.html
   66.24 +	# Config file
   66.25 +	install -Dm644 $src/doc/sample.nanorc $install/etc/nanorc
   66.26  }
   66.27  
   66.28  genpkg_rules() {
   66.29 -	copy etc/ bin/ nano/
   66.30 +	copy @std
   66.31  
   66.32  	# Shrink
   66.33  	for i in $fs/usr/share/nano/*.nanorc; do
    67.1 --- a/nano/stuff/patches/nanorc.patch	Mon Jul 30 23:44:42 2018 +0300
    67.2 +++ b/nano/stuff/patches/nanorc.patch	Tue Aug 07 00:30:45 2018 +0300
    67.3 @@ -1,9 +1,9 @@
    67.4  Adjust /etc/nanorc for SliTaz.
    67.5  
    67.6 ---- a/doc/nanorc.sample.in
    67.7 -+++ b/doc/nanorc.sample.in
    67.8 +--- a/doc/sample.nanorc.in
    67.9 ++++ b/doc/sample.nanorc.in
   67.10  @@ -1,10 +1,6 @@
   67.11 --## Sample initialization file for nano.
   67.12 +-## Sample initialization file for GNU nano.
   67.13  +## /etc/nanorc: system-wide initialization file for nano.
   67.14  +## ~/.nanorc:   personal config file.
   67.15   ##
   67.16 @@ -15,16 +15,16 @@
   67.17   ## To make sure an option is disabled, use "unset <option>".
   67.18   ##
   67.19   ## For the options that take parameters, the default value is given.
   67.20 -@@ -58,7 +54,7 @@
   67.21 +@@ -59,7 +55,7 @@
   67.22   # set fill -8
   67.23   
   67.24   ## Remember the used search/replace strings for the next session.
   67.25  -# set historylog
   67.26  +set historylog
   67.27   
   67.28 - ## Make the justify command kill whitespace at the end of lines.
   67.29 - # set justifytrim
   67.30 -@@ -80,7 +76,7 @@
   67.31 + ## Display line numbers to the left of the text.
   67.32 + # set linenumbers
   67.33 +@@ -81,7 +77,7 @@
   67.34   ## mouse clicks can be used to place the cursor, set the mark (with a
   67.35   ## double click), and execute shortcuts.  The mouse will work in the X
   67.36   ## Window System, and on the console when gpm is running.
   67.37 @@ -33,7 +33,7 @@
   67.38   
   67.39   ## Switch on multiple file buffers (inserting a file will put it into
   67.40   ## a separate buffer).
   67.41 -@@ -159,7 +155,7 @@
   67.42 +@@ -163,7 +159,7 @@
   67.43   # set suspend
   67.44   
   67.45   ## Use this tab size instead of the default; it must be greater than 0.
   67.46 @@ -42,7 +42,7 @@
   67.47   
   67.48   ## Convert typed tabs to spaces.
   67.49   # set tabstospaces
   67.50 -@@ -254,3 +250,151 @@
   67.51 +@@ -270,3 +266,150 @@
   67.52   
   67.53   ## Set this if your Backspace key sends Del most of the time.
   67.54   # bind Del backspace all
   67.55 @@ -193,4 +193,3 @@
   67.56  +color yellow "<ul>|</ul>|<hr>|<hr />"
   67.57  +color brightred "href=|name=|rel=|http-equiv=|content=|title=|type|style"
   67.58  +color brightgreen "<h1>|</h1>|<h2>|</h2>|<h3>|</h3>|<h4>|</h4>|<h5>|</h5>|<h6>|</h6>"
   67.59 -+
    68.1 --- a/nano/stuff/patches/receipt-as-sh.patch	Mon Jul 30 23:44:42 2018 +0300
    68.2 +++ b/nano/stuff/patches/receipt-as-sh.patch	Tue Aug 07 00:30:45 2018 +0300
    68.3 @@ -1,12 +1,12 @@
    68.4  SliTaz receipts are shell scripts.
    68.5  
    68.6 ---- a/doc/syntax/sh.nanorc
    68.7 -+++ b/doc/syntax/sh.nanorc
    68.8 +--- a/syntax/sh.nanorc
    68.9 ++++ b/syntax/sh.nanorc
   68.10  @@ -1,6 +1,6 @@
   68.11   ## Here is an example for Bourne shell scripts.
   68.12   
   68.13 --syntax "sh" "\.sh$"
   68.14 -+syntax "sh" "\.sh$" "receipt"
   68.15 +-syntax sh "\.sh$"
   68.16 ++syntax sh "\.sh$" "receipt"
   68.17   header "^#!.*((ba|da|k|pdk)?sh[-0-9_]*|openrc-run|runscript)"
   68.18 - magic "(POSIX|Bourne.*) shell script text"
   68.19 + magic "(POSIX|Bourne-Again) shell script.*text"
   68.20   linter dash -n
    69.1 --- a/nano/stuff/patches/series	Mon Jul 30 23:44:42 2018 +0300
    69.2 +++ b/nano/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
    69.3 @@ -1,2 +1,2 @@
    69.4 -nanorc.patch
    69.5 -receipt-as-sh.patch
    69.6 +#nanorc.patch
    69.7 +#receipt-as-sh.patch
    70.1 --- a/ncurses/receipt	Mon Jul 30 23:44:42 2018 +0300
    70.2 +++ b/ncurses/receipt	Tue Aug 07 00:30:45 2018 +0300
    70.3 @@ -1,13 +1,13 @@
    70.4  # SliTaz package receipt v2.
    70.5  
    70.6  PACKAGE="ncurses"
    70.7 -VERSION="6.0"
    70.8 +VERSION="6.1"
    70.9  CATEGORY="base-system"
   70.10  SHORT_DESC="Manage display on terminals"
   70.11  MAINTAINER="pankso@slitaz.org"
   70.12  LICENSE="MIT"
   70.13  WEB_SITE="https://www.gnu.org/software/ncurses/"
   70.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/ncurses.html"
   70.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/ncurses.html"
   70.16  
   70.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   70.18  WGET_URL="http://ftp.gnu.org/gnu/ncurses/$TARBALL"
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/ndctl/receipt	Tue Aug 07 00:30:45 2018 +0300
    71.3 @@ -0,0 +1,37 @@
    71.4 +# SliTaz package receipt v2.
    71.5 +
    71.6 +PACKAGE="ndctl"
    71.7 +VERSION="61.2"
    71.8 +CATEGORY="libs"
    71.9 +SHORT_DESC="Utility library for managing the libnvdimm (non-volatile memory \
   71.10 +device) sub-system in the Linux kernel"
   71.11 +MAINTAINER="al.bobylev@gmail.com"
   71.12 +LICENSE="LGPL2.1"
   71.13 +WEB_SITE="https://github.com/pmem/ndctl/"
   71.14 +
   71.15 +TARBALL="$PACKAGE-$VERSION.tar.gz"
   71.16 +WGET_URL="https://github.com/pmem/ndctl/archive/v$VERSION.tar.gz"
   71.17 +
   71.18 +BUILD_DEPENDS="automake libtool asciidoc xmlto kmod-dev eudev-dev \
   71.19 +util-linux-uuid-dev json-c-dev libxml2-tools docbook-xsl"
   71.20 +SPLIT="ndctl-dev"
   71.21 +
   71.22 +compile_rules() {
   71.23 +	./autogen.sh &&
   71.24 +	./configure $CONFIGURE_ARGS &&
   71.25 +	fix libtool &&
   71.26 +	make &&
   71.27 +	make install
   71.28 +}
   71.29 +
   71.30 +genpkg_rules() {
   71.31 +	case $PACKAGE in
   71.32 +		ndctl)
   71.33 +			copy @std
   71.34 +			DEPENDS="eudev json-c kmod util-linux-uuid"
   71.35 +			;;
   71.36 +		*-dev)
   71.37 +			copy @dev
   71.38 +			;;
   71.39 +	esac
   71.40 +}
    72.1 --- a/nettle/receipt	Mon Jul 30 23:44:42 2018 +0300
    72.2 +++ b/nettle/receipt	Tue Aug 07 00:30:45 2018 +0300
    72.3 @@ -1,7 +1,7 @@
    72.4  # SliTaz package receipt v2.
    72.5  
    72.6  PACKAGE="nettle"
    72.7 -VERSION="3.3"
    72.8 +VERSION="3.4"
    72.9  CATEGORY="security"
   72.10  SHORT_DESC="Nettle cryptographic library"
   72.11  MAINTAINER="devl547@gmail.com"
   72.12 @@ -21,9 +21,13 @@
   72.13  	esac
   72.14  
   72.15  	./configure \
   72.16 +		--libdir=/usr/lib \
   72.17  		--disable-static \
   72.18  		$CONFIGURE_ARGS $ARCH_ARGS &&
   72.19 -	make && make install
   72.20 +	make &&
   72.21 +	make install || return 1
   72.22 +
   72.23 +	chmod 0755 $install/usr/lib/*.so*	# was 644
   72.24  }
   72.25  
   72.26  genpkg_rules() {
    73.1 --- a/npth/receipt	Mon Jul 30 23:44:42 2018 +0300
    73.2 +++ b/npth/receipt	Tue Aug 07 00:30:45 2018 +0300
    73.3 @@ -1,18 +1,18 @@
    73.4  # SliTaz package receipt v2.
    73.5  
    73.6  PACKAGE="npth"
    73.7 -VERSION="1.5"
    73.8 +VERSION="1.6"
    73.9  CATEGORY="security"
   73.10  SHORT_DESC="The new GNU portable threads library"
   73.11  MAINTAINER="al.bobylev@gmail.com"
   73.12  LICENSE="GPL2 LGPL3"
   73.13  WEB_SITE="https://www.gnupg.org/related_software/npth/"
   73.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/npth.html"
   73.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/npth.html"
   73.16  
   73.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   73.18  WGET_URL="https://www.gnupg.org/ftp/gcrypt/npth/$TARBALL"
   73.19  # https://www.gnupg.org/download/integrity_check.html
   73.20 -TARBALL_SHA1="93ddf1a3bdbca00fb4cf811498094ca61bbb8ee1"
   73.21 +TARBALL_SHA1="f9d63e9747b027e4e404fe3c20c73c73719e1731"
   73.22  
   73.23  SPLIT="npth-dev"
   73.24  
    74.1 --- a/nspr/receipt	Mon Jul 30 23:44:42 2018 +0300
    74.2 +++ b/nspr/receipt	Tue Aug 07 00:30:45 2018 +0300
    74.3 @@ -1,13 +1,13 @@
    74.4  # SliTaz package receipt v2.
    74.5  
    74.6  PACKAGE="nspr"
    74.7 -VERSION="4.18"
    74.8 +VERSION="4.19"
    74.9  CATEGORY="utilities"
   74.10  SHORT_DESC="Netscape Portable Runtime"
   74.11  MAINTAINER="rocky@slitaz.org"
   74.12  LICENSE="MPL2"
   74.13  WEB_SITE="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR"
   74.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/nspr.html"
   74.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/nspr.html"
   74.16  
   74.17  TARBALL="nspr-$VERSION.tar.gz"
   74.18  WGET_URL="https://archive.mozilla.org/pub/nspr/releases/v$VERSION/src/$TARBALL"
    75.1 --- a/nss/receipt	Mon Jul 30 23:44:42 2018 +0300
    75.2 +++ b/nss/receipt	Tue Aug 07 00:30:45 2018 +0300
    75.3 @@ -1,13 +1,13 @@
    75.4  # SliTaz package receipt v2.
    75.5  
    75.6  PACKAGE="nss"
    75.7 -VERSION="3.35"
    75.8 +VERSION="3.38"
    75.9  CATEGORY="utilities"
   75.10  SHORT_DESC="Mozilla Network Security Services (NSS)"
   75.11  MAINTAINER="rocky@slitaz.org"
   75.12  LICENSE="MPL"
   75.13  WEB_SITE="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS"
   75.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/postlfs/nss.html"
   75.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/postlfs/nss.html"
   75.16  
   75.17  TARBALL="$PACKAGE-$VERSION.tar.gz"
   75.18  WGET_URL="https://archive.mozilla.org/pub/security/nss/releases/NSS_${VERSION//./_}_RTM/src/$TARBALL"
   75.19 @@ -59,7 +59,7 @@
   75.20  	case $PACKAGE in
   75.21  		nss)
   75.22  			copy @std
   75.23 -			DEPENDS="libsqlite3 nspr zlib"
   75.24 +			DEPENDS="libsqlite3 nspr" # zlib
   75.25  			;;
   75.26  		*-dev)
   75.27  			copy @dev
    76.1 --- a/openldap/receipt	Mon Jul 30 23:44:42 2018 +0300
    76.2 +++ b/openldap/receipt	Tue Aug 07 00:30:45 2018 +0300
    76.3 @@ -1,13 +1,13 @@
    76.4  # SliTaz package receipt v2.
    76.5  
    76.6  PACKAGE="openldap"
    76.7 -VERSION="2.4.45"
    76.8 +VERSION="2.4.46"
    76.9  CATEGORY="misc"
   76.10  SHORT_DESC="LDAP database system"
   76.11  MAINTAINER="pascal.bellard@slitaz.org"
   76.12  LICENSE="BSD"
   76.13  WEB_SITE="http://www.openldap.org/"
   76.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/server/openldap.html"
   76.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/server/openldap.html"
   76.16  
   76.17  TARBALL="$PACKAGE-$VERSION.tgz"
   76.18  WGET_URL="http://mirror.eu.oneandone.net/software/openldap/openldap-release/$TARBALL"
    77.1 --- a/opusfile/receipt	Mon Jul 30 23:44:42 2018 +0300
    77.2 +++ b/opusfile/receipt	Tue Aug 07 00:30:45 2018 +0300
    77.3 @@ -1,7 +1,7 @@
    77.4  # SliTaz package receipt v2.
    77.5  
    77.6  PACKAGE="opusfile"
    77.7 -VERSION="0.9"
    77.8 +VERSION="0.10"
    77.9  CATEGORY="multimedia"
   77.10  SHORT_DESC="Library for opening, seeking, and decoding .opus files"
   77.11  MAINTAINER="al.bobylev@gmail.com"
   77.12 @@ -25,7 +25,7 @@
   77.13  	case $PACKAGE in
   77.14  		opusfile)
   77.15  			copy @std
   77.16 -			DEPENDS="openssl libogg opus"
   77.17 +			DEPENDS="libogg openssl opus"
   77.18  			;;
   77.19  		*-dev)
   77.20  			copy @dev
    78.1 --- a/pango/receipt	Mon Jul 30 23:44:42 2018 +0300
    78.2 +++ b/pango/receipt	Tue Aug 07 00:30:45 2018 +0300
    78.3 @@ -1,7 +1,7 @@
    78.4  # SliTaz package receipt v2.
    78.5  
    78.6  PACKAGE="pango"
    78.7 -VERSION="1.40.14"
    78.8 +VERSION="1.42.2"
    78.9  CATEGORY="x-window"
   78.10  SHORT_DESC="Layout and rendering of internationalized text"
   78.11  MAINTAINER="pankso@slitaz.org"
   78.12 @@ -12,7 +12,7 @@
   78.13  WGET_URL="$GNOME_MIRROR/$PACKAGE/${VERSION%.*}/$TARBALL"
   78.14  
   78.15  BUILD_DEPENDS="harfbuzz-dev xorg-libXft-dev cairo-dev \
   78.16 -gobject-introspection-dev meson ninja"
   78.17 +gobject-introspection-dev meson ninja fribidi-dev"
   78.18  SPLIT="pango-typelib pango-dev"
   78.19  
   78.20  compile_rules() {
   78.21 @@ -33,8 +33,8 @@
   78.22  	case $PACKAGE in
   78.23  		pango)
   78.24  			copy @std
   78.25 -			DEPENDS="cairo fontconfig freetype glib libharfbuzz xorg-libX11 \
   78.26 -			xorg-libXft xorg-libXrender"
   78.27 +			DEPENDS="cairo fontconfig freetype fribidi glib libharfbuzz \
   78.28 +			xorg-libX11 xorg-libXft xorg-libXrender"
   78.29  			;;
   78.30  		pango-typelib)
   78.31  			copy *.typelib
   78.32 @@ -44,8 +44,8 @@
   78.33  		*-dev)
   78.34  			copy @dev @rm
   78.35  			DEPENDS="pango pango-typelib \
   78.36 -			cairo-dev fontconfig-dev freetype-dev glib-dev harfbuzz-dev \
   78.37 -			xorg-libXft-dev"
   78.38 +			cairo-dev fontconfig-dev freetype-dev fribidi-dev glib-dev \
   78.39 +			harfbuzz-dev xorg-libXft-dev"
   78.40  			;;
   78.41  	esac
   78.42  }
    79.1 --- a/patch/receipt	Mon Jul 30 23:44:42 2018 +0300
    79.2 +++ b/patch/receipt	Tue Aug 07 00:30:45 2018 +0300
    79.3 @@ -1,13 +1,13 @@
    79.4  # SliTaz package receipt v2.
    79.5  
    79.6  PACKAGE="patch"
    79.7 -VERSION="2.7.5"
    79.8 +VERSION="2.7.6"
    79.9  CATEGORY="utilities"
   79.10  SHORT_DESC="Utility to patch file with diff file"
   79.11  MAINTAINER="pankso@slitaz.org"
   79.12  LICENSE="GPL3"
   79.13  WEB_SITE="http://savannah.gnu.org/projects/patch/"
   79.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/patch.html"
   79.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/patch.html"
   79.16  
   79.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   79.18  WGET_URL="$GNU_MIRROR/$PACKAGE/$TARBALL"
   79.19 @@ -15,7 +15,9 @@
   79.20  BUILD_DEPENDS="attr-dev"
   79.21  
   79.22  compile_rules() {
   79.23 -	./configure $CONFIGURE_ARGS && make && make install
   79.24 +	./configure $CONFIGURE_ARGS &&
   79.25 +	make &&
   79.26 +	make install
   79.27  }
   79.28  
   79.29  genpkg_rules() {
    80.1 --- a/pcre/receipt	Mon Jul 30 23:44:42 2018 +0300
    80.2 +++ b/pcre/receipt	Tue Aug 07 00:30:45 2018 +0300
    80.3 @@ -1,13 +1,13 @@
    80.4  # SliTaz package receipt v2.
    80.5  
    80.6  PACKAGE="pcre"
    80.7 -VERSION="8.41"
    80.8 +VERSION="8.42"
    80.9  CATEGORY="meta"
   80.10  SHORT_DESC="Perl 5 Compatible Regular Expression"
   80.11  MAINTAINER="pankso@slitaz.org"
   80.12  LICENSE="BSD"
   80.13  WEB_SITE="http://www.pcre.org/"
   80.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/pcre.html"
   80.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/pcre.html"
   80.16  
   80.17  TARBALL="$PACKAGE-$VERSION.tar.bz2"
   80.18  WGET_URL="$SF_MIRROR/$PACKAGE/$TARBALL"
    81.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.2 +++ b/polkit105/receipt	Tue Aug 07 00:30:45 2018 +0300
    81.3 @@ -0,0 +1,67 @@
    81.4 +# SliTaz package receipt v2.
    81.5 +
    81.6 +PACKAGE="polkit105"
    81.7 +LEGACY_OF="polkit"; LEGACY_REASON="without JS"
    81.8 +VERSION="0.105"
    81.9 +CATEGORY="base-system"
   81.10 +SHORT_DESC="Application development toolkit for controlling system-wide \
   81.11 +privileges"
   81.12 +MAINTAINER="al.bobylev@gmail.com"
   81.13 +LICENSE="LGPL2"
   81.14 +WEB_SITE="https://www.freedesktop.org/wiki/Software/polkit/"
   81.15 +LFS="http://www.linuxfromscratch.org/blfs/view/stable/postlfs/polkit.html"
   81.16 +REPOLOGY="polkit"
   81.17 +
   81.18 +TARBALL="polkit-$VERSION.tar.gz"
   81.19 +WGET_URL="http://www.freedesktop.org/software/polkit/releases/$TARBALL"
   81.20 +
   81.21 +BUILD_DEPENDS="libtool automake intltool glib-dev gtk-doc \
   81.22 +gobject-introspection-dev expat-dev"
   81.23 +SPLIT="polkit105-dev"
   81.24 +
   81.25 +compile_rules() {
   81.26 +	libtoolize --force &&
   81.27 +	aclocal &&
   81.28 +	autoconf &&
   81.29 +	automake --add-missing
   81.30 +
   81.31 +	./configure \
   81.32 +		--libexecdir=/usr/lib/polkit-1 \
   81.33 +		--disable-static \
   81.34 +		--enable-introspection \
   81.35 +		--with-authfw=shadow \
   81.36 +		$CONFIGURE_ARGS &&
   81.37 +	make &&
   81.38 +	make install
   81.39 +}
   81.40 +
   81.41 +genpkg_rules() {
   81.42 +	case $PACKAGE in
   81.43 +		polkit105)
   81.44 +			copy @std
   81.45 +			DEPENDS="expat glib"
   81.46 +			;;
   81.47 +		*-dev)
   81.48 +			copy @dev
   81.49 +			DEPENDS="polkit105 glib-dev"
   81.50 +			;;
   81.51 +	esac
   81.52 +}
   81.53 +
   81.54 +post_install_polkit() {
   81.55 +	if ! grep -q polkitd "$1/etc/group"; then
   81.56 +		chroot "$1/" /usr/sbin/addgroup -g 27 polkitd
   81.57 +		chroot "$1/" /usr/sbin/adduser -g "PolicyKit Daemon Owner" \
   81.58 +			-h /etc/polkit-1 -u 27 -G polkitd -s /bin/false -D polkitd
   81.59 +	fi
   81.60 +
   81.61 +	chmod 0700 "$1/etc/polkit-1/localauthority/"
   81.62 +	chmod 0700 "$1/var/lib/polkit-1/"
   81.63 +	chmod 4755 "$1/usr/lib/polkit-1/polkit-agent-helper-1"
   81.64 +	chmod 4755 "$1/usr/bin/pkexec"
   81.65 +}
   81.66 +
   81.67 +post_remove_polkit() {
   81.68 +	chroot "$1/" deluser  polkitd
   81.69 +	chroot "$1/" delgroup polkitd
   81.70 +}
    82.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.2 +++ b/polkit105/stuff/10-udisks2.rules	Tue Aug 07 00:30:45 2018 +0300
    82.3 @@ -0,0 +1,13 @@
    82.4 +// See the polkit(8) man page for more information
    82.5 +// about configuring polkit.
    82.6 +
    82.7 +// Allow udisks2 to mount devices without authentication
    82.8 +// for users in the "disk" group.
    82.9 +
   82.10 +polkit.addRule(function(action, subject) {
   82.11 +    if ((action.id == "org.freedesktop.udisks2.filesystem-mount-system" ||
   82.12 +         action.id == "org.freedesktop.udisks2.filesystem-mount") &&
   82.13 +        subject.isInGroup("disk")) {
   82.14 +        return polkit.Result.YES;
   82.15 +    }
   82.16 +});
    83.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.2 +++ b/polkit105/stuff/patches/0001-Bug-50145-make-netgroup-support-optional.patch	Tue Aug 07 00:30:45 2018 +0300
    83.3 @@ -0,0 +1,108 @@
    83.4 +From 2428beec9189bb93e6e1fdd5bdde35acf5279a03 Mon Sep 17 00:00:00 2001
    83.5 +From: Natanael Copa <ncopa@alpinelinux.org>
    83.6 +Date: Sun, 20 May 2012 15:42:56 +0200
    83.7 +Subject: [PATCH] Bug 50145 - make netgroup support optional
    83.8 +
    83.9 +https://bugs.freedesktop.org/show_bug.cgi?id=50145
   83.10 +
   83.11 +netgroups are not defined in POSIX and are not be available on
   83.12 +all systems.
   83.13 +
   83.14 +We check for getnetgrent in configure script.
   83.15 +
   83.16 +Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
   83.17 +---
   83.18 + configure.ac                                             |    2 +-
   83.19 + src/polkitbackend/polkitbackendlocalauthority.c          |    8 ++++++--
   83.20 + src/polkitbackend/polkitbackendlocalauthorizationstore.c |    3 ++-
   83.21 + 3 files changed, 9 insertions(+), 4 deletions(-)
   83.22 +
   83.23 +diff --git a/configure.ac b/configure.ac
   83.24 +index f325922..711aa7c 100644
   83.25 +--- a/configure.ac
   83.26 ++++ b/configure.ac
   83.27 +@@ -141,7 +141,7 @@ AC_CHECK_LIB(expat,XML_ParserCreate,[EXPAT_LIBS="-lexpat"],
   83.28 + 	     [AC_MSG_ERROR([Can't find expat library. Please install expat.])])
   83.29 + AC_SUBST(EXPAT_LIBS)
   83.30 + 
   83.31 +-AC_CHECK_FUNCS(clearenv)
   83.32 ++AC_CHECK_FUNCS(clearenv getnetgrent)
   83.33 + 
   83.34 + if test "x$GCC" = "xyes"; then
   83.35 +   LDFLAGS="-Wl,--as-needed $LDFLAGS"
   83.36 +diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c
   83.37 +index b53eda3..f14e924 100644
   83.38 +--- a/src/polkitbackend/polkitbackendlocalauthority.c
   83.39 ++++ b/src/polkitbackend/polkitbackendlocalauthority.c
   83.40 +@@ -52,9 +52,10 @@
   83.41 + 
   83.42 + static GList *get_users_in_group (PolkitIdentity              *group,
   83.43 +                                   gboolean                     include_root);
   83.44 +-
   83.45 ++#if defined HAVE_GETNETGRENT
   83.46 + static GList *get_users_in_net_group (PolkitIdentity          *group,
   83.47 +                                       gboolean                 include_root);
   83.48 ++#endif
   83.49 + 
   83.50 + static GList *get_groups_for_user (PolkitIdentity              *user);
   83.51 + 
   83.52 +@@ -511,10 +512,12 @@ polkit_backend_local_authority_get_admin_auth_identities (PolkitBackendInteracti
   83.53 +         {
   83.54 +           ret = g_list_concat (ret, get_users_in_group (identity, FALSE));
   83.55 +         }
   83.56 ++#if defined HAVE_GETNETGRENT
   83.57 +       else if (POLKIT_IS_UNIX_NETGROUP (identity))
   83.58 +         {
   83.59 +           ret =  g_list_concat (ret, get_users_in_net_group (identity, FALSE));
   83.60 +         }
   83.61 ++#endif
   83.62 +       else
   83.63 +         {
   83.64 +           g_warning ("Unsupported identity %s", admin_identities[n]);
   83.65 +@@ -690,6 +693,7 @@ get_users_in_group (PolkitIdentity                    *group,
   83.66 +   return ret;
   83.67 + }
   83.68 + 
   83.69 ++#if defined HAVE_GETNETGRENT
   83.70 + static GList *
   83.71 + get_users_in_net_group (PolkitIdentity                    *group,
   83.72 +                         gboolean                           include_root)
   83.73 +@@ -741,7 +745,7 @@ get_users_in_net_group (PolkitIdentity                    *group,
   83.74 +   endnetgrent ();
   83.75 +   return ret;
   83.76 + }
   83.77 +-
   83.78 ++#endif
   83.79 + 
   83.80 + static GList *
   83.81 + get_groups_for_user (PolkitIdentity *user)
   83.82 +diff --git a/src/polkitbackend/polkitbackendlocalauthorizationstore.c b/src/polkitbackend/polkitbackendlocalauthorizationstore.c
   83.83 +index 2ddfe75..02553c4 100644
   83.84 +--- a/src/polkitbackend/polkitbackendlocalauthorizationstore.c
   83.85 ++++ b/src/polkitbackend/polkitbackendlocalauthorizationstore.c
   83.86 +@@ -725,6 +725,7 @@ polkit_backend_local_authorization_store_lookup (PolkitBackendLocalAuthorization
   83.87 +             break;
   83.88 +         }
   83.89 + 
   83.90 ++#if defined HAVE_GETNETGRENT
   83.91 +       /* if no identity specs matched and identity is a user, match against netgroups */
   83.92 +       if (ll == NULL && POLKIT_IS_UNIX_USER (identity))
   83.93 +         {
   83.94 +@@ -732,13 +733,13 @@ polkit_backend_local_authorization_store_lookup (PolkitBackendLocalAuthorization
   83.95 +           const gchar *user_name = polkit_unix_user_get_name (user_identity);
   83.96 +           if (!user_name)
   83.97 +             continue;
   83.98 +-
   83.99 +           for (ll = authorization->netgroup_identities; ll != NULL; ll = ll->next)
  83.100 +             {
  83.101 +               if (innetgr ((const gchar *) ll->data, NULL, user_name, NULL))
  83.102 +                 break;
  83.103 +             }
  83.104 +         }
  83.105 ++#endif
  83.106 + 
  83.107 +       if (ll == NULL)
  83.108 +         continue;
  83.109 +-- 
  83.110 +1.7.10.2
  83.111 +
    84.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    84.2 +++ b/polkit105/stuff/patches/CVE-2013-4288.patch	Tue Aug 07 00:30:45 2018 +0300
    84.3 @@ -0,0 +1,123 @@
    84.4 +From a3fa3b86f0015e42a534526ed800bcde5b3f2a15 Mon Sep 17 00:00:00 2001
    84.5 +From: Colin Walters <walters@verbum.org>
    84.6 +Date: Mon, 19 Aug 2013 12:16:11 -0400
    84.7 +Subject: [PATCH] pkcheck: Support --process=pid,start-time,uid syntax too
    84.8 +
    84.9 +The uid is a new addition; this allows callers such as libvirt to
   84.10 +close a race condition in reading the uid of the process talking to
   84.11 +them.  They can read it via getsockopt(SO_PEERCRED) or equivalent,
   84.12 +rather than having pkcheck look at /proc later after the fact.
   84.13 +
   84.14 +Programs which invoke pkcheck but need to know beforehand (i.e.  at
   84.15 +compile time) whether or not it supports passing the uid can
   84.16 +use:
   84.17 +
   84.18 +pkcheck_supports_uid=$($PKG_CONFIG --variable pkcheck_supports_uid polkit-gobject-1)
   84.19 +test x$pkcheck_supports_uid = xyes
   84.20 +
   84.21 +Conflicts:
   84.22 +	docs/man/pkcheck.xml
   84.23 +	src/programs/pkcheck.c
   84.24 +---
   84.25 + data/polkit-gobject-1.pc.in |  3 +++
   84.26 + docs/man/pkcheck.xml        | 33 +++++++++++++++++++++------------
   84.27 + src/programs/pkcheck.c      |  7 ++++++-
   84.28 + 3 files changed, 30 insertions(+), 13 deletions(-)
   84.29 +
   84.30 +diff --git a/data/polkit-gobject-1.pc.in b/data/polkit-gobject-1.pc.in
   84.31 +index c39677d..5c4c620 100644
   84.32 +--- a/data/polkit-gobject-1.pc.in
   84.33 ++++ b/data/polkit-gobject-1.pc.in
   84.34 +@@ -11,3 +11,6 @@ Version: @VERSION@
   84.35 + Libs: -L${libdir} -lpolkit-gobject-1
   84.36 + Cflags: -I${includedir}/polkit-1
   84.37 + Requires: gio-2.0 >= 2.18 glib-2.0 >= 2.18
   84.38 ++# Programs using pkcheck can use this to determine
   84.39 ++# whether or not it can be passed a uid.
   84.40 ++pkcheck_supports_uid=true
   84.41 +diff --git a/docs/man/pkcheck.xml b/docs/man/pkcheck.xml
   84.42 +index 6b8a874..9f2faef 100644
   84.43 +--- a/docs/man/pkcheck.xml
   84.44 ++++ b/docs/man/pkcheck.xml
   84.45 +@@ -55,6 +55,9 @@
   84.46 +             <arg choice="plain">
   84.47 +               <replaceable>pid,pid-start-time</replaceable>
   84.48 +             </arg>
   84.49 ++            <arg choice="plain">
   84.50 ++              <replaceable>pid,pid-start-time,uid</replaceable>
   84.51 ++            </arg>
   84.52 +           </group>
   84.53 +         </arg>
   84.54 +         <arg choice="plain">
   84.55 +@@ -90,7 +93,7 @@
   84.56 +     <title>DESCRIPTION</title>
   84.57 +     <para>
   84.58 +       <command>pkcheck</command> is used to check whether a process, specified by
   84.59 +-      either <option>--process</option> or <option>--system-bus-name</option>,
   84.60 ++      either <option>--process</option> (see below) or <option>--system-bus-name</option>,
   84.61 +       is authorized for <replaceable>action</replaceable>. The <option>--detail</option>
   84.62 +       option can be used zero or more times to pass details about <replaceable>action</replaceable>.
   84.63 +       If <option>--allow-user-interaction</option> is passed, <command>pkcheck</command> blocks
   84.64 +@@ -160,17 +163,23 @@ KEY3=VALUE3
   84.65 +   <refsect1 id="pkcheck-notes">
   84.66 +     <title>NOTES</title>
   84.67 +     <para>
   84.68 +-      Since process identifiers can be recycled, the caller should always use
   84.69 +-      <replaceable>pid,pid-start-time</replaceable> to specify the process
   84.70 +-      to check for authorization when using the <option>--process</option> option.
   84.71 +-      The value of <replaceable>pid-start-time</replaceable>
   84.72 +-      can be determined by consulting e.g. the
   84.73 +-      <citerefentry>
   84.74 +-        <refentrytitle>proc</refentrytitle><manvolnum>5</manvolnum>
   84.75 +-      </citerefentry>
   84.76 +-      file system depending on the operating system. If only <replaceable>pid</replaceable>
   84.77 +-      is passed to the <option>--process</option> option, then <command>pkcheck</command>
   84.78 +-      will look up the start time itself but note that this may be racy.
   84.79 ++      Do not use either the bare <replaceable>pid</replaceable> or
   84.80 ++      <replaceable>pid,start-time</replaceable> syntax forms for
   84.81 ++      <option>--process</option>.  There are race conditions in both.
   84.82 ++      New code should always use
   84.83 ++      <replaceable>pid,pid-start-time,uid</replaceable>.  The value of
   84.84 ++      <replaceable>start-time</replaceable> can be determined by
   84.85 ++      consulting e.g. the
   84.86 ++      <citerefentry><refentrytitle>proc</refentrytitle><manvolnum>5</manvolnum></citerefentry>
   84.87 ++      file system depending on the operating system.  If fewer than 3
   84.88 ++      arguments are passed, <command>pkcheck</command> will attempt to
   84.89 ++      look up them up internally, but note that this may be racy.
   84.90 ++    </para>
   84.91 ++    <para>
   84.92 ++      If your program is a daemon with e.g. a custom Unix domain
   84.93 ++      socket, you should determine the <replaceable>uid</replaceable>
   84.94 ++      parameter via operating system mechanisms such as
   84.95 ++      <literal>PEERCRED</literal>.
   84.96 +     </para>
   84.97 +   </refsect1>
   84.98 + 
   84.99 +diff --git a/src/programs/pkcheck.c b/src/programs/pkcheck.c
  84.100 +index 719a36c..057e926 100644
  84.101 +--- a/src/programs/pkcheck.c
  84.102 ++++ b/src/programs/pkcheck.c
  84.103 +@@ -372,6 +372,7 @@ main (int argc, char *argv[])
  84.104 +       else if (g_strcmp0 (argv[n], "--process") == 0 || g_strcmp0 (argv[n], "-p") == 0)
  84.105 +         {
  84.106 +           gint pid;
  84.107 ++	  guint uid;
  84.108 +           guint64 pid_start_time;
  84.109 + 
  84.110 +           n++;
  84.111 +@@ -381,7 +382,11 @@ main (int argc, char *argv[])
  84.112 +               goto out;
  84.113 +             }
  84.114 + 
  84.115 +-          if (sscanf (argv[n], "%i,%" G_GUINT64_FORMAT, &pid, &pid_start_time) == 2)
  84.116 ++          if (sscanf (argv[n], "%i,%" G_GUINT64_FORMAT ",%u", &pid, &pid_start_time, &uid) == 3)
  84.117 ++            {
  84.118 ++              subject = polkit_unix_process_new_for_owner (pid, pid_start_time, uid);
  84.119 ++            }
  84.120 ++          else if (sscanf (argv[n], "%i,%" G_GUINT64_FORMAT, &pid, &pid_start_time) == 2)
  84.121 +             {
  84.122 +               subject = polkit_unix_process_new_full (pid, pid_start_time);
  84.123 +             }
  84.124 +-- 
  84.125 +1.8.5.1
  84.126 +
    85.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    85.2 +++ b/polkit105/stuff/patches/CVE-2015-3218.patch	Tue Aug 07 00:30:45 2018 +0300
    85.3 @@ -0,0 +1,115 @@
    85.4 +From 48e646918efb2bf0b3b505747655726d7869f31c Mon Sep 17 00:00:00 2001
    85.5 +From: Colin Walters <walters@redhat.com>
    85.6 +Date: Sat, 30 May 2015 09:06:23 -0400
    85.7 +Subject: CVE-2015-3218: backend: Handle invalid object paths in
    85.8 + RegisterAuthenticationAgent
    85.9 +MIME-Version: 1.0
   85.10 +Content-Type: text/plain; charset=UTF-8
   85.11 +Content-Transfer-Encoding: 8bit
   85.12 +
   85.13 +Properly propagate the error, otherwise we dereference a `NULL`
   85.14 +pointer.  This is a local, authenticated DoS.
   85.15 +
   85.16 +`RegisterAuthenticationAgentWithOptions` and
   85.17 +`UnregisterAuthentication` have been validated to not need changes for
   85.18 +this.
   85.19 +
   85.20 +http://lists.freedesktop.org/archives/polkit-devel/2015-May/000420.html
   85.21 +https://bugs.freedesktop.org/show_bug.cgi?id=90829
   85.22 +
   85.23 +Reported-by: Tavis Ormandy <taviso@google.com>
   85.24 +Reviewed-by: Philip Withnall <philip@tecnocode.co.uk>
   85.25 +Reviewed-by: Miloslav Trmač <mitr@redhat.com>
   85.26 +Signed-off-by: Colin Walters <walters@redhat.com>
   85.27 +
   85.28 +diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
   85.29 +index f6ea0fc..587f954 100644
   85.30 +--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
   85.31 ++++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
   85.32 +@@ -1566,36 +1566,42 @@ authentication_agent_new (PolkitSubject *scope,
   85.33 +                           const gchar *unique_system_bus_name,
   85.34 +                           const gchar *locale,
   85.35 +                           const gchar *object_path,
   85.36 +-                          GVariant    *registration_options)
   85.37 ++                          GVariant    *registration_options,
   85.38 ++                          GError     **error)
   85.39 + {
   85.40 +   AuthenticationAgent *agent;
   85.41 +-  GError *error;
   85.42 ++  GDBusProxy *proxy;
   85.43 + 
   85.44 +-  agent = g_new0 (AuthenticationAgent, 1);
   85.45 ++  if (!g_variant_is_object_path (object_path))
   85.46 ++    {
   85.47 ++      g_set_error (error, POLKIT_ERROR, POLKIT_ERROR_FAILED,
   85.48 ++                   "Invalid object path '%s'", object_path);
   85.49 ++      return NULL;
   85.50 ++    }
   85.51 ++
   85.52 ++  proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
   85.53 ++                                         G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
   85.54 ++                                         G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
   85.55 ++                                         NULL, /* GDBusInterfaceInfo* */
   85.56 ++                                         unique_system_bus_name,
   85.57 ++                                         object_path,
   85.58 ++                                         "org.freedesktop.PolicyKit1.AuthenticationAgent",
   85.59 ++                                         NULL, /* GCancellable* */
   85.60 ++                                         error);
   85.61 ++  if (proxy == NULL)
   85.62 ++    {
   85.63 ++      g_prefix_error (error, "Failed to construct proxy for agent: " );
   85.64 ++      return NULL;
   85.65 ++    }
   85.66 + 
   85.67 ++  agent = g_new0 (AuthenticationAgent, 1);
   85.68 +   agent->ref_count = 1;
   85.69 +   agent->scope = g_object_ref (scope);
   85.70 +   agent->object_path = g_strdup (object_path);
   85.71 +   agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
   85.72 +   agent->locale = g_strdup (locale);
   85.73 +   agent->registration_options = registration_options != NULL ? g_variant_ref (registration_options) : NULL;
   85.74 +-
   85.75 +-  error = NULL;
   85.76 +-  agent->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
   85.77 +-                                                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
   85.78 +-                                                G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
   85.79 +-                                                NULL, /* GDBusInterfaceInfo* */
   85.80 +-                                                agent->unique_system_bus_name,
   85.81 +-                                                agent->object_path,
   85.82 +-                                                "org.freedesktop.PolicyKit1.AuthenticationAgent",
   85.83 +-                                                NULL, /* GCancellable* */
   85.84 +-                                                &error);
   85.85 +-  if (agent->proxy == NULL)
   85.86 +-    {
   85.87 +-      g_warning ("Error constructing proxy for agent: %s", error->message);
   85.88 +-      g_error_free (error);
   85.89 +-      /* TODO: Make authentication_agent_new() return NULL and set a GError */
   85.90 +-    }
   85.91 ++  agent->proxy = proxy;
   85.92 + 
   85.93 +   return agent;
   85.94 + }
   85.95 +@@ -2398,8 +2404,6 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
   85.96 +   caller_cmdline = NULL;
   85.97 +   agent = NULL;
   85.98 + 
   85.99 +-  /* TODO: validate that object path is well-formed */
  85.100 +-
  85.101 +   interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority);
  85.102 +   priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority);
  85.103 + 
  85.104 +@@ -2486,7 +2490,10 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
  85.105 +                                     polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
  85.106 +                                     locale,
  85.107 +                                     object_path,
  85.108 +-                                    options);
  85.109 ++                                    options,
  85.110 ++                                    error);
  85.111 ++  if (!agent)
  85.112 ++    goto out;
  85.113 + 
  85.114 +   g_hash_table_insert (priv->hash_scope_to_authentication_agent,
  85.115 +                        g_object_ref (subject),
  85.116 +-- 
  85.117 +cgit v0.10.2
  85.118 +
    86.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    86.2 +++ b/polkit105/stuff/patches/CVE-2015-3255.patch	Tue Aug 07 00:30:45 2018 +0300
    86.3 @@ -0,0 +1,67 @@
    86.4 +From 9f5e0c731784003bd4d6fc75ab739ff8b2ea269f Mon Sep 17 00:00:00 2001
    86.5 +From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= <mitr@redhat.com>
    86.6 +Date: Wed, 1 Apr 2015 05:22:37 +0200
    86.7 +Subject: CVE-2015-3255 Fix GHashTable usage.
    86.8 +
    86.9 +Don't assume that the hash table with free both the key and the value
   86.10 +at the same time, supply proper deallocation functions for the key
   86.11 +and value separately.
   86.12 +
   86.13 +Then drop ParsedAction::action_id which is no longer used for anything.
   86.14 +
   86.15 +https://bugs.freedesktop.org/show_bug.cgi?id=69501
   86.16 +and
   86.17 +https://bugs.freedesktop.org/show_bug.cgi?id=83590
   86.18 +
   86.19 +CVE: CVE-2015-3255
   86.20 +
   86.21 +diff --git a/src/polkitbackend/polkitbackendactionpool.c b/src/polkitbackend/polkitbackendactionpool.c
   86.22 +index bc14381..3894fe9 100644
   86.23 +--- a/src/polkitbackend/polkitbackendactionpool.c
   86.24 ++++ b/src/polkitbackend/polkitbackendactionpool.c
   86.25 +@@ -40,7 +40,6 @@
   86.26 + 
   86.27 + typedef struct
   86.28 + {
   86.29 +-  gchar *action_id;
   86.30 +   gchar *vendor_name;
   86.31 +   gchar *vendor_url;
   86.32 +   gchar *icon_name;
   86.33 +@@ -62,7 +61,6 @@ typedef struct
   86.34 + static void
   86.35 + parsed_action_free (ParsedAction *action)
   86.36 + {
   86.37 +-  g_free (action->action_id);
   86.38 +   g_free (action->vendor_name);
   86.39 +   g_free (action->vendor_url);
   86.40 +   g_free (action->icon_name);
   86.41 +@@ -134,7 +132,7 @@ polkit_backend_action_pool_init (PolkitBackendActionPool *pool)
   86.42 + 
   86.43 +   priv->parsed_actions = g_hash_table_new_full (g_str_hash,
   86.44 +                                                 g_str_equal,
   86.45 +-                                                NULL,
   86.46 ++                                                g_free,
   86.47 +                                                 (GDestroyNotify) parsed_action_free);
   86.48 + 
   86.49 +   priv->parsed_files = g_hash_table_new_full (g_str_hash,
   86.50 +@@ -988,7 +986,6 @@ _end (void *data, const char *el)
   86.51 +           icon_name = pd->global_icon_name;
   86.52 + 
   86.53 +         action = g_new0 (ParsedAction, 1);
   86.54 +-        action->action_id = g_strdup (pd->action_id);
   86.55 +         action->vendor_name = g_strdup (vendor);
   86.56 +         action->vendor_url = g_strdup (vendor_url);
   86.57 +         action->icon_name = g_strdup (icon_name);
   86.58 +@@ -1003,7 +1000,8 @@ _end (void *data, const char *el)
   86.59 +         action->implicit_authorization_inactive = pd->implicit_authorization_inactive;
   86.60 +         action->implicit_authorization_active = pd->implicit_authorization_active;
   86.61 + 
   86.62 +-        g_hash_table_insert (priv->parsed_actions, action->action_id, action);
   86.63 ++        g_hash_table_insert (priv->parsed_actions, g_strdup (pd->action_id),
   86.64 ++                             action);
   86.65 + 
   86.66 +         /* we steal these hash tables */
   86.67 +         pd->annotations = NULL;
   86.68 +-- 
   86.69 +cgit v0.10.2
   86.70 +
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/polkit105/stuff/patches/CVE-2015-4625.patch	Tue Aug 07 00:30:45 2018 +0300
    87.3 @@ -0,0 +1,1008 @@
    87.4 +From ea544ffc18405237ccd95d28d7f45afef49aca17 Mon Sep 17 00:00:00 2001
    87.5 +From: Colin Walters <walters@redhat.com>
    87.6 +Date: Thu, 4 Jun 2015 12:15:18 -0400
    87.7 +Subject: CVE-2015-4625: Use unpredictable cookie values, keep them secret
    87.8 +MIME-Version: 1.0
    87.9 +Content-Type: text/plain; charset=UTF-8
   87.10 +Content-Transfer-Encoding: 8bit
   87.11 +
   87.12 +Tavis noted that it'd be possible with a 32 bit counter for someone to
   87.13 +cause the cookie to wrap by creating Authentication requests in a
   87.14 +loop.
   87.15 +
   87.16 +Something important to note here is that wrapping of signed integers
   87.17 +is undefined behavior in C, so we definitely want to fix that.  All
   87.18 +counter integers used in this patch are unsigned.
   87.19 +
   87.20 +See the comment above `authentication_agent_generate_cookie` for
   87.21 +details, but basically we're now using a cookie of the form:
   87.22 +
   87.23 +```
   87.24 +        <agent serial> - <agent random id> - <session serial> - <session
   87.25 +random id>
   87.26 +```
   87.27 +
   87.28 +Which has multiple 64 bit counters, plus unpredictable random 128 bit
   87.29 +integer ids (effectively UUIDs, but we're not calling them that
   87.30 +because we don't need to be globally unique.
   87.31 +
   87.32 +We further ensure that the cookies are not visible to other processes
   87.33 +by changing the setuid helper to accept them over standard input.  This
   87.34 +means that an attacker would have to guess both ids.
   87.35 +
   87.36 +In any case, the security hole here is better fixed with the other
   87.37 +change to bind user id (uid) of the agent with cookie lookups, making
   87.38 +cookie guessing worthless.
   87.39 +
   87.40 +Nevertheless, I think it's worth doing this change too, for defense in
   87.41 +depth.
   87.42 +
   87.43 +Bug: https://bugs.freedesktop.org/show_bug.cgi?id=90832
   87.44 +CVE: CVE-2015-4625
   87.45 +Reported-by: Tavis Ormandy <taviso@google.com>
   87.46 +Reviewed-by: Miloslav Trmač <mitr@redhat.com>
   87.47 +Signed-off-by: Colin Walters <walters@redhat.com>
   87.48 +
   87.49 +diff --git a/src/polkitagent/polkitagenthelper-pam.c b/src/polkitagent/polkitagenthelper-pam.c
   87.50 +index 937386e..19062aa 100644
   87.51 +--- a/src/polkitagent/polkitagenthelper-pam.c
   87.52 ++++ b/src/polkitagent/polkitagenthelper-pam.c
   87.53 +@@ -65,7 +65,7 @@ main (int argc, char *argv[])
   87.54 + {
   87.55 +   int rc;
   87.56 +   const char *user_to_auth;
   87.57 +-  const char *cookie;
   87.58 ++  char *cookie = NULL;
   87.59 +   struct pam_conv pam_conversation;
   87.60 +   pam_handle_t *pam_h;
   87.61 +   const void *authed_user;
   87.62 +@@ -97,7 +97,7 @@ main (int argc, char *argv[])
   87.63 +   openlog ("polkit-agent-helper-1", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
   87.64 + 
   87.65 +   /* check for correct invocation */
   87.66 +-  if (argc != 3)
   87.67 ++  if (!(argc == 2 || argc == 3))
   87.68 +     {
   87.69 +       syslog (LOG_NOTICE, "inappropriate use of helper, wrong number of arguments [uid=%d]", getuid ());
   87.70 +       fprintf (stderr, "polkit-agent-helper-1: wrong number of arguments. This incident has been logged.\n");
   87.71 +@@ -105,7 +105,10 @@ main (int argc, char *argv[])
   87.72 +     }
   87.73 + 
   87.74 +   user_to_auth = argv[1];
   87.75 +-  cookie = argv[2];
   87.76 ++
   87.77 ++  cookie = read_cookie (argc, argv);
   87.78 ++  if (!cookie)
   87.79 ++    goto error;
   87.80 + 
   87.81 +   if (getuid () != 0)
   87.82 +     {
   87.83 +@@ -203,6 +206,8 @@ main (int argc, char *argv[])
   87.84 +       goto error;
   87.85 +     }
   87.86 + 
   87.87 ++  free (cookie);
   87.88 ++
   87.89 + #ifdef PAH_DEBUG
   87.90 +   fprintf (stderr, "polkit-agent-helper-1: successfully sent D-Bus message to PolicyKit daemon\n");
   87.91 + #endif /* PAH_DEBUG */
   87.92 +@@ -212,6 +217,7 @@ main (int argc, char *argv[])
   87.93 +   return 0;
   87.94 + 
   87.95 + error:
   87.96 ++  free (cookie);
   87.97 +   if (pam_h != NULL)
   87.98 +     pam_end (pam_h, rc);
   87.99 + 
  87.100 +diff --git a/src/polkitagent/polkitagenthelper-shadow.c b/src/polkitagent/polkitagenthelper-shadow.c
  87.101 +index a4f73ac..e877915 100644
  87.102 +--- a/src/polkitagent/polkitagenthelper-shadow.c
  87.103 ++++ b/src/polkitagent/polkitagenthelper-shadow.c
  87.104 +@@ -46,7 +46,7 @@ main (int argc, char *argv[])
  87.105 + {
  87.106 +   struct spwd *shadow;
  87.107 +   const char *user_to_auth;
  87.108 +-  const char *cookie;
  87.109 ++  char *cookie = NULL;
  87.110 +   time_t now;
  87.111 + 
  87.112 +   /* clear the entire environment to avoid attacks with
  87.113 +@@ -67,7 +67,7 @@ main (int argc, char *argv[])
  87.114 +   openlog ("polkit-agent-helper-1", LOG_CONS | LOG_PID, LOG_AUTHPRIV);
  87.115 + 
  87.116 +   /* check for correct invocation */
  87.117 +-  if (argc != 3)
  87.118 ++  if (!(argc == 2 || argc == 3))
  87.119 +     {
  87.120 +       syslog (LOG_NOTICE, "inappropriate use of helper, wrong number of arguments [uid=%d]", getuid ());
  87.121 +       fprintf (stderr, "polkit-agent-helper-1: wrong number of arguments. This incident has been logged.\n");
  87.122 +@@ -86,7 +86,10 @@ main (int argc, char *argv[])
  87.123 +     }
  87.124 + 
  87.125 +   user_to_auth = argv[1];
  87.126 +-  cookie = argv[2];
  87.127 ++
  87.128 ++  cookie = read_cookie (argc, argv);
  87.129 ++  if (!cookie)
  87.130 ++    goto error;
  87.131 + 
  87.132 + #ifdef PAH_DEBUG
  87.133 +   fprintf (stderr, "polkit-agent-helper-1: user to auth is '%s'.\n", user_to_auth);
  87.134 +@@ -153,6 +156,8 @@ main (int argc, char *argv[])
  87.135 +       goto error;
  87.136 +     }
  87.137 + 
  87.138 ++  free (cookie);
  87.139 ++
  87.140 + #ifdef PAH_DEBUG
  87.141 +   fprintf (stderr, "polkit-agent-helper-1: successfully sent D-Bus message to PolicyKit daemon\n");
  87.142 + #endif /* PAH_DEBUG */
  87.143 +@@ -162,6 +167,7 @@ main (int argc, char *argv[])
  87.144 +   return 0;
  87.145 + 
  87.146 + error:
  87.147 ++  free (cookie);
  87.148 +   fprintf (stdout, "FAILURE\n");
  87.149 +   flush_and_wait ();
  87.150 +   return 1;
  87.151 +diff --git a/src/polkitagent/polkitagenthelperprivate.c b/src/polkitagent/polkitagenthelperprivate.c
  87.152 +index cfa77fc..e23f9f5 100644
  87.153 +--- a/src/polkitagent/polkitagenthelperprivate.c
  87.154 ++++ b/src/polkitagent/polkitagenthelperprivate.c
  87.155 +@@ -23,6 +23,7 @@
  87.156 + #include "config.h"
  87.157 + #include "polkitagenthelperprivate.h"
  87.158 + #include <stdio.h>
  87.159 ++#include <string.h>
  87.160 + #include <stdlib.h>
  87.161 + #include <unistd.h>
  87.162 + 
  87.163 +@@ -45,6 +46,38 @@ _polkit_clearenv (void)
  87.164 + #endif
  87.165 + 
  87.166 + 
  87.167 ++char *
  87.168 ++read_cookie (int argc, char **argv)
  87.169 ++{
  87.170 ++  /* As part of CVE-2015-4625, we started passing the cookie
  87.171 ++   * on standard input, to ensure it's not visible to other
  87.172 ++   * processes.  However, to ensure that things continue
  87.173 ++   * to work if the setuid binary is upgraded while old
  87.174 ++   * agents are still running (this will be common with
  87.175 ++   * package managers), we support both modes.
  87.176 ++   */
  87.177 ++  if (argc == 3)
  87.178 ++    return strdup (argv[2]);
  87.179 ++  else
  87.180 ++    {
  87.181 ++      char *ret = NULL;
  87.182 ++      size_t n = 0;
  87.183 ++      ssize_t r = getline (&ret, &n, stdin);
  87.184 ++      if (r == -1)
  87.185 ++        {
  87.186 ++          if (!feof (stdin))
  87.187 ++            perror ("getline");
  87.188 ++          free (ret);
  87.189 ++          return NULL;
  87.190 ++        }
  87.191 ++      else
  87.192 ++        {
  87.193 ++          g_strchomp (ret);
  87.194 ++          return ret;
  87.195 ++        }
  87.196 ++    }
  87.197 ++}
  87.198 ++
  87.199 + gboolean
  87.200 + send_dbus_message (const char *cookie, const char *user)
  87.201 + {
  87.202 +diff --git a/src/polkitagent/polkitagenthelperprivate.h b/src/polkitagent/polkitagenthelperprivate.h
  87.203 +index aeca2c7..547fdcc 100644
  87.204 +--- a/src/polkitagent/polkitagenthelperprivate.h
  87.205 ++++ b/src/polkitagent/polkitagenthelperprivate.h
  87.206 +@@ -38,6 +38,8 @@
  87.207 + 
  87.208 + int _polkit_clearenv (void);
  87.209 + 
  87.210 ++char *read_cookie (int argc, char **argv);
  87.211 ++
  87.212 + gboolean send_dbus_message (const char *cookie, const char *user);
  87.213 + 
  87.214 + void flush_and_wait ();
  87.215 +diff --git a/src/polkitagent/polkitagentsession.c b/src/polkitagent/polkitagentsession.c
  87.216 +index f014773..8b93ad0 100644
  87.217 +--- a/src/polkitagent/polkitagentsession.c
  87.218 ++++ b/src/polkitagent/polkitagentsession.c
  87.219 +@@ -55,6 +55,7 @@
  87.220 + #include <stdio.h>
  87.221 + #include <sys/types.h>
  87.222 + #include <sys/wait.h>
  87.223 ++#include <gio/gunixoutputstream.h>
  87.224 + #include <pwd.h>
  87.225 + 
  87.226 + #include "polkitagentmarshal.h"
  87.227 +@@ -88,7 +89,7 @@ struct _PolkitAgentSession
  87.228 +   gchar *cookie;
  87.229 +   PolkitIdentity *identity;
  87.230 + 
  87.231 +-  int child_stdin;
  87.232 ++  GOutputStream *child_stdin;
  87.233 +   int child_stdout;
  87.234 +   GPid child_pid;
  87.235 + 
  87.236 +@@ -129,7 +130,6 @@ G_DEFINE_TYPE (PolkitAgentSession, polkit_agent_session, G_TYPE_OBJECT);
  87.237 + static void
  87.238 + polkit_agent_session_init (PolkitAgentSession *session)
  87.239 + {
  87.240 +-  session->child_stdin = -1;
  87.241 +   session->child_stdout = -1;
  87.242 + }
  87.243 + 
  87.244 +@@ -395,11 +395,7 @@ kill_helper (PolkitAgentSession *session)
  87.245 +       session->child_stdout = -1;
  87.246 +     }
  87.247 + 
  87.248 +-  if (session->child_stdin != -1)
  87.249 +-    {
  87.250 +-      g_warn_if_fail (close (session->child_stdin) == 0);
  87.251 +-      session->child_stdin = -1;
  87.252 +-    }
  87.253 ++  g_clear_object (&session->child_stdin);
  87.254 + 
  87.255 +   session->helper_is_running = FALSE;
  87.256 + 
  87.257 +@@ -545,9 +541,9 @@ polkit_agent_session_response (PolkitAgentSession *session,
  87.258 + 
  87.259 +   add_newline = (response[response_len] != '\n');
  87.260 + 
  87.261 +-  write (session->child_stdin, response, response_len);
  87.262 ++  (void) g_output_stream_write_all (session->child_stdin, response, response_len, NULL, NULL, NULL);
  87.263 +   if (add_newline)
  87.264 +-    write (session->child_stdin, newline, 1);
  87.265 ++    (void) g_output_stream_write_all (session->child_stdin, newline, 1, NULL, NULL, NULL);
  87.266 + }
  87.267 + 
  87.268 + /**
  87.269 +@@ -567,8 +563,9 @@ polkit_agent_session_initiate (PolkitAgentSession *session)
  87.270 + {
  87.271 +   uid_t uid;
  87.272 +   GError *error;
  87.273 +-  gchar *helper_argv[4];
  87.274 ++  gchar *helper_argv[3];
  87.275 +   struct passwd *passwd;
  87.276 ++  int stdin_fd = -1;
  87.277 + 
  87.278 +   g_return_if_fail (POLKIT_AGENT_IS_SESSION (session));
  87.279 + 
  87.280 +@@ -600,10 +597,8 @@ polkit_agent_session_initiate (PolkitAgentSession *session)
  87.281 + 
  87.282 +   helper_argv[0] = PACKAGE_PREFIX "/lib/polkit-1/polkit-agent-helper-1";
  87.283 +   helper_argv[1] = passwd->pw_name;
  87.284 +-  helper_argv[2] = session->cookie;
  87.285 +-  helper_argv[3] = NULL;
  87.286 ++  helper_argv[2] = NULL;
  87.287 + 
  87.288 +-  session->child_stdin = -1;
  87.289 +   session->child_stdout = -1;
  87.290 + 
  87.291 +   error = NULL;
  87.292 +@@ -615,7 +610,7 @@ polkit_agent_session_initiate (PolkitAgentSession *session)
  87.293 +                                  NULL,
  87.294 +                                  NULL,
  87.295 +                                  &session->child_pid,
  87.296 +-                                 &session->child_stdin,
  87.297 ++                                 &stdin_fd,
  87.298 +                                  &session->child_stdout,
  87.299 +                                  NULL,
  87.300 +                                  &error))
  87.301 +@@ -628,6 +623,13 @@ polkit_agent_session_initiate (PolkitAgentSession *session)
  87.302 +   if (G_UNLIKELY (_show_debug ()))
  87.303 +     g_print ("PolkitAgentSession: spawned helper with pid %d\n", (gint) session->child_pid);
  87.304 + 
  87.305 ++  session->child_stdin = (GOutputStream*)g_unix_output_stream_new (stdin_fd, TRUE);
  87.306 ++
  87.307 ++  /* Write the cookie on stdin so it can't be seen by other processes */
  87.308 ++  (void) g_output_stream_write_all (session->child_stdin, session->cookie, strlen (session->cookie),
  87.309 ++                                    NULL, NULL, NULL);
  87.310 ++  (void) g_output_stream_write_all (session->child_stdin, "\n", 1, NULL, NULL, NULL);
  87.311 ++
  87.312 +   session->child_stdout_channel = g_io_channel_unix_new (session->child_stdout);
  87.313 +   session->child_stdout_watch_source = g_io_create_watch (session->child_stdout_channel,
  87.314 +                                                           G_IO_IN | G_IO_ERR | G_IO_HUP);
  87.315 +diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
  87.316 +index 3f339e9..15adc6a 100644
  87.317 +--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
  87.318 ++++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
  87.319 +@@ -214,6 +214,8 @@ typedef struct
  87.320 + 
  87.321 +   GDBusConnection *system_bus_connection;
  87.322 +   guint name_owner_changed_signal_id;
  87.323 ++
  87.324 ++  guint64 agent_serial;
  87.325 + } PolkitBackendInteractiveAuthorityPrivate;
  87.326 + 
  87.327 + /* ---------------------------------------------------------------------------------------------------- */
  87.328 +@@ -439,11 +441,15 @@ struct AuthenticationAgent
  87.329 +   volatile gint ref_count;
  87.330 + 
  87.331 +   PolkitSubject *scope;
  87.332 ++  guint64 serial;
  87.333 + 
  87.334 +   gchar *locale;
  87.335 +   GVariant *registration_options;
  87.336 +   gchar *object_path;
  87.337 +   gchar *unique_system_bus_name;
  87.338 ++  GRand *cookie_pool;
  87.339 ++  gchar *cookie_prefix;
  87.340 ++  guint64  cookie_serial;
  87.341 + 
  87.342 +   GDBusProxy *proxy;
  87.343 + 
  87.344 +@@ -1427,9 +1433,54 @@ authentication_session_cancelled_cb (GCancellable *cancellable,
  87.345 +   authentication_session_cancel (session);
  87.346 + }
  87.347 + 
  87.348 ++/* We're not calling this a UUID, but it's basically
  87.349 ++ * the same thing, just not formatted that way because:
  87.350 ++ *
  87.351 ++ *  - I'm too lazy to do it
  87.352 ++ *  - If we did, people might think it was actually
  87.353 ++ *    generated from /dev/random, which we're not doing
  87.354 ++ *    because this value doesn't actually need to be
  87.355 ++ *    globally unique.
  87.356 ++ */
  87.357 ++static void
  87.358 ++append_rand_u128_str (GString *buf,
  87.359 ++                      GRand   *pool)
  87.360 ++{
  87.361 ++  g_string_append_printf (buf, "%08x%08x%08x%08x",
  87.362 ++                          g_rand_int (pool),
  87.363 ++                          g_rand_int (pool),
  87.364 ++                          g_rand_int (pool),
  87.365 ++                          g_rand_int (pool));
  87.366 ++}
  87.367 ++
  87.368 ++/* A value that should be unique to the (AuthenticationAgent, AuthenticationSession)
  87.369 ++ * pair, and not guessable by other agents.
  87.370 ++ *
  87.371 ++ * <agent serial> - <agent uuid> - <session serial> - <session uuid>
  87.372 ++ *
  87.373 ++ * See http://lists.freedesktop.org/archives/polkit-devel/2015-June/000425.html
  87.374 ++ *
  87.375 ++ */
  87.376 ++static gchar *
  87.377 ++authentication_agent_generate_cookie (AuthenticationAgent *agent)
  87.378 ++{
  87.379 ++  GString *buf = g_string_new ("");
  87.380 ++
  87.381 ++  g_string_append (buf, agent->cookie_prefix);
  87.382 ++  
  87.383 ++  g_string_append_c (buf, '-');
  87.384 ++  agent->cookie_serial++;
  87.385 ++  g_string_append_printf (buf, "%" G_GUINT64_FORMAT, 
  87.386 ++                          agent->cookie_serial);
  87.387 ++  g_string_append_c (buf, '-');
  87.388 ++  append_rand_u128_str (buf, agent->cookie_pool);
  87.389 ++
  87.390 ++  return g_string_free (buf, FALSE);
  87.391 ++}
  87.392 ++
  87.393 ++
  87.394 + static AuthenticationSession *
  87.395 + authentication_session_new (AuthenticationAgent         *agent,
  87.396 +-                            const gchar                 *cookie,
  87.397 +                             PolkitSubject               *subject,
  87.398 +                             PolkitIdentity              *user_of_subject,
  87.399 +                             PolkitSubject               *caller,
  87.400 +@@ -1447,7 +1498,7 @@ authentication_session_new (AuthenticationAgent         *agent,
  87.401 + 
  87.402 +   session = g_new0 (AuthenticationSession, 1);
  87.403 +   session->agent = authentication_agent_ref (agent);
  87.404 +-  session->cookie = g_strdup (cookie);
  87.405 ++  session->cookie = authentication_agent_generate_cookie (agent);
  87.406 +   session->subject = g_object_ref (subject);
  87.407 +   session->user_of_subject = g_object_ref (user_of_subject);
  87.408 +   session->caller = g_object_ref (caller);
  87.409 +@@ -1496,16 +1547,6 @@ authentication_session_free (AuthenticationSession *session)
  87.410 +   g_free (session);
  87.411 + }
  87.412 + 
  87.413 +-static gchar *
  87.414 +-authentication_agent_new_cookie (AuthenticationAgent *agent)
  87.415 +-{
  87.416 +-  static gint counter = 0;
  87.417 +-
  87.418 +-  /* TODO: use a more random-looking cookie */
  87.419 +-
  87.420 +-  return g_strdup_printf ("cookie%d", counter++);
  87.421 +-}
  87.422 +-
  87.423 + static PolkitSubject *
  87.424 + authentication_agent_get_scope (AuthenticationAgent *agent)
  87.425 + {
  87.426 +@@ -1553,12 +1594,15 @@ authentication_agent_unref (AuthenticationAgent *agent)
  87.427 +       g_free (agent->unique_system_bus_name);
  87.428 +       if (agent->registration_options != NULL)
  87.429 +         g_variant_unref (agent->registration_options);
  87.430 ++      g_rand_free (agent->cookie_pool);
  87.431 ++      g_free (agent->cookie_prefix);
  87.432 +       g_free (agent);
  87.433 +     }
  87.434 + }
  87.435 + 
  87.436 + static AuthenticationAgent *
  87.437 +-authentication_agent_new (PolkitSubject *scope,
  87.438 ++authentication_agent_new (guint64      serial,
  87.439 ++                          PolkitSubject *scope,
  87.440 +                           const gchar *unique_system_bus_name,
  87.441 +                           const gchar *locale,
  87.442 +                           const gchar *object_path,
  87.443 +@@ -1592,6 +1636,7 @@ authentication_agent_new (PolkitSubject *scope,
  87.444 + 
  87.445 +   agent = g_new0 (AuthenticationAgent, 1);
  87.446 +   agent->ref_count = 1;
  87.447 ++  agent->serial = serial;
  87.448 +   agent->scope = g_object_ref (scope);
  87.449 +   agent->object_path = g_strdup (object_path);
  87.450 +   agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
  87.451 +@@ -1599,6 +1644,25 @@ authentication_agent_new (PolkitSubject *scope,
  87.452 +   agent->registration_options = registration_options != NULL ? g_variant_ref (registration_options) : NULL;
  87.453 +   agent->proxy = proxy;
  87.454 + 
  87.455 ++  {
  87.456 ++    GString *cookie_prefix = g_string_new ("");
  87.457 ++    GRand *agent_private_rand = g_rand_new ();
  87.458 ++
  87.459 ++    g_string_append_printf (cookie_prefix, "%" G_GUINT64_FORMAT "-", agent->serial);
  87.460 ++
  87.461 ++    /* Use a uniquely seeded PRNG to get a prefix cookie for this agent,
  87.462 ++     * whose sequence will not correlate with the per-authentication session
  87.463 ++     * cookies.
  87.464 ++     */
  87.465 ++    append_rand_u128_str (cookie_prefix, agent_private_rand);
  87.466 ++    g_rand_free (agent_private_rand);
  87.467 ++
  87.468 ++    agent->cookie_prefix = g_string_free (cookie_prefix, FALSE);
  87.469 ++    
  87.470 ++    /* And a newly seeded pool for per-session cookies */
  87.471 ++    agent->cookie_pool = g_rand_new ();
  87.472 ++  }
  87.473 ++
  87.474 +   return agent;
  87.475 + }
  87.476 + 
  87.477 +@@ -2193,7 +2257,6 @@ authentication_agent_initiate_challenge (AuthenticationAgent         *agent,
  87.478 + {
  87.479 +   PolkitBackendInteractiveAuthorityPrivate *priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (authority);
  87.480 +   AuthenticationSession *session;
  87.481 +-  gchar *cookie;
  87.482 +   GList *l;
  87.483 +   GList *identities;
  87.484 +   gchar *localized_message;
  87.485 +@@ -2215,8 +2278,6 @@ authentication_agent_initiate_challenge (AuthenticationAgent         *agent,
  87.486 +                                     &localized_icon_name,
  87.487 +                                     &localized_details);
  87.488 + 
  87.489 +-  cookie = authentication_agent_new_cookie (agent);
  87.490 +-
  87.491 +   identities = NULL;
  87.492 + 
  87.493 +   /* select admin user if required by the implicit authorization */
  87.494 +@@ -2279,7 +2340,6 @@ authentication_agent_initiate_challenge (AuthenticationAgent         *agent,
  87.495 +     user_identities = g_list_prepend (NULL, polkit_unix_user_new (0));
  87.496 + 
  87.497 +   session = authentication_session_new (agent,
  87.498 +-                                        cookie,
  87.499 +                                         subject,
  87.500 +                                         user_of_subject,
  87.501 +                                         caller,
  87.502 +@@ -2335,7 +2395,6 @@ authentication_agent_initiate_challenge (AuthenticationAgent         *agent,
  87.503 +   g_list_free_full (user_identities, g_object_unref);
  87.504 +   g_list_foreach (identities, (GFunc) g_object_unref, NULL);
  87.505 +   g_list_free (identities);
  87.506 +-  g_free (cookie);
  87.507 + 
  87.508 +   g_free (localized_message);
  87.509 +   g_free (localized_icon_name);
  87.510 +@@ -2482,7 +2541,9 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
  87.511 +       goto out;
  87.512 +     }
  87.513 + 
  87.514 +-  agent = authentication_agent_new (subject,
  87.515 ++  priv->agent_serial++;
  87.516 ++  agent = authentication_agent_new (priv->agent_serial,
  87.517 ++                                    subject,
  87.518 +                                     polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
  87.519 +                                     locale,
  87.520 +                                     object_path,
  87.521 +-- 
  87.522 +cgit v0.10.2
  87.523 +
  87.524 +From 493aa5dc1d278ab9097110c1262f5229bbaf1766 Mon Sep 17 00:00:00 2001
  87.525 +From: Colin Walters <walters@redhat.com>
  87.526 +Date: Wed, 17 Jun 2015 13:07:02 -0400
  87.527 +Subject: CVE-2015-4625: Bind use of cookies to specific uids
  87.528 +MIME-Version: 1.0
  87.529 +Content-Type: text/plain; charset=UTF-8
  87.530 +Content-Transfer-Encoding: 8bit
  87.531 +
  87.532 +http://lists.freedesktop.org/archives/polkit-devel/2015-June/000425.html
  87.533 +
  87.534 +The "cookie" value that Polkit hands out is global to all polkit
  87.535 +users.  And when `AuthenticationAgentResponse` is invoked, we
  87.536 +previously only received the cookie and *target* identity, and
  87.537 +attempted to find an agent from that.
  87.538 +
  87.539 +The problem is that the current cookie is just an integer
  87.540 +counter, and if it overflowed, it would be possible for
  87.541 +an successful authorization in one session to trigger a response
  87.542 +in another session.
  87.543 +
  87.544 +The overflow and ability to guess the cookie were fixed by the
  87.545 +previous patch.
  87.546 +
  87.547 +This patch is conceptually further hardening on top of that.  Polkit
  87.548 +currently treats uids as equivalent from a security domain
  87.549 +perspective; there is no support for
  87.550 +SELinux/AppArmor/etc. differentiation.
  87.551 +
  87.552 +We can retrieve the uid from `getuid()` in the setuid helper, which
  87.553 +allows us to ensure the uid invoking `AuthenticationAgentResponse2`
  87.554 +matches that of the agent.
  87.555 +
  87.556 +Then the authority only looks at authentication sessions matching the
  87.557 +cookie that were created by a matching uid, thus removing the ability
  87.558 +for different uids to interfere with each other entirely.
  87.559 +
  87.560 +Several fixes to this patch were contributed by:
  87.561 +Miloslav Trmač <mitr@redhat.com>
  87.562 +
  87.563 +Bug: https://bugs.freedesktop.org/show_bug.cgi?id=90837
  87.564 +CVE: CVE-2015-4625
  87.565 +Reported-by: Tavis Ormandy <taviso@google.com>
  87.566 +Reviewed-by: Miloslav Trmač <mitr@redhat.com>
  87.567 +Signed-off-by: Colin Walters <walters@redhat.com>
  87.568 +
  87.569 +diff --git a/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml b/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml
  87.570 +index 3b519c2..5beef7d 100644
  87.571 +--- a/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml
  87.572 ++++ b/data/org.freedesktop.PolicyKit1.AuthenticationAgent.xml
  87.573 +@@ -8,7 +8,19 @@
  87.574 +     <annotation name="org.gtk.EggDBus.DocString" value="<para>This D-Bus interface is used for communication between the system-wide PolicyKit daemon and one or more authentication agents each running in a user session.</para><para>An authentication agent must implement this interface and register (passing the object path of the object implementing the interface) using the org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent() and org.freedesktop.PolicyKit1.Authority.UnregisterAuthenticationAgent() methods on the #org.freedesktop.PolicyKit1.Authority interface of the PolicyKit daemon.</para>"/>
  87.575 + 
  87.576 +     <method name="BeginAuthentication">
  87.577 +-      <annotation name="org.gtk.EggDBus.DocString" value="<para>Called by the PolicyKit daemon when the authentication agent needs the user to authenticate as one of the identities in @identities for the action with the identifier @action_id.</para><para>Upon succesful authentication, the authentication agent must invoke the org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse() method on the #org.freedesktop.PolicyKit1.Authority interface of the PolicyKit daemon before returning.</para><para>If the user dismisses the authentication dialog, the authentication agent should return an error.</para>"/>
  87.578 ++      <annotation name="org.gtk.EggDBus.DocString" value="<para>Called
  87.579 ++      by the PolicyKit daemon when the authentication agent needs the
  87.580 ++      user to authenticate as one of the identities in @identities for
  87.581 ++      the action with the identifier @action_id.</para><para>This
  87.582 ++      authentication is normally achieved via the
  87.583 ++      polkit_agent_session_response() API, which invokes a private
  87.584 ++      setuid helper process to verify the authentication.  When
  87.585 ++      successful, it calls the
  87.586 ++      org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse2()
  87.587 ++      method on the #org.freedesktop.PolicyKit1.Authority interface of
  87.588 ++      the PolicyKit daemon before returning.  If the user dismisses the
  87.589 ++      authentication dialog, the authentication agent should call
  87.590 ++      polkit_agent_session_cancel().</para>"/>
  87.591 + 
  87.592 +       <arg name="action_id" direction="in" type="s">
  87.593 +         <annotation name="org.gtk.EggDBus.DocString" value="The identifier for the action that the user is authentication for."/>
  87.594 +diff --git a/data/org.freedesktop.PolicyKit1.Authority.xml b/data/org.freedesktop.PolicyKit1.Authority.xml
  87.595 +index fbfb9cd..f9021ee 100644
  87.596 +--- a/data/org.freedesktop.PolicyKit1.Authority.xml
  87.597 ++++ b/data/org.freedesktop.PolicyKit1.Authority.xml
  87.598 +@@ -313,7 +313,29 @@
  87.599 +     </method>
  87.600 + 
  87.601 +     <method name="AuthenticationAgentResponse">
  87.602 +-      <annotation name="org.gtk.EggDBus.DocString" value="Method for authentication agents to invoke on successful authentication. This method will fail unless a sufficiently privileged caller invokes it."/>
  87.603 ++      <annotation name="org.gtk.EggDBus.DocString" value="Method for authentication agents to invoke on successful
  87.604 ++authentication, intended only for use by a privileged helper process
  87.605 ++internal to polkit."/>
  87.606 ++
  87.607 ++      <arg name="cookie" direction="in" type="s">
  87.608 ++        <annotation name="org.gtk.EggDBus.DocString" value="The cookie identifying the authentication request that was passed to the authentication agent."/>
  87.609 ++      </arg>
  87.610 ++
  87.611 ++      <arg name="identity" direction="in" type="(sa{sv})">
  87.612 ++        <annotation name="org.gtk.EggDBus.Type" value="Identity"/>
  87.613 ++        <annotation name="org.gtk.EggDBus.DocString" value="A #Identity struct describing what identity was authenticated."/>
  87.614 ++      </arg>
  87.615 ++    </method>
  87.616 ++
  87.617 ++    <method name="AuthenticationAgentResponse2">
  87.618 ++      <annotation name="org.gtk.EggDBus.DocString" value="Method for authentication agents to invoke on successful
  87.619 ++authentication, intended only for use by a privileged helper process
  87.620 ++internal to polkit.   Note this method was added in 0.114, and should be preferred over AuthenticationAgentResponse
  87.621 ++as it fixes a security issue."/>
  87.622 ++
  87.623 ++      <arg name="uid" direction="in" type="u">
  87.624 ++        <annotation name="org.gtk.EggDBus.DocString" value="The real uid of the agent.  Normally set by the setuid helper program."/>
  87.625 ++      </arg>
  87.626 + 
  87.627 +       <arg name="cookie" direction="in" type="s">
  87.628 +         <annotation name="org.gtk.EggDBus.DocString" value="The cookie identifying the authentication request that was passed to the authentication agent."/>
  87.629 +diff --git a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml
  87.630 +index 6525e25..e66bf53 100644
  87.631 +--- a/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml
  87.632 ++++ b/docs/polkit/docbook-interface-org.freedesktop.PolicyKit1.Authority.xml
  87.633 +@@ -42,6 +42,8 @@ Structure    <link linkend="eggdbus-struct-TemporaryAuthorization">TemporaryAuth
  87.634 +                                   IN  String                         object_path)
  87.635 + <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse</link>      (IN  String                         cookie,
  87.636 +                                   IN  <link linkend="eggdbus-struct-Identity">Identity</link>                       identity)
  87.637 ++<link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse2</link>      (IN uint32 uid, IN  String                         cookie,
  87.638 ++                                  IN  <link linkend="eggdbus-struct-Identity">Identity</link>                       identity)
  87.639 + <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.EnumerateTemporaryAuthorizations">EnumerateTemporaryAuthorizations</link> (IN  <link linkend="eggdbus-struct-Subject">Subject</link>                        subject,
  87.640 +                                   OUT Array&lt;<link linkend="eggdbus-struct-TemporaryAuthorization">TemporaryAuthorization</link>&gt;  temporary_authorizations)
  87.641 + <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RevokeTemporaryAuthorizations">RevokeTemporaryAuthorizations</link>    (IN  <link linkend="eggdbus-struct-Subject">Subject</link>                        subject)
  87.642 +@@ -777,10 +779,52 @@ AuthenticationAgentResponse (IN  String    cookie,
  87.643 +                              IN  <link linkend="eggdbus-struct-Identity">Identity</link>  identity)
  87.644 +     </programlisting>
  87.645 +     <para>
  87.646 +-Method for authentication agents to invoke on successful authentication. This method will fail unless a sufficiently privileged caller invokes it.
  87.647 ++Method for authentication agents to invoke on successful
  87.648 ++authentication, intended only for use by a privileged helper process
  87.649 ++internal to polkit.  Deprecated in favor of AuthenticationAgentResponse2.
  87.650 ++    </para>
  87.651 ++<variablelist role="params">
  87.652 ++  <varlistentry>
  87.653 ++    <term><literal>IN  String <parameter>cookie</parameter></literal>:</term>
  87.654 ++    <listitem>
  87.655 ++      <para>
  87.656 ++The cookie identifying the authentication request that was passed to the authentication agent.
  87.657 ++      </para>
  87.658 ++    </listitem>
  87.659 ++  </varlistentry>
  87.660 ++  <varlistentry>
  87.661 ++    <term><literal>IN  <link linkend="eggdbus-struct-Identity">Identity</link> <parameter>identity</parameter></literal>:</term>
  87.662 ++    <listitem>
  87.663 ++      <para>
  87.664 ++A <link linkend="eggdbus-struct-Identity">Identity</link> struct describing what identity was authenticated.
  87.665 ++      </para>
  87.666 ++    </listitem>
  87.667 ++  </varlistentry>
  87.668 ++</variablelist>
  87.669 ++    </refsect2>
  87.670 ++    <refsect2 role="function" id="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse2">
  87.671 ++      <title>AuthenticationAgentResponse2 ()</title>
  87.672 ++    <programlisting>
  87.673 ++AuthenticationAgentResponse2 (IN  uint32 uid,
  87.674 ++                              IN  String cookie,
  87.675 ++                              IN  <link linkend="eggdbus-struct-Identity">Identity</link>  identity)
  87.676 ++    </programlisting>
  87.677 ++    <para>
  87.678 ++Method for authentication agents to invoke on successful
  87.679 ++authentication, intended only for use by a privileged helper process
  87.680 ++internal to polkit.  Note this method was introduced in 0.114 to fix a security issue.
  87.681 +     </para>
  87.682 + <variablelist role="params">
  87.683 +   <varlistentry>
  87.684 ++    <term><literal>IN  uint32 <parameter>uid</parameter></literal>:</term>
  87.685 ++    <listitem>
  87.686 ++      <para>
  87.687 ++The user id of the agent; normally this is the owner of the parent pid
  87.688 ++of the process that invoked the internal setuid helper.
  87.689 ++      </para>
  87.690 ++    </listitem>
  87.691 ++  </varlistentry>
  87.692 ++  <varlistentry>
  87.693 +     <term><literal>IN  String <parameter>cookie</parameter></literal>:</term>
  87.694 +     <listitem>
  87.695 +       <para>
  87.696 +diff --git a/docs/polkit/overview.xml b/docs/polkit/overview.xml
  87.697 +index 150a7bc..176d2ea 100644
  87.698 +--- a/docs/polkit/overview.xml
  87.699 ++++ b/docs/polkit/overview.xml
  87.700 +@@ -314,16 +314,18 @@
  87.701 +     <para>
  87.702 +       Authentication agents are provided by desktop environments. When
  87.703 +       an user session starts, the agent registers with the polkit
  87.704 +-      Authority using
  87.705 +-      the <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent()</link>
  87.706 ++      Authority using the <link
  87.707 ++      linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent()</link>
  87.708 +       method. When services are needed, the authority will invoke
  87.709 +-      methods on
  87.710 +-      the <link linkend="eggdbus-interface-org.freedesktop.PolicyKit1.AuthenticationAgent">org.freedesktop.PolicyKit1.AuthenticationAgent</link>
  87.711 ++      methods on the <link
  87.712 ++      linkend="eggdbus-interface-org.freedesktop.PolicyKit1.AuthenticationAgent">org.freedesktop.PolicyKit1.AuthenticationAgent</link>
  87.713 +       D-Bus interface. Once the user is authenticated, (a privileged
  87.714 +-      part of) the agent invokes
  87.715 +-      the <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse()</link>
  87.716 +-      method.  Note that the polkit Authority itself does not care
  87.717 +-      how the agent authenticates the user.
  87.718 ++      part of) the agent invokes the <link
  87.719 ++      linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse">AuthenticationAgentResponse()</link>
  87.720 ++      method.  This method should be treated as an internal
  87.721 ++      implementation detail, and callers should use the public shared
  87.722 ++      library API to invoke it, which currently uses a setuid helper
  87.723 ++      program.
  87.724 +     </para>
  87.725 +     <para>
  87.726 +       The <link linkend="ref-authentication-agent-api">libpolkit-agent-1</link>
  87.727 +diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c
  87.728 +index ab6d3cd..6bd684a 100644
  87.729 +--- a/src/polkit/polkitauthority.c
  87.730 ++++ b/src/polkit/polkitauthority.c
  87.731 +@@ -1492,6 +1492,14 @@ polkit_authority_authentication_agent_response (PolkitAuthority      *authority,
  87.732 +                                                 gpointer              user_data)
  87.733 + {
  87.734 +   GVariant *identity_value;
  87.735 ++  /* Note that in reality, this API is only accessible to root, and
  87.736 ++   * only called from the setuid helper `polkit-agent-helper-1`.
  87.737 ++   *
  87.738 ++   * However, because this is currently public API, we avoid
  87.739 ++   * triggering warnings from ABI diff type programs by just grabbing
  87.740 ++   * the real uid of the caller here.
  87.741 ++   */
  87.742 ++  uid_t uid = getuid ();
  87.743 + 
  87.744 +   g_return_if_fail (POLKIT_IS_AUTHORITY (authority));
  87.745 +   g_return_if_fail (cookie != NULL);
  87.746 +@@ -1501,8 +1509,9 @@ polkit_authority_authentication_agent_response (PolkitAuthority      *authority,
  87.747 +   identity_value = polkit_identity_to_gvariant (identity);
  87.748 +   g_variant_ref_sink (identity_value);
  87.749 +   g_dbus_proxy_call (authority->proxy,
  87.750 +-                     "AuthenticationAgentResponse",
  87.751 +-                     g_variant_new ("(s@(sa{sv}))",
  87.752 ++                     "AuthenticationAgentResponse2",
  87.753 ++                     g_variant_new ("(us@(sa{sv}))",
  87.754 ++                                    (guint32)uid,
  87.755 +                                     cookie,
  87.756 +                                     identity_value),
  87.757 +                      G_DBUS_CALL_FLAGS_NONE,
  87.758 +diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c
  87.759 +index 601a974..03a4e84 100644
  87.760 +--- a/src/polkitbackend/polkitbackendauthority.c
  87.761 ++++ b/src/polkitbackend/polkitbackendauthority.c
  87.762 +@@ -355,6 +355,7 @@ polkit_backend_authority_unregister_authentication_agent (PolkitBackendAuthority
  87.763 + gboolean
  87.764 + polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority    *authority,
  87.765 +                                                         PolkitSubject             *caller,
  87.766 ++                                                        uid_t                      uid,
  87.767 +                                                         const gchar               *cookie,
  87.768 +                                                         PolkitIdentity            *identity,
  87.769 +                                                         GError                   **error)
  87.770 +@@ -373,7 +374,7 @@ polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority
  87.771 +     }
  87.772 +   else
  87.773 +     {
  87.774 +-      return klass->authentication_agent_response (authority, caller, cookie, identity, error);
  87.775 ++      return klass->authentication_agent_response (authority, caller, uid, cookie, identity, error);
  87.776 +     }
  87.777 + }
  87.778 + 
  87.779 +@@ -587,6 +588,11 @@ static const gchar *server_introspection_data =
  87.780 +   "      <arg type='s' name='cookie' direction='in'/>"
  87.781 +   "      <arg type='(sa{sv})' name='identity' direction='in'/>"
  87.782 +   "    </method>"
  87.783 ++  "    <method name='AuthenticationAgentResponse2'>"
  87.784 ++  "      <arg type='u' name='uid' direction='in'/>"
  87.785 ++  "      <arg type='s' name='cookie' direction='in'/>"
  87.786 ++  "      <arg type='(sa{sv})' name='identity' direction='in'/>"
  87.787 ++  "    </method>"
  87.788 +   "    <method name='EnumerateTemporaryAuthorizations'>"
  87.789 +   "      <arg type='(sa{sv})' name='subject' direction='in'/>"
  87.790 +   "      <arg type='a(ss(sa{sv})tt)' name='temporary_authorizations' direction='out'/>"
  87.791 +@@ -1035,6 +1041,57 @@ server_handle_authentication_agent_response (Server                 *server,
  87.792 +   error = NULL;
  87.793 +   if (!polkit_backend_authority_authentication_agent_response (server->authority,
  87.794 +                                                                caller,
  87.795 ++                                                               (uid_t)-1,
  87.796 ++                                                               cookie,
  87.797 ++                                                               identity,
  87.798 ++                                                               &error))
  87.799 ++    {
  87.800 ++      g_dbus_method_invocation_return_gerror (invocation, error);
  87.801 ++      g_error_free (error);
  87.802 ++      goto out;
  87.803 ++    }
  87.804 ++
  87.805 ++  g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
  87.806 ++
  87.807 ++ out:
  87.808 ++  if (identity != NULL)
  87.809 ++    g_object_unref (identity);
  87.810 ++}
  87.811 ++
  87.812 ++static void
  87.813 ++server_handle_authentication_agent_response2 (Server                 *server,
  87.814 ++                                              GVariant               *parameters,
  87.815 ++                                              PolkitSubject          *caller,
  87.816 ++                                              GDBusMethodInvocation  *invocation)
  87.817 ++{
  87.818 ++  const gchar *cookie;
  87.819 ++  GVariant *identity_gvariant;
  87.820 ++  PolkitIdentity *identity;
  87.821 ++  GError *error;
  87.822 ++  guint32 uid;
  87.823 ++
  87.824 ++  identity = NULL;
  87.825 ++
  87.826 ++  g_variant_get (parameters,
  87.827 ++                 "(u&s@(sa{sv}))",
  87.828 ++                 &uid,
  87.829 ++                 &cookie,
  87.830 ++                 &identity_gvariant);
  87.831 ++
  87.832 ++  error = NULL;
  87.833 ++  identity = polkit_identity_new_for_gvariant (identity_gvariant, &error);
  87.834 ++  if (identity == NULL)
  87.835 ++    {
  87.836 ++      g_prefix_error (&error, "Error getting identity: ");
  87.837 ++      g_dbus_method_invocation_return_gerror (invocation, error);
  87.838 ++      g_error_free (error);
  87.839 ++      goto out;
  87.840 ++    }
  87.841 ++
  87.842 ++  error = NULL;
  87.843 ++  if (!polkit_backend_authority_authentication_agent_response (server->authority,
  87.844 ++                                                               caller,
  87.845 ++                                                               (uid_t)uid,
  87.846 +                                                                cookie,
  87.847 +                                                                identity,
  87.848 +                                                                &error))
  87.849 +@@ -1222,6 +1279,8 @@ server_handle_method_call (GDBusConnection        *connection,
  87.850 +     server_handle_unregister_authentication_agent (server, parameters, caller, invocation);
  87.851 +   else if (g_strcmp0 (method_name, "AuthenticationAgentResponse") == 0)
  87.852 +     server_handle_authentication_agent_response (server, parameters, caller, invocation);
  87.853 ++  else if (g_strcmp0 (method_name, "AuthenticationAgentResponse2") == 0)
  87.854 ++    server_handle_authentication_agent_response2 (server, parameters, caller, invocation);
  87.855 +   else if (g_strcmp0 (method_name, "EnumerateTemporaryAuthorizations") == 0)
  87.856 +     server_handle_enumerate_temporary_authorizations (server, parameters, caller, invocation);
  87.857 +   else if (g_strcmp0 (method_name, "RevokeTemporaryAuthorizations") == 0)
  87.858 +diff --git a/src/polkitbackend/polkitbackendauthority.h b/src/polkitbackend/polkitbackendauthority.h
  87.859 +index f9f7385..88df82e 100644
  87.860 +--- a/src/polkitbackend/polkitbackendauthority.h
  87.861 ++++ b/src/polkitbackend/polkitbackendauthority.h
  87.862 +@@ -147,6 +147,7 @@ struct _PolkitBackendAuthorityClass
  87.863 + 
  87.864 +   gboolean (*authentication_agent_response) (PolkitBackendAuthority   *authority,
  87.865 +                                              PolkitSubject            *caller,
  87.866 ++                                             uid_t                     uid,
  87.867 +                                              const gchar              *cookie,
  87.868 +                                              PolkitIdentity           *identity,
  87.869 +                                              GError                  **error);
  87.870 +@@ -249,6 +250,7 @@ gboolean polkit_backend_authority_unregister_authentication_agent (PolkitBackend
  87.871 + 
  87.872 + gboolean polkit_backend_authority_authentication_agent_response (PolkitBackendAuthority    *authority,
  87.873 +                                                                  PolkitSubject             *caller,
  87.874 ++                                                                 uid_t                      uid,
  87.875 +                                                                  const gchar               *cookie,
  87.876 +                                                                  PolkitIdentity            *identity,
  87.877 +                                                                  GError                   **error);
  87.878 +diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c
  87.879 +index 15adc6a..96725f7 100644
  87.880 +--- a/src/polkitbackend/polkitbackendinteractiveauthority.c
  87.881 ++++ b/src/polkitbackend/polkitbackendinteractiveauthority.c
  87.882 +@@ -108,8 +108,9 @@ static AuthenticationAgent *get_authentication_agent_for_subject (PolkitBackendI
  87.883 +                                                                   PolkitSubject *subject);
  87.884 + 
  87.885 + 
  87.886 +-static AuthenticationSession *get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *authority,
  87.887 +-                                                                     const gchar *cookie);
  87.888 ++static AuthenticationSession *get_authentication_session_for_uid_and_cookie (PolkitBackendInteractiveAuthority *authority,
  87.889 ++                                                                             uid_t                              uid,
  87.890 ++                                                                             const gchar                       *cookie);
  87.891 + 
  87.892 + static GList *get_authentication_sessions_initiated_by_system_bus_unique_name (PolkitBackendInteractiveAuthority *authority,
  87.893 +                                                                                const gchar *system_bus_unique_name);
  87.894 +@@ -169,6 +170,7 @@ static gboolean polkit_backend_interactive_authority_unregister_authentication_a
  87.895 + 
  87.896 + static gboolean polkit_backend_interactive_authority_authentication_agent_response (PolkitBackendAuthority   *authority,
  87.897 +                                                                               PolkitSubject            *caller,
  87.898 ++                                                                              uid_t                     uid,
  87.899 +                                                                               const gchar              *cookie,
  87.900 +                                                                               PolkitIdentity           *identity,
  87.901 +                                                                               GError                  **error);
  87.902 +@@ -440,6 +442,7 @@ struct AuthenticationAgent
  87.903 + {
  87.904 +   volatile gint ref_count;
  87.905 + 
  87.906 ++  uid_t creator_uid;
  87.907 +   PolkitSubject *scope;
  87.908 +   guint64 serial;
  87.909 + 
  87.910 +@@ -1603,6 +1606,7 @@ authentication_agent_unref (AuthenticationAgent *agent)
  87.911 + static AuthenticationAgent *
  87.912 + authentication_agent_new (guint64      serial,
  87.913 +                           PolkitSubject *scope,
  87.914 ++                          PolkitIdentity *creator,
  87.915 +                           const gchar *unique_system_bus_name,
  87.916 +                           const gchar *locale,
  87.917 +                           const gchar *object_path,
  87.918 +@@ -1611,6 +1615,10 @@ authentication_agent_new (guint64      serial,
  87.919 + {
  87.920 +   AuthenticationAgent *agent;
  87.921 +   GDBusProxy *proxy;
  87.922 ++  PolkitUnixUser *creator_user;
  87.923 ++
  87.924 ++  g_assert (POLKIT_IS_UNIX_USER (creator));
  87.925 ++  creator_user = POLKIT_UNIX_USER (creator);
  87.926 + 
  87.927 +   if (!g_variant_is_object_path (object_path))
  87.928 +     {
  87.929 +@@ -1638,6 +1646,7 @@ authentication_agent_new (guint64      serial,
  87.930 +   agent->ref_count = 1;
  87.931 +   agent->serial = serial;
  87.932 +   agent->scope = g_object_ref (scope);
  87.933 ++  agent->creator_uid = (uid_t)polkit_unix_user_get_uid (creator_user);
  87.934 +   agent->object_path = g_strdup (object_path);
  87.935 +   agent->unique_system_bus_name = g_strdup (unique_system_bus_name);
  87.936 +   agent->locale = g_strdup (locale);
  87.937 +@@ -1736,8 +1745,9 @@ get_authentication_agent_for_subject (PolkitBackendInteractiveAuthority *authori
  87.938 + }
  87.939 + 
  87.940 + static AuthenticationSession *
  87.941 +-get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *authority,
  87.942 +-                                       const gchar *cookie)
  87.943 ++get_authentication_session_for_uid_and_cookie (PolkitBackendInteractiveAuthority *authority,
  87.944 ++                                               uid_t                              uid,
  87.945 ++                                               const gchar                       *cookie)
  87.946 + {
  87.947 +   PolkitBackendInteractiveAuthorityPrivate *priv;
  87.948 +   GHashTableIter hash_iter;
  87.949 +@@ -1755,6 +1765,23 @@ get_authentication_session_for_cookie (PolkitBackendInteractiveAuthority *author
  87.950 +     {
  87.951 +       GList *l;
  87.952 + 
  87.953 ++      /* We need to ensure that if somehow we have duplicate cookies
  87.954 ++       * due to wrapping, that the cookie used is matched to the user
  87.955 ++       * who called AuthenticationAgentResponse2.  See
  87.956 ++       * http://lists.freedesktop.org/archives/polkit-devel/2015-June/000425.html
  87.957 ++       * 
  87.958 ++       * Except if the legacy AuthenticationAgentResponse is invoked,
  87.959 ++       * we don't know the uid and hence use -1.  Continue to support
  87.960 ++       * the old behavior for backwards compatibility, although everyone
  87.961 ++       * who is using our own setuid helper will automatically be updated
  87.962 ++       * to the new API.
  87.963 ++       */
  87.964 ++      if (uid != (uid_t)-1)
  87.965 ++        {
  87.966 ++          if (agent->creator_uid != uid)
  87.967 ++            continue;
  87.968 ++        }
  87.969 ++
  87.970 +       for (l = agent->active_sessions; l != NULL; l = l->next)
  87.971 +         {
  87.972 +           AuthenticationSession *session = l->data;
  87.973 +@@ -2544,6 +2571,7 @@ polkit_backend_interactive_authority_register_authentication_agent (PolkitBacken
  87.974 +   priv->agent_serial++;
  87.975 +   agent = authentication_agent_new (priv->agent_serial,
  87.976 +                                     subject,
  87.977 ++                                    user_of_caller,
  87.978 +                                     polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (caller)),
  87.979 +                                     locale,
  87.980 +                                     object_path,
  87.981 +@@ -2757,6 +2785,7 @@ polkit_backend_interactive_authority_unregister_authentication_agent (PolkitBack
  87.982 + static gboolean
  87.983 + polkit_backend_interactive_authority_authentication_agent_response (PolkitBackendAuthority   *authority,
  87.984 +                                                               PolkitSubject            *caller,
  87.985 ++                                                              uid_t                     uid,
  87.986 +                                                               const gchar              *cookie,
  87.987 +                                                               PolkitIdentity           *identity,
  87.988 +                                                               GError                  **error)
  87.989 +@@ -2799,7 +2828,7 @@ polkit_backend_interactive_authority_authentication_agent_response (PolkitBacken
  87.990 +     }
  87.991 + 
  87.992 +   /* find the authentication session */
  87.993 +-  session = get_authentication_session_for_cookie (interactive_authority, cookie);
  87.994 ++  session = get_authentication_session_for_uid_and_cookie (interactive_authority, uid, cookie);
  87.995 +   if (session == NULL)
  87.996 +     {
  87.997 +       g_set_error (error,
  87.998 +-- 
  87.999 +cgit v0.10.2
 87.1000 +
 87.1001 +--- ./configure.ac.orig
 87.1002 ++++ ./configure.ac
 87.1003 +@@ -122,7 +122,7 @@
 87.1004 +   changequote([,])dnl
 87.1005 + fi
 87.1006 + 
 87.1007 +-PKG_CHECK_MODULES(GLIB, [gio-2.0 >= 2.28.0])
 87.1008 ++PKG_CHECK_MODULES(GLIB, [gmodule-2.0 gio-unix-2.0 gio-2.0 >= 2.30.0])
 87.1009 + AC_SUBST(GLIB_CFLAGS)
 87.1010 + AC_SUBST(GLIB_LIBS)
 87.1011 + 
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/polkit105/stuff/patches/automake.patch	Tue Aug 07 00:30:45 2018 +0300
    88.3 @@ -0,0 +1,19 @@
    88.4 +--- ./configure.ac.orig	2012-12-31 21:39:08.969445979 +0000
    88.5 ++++ ./configure.ac	2012-12-31 21:39:30.136285425 +0000
    88.6 +@@ -3,7 +3,7 @@
    88.7 + AC_PREREQ(2.59c)
    88.8 + AC_INIT(polkit, 0.105, http://lists.freedesktop.org/mailman/listinfo/polkit-devel)
    88.9 + AM_INIT_AUTOMAKE(polkit, 0.105)
   88.10 +-AM_CONFIG_HEADER(config.h)
   88.11 ++AC_CONFIG_HEADER(config.h)
   88.12 + AM_MAINTAINER_MODE
   88.13 + 
   88.14 + m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
   88.15 +@@ -24,7 +24,6 @@
   88.16 + 
   88.17 + AC_ISC_POSIX
   88.18 + AC_PROG_CC
   88.19 +-AM_PROG_CC_STDC
   88.20 + AC_HEADER_STDC
   88.21 + AM_PROG_LIBTOOL
   88.22 + AC_PROG_MAKE_SET
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/polkit105/stuff/patches/disable-ck-test.patch	Tue Aug 07 00:30:45 2018 +0300
    89.3 @@ -0,0 +1,15 @@
    89.4 +This test requires ConsoleKit to be running.
    89.5 +
    89.6 +--- polkit-0.105/test/polkitbackend/Makefile.am.old	2012-04-24 11:05:34.000000000 -0500
    89.7 ++++ polkit-0.105/test/polkitbackend/Makefile.am	2017-09-27 20:48:42.479959296 -0500
    89.8 +@@ -36,8 +36,8 @@
    89.9 + TEST_PROGS += polkitbackendlocalauthorizationstoretest
   89.10 + polkitbackendlocalauthorizationstoretest_SOURCES = polkitbackendlocalauthorizationstoretest.c
   89.11 + 
   89.12 +-TEST_PROGS += polkitbackendlocalauthoritytest
   89.13 +-polkitbackendlocalauthoritytest_SOURCES = polkitbackendlocalauthoritytest.c
   89.14 ++#TEST_PROGS += polkitbackendlocalauthoritytest
   89.15 ++#polkitbackendlocalauthoritytest_SOURCES = polkitbackendlocalauthoritytest.c
   89.16 + 
   89.17 + # ----------------------------------------------------------------------------------------------------
   89.18 + 
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/polkit105/stuff/patches/fix-consolekit-db-stat.patch	Tue Aug 07 00:30:45 2018 +0300
    90.3 @@ -0,0 +1,30 @@
    90.4 +--- polkit-0.105.orig/src/polkitbackend/polkitbackendsessionmonitor.c	2012-04-24 19:05:34.000000000 +0300
    90.5 ++++ polkit-0.105/src/polkitbackend/polkitbackendsessionmonitor.c	2015-08-17 14:50:51.428580856 +0300
    90.6 +@@ -47,7 +47,7 @@ struct _PolkitBackendSessionMonitor
    90.7 + 
    90.8 +   GKeyFile *database;
    90.9 +   GFileMonitor *database_monitor;
   90.10 +-  time_t database_mtime;
   90.11 ++  struct timespec database_mtim;
   90.12 + };
   90.13 + 
   90.14 + struct _PolkitBackendSessionMonitorClass
   90.15 +@@ -95,7 +95,7 @@ reload_database (PolkitBackendSessionMon
   90.16 +       goto out;
   90.17 +     }
   90.18 + 
   90.19 +-  monitor->database_mtime = statbuf.st_mtime;
   90.20 ++  monitor->database_mtim = statbuf.st_mtim;
   90.21 + 
   90.22 +   monitor->database = g_key_file_new ();
   90.23 +   if (!g_key_file_load_from_file (monitor->database,
   90.24 +@@ -131,7 +131,8 @@ ensure_database (PolkitBackendSessionMon
   90.25 +                        strerror (errno));
   90.26 +           goto out;
   90.27 +         }
   90.28 +-      if (statbuf.st_mtime == monitor->database_mtime)
   90.29 ++      if (statbuf.st_mtim.tv_sec  == monitor->database_mtim.tv_sec &&
   90.30 ++          statbuf.st_mtim.tv_nsec == monitor->database_mtim.tv_nsec)
   90.31 +         {
   90.32 +           ret = TRUE;
   90.33 +           goto out;
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/polkit105/stuff/patches/fix-parallel-make.patch	Tue Aug 07 00:30:45 2018 +0300
    91.3 @@ -0,0 +1,40 @@
    91.4 +From 7bd30764a5230684c7c979a08a83dfa6e327f719 Mon Sep 17 00:00:00 2001
    91.5 +From: Ryan Lortie <desrt@velocity.(none)>
    91.6 +Date: Tue, 13 Nov 2012 16:50:14 +0000
    91.7 +Subject: build: Fix .gir generation for parallel make
    91.8 +
    91.9 +As per the intructions in the introspection Makefile, we should have a
   91.10 +line declaring a dependency between the .gir and .la files.
   91.11 +
   91.12 +https://bugs.freedesktop.org/show_bug.cgi?id=57077
   91.13 +
   91.14 +Signed-off-by: David Zeuthen <zeuthen@gmail.com>
   91.15 +---
   91.16 +diff --git a/src/polkit/Makefile.am b/src/polkit/Makefile.am
   91.17 +index 39d6d84..d648d29 100644
   91.18 +--- a/src/polkit/Makefile.am
   91.19 ++++ b/src/polkit/Makefile.am
   91.20 +@@ -106,6 +106,8 @@ if HAVE_INTROSPECTION
   91.21 + 
   91.22 + INTROSPECTION_GIRS = Polkit-1.0.gir
   91.23 + 
   91.24 ++Polkit-1.0.gir: libpolkit-gobject-1.la
   91.25 ++
   91.26 + girdir = $(INTROSPECTION_GIRDIR)
   91.27 + gir_DATA = Polkit-1.0.gir
   91.28 + 
   91.29 +diff --git a/src/polkitagent/Makefile.am b/src/polkitagent/Makefile.am
   91.30 +index 1cfb73c..5b7d4c7 100644
   91.31 +--- a/src/polkitagent/Makefile.am
   91.32 ++++ b/src/polkitagent/Makefile.am
   91.33 +@@ -108,6 +108,8 @@ if HAVE_INTROSPECTION
   91.34 + girdir = $(INTROSPECTION_GIRDIR)
   91.35 + gir_DATA = PolkitAgent-1.0.gir
   91.36 + 
   91.37 ++PolkitAgent-1.0.gir: libpolkit-agent-1.la
   91.38 ++
   91.39 + typelibsdir = $(INTROSPECTION_TYPELIBDIR)
   91.40 + typelibs_DATA = PolkitAgent-1.0.typelib
   91.41 + 
   91.42 +--
   91.43 +cgit v0.9.0.2-2-gbebe
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/polkit105/stuff/patches/fix-test-fgetpwent.patch	Tue Aug 07 00:30:45 2018 +0300
    92.3 @@ -0,0 +1,20 @@
    92.4 +--- polkit-0.105/test/mocklibc/src/pwd.c.old	2012-04-24 11:05:34.000000000 -0500
    92.5 ++++ polkit-0.105/test/mocklibc/src/pwd.c	2017-09-27 19:40:57.883227673 -0500
    92.6 +@@ -16,6 +16,7 @@
    92.7 +  * Author: Nikki VonHollen <vonhollen@gmail.com>
    92.8 +  */
    92.9 + 
   92.10 ++#define _GNU_SOURCE
   92.11 + #include <pwd.h>
   92.12 + 
   92.13 + #include <stdio.h>
   92.14 +--- polkit-0.105/test/mocklibc/src/grp.c.old	2012-04-24 11:05:34.000000000 -0500
   92.15 ++++ polkit-0.105/test/mocklibc/src/grp.c	2017-09-27 19:44:57.759238450 -0500
   92.16 +@@ -16,6 +16,7 @@
   92.17 +  * Author: Nikki VonHollen <vonhollen@gmail.com>
   92.18 +  */
   92.19 + 
   92.20 ++#define _GNU_SOURCE
   92.21 + #include <grp.h>
   92.22 + 
   92.23 + #include <stdio.h>
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/polkit105/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
    93.3 @@ -0,0 +1,12 @@
    93.4 +# Use Alpine Linux patches:
    93.5 +# https://git.alpinelinux.org/cgit/aports/tree/main/polkit
    93.6 +0001-Bug-50145-make-netgroup-support-optional.patch
    93.7 +CVE-2013-4288.patch
    93.8 +CVE-2015-3218.patch
    93.9 +CVE-2015-3255.patch
   93.10 +CVE-2015-4625.patch
   93.11 +automake.patch
   93.12 +fix-parallel-make.patch
   93.13 +fix-consolekit-db-stat.patch
   93.14 +fix-test-fgetpwent.patch
   93.15 +disable-ck-test.patch
    94.1 --- a/shadow/receipt	Mon Jul 30 23:44:42 2018 +0300
    94.2 +++ b/shadow/receipt	Tue Aug 07 00:30:45 2018 +0300
    94.3 @@ -1,13 +1,13 @@
    94.4  # SliTaz package receipt v2.
    94.5  
    94.6  PACKAGE="shadow"
    94.7 -VERSION="4.5"
    94.8 +VERSION="4.6"
    94.9  CATEGORY="system-tools"
   94.10  SHORT_DESC="Programs for handling passwords in a secure way"
   94.11  MAINTAINER="al.bobylev@gmail.com"
   94.12  LICENSE="BSD"
   94.13  WEB_SITE="http://pkg-shadow.alioth.debian.org/"
   94.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/shadow.html"
   94.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/shadow.html"
   94.16  
   94.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   94.18  WGET_URL="https://github.com/shadow-maint/shadow/releases/download/$VERSION/$TARBALL"
    95.1 --- a/shared-mime-info/receipt	Mon Jul 30 23:44:42 2018 +0300
    95.2 +++ b/shared-mime-info/receipt	Tue Aug 07 00:30:45 2018 +0300
    95.3 @@ -1,13 +1,13 @@
    95.4  # SliTaz package receipt v2.
    95.5  
    95.6  PACKAGE="shared-mime-info"
    95.7 -VERSION="1.9"
    95.8 +VERSION="1.10"
    95.9  CATEGORY="system-tools"
   95.10  SHORT_DESC="Core database of common types"
   95.11  MAINTAINER="pankso@slitaz.org"
   95.12  LICENSE="GPL2"
   95.13  WEB_SITE="https://freedesktop.org/wiki/Software/shared-mime-info/"
   95.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/shared-mime-info.html"
   95.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/shared-mime-info.html"
   95.16  
   95.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
   95.18  WGET_URL="https://people.freedesktop.org/~hadess/$TARBALL"
   95.19 @@ -17,10 +17,14 @@
   95.20  SPLIT="shared-mime-info-dev"
   95.21  
   95.22  compile_rules() {
   95.23 -	# Remove unsupported locales
   95.24 -	for i in $(grep '^-[a-z]' $stuff/patches/slitaz-locales.patch); do
   95.25 -		rm $src/po/${i#-}.po
   95.26 -	done
   95.27 +	# Original size before rebuilding/stripping
   95.28 +	size0=$(ls -l freedesktop.org.xml | awk '{print $5}')
   95.29 +
   95.30 +	# Force to rebuild
   95.31 +	rm freedesktop.org.xml
   95.32 +
   95.33 +	export LINGUAS="ar ca ca@valencia cs da de el en_GB es fa fi fr hr hu id \
   95.34 +	it ja nb nl nn pl pt pt_BR ro ru sl sv tr uk vi zh_CN zh_TW"
   95.35  
   95.36  	./configure \
   95.37  		--disable-update-mimedb \
   95.38 @@ -31,14 +35,40 @@
   95.39  	# Additional MIME-types supported by SliTaz
   95.40  	cp $stuff/*.xml $install/usr/share/mime/packages
   95.41  
   95.42 -	# strip a bit
   95.43 -	sed -i 's|^ *||' "$install/usr/share/mime/packages/freedesktop.org.xml"
   95.44 +	# Strip
   95.45 +	xml="$install/usr/share/mime/packages/freedesktop.org.xml"
   95.46 +	title "Strip $xml"
   95.47 +	echo "Original size:         $size0 B"
   95.48 +	echo "Only SliTaz locales:   $(ls -l $xml | awk '{print $5}') B"
   95.49 +
   95.50 +	sed -i 's|^ *||' "$xml"
   95.51 +	echo "Strip whitespace:      $(ls -l $xml | awk '{print $5}') B"
   95.52 +
   95.53 +	echo -n "Remove non-translated: "
   95.54 +
   95.55 +	awk '{
   95.56 +		if (index($0, "<comment>")) {
   95.57 +			comment=$0;
   95.58 +			gsub("<comment>",  "", comment);
   95.59 +			gsub("</comment>", "", comment);
   95.60 +			print $0;
   95.61 +		} else if (index($0, "<comment ")) {
   95.62 +			comment2=$0;
   95.63 +			gsub("<comment [^>]+>", "", comment2);
   95.64 +			gsub("</comment>", "", comment2);
   95.65 +			if (comment != comment2)
   95.66 +				print $0;
   95.67 +		} else
   95.68 +			print $0
   95.69 +	}' $xml > $xml.1
   95.70 +	mv $xml.1 $xml
   95.71 +	echo "$(ls -l $xml | awk '{print $5}') B"
   95.72  }
   95.73  
   95.74  genpkg_rules() {
   95.75  	case $PACKAGE in
   95.76  		shared-mime-info)
   95.77 -			copy bin/ packages/
   95.78 +			copy @std
   95.79  			DEPENDS="glib libxml2"
   95.80  			;;
   95.81  		*-dev) copy @dev;;
    96.1 --- a/shared-mime-info/stuff/patches/series	Mon Jul 30 23:44:42 2018 +0300
    96.2 +++ b/shared-mime-info/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
    96.3 @@ -1,1 +1,1 @@
    96.4 -slitaz-locales.patch
    96.5 +#slitaz-locales.patch
    97.1 --- a/shared-mime-info/stuff/patches/slitaz-locales.patch	Mon Jul 30 23:44:42 2018 +0300
    97.2 +++ b/shared-mime-info/stuff/patches/slitaz-locales.patch	Tue Aug 07 00:30:45 2018 +0300
    97.3 @@ -2,11 +2,12 @@
    97.4  
    97.5  --- a/po/LINGUAS
    97.6  +++ b/po/LINGUAS
    97.7 -@@ -1,71 +1,32 @@
    97.8 +@@ -1,73 +1,32 @@
    97.9   ar
   97.10  -as
   97.11  -ast
   97.12  -az
   97.13 +-be
   97.14  -be@latin
   97.15  -bg
   97.16  -bn_IN
   97.17 @@ -26,6 +27,7 @@
   97.18   fi
   97.19  -fo
   97.20   fr
   97.21 +-fur
   97.22  -ga
   97.23  -gl
   97.24  -gu
    98.1 --- a/slim/receipt	Mon Jul 30 23:44:42 2018 +0300
    98.2 +++ b/slim/receipt	Tue Aug 07 00:30:45 2018 +0300
    98.3 @@ -1,7 +1,7 @@
    98.4  # SliTaz package receipt v2.
    98.5  
    98.6  PACKAGE="slim"
    98.7 -VERSION="1.3.5"
    98.8 +VERSION="1.3.6"
    98.9  CATEGORY="x-window"
   98.10  SHORT_DESC="Desktop-independent graphical login manager for X11"
   98.11  MAINTAINER="pankso@slitaz.org"
   98.12 @@ -16,11 +16,10 @@
   98.13  xorg-libXmu-dev pam-dev"
   98.14  BUILD_DEPENDS="cmake xorg-libX11-dev freetype-dev libjpeg-turbo-dev zlib-dev \
   98.15  libpng16-dev fontconfig-dev xorg-libXft-dev xorg-libXrender-dev xorg-libXmu-dev \
   98.16 -pam-dev"
   98.17 -SPLIT="slim-theme-default slim slim-pam:pam"
   98.18 +pam-dev   libunistring xorg-libXrandr-dev consolekit2-dev"
   98.19 +SPLIT="slim-theme-default slim" # slim-pam:pam"
   98.20  
   98.21  compile_rules() {
   98.22 -	# Handle cross compilation
   98.23  	case "$ARCH" in
   98.24  		arm*)
   98.25  			INCL=/cross/$ARCH/sysroot/usr/include
   98.26 @@ -37,7 +36,10 @@
   98.27  
   98.28  	mkdir build; cd build
   98.29  	cmake \
   98.30 +		-DCMAKE_BUILD_TYPE=Release \
   98.31 +		-DCMAKE_SKIP_RPATH=ON \
   98.32  		-DCMAKE_INSTALL_PREFIX=/usr \
   98.33 +		-DUSE_CONSOLEKIT=yes \
   98.34  		-DX11_Xmu_LIB="$LIBS/libXmu.so" \
   98.35  		-DX11_Xft_INCLUDE_PATH=$INCL \
   98.36  		-DX11_Xmu_INCLUDE_PATH=$INCL \
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/slim/stuff/patches/libslim-underlinking.patch	Tue Aug 07 00:30:45 2018 +0300
    99.3 @@ -0,0 +1,13 @@
    99.4 +diff --git a/CMakeLists.txt b/CMakeLists.txt
    99.5 +index eb1608b..195cefd 100644
    99.6 +--- a/CMakeLists.txt
    99.7 ++++ b/CMakeLists.txt
    99.8 +@@ -180,6 +180,8 @@ include_directories(
    99.9 + target_link_libraries(libslim
   99.10 +     ${JPEG_LIBRARIES}
   99.11 + 	${PNG_LIBRARIES}
   99.12 ++	${X11_Xft_LIB}
   99.13 ++	${X11_Xrandr_LIB}
   99.14 + )
   99.15 + 
   99.16 + #Set up library with all found packages for slim
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/slim/stuff/patches/no-slimlock.patch	Tue Aug 07 00:30:45 2018 +0300
   100.3 @@ -0,0 +1,16 @@
   100.4 +Fixes building without PAM
   100.5 +diff --git a/CMakeLists.txt b/CMakeLists.txt
   100.6 +index 9892c1d..eb1608b 100644
   100.7 +--- a/CMakeLists.txt
   100.8 ++++ b/CMakeLists.txt
   100.9 +@@ -222,7 +222,9 @@ endif(BUILD_SLIMLOCK)
  100.10 + ####### install
  100.11 + # slim
  100.12 + install(TARGETS slim RUNTIME DESTINATION bin)
  100.13 +-install(TARGETS slimlock RUNTIME DESTINATION bin)
  100.14 ++if(BUILD_SLIMLOCK)
  100.15 ++    install(TARGETS slimlock RUNTIME DESTINATION bin)
  100.16 ++endif(BUILD_SLIMLOCK)
  100.17 + 
  100.18 + if (BUILD_SHARED_LIBS)
  100.19 + 	set_target_properties(libslim PROPERTIES
   101.1 --- a/slim/stuff/patches/series	Mon Jul 30 23:44:42 2018 +0300
   101.2 +++ b/slim/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
   101.3 @@ -1,1 +1,8 @@
   101.4 -slim-1.3.5.patch
   101.5 +# Alpine Linux patches:
   101.6 +#https://git.alpinelinux.org/cgit/aports/tree/main/slim
   101.7 +no-slimlock.patch
   101.8 +libslim-underlinking.patch
   101.9 +slim-freetype-dirs.patch
  101.10 +snprintf.patch
  101.11 +
  101.12 +slim-1.3.6-slitaz.patch
   102.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   102.2 +++ b/slim/stuff/patches/slim-1.3.6-slitaz.patch	Tue Aug 07 00:30:45 2018 +0300
   102.3 @@ -0,0 +1,129 @@
   102.4 +--- a/cfg.cpp
   102.5 ++++ b/cfg.cpp
   102.6 +@@ -29,30 +29,31 @@
   102.7 + 	: currentSession(-1)
   102.8 + {
   102.9 + 	/* Configuration options */
  102.10 +-	options.insert(option("default_path","/bin:/usr/bin:/usr/local/bin"));
  102.11 +-	options.insert(option("default_xserver","/usr/bin/X"));
  102.12 ++	options.insert(option("default_path","/sbin:/bin:/usr/sbin:/usr/bin"));
  102.13 ++	options.insert(option("default_xserver","/usr/libexec/Xorg.wrap"));
  102.14 + 	options.insert(option("xserver_arguments",""));
  102.15 + 	options.insert(option("numlock",""));
  102.16 + 	options.insert(option("daemon",""));
  102.17 + 	options.insert(option("xauth_path","/usr/bin/xauth"));
  102.18 +-	options.insert(option("login_cmd","exec /bin/bash -login ~/.xinitrc %session"));
  102.19 +-	options.insert(option("halt_cmd","/sbin/shutdown -h now"));
  102.20 +-	options.insert(option("reboot_cmd","/sbin/shutdown -r now"));
  102.21 ++	options.insert(option("login_cmd","exec /bin/sh -l ~/.xinitrc %session"));
  102.22 ++	options.insert(option("halt_cmd","/sbin/poweroff"));
  102.23 ++	options.insert(option("reboot_cmd","/sbin/reboot"));
  102.24 ++	options.insert(option("root_password","true"));
  102.25 + 	options.insert(option("suspend_cmd",""));
  102.26 + 	options.insert(option("sessionstart_cmd",""));
  102.27 + 	options.insert(option("sessionstop_cmd",""));
  102.28 +-	options.insert(option("console_cmd","/usr/bin/xterm -C -fg white -bg black +sb -g %dx%d+%d+%d -fn %dx%d -T ""Console login"" -e /bin/sh -c ""/bin/cat /etc/issue; exec /bin/login"""));
  102.29 +-	options.insert(option("screenshot_cmd","import -window root /slim.png"));
  102.30 ++	options.insert(option("console_cmd","/usr/bin/xterm -C -fg white -bg black +sb -T ""Console login"" -e /bin/sh -l -c ""exec /bin/login"""));
  102.31 ++	options.insert(option("screenshot_cmd","mtpaint -s /root/slim-shot.png"));
  102.32 + 	options.insert(option("welcome_msg","Welcome to %host"));
  102.33 + 	options.insert(option("session_msg","Session:"));
  102.34 +-	options.insert(option("default_user",""));
  102.35 ++	options.insert(option("default_user","tux"));
  102.36 + 	options.insert(option("focus_password","no"));
  102.37 + 	options.insert(option("auto_login","no"));
  102.38 +-	options.insert(option("current_theme","default"));
  102.39 +-	options.insert(option("lockfile","/var/run/slim.lock"));
  102.40 ++	options.insert(option("current_theme","slitaz,base"));
  102.41 ++	options.insert(option("lockfile","/var/lock/slim.lock"));
  102.42 + 	options.insert(option("logfile","/var/log/slim.log"));
  102.43 + 	options.insert(option("authfile","/var/run/slim.auth"));
  102.44 +-	options.insert(option("shutdown_msg","The system is halting..."));
  102.45 ++	options.insert(option("shutdown_msg","The system is going down..."));
  102.46 + 	options.insert(option("reboot_msg","The system is rebooting..."));
  102.47 + 	options.insert(option("sessiondir",""));
  102.48 + 	options.insert(option("hidecursor","false"));
  102.49 +--- a/slim.conf
  102.50 ++++ b/slim.conf
  102.51 +@@ -1,13 +1,16 @@
  102.52 ++# /etc/slim.conf: Slim LogIn Manger configuration file
  102.53 ++#
  102.54 ++
  102.55 + # Path, X server and arguments (if needed)
  102.56 + # Note: -xauth $authfile is automatically appended
  102.57 +-default_path        /bin:/usr/bin:/usr/local/bin
  102.58 +-default_xserver     /usr/bin/X
  102.59 ++default_path        ./:/bin:/usr/bin:/usr/local/bin
  102.60 ++default_xserver     /usr/libexec/Xorg.wrap
  102.61 + #xserver_arguments   -dpi 75
  102.62 + 
  102.63 + # Commands for halt, login, etc.
  102.64 +-halt_cmd            /sbin/shutdown -h now
  102.65 +-reboot_cmd          /sbin/shutdown -r now
  102.66 +-console_cmd         /usr/bin/xterm -C -fg white -bg black +sb -T "Console login" -e /bin/sh -c "/bin/cat /etc/issue; exec /bin/login"
  102.67 ++halt_cmd            /sbin/poweroff
  102.68 ++reboot_cmd          /sbin/reboot
  102.69 ++console_cmd         /usr/bin/xterm -C -fg white -bg black +sb -T "Console login" -e /bin/sh -l -c "exec /bin/login"
  102.70 + #suspend_cmd        /usr/sbin/suspend
  102.71 + 
  102.72 + # Full path to the xauth binary
  102.73 +@@ -22,7 +25,7 @@
  102.74 + 
  102.75 + # Hide the mouse cursor (note: does not work with some WMs).
  102.76 + # Valid values: true|false
  102.77 +-# hidecursor          false
  102.78 ++hidecursor          true
  102.79 + 
  102.80 + # This command is executed after a succesful login.
  102.81 + # you can place the %session and %theme variables
  102.82 +@@ -33,7 +36,7 @@
  102.83 + # to adjust the command according to your preferred shell,
  102.84 + # i.e. for freebsd use:
  102.85 + # login_cmd           exec /bin/sh - ~/.xinitrc %session
  102.86 +-login_cmd           exec /bin/bash -login ~/.xinitrc %session
  102.87 ++login_cmd           exec /bin/sh -l ~/.xinitrc %session
  102.88 + 
  102.89 + # Commands executed when starting and exiting a session.
  102.90 + # They can be used for registering a X11 session with
  102.91 +@@ -51,10 +54,11 @@
  102.92 + # The current chosen session name is replaced in the login_cmd
  102.93 + # above, so your login command can handle different sessions.
  102.94 + # see the xinitrc.sample file shipped with slim sources
  102.95 +-sessions            xfce4,icewm-session,wmaker,blackbox
  102.96 ++sessions            openbox,e17,jwm
  102.97 + 
  102.98 + # Executed when pressing F11 (requires imagemagick)
  102.99 +-screenshot_cmd      import -window root /slim.png
 102.100 ++#screenshot_cmd      import -window root /slim.png
 102.101 ++screenshot_cmd      mtpaint -s /root/slim-shot.png
 102.102 + 
 102.103 + # welcome message. Available variables: %host, %domain
 102.104 + welcome_msg         Welcome to %host
 102.105 +@@ -63,12 +67,12 @@
 102.106 + # session_msg         Session: 
 102.107 + 
 102.108 + # shutdown / reboot messages
 102.109 +-shutdown_msg       The system is halting...
 102.110 ++shutdown_msg       The system is going down...
 102.111 + reboot_msg         The system is rebooting...
 102.112 + 
 102.113 + # default user, leave blank or remove this line
 102.114 + # for avoid pre-loading the username.
 102.115 +-#default_user        simone
 102.116 ++default_user        tux
 102.117 + 
 102.118 + # Focus the password field on start when default_user is set
 102.119 + # Set to "yes" to enable this feature
 102.120 +@@ -81,10 +85,10 @@
 102.121 + 
 102.122 + # current theme, use comma separated list to specify a set to 
 102.123 + # randomly choose from
 102.124 +-current_theme       default
 102.125 ++current_theme       slitaz,base
 102.126 + 
 102.127 + # Lock file
 102.128 +-lockfile            /var/run/slim.lock
 102.129 ++lockfile            /var/lock/slim.lock
 102.130 + 
 102.131 + # Log file
 102.132 + logfile             /var/log/slim.log
   103.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   103.2 +++ b/slim/stuff/patches/slim-freetype-dirs.patch	Tue Aug 07 00:30:45 2018 +0300
   103.3 @@ -0,0 +1,11 @@
   103.4 +--- slim-1.3.6.orig/CMakeLists.txt
   103.5 ++++ slim-1.3.6/CMakeLists.txt
   103.6 +@@ -170,7 +170,7 @@
   103.7 + 	${X11_Xft_INCLUDE_PATH}
   103.8 + 	${X11_Xrender_INCLUDE_PATH}
   103.9 + 	${X11_Xrandr_INCLUDE_PATH}
  103.10 +-	${FREETYPE_INCLUDE_DIR_freetype2}
  103.11 ++	${FREETYPE_INCLUDE_DIRS}
  103.12 + 	${X11_Xmu_INCLUDE_PATH}
  103.13 + 	${ZLIB_INCLUDE_DIR}
  103.14 + 	${JPEG_INCLUDE_DIR}
   104.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   104.2 +++ b/slim/stuff/patches/snprintf.patch	Tue Aug 07 00:30:45 2018 +0300
   104.3 @@ -0,0 +1,13 @@
   104.4 +diff --git a/Ck.cpp b/Ck.cpp
   104.5 +index 3b94426..85cc022 100644
   104.6 +--- a/Ck.cpp
   104.7 ++++ b/Ck.cpp
   104.8 +@@ -91,7 +91,7 @@ namespace Ck {
   104.9 + 
  104.10 + 	vt = *((long *)return_value);
  104.11 + 
  104.12 +-	std::snprintf(device, 32, "/dev/tty%ld", vt);
  104.13 ++	snprintf(device, 32, "/dev/tty%ld", vt);
  104.14 + 
  104.15 + 	if(return_value)
  104.16 + 	  XFree(return_value);
   105.1 --- a/sudoku/receipt	Mon Jul 30 23:44:42 2018 +0300
   105.2 +++ b/sudoku/receipt	Tue Aug 07 00:30:45 2018 +0300
   105.3 @@ -1,4 +1,4 @@
   105.4 -# SliTaz package receipt.
   105.5 +# SliTaz package receipt v2.
   105.6  
   105.7  PACKAGE="sudoku"
   105.8  VERSION="2.3"
   105.9 @@ -6,26 +6,19 @@
  105.10  SHORT_DESC="Sudoku game in javascript"
  105.11  MAINTAINER="pascal.bellard@slitaz.org"
  105.12  LICENSE="unknown"
  105.13 -TARBALL="$PACKAGE-$VERSION"
  105.14 -WEB_SITE="http://10k.aneventapart.com/1/Entry/81"
  105.15 -WGET_URL="http://10k.aneventapart.com/1/Uploads/81/index.html"
  105.16 +WEB_SITE="https://web.archive.org/web/20140124072600/http://10k.aneventapart.com/1/Entry/81"
  105.17 +REPOLOGY="-"
  105.18  
  105.19 -# Rules to gen a SliTaz package suitable for Tazpkg.
  105.20 -genpkg_rules()
  105.21 -{
  105.22 -        mkdir -p $fs/var/www/$PACKAGE $fs/usr/share/applications
  105.23 -	cp $src/$TARBALL $fs/var/www/$PACKAGE/index.html
  105.24 -	chown -R 80.80 $fs/var/www/$PACKAGE
  105.25 -	cat > $fs/usr/share/applications/sudoku.desktop <<EOT
  105.26 -[Desktop Entry]
  105.27 -Type=Application
  105.28 -Name=Sudoku
  105.29 -Name[zh_CN]=数独
  105.30 -Exec=sh -c "url=file:///var/www/sudoku/index.html ; tazweb --notoolbar \$url || browser \$url"
  105.31 -Icon=sudoku
  105.32 -Terminal=false
  105.33 -Categories=Game;
  105.34 -Comment=Sudoku game
  105.35 -EOT
  105.36 +TARBALL="$PACKAGE-$VERSION.html"
  105.37 +#WGET_URL="http://10k.aneventapart.com/1/Uploads/81/index.html"
  105.38 +WGET_URL="http://mirror1.slitaz.org/sources/packages-4.0/s/$TARBALL"
  105.39 +
  105.40 +compile_rules() {
  105.41 +	install -Dm644 -o80 -g80 $TARBALL $install/var/www/sudoku/index.html
  105.42 +
  105.43 +	install -Dm755 $stuff/sudoku $install/usr/bin/sudoku
  105.44  }
  105.45  
  105.46 +genpkg_rules() {
  105.47 +	copy @std
  105.48 +}
   106.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   106.2 +++ b/sudoku/stuff/sudoku	Tue Aug 07 00:30:45 2018 +0300
   106.3 @@ -0,0 +1,3 @@
   106.4 +#!/bin/sh
   106.5 +url='file:///var/www/sudoku/index.html'
   106.6 +tazweb --notoolbar $url || browser $url
   107.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   107.2 +++ b/sudoku/stuff/sudoku.desktop	Tue Aug 07 00:30:45 2018 +0300
   107.3 @@ -0,0 +1,9 @@
   107.4 +[Desktop Entry]
   107.5 +Type=Application
   107.6 +Name=Sudoku
   107.7 +Name[zh_CN]=数独
   107.8 +Comment=Sudoku game
   107.9 +Exec=sudoku
  107.10 +Icon=sudoku
  107.11 +Terminal=false
  107.12 +Categories=Game;
   108.1 Binary file sudoku/stuff/sudoku48.png has changed
   109.1 --- a/texinfo/receipt	Mon Jul 30 23:44:42 2018 +0300
   109.2 +++ b/texinfo/receipt	Tue Aug 07 00:30:45 2018 +0300
   109.3 @@ -1,13 +1,13 @@
   109.4  # SliTaz package receipt v2.
   109.5  
   109.6  PACKAGE="texinfo"
   109.7 -VERSION="6.4"
   109.8 +VERSION="6.5"
   109.9  CATEGORY="development"
  109.10  SHORT_DESC="GNU documentation tools"
  109.11  MAINTAINER="rcx@zoominternet.net"
  109.12  LICENSE="GPL3"
  109.13  WEB_SITE="https://www.gnu.org/software/texinfo/"
  109.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/texinfo.html"
  109.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/texinfo.html"
  109.16  
  109.17  TARBALL="$PACKAGE-$VERSION.tar.xz"
  109.18  WGET_URL="$GNU_MIRROR/$PACKAGE/$TARBALL"
  109.19 @@ -18,7 +18,8 @@
  109.20  	./configure \
  109.21  		--disable-static \
  109.22  		$CONFIGURE_ARGS &&
  109.23 -	make && make install
  109.24 +	make &&
  109.25 +	make install
  109.26  }
  109.27  
  109.28  genpkg_rules() {
   110.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   110.2 +++ b/texinfo/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
   110.3 @@ -0,0 +1,1 @@
   110.4 +texinfo-escape.patch
   111.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   111.2 +++ b/texinfo/stuff/patches/texinfo-escape.patch	Tue Aug 07 00:30:45 2018 +0300
   111.3 @@ -0,0 +1,28 @@
   111.4 +Fix the following warnings when texinfo used:
   111.5 +
   111.6 +Unescaped left brace in regex is deprecated here (and will be fatal in
   111.7 +Perl 5.32), passed through in regex; marked by <-- HERE in
   111.8 +m/^\s+@([[:alnum:]][[:alnum:]\-]*)({ <-- HERE })?\s*/
   111.9 +at /usr/share/texinfo/Texinfo/Parser.pm line 5481.
  111.10 +
  111.11 +Unescaped left brace in regex is deprecated here (and will be fatal in
  111.12 +Perl 5.32), passed through in regex; marked by <-- HERE in
  111.13 +m/^\s+@([[:alnum:]][[:alnum:]\-]*)({ <-- HERE })?\s*(\@(c|comment)((\@|\s+).*)?)?/
  111.14 +at /usr/share/texinfo/Texinfo/Parser.pm line 5485.
  111.15 +
  111.16 +--- a/tp/Texinfo/Parser.pm
  111.17 ++++ b/tp/Texinfo/Parser.pm
  111.18 +@@ -5478,11 +5478,11 @@
  111.19 +     }
  111.20 +   } elsif ($command eq 'clickstyle') {
  111.21 +     # REMACRO
  111.22 +-    if ($line =~ /^\s+@([[:alnum:]][[:alnum:]\-]*)({})?\s*/) {
  111.23 ++    if ($line =~ /^\s+@([[:alnum:]][[:alnum:]\-]*)(\{\})?\s*/) {
  111.24 +       $args = ['@'.$1];
  111.25 +       $self->{'clickstyle'} = $1;
  111.26 +       $remaining = $line;
  111.27 +-      $remaining =~ s/^\s+@([[:alnum:]][[:alnum:]\-]*)({})?\s*(\@(c|comment)((\@|\s+).*)?)?//;
  111.28 ++      $remaining =~ s/^\s+@([[:alnum:]][[:alnum:]\-]*)(\{\})?\s*(\@(c|comment)((\@|\s+).*)?)?//;
  111.29 +       $has_comment = 1 if (defined($4));
  111.30 +     } else {
  111.31 +       $self->line_error (sprintf($self->__(
   112.1 --- a/udisks2/receipt	Mon Jul 30 23:44:42 2018 +0300
   112.2 +++ b/udisks2/receipt	Tue Aug 07 00:30:45 2018 +0300
   112.3 @@ -1,13 +1,13 @@
   112.4  # SliTaz package receipt v2.
   112.5  
   112.6  PACKAGE="udisks2"
   112.7 -VERSION="2.7.6"
   112.8 +VERSION="2.7.7"
   112.9  CATEGORY="system-tools"
  112.10  SHORT_DESC="D-Bus service to access and manipulate storage devices"
  112.11  MAINTAINER="pankso@slitaz.org"
  112.12  LICENSE="GPL2"
  112.13  WEB_SITE="https://www.freedesktop.org/wiki/Software/udisks/"
  112.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/general/udisks2.html"
  112.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/general/udisks2.html"
  112.16  
  112.17  TARBALL="udisks-$VERSION.tar.bz2"
  112.18  WGET_URL="https://github.com/storaged-project/udisks/releases/download/udisks-$VERSION/$TARBALL"
   113.1 --- a/unbound/receipt	Mon Jul 30 23:44:42 2018 +0300
   113.2 +++ b/unbound/receipt	Tue Aug 07 00:30:45 2018 +0300
   113.3 @@ -1,7 +1,7 @@
   113.4  # SliTaz package receipt v2.
   113.5  
   113.6  PACKAGE="unbound"
   113.7 -VERSION="1.6.7"
   113.8 +VERSION="1.7.3"
   113.9  CATEGORY="network"
  113.10  SHORT_DESC="A validating, recursive, and caching DNS resolver"
  113.11  MAINTAINER="pascal.bellard@slitaz.org"
   114.1 --- a/util-linux/receipt	Mon Jul 30 23:44:42 2018 +0300
   114.2 +++ b/util-linux/receipt	Tue Aug 07 00:30:45 2018 +0300
   114.3 @@ -1,13 +1,13 @@
   114.4  # SliTaz package receipt v2.
   114.5  
   114.6  PACKAGE="util-linux"
   114.7 -VERSION="2.31.1"
   114.8 +VERSION="2.32.1"
   114.9  CATEGORY="meta"
  114.10  SHORT_DESC="Random collection of Linux utilities"
  114.11  MAINTAINER="pankso@slitaz.org"
  114.12  LICENSE="GPL2 LGPL2.1 BSD PublicDomain"
  114.13  WEB_SITE="https://en.wikipedia.org/wiki/Util-linux"
  114.14 -LFS="http://www.linuxfromscratch.org/lfs/view/stable/chapter06/util-linux.html"
  114.15 +LFS="http://www.linuxfromscratch.org/lfs/view/development/chapter06/util-linux.html"
  114.16  
  114.17  TARBALL="$PACKAGE-${VERSION%.0}.tar.xz"
  114.18  WGET_URL="https://www.kernel.org/pub/linux/utils/util-linux/v${VERSION%.*}/$TARBALL"
  114.19 @@ -36,7 +36,8 @@
  114.20  		--without-systemd \
  114.21  		--without-systemdsystemunitdir &&
  114.22  	fix libtool &&
  114.23 -	make && make install || exit 1
  114.24 +	make &&
  114.25 +	make install || exit 1
  114.26  
  114.27  	install -Dm644 $stuff/cfdisk.desktop \
  114.28  		$install/usr/share/applications/cfdisk.desktop
   115.1 Binary file vim/.icon.png has changed
   116.1 --- a/vim/receipt	Mon Jul 30 23:44:42 2018 +0300
   116.2 +++ b/vim/receipt	Tue Aug 07 00:30:45 2018 +0300
   116.3 @@ -1,7 +1,7 @@
   116.4  # SliTaz package receipt v2.
   116.5  
   116.6  PACKAGE="vim"
   116.7 -VERSION="8.0.069"
   116.8 +VERSION="8.1"
   116.9  CATEGORY="editors"
  116.10  SHORT_DESC="Advanced text editor"
  116.11  MAINTAINER="erjo@slitaz.org"
  116.12 @@ -11,54 +11,66 @@
  116.13  TARBALL="$PACKAGE-$VERSION.tar.bz2"
  116.14  WGET_URL="ftp://ftp.vim.org/pub/vim/unix/$TARBALL"
  116.15  
  116.16 -# python may be removed after "ncursesw problem" solved
  116.17  BUILD_DEPENDS="python ncurses-dev acl-dev diffutils gettext"
  116.18 -SIBLINGS="vim-tiny"
  116.19 +SPLIT="vim-tiny:tiny"
  116.20  
  116.21 -# Rules to configure and make the package.
  116.22 -compile_rules()
  116.23 -{
  116.24 +compile_rules() {
  116.25  	echo '#define SYS_VIMRC_FILE "/etc/vimrc"' >> src/feature.h
  116.26  
  116.27 +	case $SET in
  116.28 +		'')   SET_ARGS='';;
  116.29 +		tiny) SET_ARGS='--with-features=tiny --with-vim-name=vim-tiny --disable-acl';;
  116.30 +	esac
  116.31 +
  116.32  	./configure \
  116.33  		--without-x \
  116.34  		--disable-gui \
  116.35  		--enable-multibyte \
  116.36 +		$SET_ARGS \
  116.37  		$CONFIGURE_ARGS &&
  116.38 -	make && make install
  116.39 +	make &&
  116.40 +	make install || return 1
  116.41  
  116.42 -	mkdir -p $install/etc/vim
  116.43 -	cp $src/runtime/vimrc_example.vim $install/etc/vim/vimrc
  116.44 +	install -Dm644 runtime/vimrc_example.vim $install/etc/vim/vimrc
  116.45  
  116.46  	mkdir -p $install/usr/share/doc
  116.47 -	ln -s ../vim/vim*/doc $install/usr/share/doc/vim-$VERSION
  116.48 +	ln -s ../vim/vim${VERSION//./}/doc $install/usr/share/doc/vim-$VERSION
  116.49  }
  116.50  
  116.51 -# Rules to gen a SliTaz package suitable for Tazpkg.
  116.52 -genpkg_rules()
  116.53 -{
  116.54 -	copy @std
  116.55 +# TODO: put common files to vim-common package; maybe compile in the single set
  116.56 +
  116.57 +genpkg_rules() {
  116.58 +	case $PACKAGE in
  116.59 +		vim)
  116.60 +			copy @std
  116.61 +			DEPENDS="ncurses acl attr diffutils"
  116.62 +			;;
  116.63 +		vim-tiny)
  116.64 +			copy @std
  116.65 +			rm -f  $fs/usr/bin/*tutor
  116.66 +			rm -rf $fs/usr/share/vim/vim*/tutor
  116.67 +			DEPENDS="ncurses"
  116.68 +			;;
  116.69 +	esac
  116.70  	CONFIG_FILES="/etc/vim/vimrc"
  116.71  	TAGS="text-editor"
  116.72 -	DEPENDS="ncurses acl attr diffutils"
  116.73  }
  116.74  
  116.75 -post_install_vim()
  116.76 -{
  116.77 +# common post-install for vim and vim-tiny
  116.78 +post_install() {
  116.79  	cmd=$(readlink "$1/bin/vi")
  116.80 -	if [ "$cmd" != '/usr/bin/vim' ]; then
  116.81 +	[ "$cmd" != '/usr/bin/vim' ] || return
  116.82 +	echo
  116.83 +	echo "**** Actual VI link : $cmd"
  116.84 +	echo
  116.85 +	echo -n 'Do you want vim for /bin/vi (y/N)? : '; read -t 30 anser
  116.86 +	if [ "$anser" == 'y' ]; then
  116.87  		echo
  116.88 -		echo "**** Actual VI link : $cmd"
  116.89 +		action 'Removing vi link to make a new one pointing on /usr/bin/vim...'
  116.90 +		rm "$1/bin/vi"; ln -sf ../usr/bin/vim "$1/bin/vi"
  116.91 +		status
  116.92 +	else
  116.93  		echo
  116.94 -		echo -n 'Do you want vim for /bin/vi (y/N)? : '; read -t 30 anser
  116.95 -		if [ "$anser" == 'y' ]; then
  116.96 -			echo
  116.97 -			echo -n 'Removing vi link to make a new one pointing on /usr/bin/vim...'
  116.98 -			rm "$1/bin/vi" && ln -sf /usr/bin/vim "$1/bin/vi"
  116.99 -			status
 116.100 -		else
 116.101 -			echo
 116.102 -			echo "Leaving /bin/vi to : $cmd"
 116.103 -		fi
 116.104 +		echo "Leaving /bin/vi to $cmd"
 116.105  	fi
 116.106  }
   117.1 --- a/volume_key/receipt	Mon Jul 30 23:44:42 2018 +0300
   117.2 +++ b/volume_key/receipt	Tue Aug 07 00:30:45 2018 +0300
   117.3 @@ -1,20 +1,20 @@
   117.4  # SliTaz package receipt v2.
   117.5  
   117.6  PACKAGE="volume_key"
   117.7 -VERSION="0.3.9"
   117.8 +VERSION="0.3.11"
   117.9  CATEGORY="libs"
  117.10  SHORT_DESC="Manipulating storage volume encryption keys"
  117.11  MAINTAINER="al.bobylev@gmail.com"
  117.12  LICENSE="GPL2"
  117.13  WEB_SITE="https://pagure.io/volume_key"
  117.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/postlfs/volume_key.html"
  117.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/postlfs/volume_key.html"
  117.16  REPOLOGY="volume-key"
  117.17  
  117.18  TARBALL="$PACKAGE-$VERSION.tar.xz"
  117.19  WGET_URL="https://releases.pagure.org/volume_key/$TARBALL"
  117.20  
  117.21  BUILD_DEPENDS="automake gettext gpgme-dev libtool cryptsetup-dev nss-dev \
  117.22 -python-dev util-linux-blkid-dev glib-dev"
  117.23 +python3-dev util-linux-blkid-dev glib-dev"
  117.24  SPLIT="volume_key-python volume_key volume_key-dev"
  117.25  
  117.26  compile_rules() {
  117.27 @@ -30,10 +30,10 @@
  117.28  genpkg_rules() {
  117.29  	case $PACKAGE in
  117.30  		*-python)
  117.31 -			copy python2.7/
  117.32 +			copy python3.*/
  117.33  			find $fs -name '*.la' -delete
  117.34 -			CAT="libs|python bindings"
  117.35 -			DEPENDS="glib nss python volume_key"
  117.36 +			CAT="libs|python 3 bindings"
  117.37 +			DEPENDS="glib nss python3 volume_key"
  117.38  			;;
  117.39  		volume_key)
  117.40  			copy @std @rm
   118.1 Binary file xarchiver/.icon.png has changed
   119.1 --- a/xarchiver/receipt	Mon Jul 30 23:44:42 2018 +0300
   119.2 +++ b/xarchiver/receipt	Tue Aug 07 00:30:45 2018 +0300
   119.3 @@ -1,27 +1,28 @@
   119.4  # SliTaz package receipt v2.
   119.5  
   119.6  PACKAGE="xarchiver"
   119.7 -VERSION="0.5.4"
   119.8 +VERSION="0.5.4.13"
   119.9  CATEGORY="x-window"
  119.10  SHORT_DESC="A GTK+ lightweight archive manager"
  119.11  MAINTAINER="erjo@slitaz.org"
  119.12  LICENSE="GPL2"
  119.13 -WEB_SITE="https://wiki.lxde.org/en/Xarchiver"
  119.14 +#WEB_SITE="https://wiki.lxde.org/en/Xarchiver"
  119.15 +WEB_SITE="https://github.com/ib/xarchiver"
  119.16  
  119.17 -TARBALL="$PACKAGE-$VERSION.tar.bz2"
  119.18 -WGET_URL="$SF_MIRROR/xarchiver/$VERSION/$TARBALL"
  119.19 +TARBALL="$PACKAGE-$VERSION.tar.gz"
  119.20 +WGET_URL="https://github.com/ib/xarchiver/archive/$VERSION.tar.gz"
  119.21  
  119.22 -BUILD_DEPENDS="gtk+-dev intltool"
  119.23 +BUILD_DEPENDS="gtk+-dev intltool libxslt"
  119.24 +COOKOPTS="skip-log-errors"
  119.25  
  119.26  compile_rules() {
  119.27  	./configure $CONFIGURE_ARGS &&
  119.28  	fix libtool &&
  119.29  	make &&
  119.30 -	make install
  119.31 +	make install || return 1
  119.32  
  119.33 -	mkdir -p $install/var/www/cgi-bin $install/usr/share/doc/xarchiver/html
  119.34 -	cp $stuff/xarchiver.cgi $install/var/www/cgi-bin
  119.35 -	cp $stuff/index.html    $install/usr/share/doc/xarchiver/html
  119.36 +	install -Dm644 $stuff/xarchiver.cgi $install/var/www/cgi-bin/xarchiver.cgi
  119.37 +	install -Dm644 $stuff/index.html    $install/usr/share/doc/xarchiver/html/index.html
  119.38  
  119.39  	sed -i 's|multipart/x-zip;||; /Exec/s/.*/& %f/' \
  119.40  		$install/usr/share/applications/xarchiver.desktop
  119.41 @@ -29,7 +30,8 @@
  119.42  
  119.43  genpkg_rules() {
  119.44  	copy @std @ico
  119.45 -	DEPENDS="atk cairo fontconfig freetype gdk-pixbuf glib gtk+ pango"
  119.46 +	rm -r $fs/usr/share/pixmaps/
  119.47 +	DEPENDS="gdk-pixbuf glib gtk+"
  119.48  	# binutils for ar; busybox also contains gzip & cpio; rar is get-rar;
  119.49  	# gtar is absent
  119.50  	SUGGESTED="arj binutils bzip2 cpio gzip lha lzma lzop p7zip-full rar xz zip"
   120.1 --- a/xarchiver/stuff/patches/series	Mon Jul 30 23:44:42 2018 +0300
   120.2 +++ b/xarchiver/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
   120.3 @@ -1,1 +1,1 @@
   120.4 -xarchiver-0.5.3-icons.patch
   120.5 +xarchiver-0.5.4.13-icons.patch
   121.1 --- a/xarchiver/stuff/patches/xarchiver-0.5.3-icons.patch	Mon Jul 30 23:44:42 2018 +0300
   121.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.3 @@ -1,136 +0,0 @@
   121.4 ---- a/src/add_dialog.c
   121.5 -+++ b/src/add_dialog.c
   121.6 -@@ -180,7 +180,7 @@
   121.7 - 	GTK_WIDGET_SET_FLAGS (add_dialog->cancel_button, GTK_CAN_DEFAULT);
   121.8 - 
   121.9 - 	add_dialog->add_button = gtk_button_new();
  121.10 --	add_dialog->add_image = xa_main_window_find_image("xarchiver-add.png", GTK_ICON_SIZE_SMALL_TOOLBAR);
  121.11 -+	add_dialog->add_image = gtk_image_new_from_icon_name ("add-files-to-archive",GTK_ICON_SIZE_SMALL_TOOLBAR);
  121.12 - 	add_dialog->add_hbox = gtk_hbox_new(FALSE, 4);
  121.13 - 	add_dialog->add_label = gtk_label_new_with_mnemonic(_("_Add"));
  121.14 - 
  121.15 ---- a/src/extract_dialog.c
  121.16 -+++ b/src/extract_dialog.c
  121.17 -@@ -167,7 +167,7 @@
  121.18 - 	GTK_WIDGET_SET_FLAGS (cancel_button,GTK_CAN_DEFAULT);
  121.19 - 
  121.20 - 	extract_button = gtk_button_new();
  121.21 --	extract_image = xa_main_window_find_image("xarchiver-extract.png",GTK_ICON_SIZE_SMALL_TOOLBAR);
  121.22 -+	extract_image = gtk_image_new_from_icon_name ("extract-archive",GTK_ICON_SIZE_SMALL_TOOLBAR);
  121.23 - 	extract_hbox = gtk_hbox_new(FALSE,4);
  121.24 - 	extract_label = gtk_label_new_with_mnemonic(_("_Extract"));
  121.25 - 
  121.26 -@@ -503,7 +503,7 @@
  121.27 - 	GTK_WIDGET_SET_FLAGS (cancelbutton1,GTK_CAN_DEFAULT);
  121.28 - 	
  121.29 - 	extract_button = gtk_button_new();
  121.30 --	extract_image = xa_main_window_find_image("xarchiver-extract.png",GTK_ICON_SIZE_SMALL_TOOLBAR);
  121.31 -+	extract_image = gtk_image_new_from_icon_name ("extract-archive",GTK_ICON_SIZE_SMALL_TOOLBAR);
  121.32 - 	extract_hbox = gtk_hbox_new(FALSE,4);
  121.33 - 	extract_label = gtk_label_new_with_mnemonic(_("_Extract"));
  121.34 - 
  121.35 ---- a/src/interface.c
  121.36 -+++ b/src/interface.c
  121.37 -@@ -110,7 +110,7 @@
  121.38 - 	listing_html = gtk_image_menu_item_new_with_mnemonic (_("HTML file"));
  121.39 - 	gtk_widget_show (listing_html);
  121.40 - 	gtk_container_add (GTK_CONTAINER (listing_submenu),listing_html);
  121.41 --	tmp_image =  xa_main_window_find_image ("xarchiver-html.png",GTK_ICON_SIZE_MENU);
  121.42 -+	tmp_image = gtk_image_new_from_icon_name ("browser",GTK_ICON_SIZE_MENU);
  121.43 - 	gtk_widget_show (tmp_image);
  121.44 - 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (listing_html),tmp_image);
  121.45 - 	
  121.46 -@@ -171,7 +171,7 @@
  121.47 - 	gtk_container_add (GTK_CONTAINER (menuitem2_menu),addfile);
  121.48 - 	gtk_widget_add_accelerator (addfile,"activate",accel_group,GDK_d,GDK_CONTROL_MASK,GTK_ACCEL_VISIBLE);
  121.49 - 
  121.50 --	image2 = xa_main_window_find_image ("xarchiver-add.png",GTK_ICON_SIZE_MENU);
  121.51 -+	image2 = gtk_image_new_from_icon_name ("add-files-to-archive",GTK_ICON_SIZE_MENU);
  121.52 - 	gtk_widget_show (image2);
  121.53 - 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (addfile),image2);
  121.54 - 
  121.55 -@@ -181,7 +181,7 @@
  121.56 - 	gtk_container_add (GTK_CONTAINER (menuitem2_menu),extract_menu);
  121.57 - 	gtk_widget_add_accelerator (extract_menu,"activate",accel_group,GDK_e,GDK_CONTROL_MASK,GTK_ACCEL_VISIBLE);
  121.58 - 
  121.59 --	image2 =  xa_main_window_find_image ("xarchiver-extract.png",GTK_ICON_SIZE_MENU);
  121.60 -+	image2 = gtk_image_new_from_icon_name ("extract-archive",GTK_ICON_SIZE_MENU);
  121.61 - 	gtk_widget_show (image2);
  121.62 - 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (extract_menu),image2);
  121.63 - 
  121.64 -@@ -387,7 +387,7 @@
  121.65 - 	gtk_widget_show (separatortoolitem3);
  121.66 - 	gtk_container_add (GTK_CONTAINER (toolbar1),separatortoolitem3);
  121.67 - 
  121.68 --	tmp_image = xa_main_window_find_image("xarchiver-add.png",GTK_ICON_SIZE_LARGE_TOOLBAR);
  121.69 -+	tmp_image = gtk_image_new_from_icon_name ("add-files-to-archive",GTK_ICON_SIZE_LARGE_TOOLBAR);
  121.70 - 	gtk_widget_show (tmp_image);
  121.71 - 	AddFile_button = (GtkWidget*) gtk_tool_button_new (tmp_image,_("Add"));
  121.72 - 	gtk_widget_set_sensitive (AddFile_button,FALSE);
  121.73 -@@ -396,7 +396,7 @@
  121.74 - 	gtk_container_add (GTK_CONTAINER (toolbar1),AddFile_button);
  121.75 - 	gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (AddFile_button),tooltips,_("Add files"),NULL);
  121.76 - 
  121.77 --	tmp_image = xa_main_window_find_image("xarchiver-extract.png",GTK_ICON_SIZE_LARGE_TOOLBAR);
  121.78 -+	tmp_image = gtk_image_new_from_icon_name ("extract-archive",GTK_ICON_SIZE_LARGE_TOOLBAR);
  121.79 - 	gtk_widget_show (tmp_image);
  121.80 - 	Extract_button = (GtkWidget*) gtk_tool_button_new (tmp_image,_("Extract"));
  121.81 - 	gtk_widget_set_sensitive (Extract_button,FALSE);
  121.82 -@@ -863,7 +863,7 @@
  121.83 - 	gtk_widget_show (extract);
  121.84 - 	gtk_container_add (GTK_CONTAINER (xa_popup_menu),extract);
  121.85 - 
  121.86 --	image9 =  xa_main_window_find_image ("xarchiver-extract.png",GTK_ICON_SIZE_MENU);
  121.87 -+	image9 = gtk_image_new_from_icon_name ("extract-archive",GTK_ICON_SIZE_MENU);
  121.88 - 	gtk_widget_show (image9);
  121.89 - 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (extract),image9);
  121.90 - 
  121.91 -@@ -1527,7 +1527,7 @@
  121.92 - 	hbox1 = gtk_hbox_new (FALSE,12);
  121.93 - 	gtk_box_pack_start (GTK_BOX (vbox1),hbox1,TRUE,TRUE,0);
  121.94 - 
  121.95 --	pixbuf = gtk_icon_theme_load_icon(icon_theme,"gnome-mime-application-zip",40,0,NULL);
  121.96 -+	pixbuf = gtk_icon_theme_load_icon(icon_theme,"application-zip",40,0,NULL);
  121.97 - 	icon_pixbuf = gtk_image_new_from_pixbuf(pixbuf);
  121.98 - 	g_object_unref(pixbuf);
  121.99 - 
 121.100 ---- a/src/mime.c
 121.101 -+++ b/src/mime.c
 121.102 -@@ -41,9 +41,9 @@
 121.103 - 	else if (strcmp(mime,"audio/mpeg") == 0 || strcmp(mime,"audio/midi") == 0 || strcmp (mime,"audio/mp2") == 0)
 121.104 - 		icon_name = "sound";
 121.105 - 	else if (strcmp(mime,"application/vnd.ms-excel") == 0 || strcmp(mime,"application/vnd.oasis.opendocument.spreadsheet") == 0)
 121.106 --		icon_name = "gnome-mime-application-vnd.ms-excel";
 121.107 -+		icon_name = "application-vnd.ms-excel";
 121.108 - 	else if (strcmp(mime,"application/vnd.ms-powerpoint") == 0 || strcmp (mime,"application/vnd.oasis.opendocument.presentation") == 0)
 121.109 --		icon_name = "gnome-mime-application-vnd.ms-powerpoint";
 121.110 -+		icon_name = "application-vnd.ms-powerpoint";
 121.111 - 	else if (strcmp(mime,"application/zip") == 0 || strcmp(mime,"application/x-rar") == 0 || strcmp(mime,"application/x-tar") == 0
 121.112 - 		|| strcmp(mime,"application/x-7z-compressed") == 0 || strcmp(mime,"application/x-bzip-compressed-tar") == 0
 121.113 - 		|| strcmp (mime,"application/x-compressed-tar") == 0 || strcmp (mime,"application/x-lha") == 0
 121.114 -@@ -57,11 +57,11 @@
 121.115 - 	else if (strcmp(mime,"application/x-cd-image") == 0)
 121.116 - 		icon_name = "application-x-cd-image";
 121.117 - 	else if (strcmp(mime,"application/x-php") == 0)
 121.118 --		icon_name = "gnome-mime-application-x-php";
 121.119 -+		icon_name = "application-x-php";
 121.120 - 	else if (strcmp(mime,"application/x-perl") == 0 || strcmp (mime,"application/x-csh") == 0 || strcmp (mime,"application/x-shellscript") == 0)
 121.121 --		icon_name = "gnome-mime-application-x-perl";
 121.122 -+		icon_name = "text-x-script";
 121.123 - 	else if (strcmp(mime,"application/x-font-ttf") == 0)
 121.124 --		icon_name = "gnome-mime-application-x-font-ttf";
 121.125 -+		icon_name = "font";
 121.126 - 	return icon_name;		
 121.127 - }
 121.128 - 
 121.129 ---- a/src/pref_dialog.c
 121.130 -+++ b/src/pref_dialog.c
 121.131 -@@ -57,7 +57,7 @@
 121.132 - 
 121.133 - 	prefs_data->prefs_liststore = gtk_list_store_new (3,GDK_TYPE_PIXBUF,G_TYPE_STRING,G_TYPE_UINT);
 121.134 - 	gtk_list_store_append (prefs_data->prefs_liststore,&iter);
 121.135 --	icon_pixbuf = gtk_icon_theme_load_icon(icon_theme,"gnome-mime-application-zip",40,0,NULL);
 121.136 -+	icon_pixbuf = gtk_icon_theme_load_icon(icon_theme,"application-zip",40,0,NULL);
 121.137 - 	gtk_list_store_set (prefs_data->prefs_liststore, &iter, 0, icon_pixbuf, 1, _("Archive"),2,0,-1);
 121.138 - 	if(icon_pixbuf != NULL)
 121.139 - 		g_object_unref (icon_pixbuf);
   122.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   122.2 +++ b/xarchiver/stuff/patches/xarchiver-0.5.4.13-icons.patch	Tue Aug 07 00:30:45 2018 +0300
   122.3 @@ -0,0 +1,124 @@
   122.4 +--- a/src/add_dialog.c
   122.5 ++++ b/src/add_dialog.c
   122.6 +@@ -216,7 +216,7 @@
   122.7 + 	gtk_widget_set_can_default(add_dialog->cancel_button, TRUE);
   122.8 + 
   122.9 + 	add_dialog->add_button = gtk_button_new();
  122.10 +-	add_dialog->add_image = xa_main_window_find_image("xarchiver-add.png", GTK_ICON_SIZE_SMALL_TOOLBAR);
  122.11 ++	add_dialog->add_image = gtk_image_new_from_icon_name("add-files-to-archive", GTK_ICON_SIZE_SMALL_TOOLBAR);
  122.12 + 	add_dialog->add_hbox = gtk_hbox_new(FALSE, 4);
  122.13 + 	add_dialog->add_label = gtk_label_new_with_mnemonic(_("_Add"));
  122.14 + 
  122.15 +--- a/src/extract_dialog.c
  122.16 ++++ b/src/extract_dialog.c
  122.17 +@@ -418,7 +418,7 @@
  122.18 + 	gtk_widget_set_can_default(cancel_button, TRUE);
  122.19 + 
  122.20 + 	extract_button = gtk_button_new();
  122.21 +-	extract_image = xa_main_window_find_image("xarchiver-extract.png",GTK_ICON_SIZE_SMALL_TOOLBAR);
  122.22 ++	extract_image = gtk_image_new_from_icon_name("extract-archive",GTK_ICON_SIZE_SMALL_TOOLBAR);
  122.23 + 	extract_hbox = gtk_hbox_new(FALSE,4);
  122.24 + 	extract_label = gtk_label_new_with_mnemonic(_("_Extract"));
  122.25 + 
  122.26 +@@ -737,7 +737,7 @@
  122.27 + 	gtk_widget_set_can_default(cancelbutton1, TRUE);
  122.28 + 
  122.29 + 	extract_button = gtk_button_new();
  122.30 +-	extract_image = xa_main_window_find_image("xarchiver-extract.png",GTK_ICON_SIZE_SMALL_TOOLBAR);
  122.31 ++	extract_image = gtk_image_new_from_icon_name("extract-archive",GTK_ICON_SIZE_SMALL_TOOLBAR);
  122.32 + 	extract_hbox = gtk_hbox_new(FALSE,4);
  122.33 + 	extract_label = gtk_label_new_with_mnemonic(_("_Extract"));
  122.34 + 
  122.35 +--- a/src/interface.c
  122.36 ++++ b/src/interface.c
  122.37 +@@ -127,7 +127,7 @@
  122.38 + 	gtk_widget_show(eextract);
  122.39 + 	gtk_container_add(GTK_CONTAINER(xa_popup_menu), eextract);
  122.40 + 
  122.41 +-	image9 =  xa_main_window_find_image ("xarchiver-extract.png",GTK_ICON_SIZE_MENU);
  122.42 ++	image9 = gtk_image_new_from_icon_name("extract-archive",GTK_ICON_SIZE_MENU);
  122.43 + 	gtk_widget_show (image9);
  122.44 + 	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(eextract), image9);
  122.45 + 
  122.46 +@@ -684,14 +684,14 @@
  122.47 + 	listing_text = gtk_image_menu_item_new_with_mnemonic (_("_Text file"));
  122.48 + 	gtk_widget_show (listing_text);
  122.49 + 	gtk_container_add (GTK_CONTAINER (listing_submenu),listing_text);
  122.50 +-	tmp_image = gtk_image_new_from_stock ("gtk-justify-fill",GTK_ICON_SIZE_MENU);
  122.51 ++	tmp_image = gtk_image_new_from_icon_name ("text-x-generic",GTK_ICON_SIZE_MENU);
  122.52 + 	gtk_widget_show (tmp_image);
  122.53 + 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (listing_text),tmp_image);
  122.54 + 
  122.55 + 	listing_html = gtk_image_menu_item_new_with_mnemonic (_("_HTML file"));
  122.56 + 	gtk_widget_show (listing_html);
  122.57 + 	gtk_container_add (GTK_CONTAINER (listing_submenu),listing_html);
  122.58 +-	tmp_image =  xa_main_window_find_image ("xarchiver-html.png",GTK_ICON_SIZE_MENU);
  122.59 ++	tmp_image = gtk_image_new_from_icon_name("text-html",GTK_ICON_SIZE_MENU);
  122.60 + 	gtk_widget_show (tmp_image);
  122.61 + 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (listing_html),tmp_image);
  122.62 + 
  122.63 +@@ -752,7 +752,7 @@
  122.64 + 	gtk_container_add (GTK_CONTAINER (menuitem2_menu),addfile);
  122.65 + 	gtk_widget_add_accelerator(addfile, "activate", accel_group, GDK_KEY_d, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
  122.66 + 
  122.67 +-	image2 = xa_main_window_find_image ("xarchiver-add.png",GTK_ICON_SIZE_MENU);
  122.68 ++	image2 = gtk_image_new_from_icon_name ("add-files-to-archive",GTK_ICON_SIZE_MENU);
  122.69 + 	gtk_widget_show (image2);
  122.70 + 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (addfile),image2);
  122.71 + 
  122.72 +@@ -762,7 +762,7 @@
  122.73 + 	gtk_container_add (GTK_CONTAINER (menuitem2_menu),extract_menu);
  122.74 + 	gtk_widget_add_accelerator(extract_menu, "activate", accel_group, GDK_KEY_e, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
  122.75 + 
  122.76 +-	image2 =  xa_main_window_find_image ("xarchiver-extract.png",GTK_ICON_SIZE_MENU);
  122.77 ++	image2 = gtk_image_new_from_icon_name ("extract-archive",GTK_ICON_SIZE_MENU);
  122.78 + 	gtk_widget_show (image2);
  122.79 + 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (extract_menu),image2);
  122.80 + 
  122.81 +@@ -973,7 +973,7 @@
  122.82 + 	gtk_widget_show (separatortoolitem3);
  122.83 + 	gtk_container_add (GTK_CONTAINER (toolbar1),separatortoolitem3);
  122.84 + 
  122.85 +-	tmp_image = xa_main_window_find_image("xarchiver-add.png",GTK_ICON_SIZE_LARGE_TOOLBAR);
  122.86 ++	tmp_image = gtk_image_new_from_icon_name ("add-files-to-archive",GTK_ICON_SIZE_LARGE_TOOLBAR);
  122.87 + 	gtk_widget_show (tmp_image);
  122.88 + 	AddFile_button = (GtkWidget*) gtk_tool_button_new (tmp_image,_("Add"));
  122.89 + 	gtk_widget_set_sensitive (AddFile_button,FALSE);
  122.90 +@@ -982,7 +982,7 @@
  122.91 + 	gtk_container_add (GTK_CONTAINER (toolbar1),AddFile_button);
  122.92 + 	gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(AddFile_button), _("Add files"));
  122.93 + 
  122.94 +-	tmp_image = xa_main_window_find_image("xarchiver-extract.png",GTK_ICON_SIZE_LARGE_TOOLBAR);
  122.95 ++	tmp_image = gtk_image_new_from_icon_name("extract-archive",GTK_ICON_SIZE_LARGE_TOOLBAR);
  122.96 + 	gtk_widget_show (tmp_image);
  122.97 + 	Extract_button = (GtkWidget*) gtk_tool_button_new (tmp_image,_("Extract"));
  122.98 + 	gtk_widget_set_sensitive (Extract_button,FALSE);
  122.99 +@@ -1214,7 +1214,7 @@
 122.100 + 	gtk_widget_modify_style(close_button,rcstyle);
 122.101 + 	g_object_unref(rcstyle);
 122.102 + 
 122.103 +-	image = xa_main_window_find_image("xarchiver-close.png", 8);
 122.104 ++	image = gtk_image_new_from_stock("gtk-close", 8);
 122.105 + 	gtk_container_add (GTK_CONTAINER(close_button),image);
 122.106 + 	align = gtk_alignment_new(1.0, 0.5, 0.0, 0.0);
 122.107 + 	gtk_container_add(GTK_CONTAINER(align),close_button);
 122.108 +@@ -1597,7 +1597,7 @@
 122.109 + 	hbox1 = gtk_hbox_new (FALSE,12);
 122.110 + 	gtk_box_pack_start (GTK_BOX (vbox1),hbox1,TRUE,TRUE,0);
 122.111 + 
 122.112 +-	pixbuf = gtk_icon_theme_load_icon(icon_theme,"gnome-mime-application-zip",40,0,NULL);
 122.113 ++	pixbuf = gtk_icon_theme_load_icon(icon_theme,"application-zip",40,0,NULL);
 122.114 + 	if (!pixbuf) pixbuf = gtk_icon_theme_load_icon(icon_theme,"package-x-generic",40,GTK_ICON_LOOKUP_FORCE_SIZE,NULL);
 122.115 + 	icon_pixbuf = gtk_image_new_from_pixbuf(pixbuf);
 122.116 + 	g_object_unref(pixbuf);
 122.117 +--- a/src/pref_dialog.c
 122.118 ++++ b/src/pref_dialog.c
 122.119 +@@ -155,7 +155,7 @@
 122.120 + 
 122.121 + 	prefs_data->prefs_liststore = gtk_list_store_new (3,GDK_TYPE_PIXBUF,G_TYPE_STRING,G_TYPE_UINT);
 122.122 + 	gtk_list_store_append (prefs_data->prefs_liststore,&iter);
 122.123 +-	icon_pixbuf = gtk_icon_theme_load_icon(icon_theme,"gnome-mime-application-zip",40,0,NULL);
 122.124 ++	icon_pixbuf = gtk_icon_theme_load_icon(icon_theme,"application-zip",40,0,NULL);
 122.125 + 	if (!icon_pixbuf) icon_pixbuf = gtk_icon_theme_load_icon(icon_theme,"package-x-generic",32,GTK_ICON_LOOKUP_FORCE_SIZE,NULL);
 122.126 + 	gtk_list_store_set (prefs_data->prefs_liststore, &iter, 0, icon_pixbuf, 1, _("Archive"),2,0,-1);
 122.127 + 	if(icon_pixbuf != NULL)
   123.1 --- a/xfce4-mixer/receipt	Mon Jul 30 23:44:42 2018 +0300
   123.2 +++ b/xfce4-mixer/receipt	Tue Aug 07 00:30:45 2018 +0300
   123.3 @@ -12,7 +12,7 @@
   123.4  WGET_URL="http://archive.xfce.org/src/apps/$PACKAGE/${VERSION%.*}/$TARBALL"
   123.5  
   123.6  BUILD_DEPENDS="intltool dbus-glib-dev gst0-plugins-base-dev gtk+-dev \
   123.7 -libunique-dev libxfce4util-dev libxfce4ui-dev xfce4-panel-dev libkeybinder-dev \
   123.8 +libunique-dev libxfce4util-dev libxfce4ui-dev xfce4-panel-dev keybinder-dev \
   123.9  startup-notification-dev xorg-xcb-util-dev"
  123.10  
  123.11  compile_rules() {
  123.12 @@ -27,6 +27,6 @@
  123.13  genpkg_rules() {
  123.14  	copy @std
  123.15  	DEPENDS="cairo dbus-glib gdk-pixbuf glib gst0-plugins-base gstreamer0 gtk+ \
  123.16 -	libkeybinder libunique libxfce4ui libxfce4util xfce4-panel xfconf"
  123.17 +	keybinder libunique libxfce4ui libxfce4util xfce4-panel xfconf"
  123.18  	TAGS="Xfce"
  123.19  }
   124.1 --- a/xfce4-volumed/receipt	Mon Jul 30 23:44:42 2018 +0300
   124.2 +++ b/xfce4-volumed/receipt	Tue Aug 07 00:30:45 2018 +0300
   124.3 @@ -12,7 +12,7 @@
   124.4  WGET_URL="http://archive.xfce.org/src/apps/xfce4-volumed/${VERSION%.*}/$TARBALL"
   124.5  
   124.6  BUILD_DEPENDS="xfconf-dev gstreamer0-dev gst0-plugins-base-dev \
   124.7 -libkeybinder-dev libxml2-dev libnotify-dev"
   124.8 +keybinder-dev libxml2-dev libnotify-dev"
   124.9  
  124.10  compile_rules() {
  124.11  	./configure $CONFIGURE_ARGS &&
  124.12 @@ -22,7 +22,7 @@
  124.13  
  124.14  genpkg_rules() {
  124.15  	copy @std
  124.16 -	DEPENDS="glib gst0-plugins-base gstreamer0 gtk+ libkeybinder libnotify \
  124.17 +	DEPENDS="glib gst0-plugins-base gstreamer0 gtk+ keybinder libnotify \
  124.18  	xfconf"
  124.19  	TAGS="Xfce"
  124.20  }
   125.1 --- a/xorg-libXScrnSaver/receipt	Mon Jul 30 23:44:42 2018 +0300
   125.2 +++ b/xorg-libXScrnSaver/receipt	Tue Aug 07 00:30:45 2018 +0300
   125.3 @@ -1,7 +1,7 @@
   125.4  # SliTaz package receipt v2.
   125.5  
   125.6  PACKAGE="xorg-libXScrnSaver"
   125.7 -VERSION="1.2.2"
   125.8 +VERSION="1.2.3"
   125.9  CATEGORY="x-window"
  125.10  SHORT_DESC="MIT-SCREEN-SAVER extension"
  125.11  MAINTAINER="al.bobylev@gmail.com"
   126.1 --- a/xorg-libXcomposite/receipt	Mon Jul 30 23:44:42 2018 +0300
   126.2 +++ b/xorg-libXcomposite/receipt	Tue Aug 07 00:30:45 2018 +0300
   126.3 @@ -8,7 +8,7 @@
   126.4  LICENSE="MIT"
   126.5  WEB_SITE="https://www.x.org/wiki/"
   126.6  LFS="http://www.linuxfromscratch.org/blfs/view/stable/x/x7lib.html"
   126.7 -REPOLOGY="libXcomposite"
   126.8 +REPOLOGY="libxcomposite"
   126.9  
  126.10  TARBALL="libXcomposite-$VERSION.tar.bz2"
  126.11  WGET_URL="$XORG_MIRROR/lib/$TARBALL"
   127.1 --- a/xorg-libXcursor/receipt	Mon Jul 30 23:44:42 2018 +0300
   127.2 +++ b/xorg-libXcursor/receipt	Tue Aug 07 00:30:45 2018 +0300
   127.3 @@ -1,7 +1,7 @@
   127.4  # SliTaz package receipt v2.
   127.5  
   127.6  PACKAGE="xorg-libXcursor"
   127.7 -VERSION="1.1.14"
   127.8 +VERSION="1.1.15"
   127.9  CATEGORY="x-window"
  127.10  SHORT_DESC="Cursor extension"
  127.11  MAINTAINER="pankso@slitaz.org"
   128.1 --- a/xorg-libXfont2/receipt	Mon Jul 30 23:44:42 2018 +0300
   128.2 +++ b/xorg-libXfont2/receipt	Tue Aug 07 00:30:45 2018 +0300
   128.3 @@ -1,7 +1,7 @@
   128.4  # SliTaz package receipt v2.
   128.5  
   128.6  PACKAGE="xorg-libXfont2"
   128.7 -VERSION="2.0.1"
   128.8 +VERSION="2.0.3"
   128.9  CATEGORY="x-window"
  128.10  SHORT_DESC="X font2 handling library for server & utilities"
  128.11  MAINTAINER="al.bobylev@gmail.com"
   129.1 --- a/xorg-libXinerama/receipt	Mon Jul 30 23:44:42 2018 +0300
   129.2 +++ b/xorg-libXinerama/receipt	Tue Aug 07 00:30:45 2018 +0300
   129.3 @@ -1,7 +1,7 @@
   129.4  # SliTaz package receipt v2.
   129.5  
   129.6  PACKAGE="xorg-libXinerama"
   129.7 -VERSION="1.1.3"
   129.8 +VERSION="1.1.4"
   129.9  CATEGORY="x-window"
  129.10  SHORT_DESC="Xinerama protocol library"
  129.11  MAINTAINER="pankso@slitaz.org"
   130.1 --- a/xorg-libXxf86misc/receipt	Mon Jul 30 23:44:42 2018 +0300
   130.2 +++ b/xorg-libXxf86misc/receipt	Tue Aug 07 00:30:45 2018 +0300
   130.3 @@ -1,7 +1,7 @@
   130.4  # SliTaz package receipt v2.
   130.5  
   130.6  PACKAGE="xorg-libXxf86misc"
   130.7 -VERSION="1.0.3"
   130.8 +VERSION="1.0.4"
   130.9  CATEGORY="x-window"
  130.10  SHORT_DESC="XFree86-MISC extension library"
  130.11  MAINTAINER="al.bobylev@gmail.com"
   131.1 --- a/xorg-libdmx/receipt	Mon Jul 30 23:44:42 2018 +0300
   131.2 +++ b/xorg-libdmx/receipt	Tue Aug 07 00:30:45 2018 +0300
   131.3 @@ -1,7 +1,7 @@
   131.4  # SliTaz package receipt v2.
   131.5  
   131.6  PACKAGE="xorg-libdmx"
   131.7 -VERSION="1.1.3"
   131.8 +VERSION="1.1.4"
   131.9  CATEGORY="x-window"
  131.10  SHORT_DESC="Xorg DMX library"
  131.11  MAINTAINER="pankso@slitaz.org"
   132.1 --- a/xorg-libpciaccess/receipt	Mon Jul 30 23:44:42 2018 +0300
   132.2 +++ b/xorg-libpciaccess/receipt	Tue Aug 07 00:30:45 2018 +0300
   132.3 @@ -1,7 +1,7 @@
   132.4  # SliTaz package receipt v2.
   132.5  
   132.6  PACKAGE="xorg-libpciaccess"
   132.7 -VERSION="0.13.5"
   132.8 +VERSION="0.14"
   132.9  CATEGORY="x-window"
  132.10  SHORT_DESC="Xorg server module"
  132.11  MAINTAINER="pankso@slitaz.org"
   133.1 --- a/xorg-libxcb/receipt	Mon Jul 30 23:44:42 2018 +0300
   133.2 +++ b/xorg-libxcb/receipt	Tue Aug 07 00:30:45 2018 +0300
   133.3 @@ -1,7 +1,7 @@
   133.4  # SliTaz package receipt v2.
   133.5  
   133.6  PACKAGE="xorg-libxcb"
   133.7 -VERSION="1.12"
   133.8 +VERSION="1.13"
   133.9  CATEGORY="x-window"
  133.10  SHORT_DESC="A C binding to the X11 protocol"
  133.11  MAINTAINER="pankso@slitaz.org"
   134.1 --- a/xorg-xcb-proto/receipt	Mon Jul 30 23:44:42 2018 +0300
   134.2 +++ b/xorg-xcb-proto/receipt	Tue Aug 07 00:30:45 2018 +0300
   134.3 @@ -1,20 +1,20 @@
   134.4  # SliTaz package receipt v2.
   134.5  
   134.6  PACKAGE="xorg-xcb-proto"
   134.7 -VERSION="1.12"
   134.8 +VERSION="1.13"
   134.9  CATEGORY="development"
  134.10  SHORT_DESC="X protocol descriptions for XCB"
  134.11  MAINTAINER="mallory@sweetpeople.org"
  134.12  LICENSE="MIT"
  134.13  WEB_SITE="https://xcb.freedesktop.org/"
  134.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/x/xcb-proto.html"
  134.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/x/xcb-proto.html"
  134.16  REPOLOGY="xcb-proto"
  134.17  
  134.18  TARBALL="xcb-proto-$VERSION.tar.bz2"
  134.19  WGET_URL="$XORG_MIRROR/xcb/$TARBALL"
  134.20  
  134.21  BUILD_DEPENDS_arm=" "
  134.22 -BUILD_DEPENDS="patch python-dev libxml2-tools"
  134.23 +BUILD_DEPENDS="python-dev libxml2-tools"
  134.24  
  134.25  compile_rules() {
  134.26  	./configure $CONFIGURE_ARGS &&
   135.1 --- a/xorg-xcb-proto/stuff/patches/series	Mon Jul 30 23:44:42 2018 +0300
   135.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   135.3 @@ -1,1 +0,0 @@
   135.4 -xcb-proto-1.12-schema-1.patch
   136.1 --- a/xorg-xcb-proto/stuff/patches/xcb-proto-1.12-schema-1.patch	Mon Jul 30 23:44:42 2018 +0300
   136.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   136.3 @@ -1,52 +0,0 @@
   136.4 -Submitted By: Bruce Dubbs <bdubbs at linuxfromscratch dot org>
   136.5 -Date: 2016-06-01
   136.6 -Initial Package Version: 1.12
   136.7 -Upstream Status: Not Committed
   136.8 -Origin: https://lists.freedesktop.org/archives/xcb/2016-February/010676.html
   136.9 -Description: Fixes make check
  136.10 -
  136.11 -
  136.12 ---- a/src/xcb.xsd
  136.13 -+++ b/src/xcb.xsd
  136.14 -@@ -44,6 +44,15 @@ authorization from the authors.
  136.15 -     <xsd:complexType>
  136.16 -       <xsd:attribute name="bytes" type="xsd:integer" use="optional" />
  136.17 -       <xsd:attribute name="align" type="xsd:integer" use="optional" />
  136.18 -+      <xsd:attribute name="serialize" type="xsd:boolean" use="optional" />
  136.19 -+    </xsd:complexType>
  136.20 -+  </xsd:element>
  136.21 -+
  136.22 -+  <!-- Alignment -->
  136.23 -+  <xsd:element name="required_start_align" >
  136.24 -+    <xsd:complexType>
  136.25 -+      <xsd:attribute name="align" type="xsd:integer" use="required" />
  136.26 -+      <xsd:attribute name="offset" type="xsd:integer" use="optional" />
  136.27 -     </xsd:complexType>
  136.28 -   </xsd:element>
  136.29 - 
  136.30 -@@ -76,14 +85,13 @@ authorization from the authors.
  136.31 -     <xsd:sequence>
  136.32 -       <!-- switch(expression) -->
  136.33 -       <xsd:group ref="expression" minOccurs="1" maxOccurs="1" />
  136.34 -+      <xsd:element ref="required_start_align" minOccurs="0" maxOccurs="1" />
  136.35 -       <xsd:choice>
  136.36 -         <!-- bitcase expression - bit test -->
  136.37 -         <xsd:element name="bitcase" type="caseexpr" minOccurs="0" maxOccurs="unbounded" />
  136.38 -         <!-- case expression - value test -->
  136.39 -         <xsd:element name="case" type="caseexpr" minOccurs="0" maxOccurs="unbounded" />
  136.40 -       </xsd:choice>
  136.41 --      <!-- default: -->
  136.42 --      <xsd:group ref="fields" minOccurs="0" maxOccurs="1" />
  136.43 -     </xsd:sequence>
  136.44 -     <xsd:attribute name="name" type="xsd:string" use="required" />
  136.45 -   </xsd:complexType>
  136.46 -@@ -201,6 +209,7 @@ authorization from the authors.
  136.47 -       <xsd:element ref="field" />
  136.48 -       <xsd:element ref="list" />
  136.49 -       <xsd:element ref="fd" />
  136.50 -+      <xsd:element ref="required_start_align" />
  136.51 -     </xsd:choice>
  136.52 -   </xsd:group>
  136.53 - 
  136.54 -
  136.55 -
   137.1 --- a/xorg-xcompmgr/receipt	Mon Jul 30 23:44:42 2018 +0300
   137.2 +++ b/xorg-xcompmgr/receipt	Tue Aug 07 00:30:45 2018 +0300
   137.3 @@ -1,7 +1,7 @@
   137.4  # SliTaz package receipt v2.
   137.5  
   137.6  PACKAGE="xorg-xcompmgr"
   137.7 -VERSION="1.1.6"
   137.8 +VERSION="1.1.7"
   137.9  CATEGORY="x-window"
  137.10  SHORT_DESC="X composite manager"
  137.11  MAINTAINER="pankso@slitaz.org"
   138.1 --- a/xorg-xf86-input-evdev/receipt	Mon Jul 30 23:44:42 2018 +0300
   138.2 +++ b/xorg-xf86-input-evdev/receipt	Tue Aug 07 00:30:45 2018 +0300
   138.3 @@ -1,7 +1,7 @@
   138.4  # SliTaz package receipt v2.
   138.5  
   138.6  PACKAGE="xorg-xf86-input-evdev"
   138.7 -VERSION="2.10.5"
   138.8 +VERSION="2.10.6"
   138.9  CATEGORY="x-window"
  138.10  SHORT_DESC="Generic Linux input driver"
  138.11  MAINTAINER="pankso@slitaz.org"
   139.1 --- a/xorg-xf86-input-mouse/receipt	Mon Jul 30 23:44:42 2018 +0300
   139.2 +++ b/xorg-xf86-input-mouse/receipt	Tue Aug 07 00:30:45 2018 +0300
   139.3 @@ -1,7 +1,7 @@
   139.4  # SliTaz package receipt v2.
   139.5  
   139.6  PACKAGE="xorg-xf86-input-mouse"
   139.7 -VERSION="1.9.2"
   139.8 +VERSION="1.9.3"
   139.9  CATEGORY="x-window"
  139.10  SHORT_DESC="Xorg mouse input driver"
  139.11  MAINTAINER="pankso@slitaz.org"
  139.12 @@ -27,11 +27,11 @@
  139.13  	case $PACKAGE in
  139.14  		*-mouse)
  139.15  			copy @std
  139.16 -			DEPENDS="xorg-server"
  139.17 +			DEPENDS="xorg-server" # implicit
  139.18  			;;
  139.19  		*-dev)
  139.20  			copy @dev
  139.21 -			DEPENDS="xorg-xf86-input-mouse xorg-server-dev"
  139.22 +			DEPENDS="xorg-xf86-input-mouse xorg-server-dev" # implicit
  139.23  			;;
  139.24  	esac
  139.25  }
   140.1 --- a/xorg-xf86-input-synaptics/receipt	Mon Jul 30 23:44:42 2018 +0300
   140.2 +++ b/xorg-xf86-input-synaptics/receipt	Tue Aug 07 00:30:45 2018 +0300
   140.3 @@ -1,7 +1,7 @@
   140.4  # SliTaz package receipt v2.
   140.5  
   140.6  PACKAGE="xorg-xf86-input-synaptics"
   140.7 -VERSION="1.9.0"
   140.8 +VERSION="1.9.1"
   140.9  CATEGORY="x-window"
  140.10  SHORT_DESC="Xorg input driver for touchpads"
  140.11  MAINTAINER="pankso@slitaz.org"
   141.1 --- a/xorg-xf86-video-fbdev/receipt	Mon Jul 30 23:44:42 2018 +0300
   141.2 +++ b/xorg-xf86-video-fbdev/receipt	Tue Aug 07 00:30:45 2018 +0300
   141.3 @@ -1,7 +1,7 @@
   141.4  # SliTaz package receipt v2.
   141.5  
   141.6  PACKAGE="xorg-xf86-video-fbdev"
   141.7 -VERSION="0.4.4"
   141.8 +VERSION="0.5.0"
   141.9  CATEGORY="x-window"
  141.10  SHORT_DESC="Xorg video driver for framebuffer device"
  141.11  MAINTAINER="pankso@slitaz.org"
  141.12 @@ -26,6 +26,6 @@
  141.13  
  141.14  genpkg_rules() {
  141.15  	copy @std
  141.16 -	DEPENDS="xorg-server"
  141.17 +	DEPENDS="xorg-server" # implicit
  141.18  	TAGS="xorg display"
  141.19  }
   142.1 --- a/xorg-xf86-video-intel/receipt	Mon Jul 30 23:44:42 2018 +0300
   142.2 +++ b/xorg-xf86-video-intel/receipt	Tue Aug 07 00:30:45 2018 +0300
   142.3 @@ -1,7 +1,7 @@
   142.4  # SliTaz package receipt v2.
   142.5  
   142.6  PACKAGE="xorg-xf86-video-intel"
   142.7 -VERSION="20170216"
   142.8 +VERSION="2.99.917"
   142.9  CATEGORY="x-window"
  142.10  SHORT_DESC="Xorg driver for Intel integrated graphics chipsets"
  142.11  MAINTAINER="pankso@slitaz.org"
  142.12 @@ -9,33 +9,39 @@
  142.13  WEB_SITE="https://www.x.org/wiki/intel/"
  142.14  REPOLOGY="xdrv:intel"
  142.15  
  142.16 -TARBALL="xf86-video-intel-$VERSION.tar.xz"
  142.17 -WGET_URL="http://anduin.linuxfromscratch.org/BLFS/xf86-video-intel/$TARBALL"
  142.18 +TARBALL="xf86-video-intel-$VERSION.tar.bz2"
  142.19 +WGET_URL="https://www.x.org/releases/individual/driver/$TARBALL"
  142.20  
  142.21  BUILD_DEPENDS="xorg-util-macros eudev-dev xorg-libX11-dev \
  142.22  xorg-libXcomposite-dev xorg-libXdamage-dev xorg-libXrender-dev \
  142.23  xorg-libXrandr-dev cairo-dev xorg-libxshmfence-dev xorg-libXxf86vm-dev \
  142.24  libdrm-dev xorg-libXinerama-dev xorg-libXcursor-dev xorg-libXtst-dev \
  142.25  xorg-libXScrnSaver-dev xorg-server-dev xorg-libXvMC-dev xorg-xcb-util-dev \
  142.26 -xorg-libXfont2-dev"
  142.27 +xorg-libXfont2-dev automake libtool git"
  142.28  
  142.29  compile_rules() {
  142.30 +	autoreconf -vif
  142.31 +	export LDFLAGS="$LDFLAGS -Wl,-z,lazy"
  142.32 +
  142.33  	./configure \
  142.34  		--enable-kms-only \
  142.35  		--enable-uxa \
  142.36 +		--enable-xvmc \
  142.37 +		--disable-selective-werror \
  142.38 +		--with-default-dri=3 \
  142.39  		$CONFIGURE_ARGS &&
  142.40  	fix libtool &&
  142.41  	make &&
  142.42 -	make install
  142.43 +	make install || return 1
  142.44 +
  142.45 +	chmod o-x $install/usr/libexec/xf86-video-intel-backlight-helper
  142.46  }
  142.47  
  142.48  genpkg_rules() {
  142.49  	copy @std
  142.50  	DEPENDS="eudev libdrm libdrm-intel xorg-libX11 xorg-libXScrnSaver \
  142.51 -	xorg-libXau xorg-libXcursor xorg-libXdamage xorg-libXdmcp \
  142.52 -	xorg-libXext xorg-libXfixes xorg-libXi xorg-libXinerama \
  142.53 -	xorg-libXrandr xorg-libXrender xorg-libXtst xorg-libXv \
  142.54 -	xorg-libXvMC xorg-libpciaccess xorg-libxcb xorg-libxshmfence \
  142.55 -	xorg-pixman xorg-xcb-util"
  142.56 +	xorg-libXcursor xorg-libXdamage xorg-libXext xorg-libXfixes \
  142.57 +	xorg-libXinerama xorg-libXrandr xorg-libXrender xorg-libXtst xorg-libXv \
  142.58 +	xorg-libXvMC xorg-libxcb xorg-libxshmfence xorg-pixman xorg-xcb-util"
  142.59  	TAGS="xorg display"
  142.60  }
   143.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   143.2 +++ b/xorg-xf86-video-intel/stuff/patches/git.patch	Tue Aug 07 00:30:45 2018 +0300
   143.3 @@ -0,0 +1,43164 @@
   143.4 +diff --git a/Makefile.am b/Makefile.am
   143.5 +index 418fdc92..de5fbe12 100644
   143.6 +--- a/Makefile.am
   143.7 ++++ b/Makefile.am
   143.8 +@@ -18,14 +18,16 @@
   143.9 + #  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  143.10 + #  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  143.11 + 
  143.12 +-ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
  143.13 ++#Having problems passing through user flags as libtool complains
  143.14 ++#ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
  143.15 ++ACLOCAL_AMFLAGS = -I m4
  143.16 + 
  143.17 + SUBDIRS = man libobj xvmc src tools
  143.18 + 
  143.19 + MAINTAINERCLEANFILES = ChangeLog INSTALL
  143.20 + 
  143.21 + if HAVE_X11
  143.22 +-SUBDIRS += test
  143.23 ++SUBDIRS += test benchmarks
  143.24 + endif
  143.25 + 
  143.26 + .PHONY: ChangeLog INSTALL
  143.27 +diff --git a/NEWS b/NEWS
  143.28 +index 604b9cce..0e200332 100644
  143.29 +--- a/NEWS
  143.30 ++++ b/NEWS
  143.31 +@@ -21,7 +21,7 @@ should make one more snapshot before an imminent release.
  143.32 +    Before kernel 3.19, O_NONBLOCK support is broken and so we must avoid
  143.33 +    reading if we are not expecting an event.
  143.34 + 
  143.35 +- * Backwards compatibilty fix for fake triple buffering with PRIME and
  143.36 ++ * Backwards compatibility fix for fake triple buffering with PRIME and
  143.37 +    Xorg-1.15
  143.38 +    https://bugs.freedesktop.org/show_bug.cgi?id=85144#c12
  143.39 + 
  143.40 +@@ -51,7 +51,7 @@ should make one more snapshot before an imminent release.
  143.41 + Snapshot 2.99.916 (2014-09-08)
  143.42 + ==============================
  143.43 + Quick update for MST in UXA - we need to hook up the RandR outputs for
  143.44 +-dynamicaly added connectors.
  143.45 ++dynamically added connectors.
  143.46 + 
  143.47 + 
  143.48 + Snapshot 2.99.915 (2014-09-08)
  143.49 +@@ -503,7 +503,7 @@ release.
  143.50 +    backlight property is queried whilst the connector is disabled
  143.51 +    https://bugs.freedesktop.org/show_bug.cgi?id=70406
  143.52 + 
  143.53 +- * Pad GETCONNECTOR ioctl for compatability between 32/64-bit userspace
  143.54 ++ * Pad GETCONNECTOR ioctl for compatibility between 32/64-bit userspace
  143.55 +    and kernel
  143.56 + 
  143.57 +  * Handle long glyph runs correctly
  143.58 +@@ -523,7 +523,7 @@ snapshot beforehand to push out the bug fixes from the last week.
  143.59 + 
  143.60 +  * Fix video output using sprites when changing the image size
  143.61 + 
  143.62 +- * Apply more restrictive tile constaints for 915g class devices
  143.63 ++ * Apply more restrictive tile constraints for 915g class devices
  143.64 +    https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/1232546
  143.65 + 
  143.66 +  * Ensure all overlapping rectangles are drawn for XRenderFillRectangles
  143.67 +@@ -1132,7 +1132,7 @@ operation.
  143.68 +  * Explicitly prevent ring-switching for synchronized rendering to
  143.69 +    scanouts (for vsync).
  143.70 + 
  143.71 +- * Clip dirty region to slave pixmaps (otherwise UDL is nigh unusuable)
  143.72 ++ * Clip dirty region to slave pixmaps (otherwise UDL is nigh unusable)
  143.73 +    https://bugs.freedesktop.org/show_bug.cgi?id=59539
  143.74 + 
  143.75 + 
  143.76 +@@ -1226,7 +1226,7 @@ Release 2.20.15 (2012-12-03)
  143.77 + ============================
  143.78 + And lo, enabling more of the common acceleration paths for gen4 revealed
  143.79 + another lurking bug - something is wrong with how we prepare Y-tiling
  143.80 +-surfaces for rendering. For the time being, we can surreptiously disable
  143.81 ++surfaces for rendering. For the time being, we can surreptitiously disable
  143.82 + them for gen4 and avoid hitting GPU hangs.
  143.83 + 
  143.84 +  * Avoid clobbering the render state after failing to convert the
  143.85 +@@ -1515,7 +1515,7 @@ Release 2.20.5 (2012-08-26)
  143.86 + Another silly bug found, another small bugfix release. The goal was for
  143.87 + the driver to bind to all Intel devices supported by the kernel.
  143.88 + Unfortunately we were too successful and started claiming Pouslbo,
  143.89 +-Medfield and Cedarview devices which are still encumbered by propietary
  143.90 ++Medfield and Cedarview devices which are still encumbered by proprietary
  143.91 + IP and not supported by this driver.
  143.92 + 
  143.93 + Bugs fixed since 2.20.4:
  143.94 +diff --git a/README b/README
  143.95 +index cf4d88d8..348983b4 100644
  143.96 +--- a/README
  143.97 ++++ b/README
  143.98 +@@ -15,9 +15,9 @@ Intel graphics chipsets including:
  143.99 + 	G/Q33,G/Q35,G41,G/Q43,G/GM/Q45
 143.100 + 	PineView-M (Atom N400 series)
 143.101 + 	PineView-D (Atom D400/D500 series)
 143.102 +-	Intel(R) HD Graphics: 2000-6000,
 143.103 +-	Intel(R) Iris(TM) Graphics: 5100/6100, and
 143.104 +-	Intel(R) Iris(TM) Pro Graphics: 5200/6200/P6300.
 143.105 ++	Intel(R) HD Graphics,
 143.106 ++	Intel(R) Iris(TM) Graphics,
 143.107 ++	Intel(R) Iris(TM) Pro Graphics.
 143.108 + 
 143.109 + Where to get more information about the driver
 143.110 + ----------------------------------------------
 143.111 +diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
 143.112 +new file mode 100644
 143.113 +index 00000000..301c0129
 143.114 +--- /dev/null
 143.115 ++++ b/benchmarks/.gitignore
 143.116 +@@ -0,0 +1,2 @@
 143.117 ++dri2-swap
 143.118 ++dri3-swap
 143.119 +diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
 143.120 +new file mode 100644
 143.121 +index 00000000..4976e8a3
 143.122 +--- /dev/null
 143.123 ++++ b/benchmarks/Makefile.am
 143.124 +@@ -0,0 +1,14 @@
 143.125 ++AM_CFLAGS = @CWARNFLAGS@ $(X11_CFLAGS) $(DRM_CFLAGS)
 143.126 ++LDADD = $(X11_LIBS) $(DRM_LIBS) $(CLOCK_GETTIME_LIBS)
 143.127 ++
 143.128 ++check_PROGRAMS =
 143.129 ++
 143.130 ++if DRI2
 143.131 ++check_PROGRAMS += dri2-swap
 143.132 ++endif
 143.133 ++
 143.134 ++if DRI3
 143.135 ++check_PROGRAMS += dri3-swap
 143.136 ++AM_CFLAGS += $(X11_DRI3_CFLAGS)
 143.137 ++LDADD += $(X11_DRI3_LIBS)
 143.138 ++endif
 143.139 +diff --git a/benchmarks/dri2-swap.c b/benchmarks/dri2-swap.c
 143.140 +new file mode 100644
 143.141 +index 00000000..3d9d30aa
 143.142 +--- /dev/null
 143.143 ++++ b/benchmarks/dri2-swap.c
 143.144 +@@ -0,0 +1,588 @@
 143.145 ++/*
 143.146 ++ * Copyright (c) 2015 Intel Corporation
 143.147 ++ *
 143.148 ++ * Permission is hereby granted, free of charge, to any person obtaining a
 143.149 ++ * copy of this software and associated documentation files (the "Software"),
 143.150 ++ * to deal in the Software without restriction, including without limitation
 143.151 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 143.152 ++ * and/or sell copies of the Software, and to permit persons to whom the
 143.153 ++ * Software is furnished to do so, subject to the following conditions:
 143.154 ++ *
 143.155 ++ * The above copyright notice and this permission notice (including the next
 143.156 ++ * paragraph) shall be included in all copies or substantial portions of the
 143.157 ++ * Software.
 143.158 ++ *
 143.159 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 143.160 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 143.161 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 143.162 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 143.163 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 143.164 ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 143.165 ++ * SOFTWARE.
 143.166 ++ *
 143.167 ++ */
 143.168 ++
 143.169 ++#ifdef HAVE_CONFIG_H
 143.170 ++#include "config.h"
 143.171 ++#endif
 143.172 ++
 143.173 ++#include <X11/Xlib.h>
 143.174 ++#include <X11/Xatom.h>
 143.175 ++#include <X11/Xlib-xcb.h>
 143.176 ++#include <X11/Xutil.h>
 143.177 ++#include <X11/Xlibint.h>
 143.178 ++#include <X11/extensions/dpms.h>
 143.179 ++#include <X11/extensions/randr.h>
 143.180 ++#include <X11/extensions/Xcomposite.h>
 143.181 ++#include <X11/extensions/Xdamage.h>
 143.182 ++#include <X11/extensions/Xrandr.h>
 143.183 ++#include <xcb/xcb.h>
 143.184 ++#include <xcb/dri2.h>
 143.185 ++#include <xf86drm.h>
 143.186 ++
 143.187 ++#include <stdio.h>
 143.188 ++#include <string.h>
 143.189 ++#include <fcntl.h>
 143.190 ++#include <unistd.h>
 143.191 ++#include <assert.h>
 143.192 ++#include <errno.h>
 143.193 ++#include <setjmp.h>
 143.194 ++#include <signal.h>
 143.195 ++
 143.196 ++#include <X11/Xlibint.h>
 143.197 ++#include <X11/extensions/Xext.h>
 143.198 ++#include <X11/extensions/extutil.h>
 143.199 ++#include <X11/extensions/dri2proto.h>
 143.200 ++#include <X11/extensions/dri2tokens.h>
 143.201 ++#include <X11/extensions/Xfixes.h>
 143.202 ++
 143.203 ++static char dri2ExtensionName[] = DRI2_NAME;
 143.204 ++static XExtensionInfo *dri2Info;
 143.205 ++static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
 143.206 ++
 143.207 ++static Bool
 143.208 ++DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
 143.209 ++static Status
 143.210 ++DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
 143.211 ++static int
 143.212 ++DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code);
 143.213 ++
 143.214 ++static /* const */ XExtensionHooks dri2ExtensionHooks = {
 143.215 ++  NULL,                   /* create_gc */
 143.216 ++  NULL,                   /* copy_gc */
 143.217 ++  NULL,                   /* flush_gc */
 143.218 ++  NULL,                   /* free_gc */
 143.219 ++  NULL,                   /* create_font */
 143.220 ++  NULL,                   /* free_font */
 143.221 ++  DRI2CloseDisplay,       /* close_display */
 143.222 ++  DRI2WireToEvent,        /* wire_to_event */
 143.223 ++  DRI2EventToWire,        /* event_to_wire */
 143.224 ++  DRI2Error,              /* error */
 143.225 ++  NULL,                   /* error_string */
 143.226 ++};
 143.227 ++
 143.228 ++static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
 143.229 ++                                   dri2Info,
 143.230 ++                                   dri2ExtensionName,
 143.231 ++                                   &dri2ExtensionHooks,
 143.232 ++                                   0, NULL)
 143.233 ++
 143.234 ++static Bool
 143.235 ++DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
 143.236 ++{
 143.237 ++   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
 143.238 ++
 143.239 ++   XextCheckExtension(dpy, info, dri2ExtensionName, False);
 143.240 ++
 143.241 ++   switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
 143.242 ++#ifdef X_DRI2SwapBuffers
 143.243 ++   case DRI2_BufferSwapComplete:
 143.244 ++      return False;
 143.245 ++#endif
 143.246 ++#ifdef DRI2_InvalidateBuffers
 143.247 ++   case DRI2_InvalidateBuffers:
 143.248 ++      return False;
 143.249 ++#endif
 143.250 ++   default:
 143.251 ++      /* client doesn't support server event */
 143.252 ++      break;
 143.253 ++   }
 143.254 ++
 143.255 ++   return False;
 143.256 ++}
 143.257 ++
 143.258 ++/* We don't actually support this.  It doesn't make sense for clients to
 143.259 ++ * send each other DRI2 events.
 143.260 ++ */
 143.261 ++static Status
 143.262 ++DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
 143.263 ++{
 143.264 ++   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
 143.265 ++
 143.266 ++   XextCheckExtension(dpy, info, dri2ExtensionName, False);
 143.267 ++
 143.268 ++   switch (event->type) {
 143.269 ++   default:
 143.270 ++      /* client doesn't support server event */
 143.271 ++      break;
 143.272 ++   }
 143.273 ++
 143.274 ++   return Success;
 143.275 ++}
 143.276 ++
 143.277 ++static int
 143.278 ++DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code)
 143.279 ++{
 143.280 ++	if (err->majorCode == codes->major_opcode &&
 143.281 ++	    err->errorCode == BadDrawable &&
 143.282 ++	    err->minorCode == X_DRI2CopyRegion)
 143.283 ++		return True;
 143.284 ++
 143.285 ++	/* If the X drawable was destroyed before the GLX drawable, the
 143.286 ++	 * DRI2 drawble will be gone by the time we call
 143.287 ++	 * DRI2DestroyDrawable.  So just ignore BadDrawable here. */
 143.288 ++	if (err->majorCode == codes->major_opcode &&
 143.289 ++	    err->errorCode == BadDrawable &&
 143.290 ++	    err->minorCode == X_DRI2DestroyDrawable)
 143.291 ++		return True;
 143.292 ++
 143.293 ++	/* If the server is non-local DRI2Connect will raise BadRequest.
 143.294 ++	 * Swallow this so that DRI2Connect can signal this in its return code */
 143.295 ++	if (err->majorCode == codes->major_opcode &&
 143.296 ++	    err->minorCode == X_DRI2Connect &&
 143.297 ++	    err->errorCode == BadRequest) {
 143.298 ++		*ret_code = False;
 143.299 ++		return True;
 143.300 ++	}
 143.301 ++
 143.302 ++	return False;
 143.303 ++}
 143.304 ++
 143.305 ++static Bool
 143.306 ++DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
 143.307 ++{
 143.308 ++	XExtDisplayInfo *info = DRI2FindDisplay(dpy);
 143.309 ++
 143.310 ++	if (XextHasExtension(info)) {
 143.311 ++		*eventBase = info->codes->first_event;
 143.312 ++		*errorBase = info->codes->first_error;
 143.313 ++		return True;
 143.314 ++	}
 143.315 ++
 143.316 ++	return False;
 143.317 ++}
 143.318 ++
 143.319 ++static Bool
 143.320 ++DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
 143.321 ++{
 143.322 ++	XExtDisplayInfo *info = DRI2FindDisplay(dpy);
 143.323 ++	xDRI2ConnectReply rep;
 143.324 ++	xDRI2ConnectReq *req;
 143.325 ++
 143.326 ++	XextCheckExtension(dpy, info, dri2ExtensionName, False);
 143.327 ++
 143.328 ++	LockDisplay(dpy);
 143.329 ++	GetReq(DRI2Connect, req);
 143.330 ++	req->reqType = info->codes->major_opcode;
 143.331 ++	req->dri2ReqType = X_DRI2Connect;
 143.332 ++	req->window = window;
 143.333 ++	req->driverType = DRI2DriverDRI;
 143.334 ++	if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
 143.335 ++		UnlockDisplay(dpy);
 143.336 ++		SyncHandle();
 143.337 ++		return False;
 143.338 ++	}
 143.339 ++
 143.340 ++	if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
 143.341 ++		UnlockDisplay(dpy);
 143.342 ++		SyncHandle();
 143.343 ++		return False;
 143.344 ++	}
 143.345 ++
 143.346 ++	*driverName = Xmalloc(rep.driverNameLength + 1);
 143.347 ++	if (*driverName == NULL) {
 143.348 ++		_XEatData(dpy,
 143.349 ++			  ((rep.driverNameLength + 3) & ~3) +
 143.350 ++			  ((rep.deviceNameLength + 3) & ~3));
 143.351 ++		UnlockDisplay(dpy);
 143.352 ++		SyncHandle();
 143.353 ++		return False;
 143.354 ++	}
 143.355 ++	_XReadPad(dpy, *driverName, rep.driverNameLength);
 143.356 ++	(*driverName)[rep.driverNameLength] = '\0';
 143.357 ++
 143.358 ++	*deviceName = Xmalloc(rep.deviceNameLength + 1);
 143.359 ++	if (*deviceName == NULL) {
 143.360 ++		Xfree(*driverName);
 143.361 ++		_XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
 143.362 ++		UnlockDisplay(dpy);
 143.363 ++		SyncHandle();
 143.364 ++		return False;
 143.365 ++	}
 143.366 ++	_XReadPad(dpy, *deviceName, rep.deviceNameLength);
 143.367 ++	(*deviceName)[rep.deviceNameLength] = '\0';
 143.368 ++
 143.369 ++	UnlockDisplay(dpy);
 143.370 ++	SyncHandle();
 143.371 ++
 143.372 ++	return True;
 143.373 ++}
 143.374 ++
 143.375 ++static Bool
 143.376 ++DRI2Authenticate(Display * dpy, XID window, unsigned int magic)
 143.377 ++{
 143.378 ++	XExtDisplayInfo *info = DRI2FindDisplay(dpy);
 143.379 ++	xDRI2AuthenticateReq *req;
 143.380 ++	xDRI2AuthenticateReply rep;
 143.381 ++
 143.382 ++	XextCheckExtension(dpy, info, dri2ExtensionName, False);
 143.383 ++
 143.384 ++	LockDisplay(dpy);
 143.385 ++	GetReq(DRI2Authenticate, req);
 143.386 ++	req->reqType = info->codes->major_opcode;
 143.387 ++	req->dri2ReqType = X_DRI2Authenticate;
 143.388 ++	req->window = window;
 143.389 ++	req->magic = magic;
 143.390 ++
 143.391 ++	if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
 143.392 ++		UnlockDisplay(dpy);
 143.393 ++		SyncHandle();
 143.394 ++		return False;
 143.395 ++	}
 143.396 ++
 143.397 ++	UnlockDisplay(dpy);
 143.398 ++	SyncHandle();
 143.399 ++
 143.400 ++	return rep.authenticated;
 143.401 ++}
 143.402 ++
 143.403 ++static void
 143.404 ++DRI2CreateDrawable(Display * dpy, XID drawable)
 143.405 ++{
 143.406 ++	XExtDisplayInfo *info = DRI2FindDisplay(dpy);
 143.407 ++	xDRI2CreateDrawableReq *req;
 143.408 ++
 143.409 ++	XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
 143.410 ++
 143.411 ++	LockDisplay(dpy);
 143.412 ++	GetReq(DRI2CreateDrawable, req);
 143.413 ++	req->reqType = info->codes->major_opcode;
 143.414 ++	req->dri2ReqType = X_DRI2CreateDrawable;
 143.415 ++	req->drawable = drawable;
 143.416 ++	UnlockDisplay(dpy);
 143.417 ++	SyncHandle();
 143.418 ++}
 143.419 ++
 143.420 ++static void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
 143.421 ++{
 143.422 ++    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
 143.423 ++    xDRI2SwapIntervalReq *req;
 143.424 ++
 143.425 ++    XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
 143.426 ++
 143.427 ++    LockDisplay(dpy);
 143.428 ++    GetReq(DRI2SwapInterval, req);
 143.429 ++    req->reqType = info->codes->major_opcode;
 143.430 ++    req->dri2ReqType = X_DRI2SwapInterval;
 143.431 ++    req->drawable = drawable;
 143.432 ++    req->interval = interval;
 143.433 ++    UnlockDisplay(dpy);
 143.434 ++    SyncHandle();
 143.435 ++}
 143.436 ++
 143.437 ++static int _x_error_occurred;
 143.438 ++
 143.439 ++static int
 143.440 ++_check_error_handler(Display     *display,
 143.441 ++		     XErrorEvent *event)
 143.442 ++{
 143.443 ++	fprintf(stderr,
 143.444 ++		"X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
 143.445 ++	       DisplayString(display),
 143.446 ++	       event->serial,
 143.447 ++	       event->error_code,
 143.448 ++	       event->request_code,
 143.449 ++	       event->minor_code);
 143.450 ++	_x_error_occurred++;
 143.451 ++	return False; /* ignored */
 143.452 ++}
 143.453 ++
 143.454 ++static double elapsed(const struct timespec *start,
 143.455 ++		      const struct timespec *end)
 143.456 ++{
 143.457 ++	return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
 143.458 ++}
 143.459 ++
 143.460 ++static void run(Display *dpy, Window win)
 143.461 ++{
 143.462 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
 143.463 ++	struct timespec start, end;
 143.464 ++	int n, completed = 0;
 143.465 ++
 143.466 ++	clock_gettime(CLOCK_MONOTONIC, &start);
 143.467 ++	do {
 143.468 ++		for (n = 0; n < 1000; n++) {
 143.469 ++			unsigned int attachments[] = { DRI2BufferBackLeft };
 143.470 ++			unsigned int seq[2];
 143.471 ++
 143.472 ++			seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
 143.473 ++								 0, 0, 0, 0, 0, 0).sequence;
 143.474 ++
 143.475 ++
 143.476 ++			seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
 143.477 ++								1, 1, attachments).sequence;
 143.478 ++
 143.479 ++			xcb_flush(c);
 143.480 ++			xcb_discard_reply(c, seq[0]);
 143.481 ++			xcb_discard_reply(c, seq[1]);
 143.482 ++			completed++;
 143.483 ++		}
 143.484 ++		clock_gettime(CLOCK_MONOTONIC, &end);
 143.485 ++	} while (end.tv_sec < start.tv_sec + 10);
 143.486 ++
 143.487 ++	printf("%f\n", completed / (elapsed(&start, &end) / 1000000));
 143.488 ++}
 143.489 ++
 143.490 ++static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
 143.491 ++{
 143.492 ++	XRRScreenResources *res;
 143.493 ++
 143.494 ++	res = XRRGetScreenResourcesCurrent(dpy, window);
 143.495 ++	if (res == NULL)
 143.496 ++		res = XRRGetScreenResources(dpy, window);
 143.497 ++
 143.498 ++	return res;
 143.499 ++}
 143.500 ++
 143.501 ++static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
 143.502 ++{
 143.503 ++	int i;
 143.504 ++
 143.505 ++	for (i = 0; i < res->nmode; i++) {
 143.506 ++		if (res->modes[i].id == id)
 143.507 ++			return &res->modes[i];
 143.508 ++	}
 143.509 ++
 143.510 ++	return NULL;
 143.511 ++}
 143.512 ++
 143.513 ++static int dri2_open(Display *dpy)
 143.514 ++{
 143.515 ++	drm_auth_t auth;
 143.516 ++	char *driver, *device;
 143.517 ++	int fd;
 143.518 ++
 143.519 ++	if (!DRI2QueryExtension(dpy, &fd, &fd))
 143.520 ++		return -1;
 143.521 ++
 143.522 ++	if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
 143.523 ++		return -1;
 143.524 ++
 143.525 ++	fd = open(device, O_RDWR);
 143.526 ++	if (fd < 0)
 143.527 ++		return -1;
 143.528 ++
 143.529 ++	if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
 143.530 ++		return -1;
 143.531 ++
 143.532 ++	if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
 143.533 ++		return -1;
 143.534 ++
 143.535 ++	return fd;
 143.536 ++}
 143.537 ++
 143.538 ++static void fullscreen(Display *dpy, Window win)
 143.539 ++{
 143.540 ++	Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
 143.541 ++	XChangeProperty(dpy, win,
 143.542 ++			XInternAtom(dpy, "_NET_WM_STATE", False),
 143.543 ++			XA_ATOM, 32, PropModeReplace,
 143.544 ++			(unsigned char *)&atom, 1);
 143.545 ++}
 143.546 ++
 143.547 ++static int has_composite(Display *dpy)
 143.548 ++{
 143.549 ++	int event, error;
 143.550 ++	int major, minor;
 143.551 ++
 143.552 ++	if (!XDamageQueryExtension (dpy, &event, &error))
 143.553 ++		return 0;
 143.554 ++
 143.555 ++	if (!XCompositeQueryExtension(dpy, &event, &error))
 143.556 ++		return 0;
 143.557 ++
 143.558 ++	XCompositeQueryVersion(dpy, &major, &minor);
 143.559 ++
 143.560 ++	return major > 0 || minor >= 4;
 143.561 ++}
 143.562 ++
 143.563 ++int main(int argc, char **argv)
 143.564 ++{
 143.565 ++	Display *dpy;
 143.566 ++	Window root, win;
 143.567 ++	XRRScreenResources *res;
 143.568 ++	XRRCrtcInfo **original_crtc;
 143.569 ++	XSetWindowAttributes attr;
 143.570 ++	enum window { ROOT, FULLSCREEN, WINDOW } w = FULLSCREEN;
 143.571 ++	enum visible {REDIRECTED, NORMAL } v = NORMAL;
 143.572 ++	enum display { OFF, ON } d = OFF;
 143.573 ++	int width, height;
 143.574 ++	int i, fd;
 143.575 ++	int c;
 143.576 ++
 143.577 ++	while ((c = getopt(argc, argv, "d:v:w:")) != -1) {
 143.578 ++		switch (c) {
 143.579 ++		case 'd':
 143.580 ++			if (strcmp(optarg, "off") == 0)
 143.581 ++				d = OFF;
 143.582 ++			else if (strcmp(optarg, "on") == 0)
 143.583 ++				d = ON;
 143.584 ++			else
 143.585 ++				abort();
 143.586 ++			break;
 143.587 ++
 143.588 ++		case 'v':
 143.589 ++			if (strcmp(optarg, "redirected") == 0)
 143.590 ++				v = REDIRECTED;
 143.591 ++			else if (strcmp(optarg, "normal") == 0)
 143.592 ++				v = NORMAL;
 143.593 ++			else
 143.594 ++				abort();
 143.595 ++			break;
 143.596 ++
 143.597 ++		case 'w':
 143.598 ++			if (strcmp(optarg, "fullscreen") == 0)
 143.599 ++				w = FULLSCREEN;
 143.600 ++			else if (strcmp(optarg, "window") == 0)
 143.601 ++				w = WINDOW;
 143.602 ++			else if (strcmp(optarg, "root") == 0)
 143.603 ++				w = ROOT;
 143.604 ++			else
 143.605 ++				abort();
 143.606 ++			break;
 143.607 ++		}
 143.608 ++	}
 143.609 ++
 143.610 ++	attr.override_redirect = 1;
 143.611 ++
 143.612 ++	dpy = XOpenDisplay(NULL);
 143.613 ++	if (dpy == NULL)
 143.614 ++		return 77;
 143.615 ++
 143.616 ++	width = DisplayWidth(dpy, DefaultScreen(dpy));
 143.617 ++	height = DisplayHeight(dpy, DefaultScreen(dpy));
 143.618 ++
 143.619 ++	fd = dri2_open(dpy);
 143.620 ++	if (fd < 0)
 143.621 ++		return 77;
 143.622 ++
 143.623 ++	if (DPMSQueryExtension(dpy, &i, &i))
 143.624 ++		DPMSDisable(dpy);
 143.625 ++
 143.626 ++	root = DefaultRootWindow(dpy);
 143.627 ++
 143.628 ++	signal(SIGALRM, SIG_IGN);
 143.629 ++	XSetErrorHandler(_check_error_handler);
 143.630 ++
 143.631 ++	res = NULL;
 143.632 ++	if (XRRQueryVersion(dpy, &i, &i))
 143.633 ++		res = _XRRGetScreenResourcesCurrent(dpy, root);
 143.634 ++	if (res == NULL)
 143.635 ++		return 77;
 143.636 ++
 143.637 ++	if (v == REDIRECTED && !has_composite(dpy))
 143.638 ++		return 77;
 143.639 ++
 143.640 ++	original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
 143.641 ++	for (i = 0; i < res->ncrtc; i++)
 143.642 ++		original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
 143.643 ++
 143.644 ++	for (i = 0; i < res->ncrtc; i++)
 143.645 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
 143.646 ++				 0, 0, None, RR_Rotate_0, NULL, 0);
 143.647 ++
 143.648 ++	DRI2CreateDrawable(dpy, root);
 143.649 ++	DRI2SwapInterval(dpy, root, 0);
 143.650 ++
 143.651 ++	if (d != OFF) {
 143.652 ++		for (i = 0; i < res->noutput; i++) {
 143.653 ++			XRROutputInfo *output;
 143.654 ++			XRRModeInfo *mode;
 143.655 ++
 143.656 ++			output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
 143.657 ++			if (output == NULL)
 143.658 ++				continue;
 143.659 ++
 143.660 ++			mode = NULL;
 143.661 ++			if (res->nmode)
 143.662 ++				mode = lookup_mode(res, output->modes[0]);
 143.663 ++			if (mode == NULL)
 143.664 ++				continue;
 143.665 ++
 143.666 ++			XRRSetCrtcConfig(dpy, res, output->crtcs[0], CurrentTime,
 143.667 ++					 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
 143.668 ++			width = mode->width;
 143.669 ++			height = mode->height;
 143.670 ++			break;
 143.671 ++		}
 143.672 ++		if (i == res->noutput) {
 143.673 ++			_x_error_occurred = 77;
 143.674 ++			goto restore;
 143.675 ++		}
 143.676 ++	}
 143.677 ++
 143.678 ++	if (w == ROOT) {
 143.679 ++		run(dpy, root);
 143.680 ++	} else if (w == FULLSCREEN) {
 143.681 ++		win = XCreateWindow(dpy, root,
 143.682 ++				    0, 0, width, height, 0,
 143.683 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
 143.684 ++				    InputOutput,
 143.685 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
 143.686 ++				    CWOverrideRedirect, &attr);
 143.687 ++		DRI2CreateDrawable(dpy, win);
 143.688 ++		DRI2SwapInterval(dpy, win, 0);
 143.689 ++		if (v == REDIRECTED) {
 143.690 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
 143.691 ++			XDamageCreate(dpy, win, XDamageReportRawRectangles);
 143.692 ++		} else
 143.693 ++			fullscreen(dpy, win);
 143.694 ++		XMapWindow(dpy, win);
 143.695 ++		run(dpy, win);
 143.696 ++	} else if (w == WINDOW) {
 143.697 ++		win = XCreateWindow(dpy, root,
 143.698 ++				    0, 0, width/2, height/2, 0,
 143.699 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
 143.700 ++				    InputOutput,
 143.701 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
 143.702 ++				    CWOverrideRedirect, &attr);
 143.703 ++		DRI2CreateDrawable(dpy, win);
 143.704 ++		DRI2SwapInterval(dpy, win, 0);
 143.705 ++		if (v == REDIRECTED) {
 143.706 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
 143.707 ++			XDamageCreate(dpy, win, XDamageReportRawRectangles);
 143.708 ++		}
 143.709 ++		XMapWindow(dpy, win);
 143.710 ++		run(dpy, win);
 143.711 ++	}
 143.712 ++
 143.713 ++restore:
 143.714 ++	for (i = 0; i < res->ncrtc; i++)
 143.715 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
 143.716 ++				 0, 0, None, RR_Rotate_0, NULL, 0);
 143.717 ++
 143.718 ++	for (i = 0; i < res->ncrtc; i++)
 143.719 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
 143.720 ++				 original_crtc[i]->x,
 143.721 ++				 original_crtc[i]->y,
 143.722 ++				 original_crtc[i]->mode,
 143.723 ++				 original_crtc[i]->rotation,
 143.724 ++				 original_crtc[i]->outputs,
 143.725 ++				 original_crtc[i]->noutput);
 143.726 ++
 143.727 ++	if (DPMSQueryExtension(dpy, &i, &i))
 143.728 ++		DPMSEnable(dpy);
 143.729 ++
 143.730 ++	XSync(dpy, True);
 143.731 ++	return _x_error_occurred;
 143.732 ++}
 143.733 +diff --git a/benchmarks/dri3-swap.c b/benchmarks/dri3-swap.c
 143.734 +new file mode 100644
 143.735 +index 00000000..4dd423b3
 143.736 +--- /dev/null
 143.737 ++++ b/benchmarks/dri3-swap.c
 143.738 +@@ -0,0 +1,595 @@
 143.739 ++/*
 143.740 ++ * Copyright (c) 2015 Intel Corporation
 143.741 ++ *
 143.742 ++ * Permission is hereby granted, free of charge, to any person obtaining a
 143.743 ++ * copy of this software and associated documentation files (the "Software"),
 143.744 ++ * to deal in the Software without restriction, including without limitation
 143.745 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 143.746 ++ * and/or sell copies of the Software, and to permit persons to whom the
 143.747 ++ * Software is furnished to do so, subject to the following conditions:
 143.748 ++ *
 143.749 ++ * The above copyright notice and this permission notice (including the next
 143.750 ++ * paragraph) shall be included in all copies or substantial portions of the
 143.751 ++ * Software.
 143.752 ++ *
 143.753 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 143.754 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 143.755 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 143.756 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 143.757 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 143.758 ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 143.759 ++ * SOFTWARE.
 143.760 ++ *
 143.761 ++ */
 143.762 ++
 143.763 ++#ifdef HAVE_CONFIG_H
 143.764 ++#include "config.h"
 143.765 ++#endif
 143.766 ++
 143.767 ++#include <X11/Xlib.h>
 143.768 ++#include <X11/Xatom.h>
 143.769 ++#include <X11/Xlib-xcb.h>
 143.770 ++#include <X11/xshmfence.h>
 143.771 ++#include <X11/Xutil.h>
 143.772 ++#include <X11/Xlibint.h>
 143.773 ++#include <X11/extensions/Xcomposite.h>
 143.774 ++#include <X11/extensions/Xdamage.h>
 143.775 ++#include <X11/extensions/dpms.h>
 143.776 ++#include <X11/extensions/randr.h>
 143.777 ++#include <X11/extensions/Xrandr.h>
 143.778 ++#include <xcb/xcb.h>
 143.779 ++#include <xcb/present.h>
 143.780 ++#include <xcb/dri3.h>
 143.781 ++#include <xcb/xfixes.h>
 143.782 ++#include <xf86drm.h>
 143.783 ++#include <i915_drm.h>
 143.784 ++
 143.785 ++#include <stdio.h>
 143.786 ++#include <string.h>
 143.787 ++#include <fcntl.h>
 143.788 ++#include <unistd.h>
 143.789 ++#include <assert.h>
 143.790 ++#include <errno.h>
 143.791 ++#include <setjmp.h>
 143.792 ++#include <signal.h>
 143.793 ++
 143.794 ++struct dri3_fence {
 143.795 ++	XID xid;
 143.796 ++	void *addr;
 143.797 ++};
 143.798 ++
 143.799 ++static int _x_error_occurred;
 143.800 ++static uint32_t stamp;
 143.801 ++
 143.802 ++struct list {
 143.803 ++    struct list *next, *prev;
 143.804 ++};
 143.805 ++
 143.806 ++static void
 143.807 ++list_init(struct list *list)
 143.808 ++{
 143.809 ++    list->next = list->prev = list;
 143.810 ++}
 143.811 ++
 143.812 ++static inline void
 143.813 ++__list_add(struct list *entry,
 143.814 ++	    struct list *prev,
 143.815 ++	    struct list *next)
 143.816 ++{
 143.817 ++    next->prev = entry;
 143.818 ++    entry->next = next;
 143.819 ++    entry->prev = prev;
 143.820 ++    prev->next = entry;
 143.821 ++}
 143.822 ++
 143.823 ++static inline void
 143.824 ++list_add(struct list *entry, struct list *head)
 143.825 ++{
 143.826 ++    __list_add(entry, head, head->next);
 143.827 ++}
 143.828 ++
 143.829 ++static inline void
 143.830 ++__list_del(struct list *prev, struct list *next)
 143.831 ++{
 143.832 ++	next->prev = prev;
 143.833 ++	prev->next = next;
 143.834 ++}
 143.835 ++
 143.836 ++static inline void
 143.837 ++_list_del(struct list *entry)
 143.838 ++{
 143.839 ++    __list_del(entry->prev, entry->next);
 143.840 ++}
 143.841 ++
 143.842 ++static inline void
 143.843 ++list_move(struct list *list, struct list *head)
 143.844 ++{
 143.845 ++	if (list->prev != head) {
 143.846 ++		_list_del(list);
 143.847 ++		list_add(list, head);
 143.848 ++	}
 143.849 ++}
 143.850 ++
 143.851 ++#define __container_of(ptr, sample, member)				\
 143.852 ++    (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
 143.853 ++
 143.854 ++#define list_for_each_entry(pos, head, member)				\
 143.855 ++    for (pos = __container_of((head)->next, pos, member);		\
 143.856 ++	 &pos->member != (head);					\
 143.857 ++	 pos = __container_of(pos->member.next, pos, member))
 143.858 ++
 143.859 ++static int
 143.860 ++_check_error_handler(Display     *display,
 143.861 ++		     XErrorEvent *event)
 143.862 ++{
 143.863 ++	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
 143.864 ++	       DisplayString(display),
 143.865 ++	       event->serial,
 143.866 ++	       event->error_code,
 143.867 ++	       event->request_code,
 143.868 ++	       event->minor_code);
 143.869 ++	_x_error_occurred++;
 143.870 ++	return False; /* ignored */
 143.871 ++}
 143.872 ++
 143.873 ++static int dri3_create_fence(Display *dpy,
 143.874 ++			     Pixmap pixmap,
 143.875 ++			     struct dri3_fence *fence)
 143.876 ++{
 143.877 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
 143.878 ++	struct dri3_fence f;
 143.879 ++	int fd;
 143.880 ++
 143.881 ++	fd = xshmfence_alloc_shm();
 143.882 ++	if (fd < 0)
 143.883 ++		return -1;
 143.884 ++
 143.885 ++	f.addr = xshmfence_map_shm(fd);
 143.886 ++	if (f.addr == NULL) {
 143.887 ++		close(fd);
 143.888 ++		return -1;
 143.889 ++	}
 143.890 ++
 143.891 ++	f.xid = xcb_generate_id(c);
 143.892 ++	xcb_dri3_fence_from_fd(c, pixmap, f.xid, 0, fd);
 143.893 ++
 143.894 ++	*fence = f;
 143.895 ++	return 0;
 143.896 ++}
 143.897 ++
 143.898 ++static double elapsed(const struct timespec *start,
 143.899 ++		      const struct timespec *end)
 143.900 ++{
 143.901 ++	return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
 143.902 ++}
 143.903 ++
 143.904 ++struct buffer {
 143.905 ++	struct list link;
 143.906 ++	Pixmap pixmap;
 143.907 ++	struct dri3_fence fence;
 143.908 ++	int fd;
 143.909 ++	int busy;
 143.910 ++};
 143.911 ++
 143.912 ++static void run(Display *dpy, Window win)
 143.913 ++{
 143.914 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
 143.915 ++	struct timespec start, end;
 143.916 ++#define N_BACK 8
 143.917 ++	struct buffer buffer[N_BACK];
 143.918 ++	struct list mru;
 143.919 ++	Window root;
 143.920 ++	unsigned int width, height;
 143.921 ++	unsigned border, depth;
 143.922 ++	unsigned present_flags = XCB_PRESENT_OPTION_ASYNC;
 143.923 ++	xcb_xfixes_region_t update = 0;
 143.924 ++	int completed = 0;
 143.925 ++	int queued = 0;
 143.926 ++	uint32_t eid;
 143.927 ++	void *Q;
 143.928 ++	int i, n;
 143.929 ++
 143.930 ++	list_init(&mru);
 143.931 ++
 143.932 ++	XGetGeometry(dpy, win,
 143.933 ++		     &root, &i, &n, &width, &height, &border, &depth);
 143.934 ++
 143.935 ++	_x_error_occurred = 0;
 143.936 ++
 143.937 ++	for (n = 0; n < N_BACK; n++) {
 143.938 ++		xcb_dri3_buffer_from_pixmap_reply_t *reply;
 143.939 ++		int *fds;
 143.940 ++
 143.941 ++		buffer[n].pixmap =
 143.942 ++			XCreatePixmap(dpy, win, width, height, depth);
 143.943 ++		buffer[n].fence.xid = 0;
 143.944 ++		buffer[n].fd = -1;
 143.945 ++
 143.946 ++		if (dri3_create_fence(dpy, win, &buffer[n].fence))
 143.947 ++			return;
 143.948 ++
 143.949 ++		reply = xcb_dri3_buffer_from_pixmap_reply (c,
 143.950 ++							   xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
 143.951 ++							   NULL);
 143.952 ++		if (reply == NULL)
 143.953 ++			return;
 143.954 ++
 143.955 ++		fds = xcb_dri3_buffer_from_pixmap_reply_fds (c, reply);
 143.956 ++		buffer[n].fd = fds[0];
 143.957 ++		free(reply);
 143.958 ++
 143.959 ++		/* start idle */
 143.960 ++		xshmfence_trigger(buffer[n].fence.addr);
 143.961 ++		buffer[n].busy = 0;
 143.962 ++		list_add(&buffer[n].link, &mru);
 143.963 ++	}
 143.964 ++
 143.965 ++	eid = xcb_generate_id(c);
 143.966 ++	xcb_present_select_input(c, eid, win,
 143.967 ++                                 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY |
 143.968 ++                                 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
 143.969 ++	Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp);
 143.970 ++
 143.971 ++	clock_gettime(CLOCK_MONOTONIC, &start);
 143.972 ++	do {
 143.973 ++		for (n = 0; n < 1000; n++) {
 143.974 ++			struct buffer *tmp, *b = NULL;
 143.975 ++			list_for_each_entry(tmp, &mru, link) {
 143.976 ++				if (!tmp->busy) {
 143.977 ++					b = tmp;
 143.978 ++					break;
 143.979 ++				}
 143.980 ++			}
 143.981 ++			while (b == NULL) {
 143.982 ++				xcb_present_generic_event_t *ev;
 143.983 ++
 143.984 ++				ev = (xcb_present_generic_event_t *)
 143.985 ++					xcb_wait_for_special_event(c, Q);
 143.986 ++				if (ev == NULL)
 143.987 ++					abort();
 143.988 ++
 143.989 ++				do {
 143.990 ++					switch (ev->evtype) {
 143.991 ++					case XCB_PRESENT_COMPLETE_NOTIFY:
 143.992 ++						completed++;
 143.993 ++						queued--;
 143.994 ++						break;
 143.995 ++
 143.996 ++					case XCB_PRESENT_EVENT_IDLE_NOTIFY:
 143.997 ++						{
 143.998 ++							xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
 143.999 ++							assert(ie->serial < N_BACK);
143.1000 ++							buffer[ie->serial].busy = 0;
143.1001 ++							if (b == NULL)
143.1002 ++								b = &buffer[ie->serial];
143.1003 ++							break;
143.1004 ++						}
143.1005 ++					}
143.1006 ++					free(ev);
143.1007 ++				} while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
143.1008 ++			}
143.1009 ++
143.1010 ++			b->busy = 1;
143.1011 ++			if (b->fence.xid) {
143.1012 ++				xshmfence_await(b->fence.addr);
143.1013 ++				xshmfence_reset(b->fence.addr);
143.1014 ++			}
143.1015 ++			xcb_present_pixmap(c, win, b->pixmap, b - buffer,
143.1016 ++					   0, /* valid */
143.1017 ++					   update, /* update */
143.1018 ++					   0, /* x_off */
143.1019 ++					   0, /* y_off */
143.1020 ++					   None,
143.1021 ++					   None, /* wait fence */
143.1022 ++					   b->fence.xid,
143.1023 ++					   present_flags,
143.1024 ++					   0, /* target msc */
143.1025 ++					   0, /* divisor */
143.1026 ++					   0, /* remainder */
143.1027 ++					   0, NULL);
143.1028 ++			list_move(&b->link, &mru);
143.1029 ++			queued++;
143.1030 ++			xcb_flush(c);
143.1031 ++		}
143.1032 ++		clock_gettime(CLOCK_MONOTONIC, &end);
143.1033 ++	} while (end.tv_sec < start.tv_sec + 10);
143.1034 ++
143.1035 ++	while (queued) {
143.1036 ++		xcb_present_generic_event_t *ev;
143.1037 ++
143.1038 ++		ev = (xcb_present_generic_event_t *)
143.1039 ++			xcb_wait_for_special_event(c, Q);
143.1040 ++		if (ev == NULL)
143.1041 ++			abort();
143.1042 ++
143.1043 ++		do {
143.1044 ++			switch (ev->evtype) {
143.1045 ++			case XCB_PRESENT_COMPLETE_NOTIFY:
143.1046 ++				completed++;
143.1047 ++				queued--;
143.1048 ++				break;
143.1049 ++
143.1050 ++			case XCB_PRESENT_EVENT_IDLE_NOTIFY:
143.1051 ++				break;
143.1052 ++			}
143.1053 ++			free(ev);
143.1054 ++		} while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
143.1055 ++	}
143.1056 ++	clock_gettime(CLOCK_MONOTONIC, &end);
143.1057 ++
143.1058 ++	printf("%f\n", completed / (elapsed(&start, &end) / 1000000));
143.1059 ++}
143.1060 ++
143.1061 ++static int has_present(Display *dpy)
143.1062 ++{
143.1063 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.1064 ++	xcb_generic_error_t *error = NULL;
143.1065 ++	void *reply;
143.1066 ++
143.1067 ++	reply = xcb_present_query_version_reply(c,
143.1068 ++						xcb_present_query_version(c,
143.1069 ++									  XCB_PRESENT_MAJOR_VERSION,
143.1070 ++									  XCB_PRESENT_MINOR_VERSION),
143.1071 ++						&error);
143.1072 ++
143.1073 ++	free(reply);
143.1074 ++	free(error);
143.1075 ++	if (reply == NULL) {
143.1076 ++		fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
143.1077 ++		return 0;
143.1078 ++	}
143.1079 ++
143.1080 ++	return 1;
143.1081 ++}
143.1082 ++
143.1083 ++static int has_composite(Display *dpy)
143.1084 ++{
143.1085 ++	int event, error;
143.1086 ++	int major, minor;
143.1087 ++
143.1088 ++	if (!XDamageQueryExtension (dpy, &event, &error))
143.1089 ++		return 0;
143.1090 ++
143.1091 ++	if (!XCompositeQueryExtension(dpy, &event, &error))
143.1092 ++		return 0;
143.1093 ++
143.1094 ++	XCompositeQueryVersion(dpy, &major, &minor);
143.1095 ++
143.1096 ++	return major > 0 || minor >= 4;
143.1097 ++}
143.1098 ++
143.1099 ++static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
143.1100 ++{
143.1101 ++	XRRScreenResources *res;
143.1102 ++
143.1103 ++	res = XRRGetScreenResourcesCurrent(dpy, window);
143.1104 ++	if (res == NULL)
143.1105 ++		res = XRRGetScreenResources(dpy, window);
143.1106 ++
143.1107 ++	return res;
143.1108 ++}
143.1109 ++
143.1110 ++static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
143.1111 ++{
143.1112 ++	int i;
143.1113 ++
143.1114 ++	for (i = 0; i < res->nmode; i++) {
143.1115 ++		if (res->modes[i].id == id)
143.1116 ++			return &res->modes[i];
143.1117 ++	}
143.1118 ++
143.1119 ++	return NULL;
143.1120 ++}
143.1121 ++
143.1122 ++static void fullscreen(Display *dpy, Window win)
143.1123 ++{
143.1124 ++	Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
143.1125 ++	XChangeProperty(dpy, win,
143.1126 ++			XInternAtom(dpy, "_NET_WM_STATE", False),
143.1127 ++			XA_ATOM, 32, PropModeReplace,
143.1128 ++			(unsigned char *)&atom, 1);
143.1129 ++}
143.1130 ++
143.1131 ++static int dri3_query_version(Display *dpy, int *major, int *minor)
143.1132 ++{
143.1133 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.1134 ++	xcb_dri3_query_version_reply_t *reply;
143.1135 ++	xcb_generic_error_t *error;
143.1136 ++
143.1137 ++	*major = *minor = -1;
143.1138 ++
143.1139 ++	reply = xcb_dri3_query_version_reply(c,
143.1140 ++					     xcb_dri3_query_version(c,
143.1141 ++								    XCB_DRI3_MAJOR_VERSION,
143.1142 ++								    XCB_DRI3_MINOR_VERSION),
143.1143 ++					     &error);
143.1144 ++	free(error);
143.1145 ++	if (reply == NULL)
143.1146 ++		return -1;
143.1147 ++
143.1148 ++	*major = reply->major_version;
143.1149 ++	*minor = reply->minor_version;
143.1150 ++	free(reply);
143.1151 ++
143.1152 ++	return 0;
143.1153 ++}
143.1154 ++
143.1155 ++static int has_dri3(Display *dpy)
143.1156 ++{
143.1157 ++	const xcb_query_extension_reply_t *ext;
143.1158 ++	int major, minor;
143.1159 ++
143.1160 ++	ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
143.1161 ++	if (ext == NULL || !ext->present)
143.1162 ++		return 0;
143.1163 ++
143.1164 ++	if (dri3_query_version(dpy, &major, &minor) < 0)
143.1165 ++		return 0;
143.1166 ++
143.1167 ++	return major >= 0;
143.1168 ++}
143.1169 ++
143.1170 ++int main(int argc, char **argv)
143.1171 ++{
143.1172 ++	Display *dpy;
143.1173 ++	Window root, win;
143.1174 ++	XRRScreenResources *res;
143.1175 ++	XRRCrtcInfo **original_crtc;
143.1176 ++	XSetWindowAttributes attr;
143.1177 ++	enum window { ROOT, FULLSCREEN, WINDOW } w = FULLSCREEN;
143.1178 ++	enum visible {REDIRECTED, NORMAL } v = NORMAL;
143.1179 ++	enum display { OFF, ON } d = OFF;
143.1180 ++	int width, height;
143.1181 ++	int i;
143.1182 ++
143.1183 ++	while ((i = getopt(argc, argv, "d:v:w:")) != -1) {
143.1184 ++		switch (i) {
143.1185 ++		case 'd':
143.1186 ++			if (strcmp(optarg, "off") == 0)
143.1187 ++				d = OFF;
143.1188 ++			else if (strcmp(optarg, "on") == 0)
143.1189 ++				d = ON;
143.1190 ++			else
143.1191 ++				abort();
143.1192 ++			break;
143.1193 ++
143.1194 ++		case 'v':
143.1195 ++			if (strcmp(optarg, "redirected") == 0)
143.1196 ++				v = REDIRECTED;
143.1197 ++			else if (strcmp(optarg, "normal") == 0)
143.1198 ++				v = NORMAL;
143.1199 ++			else
143.1200 ++				abort();
143.1201 ++			break;
143.1202 ++
143.1203 ++		case 'w':
143.1204 ++			if (strcmp(optarg, "fullscreen") == 0)
143.1205 ++				w = FULLSCREEN;
143.1206 ++			else if (strcmp(optarg, "window") == 0)
143.1207 ++				w = WINDOW;
143.1208 ++			else if (strcmp(optarg, "root") == 0)
143.1209 ++				w = ROOT;
143.1210 ++			else
143.1211 ++				abort();
143.1212 ++			break;
143.1213 ++		}
143.1214 ++	}
143.1215 ++
143.1216 ++	attr.override_redirect = 1;
143.1217 ++
143.1218 ++	dpy = XOpenDisplay(NULL);
143.1219 ++	if (dpy == NULL)
143.1220 ++		return 77;
143.1221 ++
143.1222 ++	width = DisplayWidth(dpy, DefaultScreen(dpy));
143.1223 ++	height = DisplayHeight(dpy, DefaultScreen(dpy));
143.1224 ++
143.1225 ++	if (!has_present(dpy))
143.1226 ++		return 77;
143.1227 ++
143.1228 ++	if (!has_dri3(dpy))
143.1229 ++		return 77;
143.1230 ++
143.1231 ++	if (DPMSQueryExtension(dpy, &i, &i))
143.1232 ++		DPMSDisable(dpy);
143.1233 ++
143.1234 ++	root = DefaultRootWindow(dpy);
143.1235 ++
143.1236 ++	signal(SIGALRM, SIG_IGN);
143.1237 ++	XSetErrorHandler(_check_error_handler);
143.1238 ++
143.1239 ++	res = NULL;
143.1240 ++	if (XRRQueryVersion(dpy, &i, &i))
143.1241 ++		res = _XRRGetScreenResourcesCurrent(dpy, root);
143.1242 ++	if (res == NULL)
143.1243 ++		return 77;
143.1244 ++
143.1245 ++	if (v == REDIRECTED && !has_composite(dpy))
143.1246 ++		return 77;
143.1247 ++
143.1248 ++	original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
143.1249 ++	for (i = 0; i < res->ncrtc; i++)
143.1250 ++		original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
143.1251 ++
143.1252 ++	for (i = 0; i < res->ncrtc; i++)
143.1253 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
143.1254 ++				 0, 0, None, RR_Rotate_0, NULL, 0);
143.1255 ++
143.1256 ++	if (d != OFF) {
143.1257 ++		for (i = 0; i < res->noutput; i++) {
143.1258 ++			XRROutputInfo *output;
143.1259 ++			XRRModeInfo *mode;
143.1260 ++
143.1261 ++			output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
143.1262 ++			if (output == NULL)
143.1263 ++				continue;
143.1264 ++
143.1265 ++			mode = NULL;
143.1266 ++			if (res->nmode)
143.1267 ++				mode = lookup_mode(res, output->modes[0]);
143.1268 ++			if (mode == NULL)
143.1269 ++				continue;
143.1270 ++
143.1271 ++			XRRSetCrtcConfig(dpy, res, output->crtcs[0], CurrentTime,
143.1272 ++					 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
143.1273 ++			width = mode->width;
143.1274 ++			height = mode->height;
143.1275 ++			break;
143.1276 ++		}
143.1277 ++		if (i == res->noutput) {
143.1278 ++			_x_error_occurred = 77;
143.1279 ++			goto restore;
143.1280 ++		}
143.1281 ++	}
143.1282 ++
143.1283 ++	if (w == ROOT) {
143.1284 ++		run(dpy, root);
143.1285 ++	} else if (w == FULLSCREEN) {
143.1286 ++		win = XCreateWindow(dpy, root,
143.1287 ++				    0, 0, width, height, 0,
143.1288 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
143.1289 ++				    InputOutput,
143.1290 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
143.1291 ++				    CWOverrideRedirect, &attr);
143.1292 ++		if (v == REDIRECTED) {
143.1293 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.1294 ++			XDamageCreate(dpy, win, XDamageReportRawRectangles);
143.1295 ++		} else
143.1296 ++			fullscreen(dpy, win);
143.1297 ++		XMapWindow(dpy, win);
143.1298 ++		run(dpy, win);
143.1299 ++	} else if (w == WINDOW) {
143.1300 ++		win = XCreateWindow(dpy, root,
143.1301 ++				    0, 0, width/2, height/2, 0,
143.1302 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
143.1303 ++				    InputOutput,
143.1304 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
143.1305 ++				    CWOverrideRedirect, &attr);
143.1306 ++		if (v == REDIRECTED) {
143.1307 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.1308 ++			XDamageCreate(dpy, win, XDamageReportRawRectangles);
143.1309 ++		}
143.1310 ++		XMapWindow(dpy, win);
143.1311 ++		run(dpy, win);
143.1312 ++	}
143.1313 ++
143.1314 ++restore:
143.1315 ++	for (i = 0; i < res->ncrtc; i++)
143.1316 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
143.1317 ++				 0, 0, None, RR_Rotate_0, NULL, 0);
143.1318 ++
143.1319 ++	for (i = 0; i < res->ncrtc; i++)
143.1320 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
143.1321 ++				 original_crtc[i]->x,
143.1322 ++				 original_crtc[i]->y,
143.1323 ++				 original_crtc[i]->mode,
143.1324 ++				 original_crtc[i]->rotation,
143.1325 ++				 original_crtc[i]->outputs,
143.1326 ++				 original_crtc[i]->noutput);
143.1327 ++
143.1328 ++	if (DPMSQueryExtension(dpy, &i, &i))
143.1329 ++		DPMSEnable(dpy);
143.1330 ++
143.1331 ++	XSync(dpy, True);
143.1332 ++	return _x_error_occurred;
143.1333 ++}
143.1334 +diff --git a/configure.ac b/configure.ac
143.1335 +index 61bea435..d13917ec 100644
143.1336 +--- a/configure.ac
143.1337 ++++ b/configure.ac
143.1338 +@@ -195,18 +195,24 @@ AC_ARG_ENABLE(udev,
143.1339 +               [UDEV="$enableval"],
143.1340 +               [UDEV=auto])
143.1341 + 
143.1342 ++udev_msg=" disabled"
143.1343 + if test "x$UDEV" != "xno"; then
143.1344 + 	PKG_CHECK_MODULES(UDEV, [libudev], [udev="yes"], [udev="no"])
143.1345 ++	AC_CHECK_HEADERS([sys/stat.h], [], [udev="no"])
143.1346 + 	if test "x$UDEV" = "xyes" -a "x$udev" != "xyes"; then
143.1347 + 		AC_MSG_ERROR([udev support requested but not found (libudev)])
143.1348 + 	fi
143.1349 + 	if test "x$udev" = "xyes"; then
143.1350 + 		AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
143.1351 ++		udev_msg=" yes"
143.1352 ++	else
143.1353 ++		udev_msg=" no"
143.1354 + 	fi
143.1355 + fi
143.1356 + 
143.1357 +-PKG_CHECK_MODULES(X11, [x11 xrender xrandr xext xfixes cairo cairo-xlib-xrender pixman-1 libpng], [x11="yes"], [x11="no"])
143.1358 ++PKG_CHECK_MODULES(X11, [x11 x11-xcb xcb-dri2 xcomposite xdamage xrender xrandr xext xfixes cairo cairo-xlib-xrender pixman-1 libpng], [x11="yes"], [x11="no"])
143.1359 + AM_CONDITIONAL(HAVE_X11, test "x$x11" = "xyes")
143.1360 ++echo X11_CLFAGS="$X11_CLFAGS" X11_LIBS="$X11_LIBS"
143.1361 + 
143.1362 + cpuid="yes"
143.1363 + AC_TRY_LINK([
143.1364 +@@ -270,10 +276,13 @@ if test "x$shm" = "xyes"; then
143.1365 + 	AC_DEFINE([HAVE_MIT_SHM], 1, [Define to 1 if MIT-SHM is available])
143.1366 + fi
143.1367 + 
143.1368 +-PKG_CHECK_MODULES(X11_DRI3, [xcb-dri3 xcb-sync xcb-present x11-xcb xshmfence x11 xrender xext libdrm], [x11_dri3="yes"], [x11_dri3="no"])
143.1369 ++PKG_CHECK_MODULES(X11_DRI3, [xcb-dri3 xcb-sync xcb-xfixes xcb-present x11-xcb xshmfence x11 xcomposite xdamage xrender xrandr xxf86vm xext libdrm], [x11_dri3="yes"], [x11_dri3="no"])
143.1370 + AM_CONDITIONAL(X11_DRI3, test "x$x11_dri3" = "xyes" -a "x$shm" = "xyes")
143.1371 + AM_CONDITIONAL(X11_SHM, test "x$shm" = "xyes")
143.1372 + 
143.1373 ++PKG_CHECK_MODULES(X11_VM, [xxf86vm], [x11_vm="yes"], [x11_vm="no"])
143.1374 ++AM_CONDITIONAL(X11_VM, test "x$x11_vm" = "xyes")
143.1375 ++
143.1376 + AC_ARG_ENABLE(tools,
143.1377 +               AS_HELP_STRING([--disable-tools],
143.1378 + 			     [Enable building and installing the miscellaneous tools [default=auto]]),
143.1379 +@@ -285,7 +294,7 @@ if test "x$shm" != "xyes"; then
143.1380 + 	tools="no"
143.1381 + fi
143.1382 + if test "x$tools" != "xno"; then
143.1383 +-	ivo_requires="xrandr xdamage xfixes xcursor xtst xrender xext x11 pixman-1"
143.1384 ++	ivo_requires="xrandr xdamage xfixes xcursor xtst xrender xscrnsaver xext x11 pixman-1"
143.1385 + 	extra_cflags=""
143.1386 + 
143.1387 + 	ignore="xinerama"
143.1388 +@@ -307,6 +316,8 @@ if test "x$tools" != "xno"; then
143.1389 + 		tools="no"
143.1390 + 	fi
143.1391 + 
143.1392 ++	PKG_CHECK_MODULES(TOOL_CURSOR, [xfixes x11 libpng], [cursor="yes"], [ivo="no"])
143.1393 ++
143.1394 + 	IVO_CFLAGS="$IVO_CFLAGS $extra_cflags"
143.1395 + fi
143.1396 + if test "x$tools" != "xno"; then
143.1397 +@@ -315,6 +326,7 @@ fi
143.1398 + AC_MSG_CHECKING([whether to build additional tools])
143.1399 + AC_MSG_RESULT([$tools])
143.1400 + AM_CONDITIONAL(BUILD_TOOLS, test "x$tools" != "xno")
143.1401 ++AM_CONDITIONAL(BUILD_TOOL_CURSOR, test "x$cursor" = "xyes")
143.1402 + 
143.1403 + # Define a configure option for an alternate module directory
143.1404 + AC_ARG_WITH(xorg-module-dir,
143.1405 +@@ -339,10 +351,20 @@ AC_ARG_ENABLE(dri2,
143.1406 + 	      [DRI2=$enableval],
143.1407 + 	      [DRI2=yes])
143.1408 + AC_ARG_ENABLE(dri3,
143.1409 +-	      AS_HELP_STRING([--enable-dri3],
143.1410 +-			     [Enable DRI3 support [[default=no]]]),
143.1411 ++	      AS_HELP_STRING([--disable-dri3],
143.1412 ++			     [Disable DRI3 support [[default=yes]]]),
143.1413 + 	      [DRI3=$enableval],
143.1414 +-	      [DRI3=no])
143.1415 ++	      [DRI3=yes])
143.1416 ++AC_ARG_WITH(default-dri,
143.1417 ++	    AS_HELP_STRING([--with-default-dri],
143.1418 ++			   [Select the default maximum DRI level [default 2]]),
143.1419 ++	      [DRI_DEFAULT=$withval],
143.1420 ++	      [DRI_DEFAULT=2])
143.1421 ++if test "x$DRI_DEFAULT" = "x0"; then
143.1422 ++	AC_DEFINE(DEFAULT_DRI_LEVEL, 0,[Default DRI level])
143.1423 ++else
143.1424 ++	AC_DEFINE(DEFAULT_DRI_LEVEL, ~0, [Default DRI level])
143.1425 ++fi
143.1426 + 
143.1427 + AC_ARG_ENABLE(xvmc, AS_HELP_STRING([--disable-xvmc],
143.1428 +                                   [Disable XvMC support [[default=yes]]]),
143.1429 +@@ -375,14 +397,12 @@ AC_ARG_ENABLE(ums-only,
143.1430 + required_xorg_server_version=1.6
143.1431 + required_pixman_version=0.16
143.1432 + 
143.1433 +-if pkg-config --exists 'pixman-1 >= 0.27.1'; then
143.1434 +-	AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])
143.1435 +-fi
143.1436 +-
143.1437 +-if pkg-config --exists 'pixman-1 >= 0.24.0'; then
143.1438 +-	AC_DEFINE([HAS_PIXMAN_TRIANGLES], 1, [Enable pixman triangle rasterisation])
143.1439 +-fi
143.1440 +-
143.1441 ++PKG_CHECK_EXISTS([pixman-1 >= 0.24.0],
143.1442 ++		 AC_DEFINE([HAS_PIXMAN_TRIANGLES], 1, [Enable pixman triangle rasterisation])
143.1443 ++		 [])
143.1444 ++PKG_CHECK_EXISTS([pixman-1 >= 0.27.1],
143.1445 ++		 [AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])],
143.1446 ++		 [])
143.1447 + # Store the list of server defined optional extensions in REQUIRED_MODULES
143.1448 + XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
143.1449 + XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
143.1450 +@@ -398,24 +418,25 @@ AC_ARG_ENABLE(sna,
143.1451 + 	      [SNA="$enableval"],
143.1452 + 	      [SNA=auto])
143.1453 + 
143.1454 ++AC_CHECK_HEADERS([dev/wscons/wsconsio.h])
143.1455 ++AC_FUNC_ALLOCA
143.1456 ++AC_HEADER_MAJOR
143.1457 ++
143.1458 + if test "x$SNA" != "xno"; then
143.1459 + 	AC_DEFINE(USE_SNA, 1, [Enable SNA support])
143.1460 + 	AC_CHECK_HEADERS([sys/sysinfo.h], AC_CHECK_MEMBERS([struct sysinfo.totalram], [], [], [[#include <sys/sysinfo.h>]]))
143.1461 + fi
143.1462 + 
143.1463 + uxa_requires_libdrm=2.4.52
143.1464 ++uxa_requires_pixman=0.24.0
143.1465 ++
143.1466 + AC_ARG_ENABLE(uxa,
143.1467 + 	      AS_HELP_STRING([--enable-uxa],
143.1468 + 			     [Enable Unified Acceleration Architecture (UXA) [default=auto]]),
143.1469 + 	      [UXA="$enableval"],
143.1470 + 	      [UXA=auto])
143.1471 + if test "x$UXA" = "xauto"; then
143.1472 +-	if ! pkg-config --exists "libdrm_intel >= $uxa_requires_libdrm"; then
143.1473 +-		UXA=no
143.1474 +-	fi
143.1475 +-	if ! pkg-config --exists 'pixman-1 >= 0.24.0'; then
143.1476 +-		UXA=no
143.1477 +-	fi
143.1478 ++	PKG_CHECK_EXISTS([libdrm_intel >= $uxa_requires_libdrm pixman-1 >= $uxa_requires_pixman], [], [UXA=no])
143.1479 + fi
143.1480 + if test "x$UXA" != "xno"; then
143.1481 + 	AC_DEFINE(USE_UXA, 1, [Enable UXA support])
143.1482 +@@ -424,8 +445,10 @@ if test "x$UXA" != "xno"; then
143.1483 + 	UXA=yes
143.1484 + fi
143.1485 + 
143.1486 +-PKG_CHECK_MODULES(XORG, [xorg-server >= $required_xorg_server_version xproto fontsproto pixman-1 >= $required_pixman_version $REQUIRED_MODULES])
143.1487 ++PKG_CHECK_MODULES(XORG, [xorg-server >= $required_xorg_server_version xproto fontsproto damageproto pixman-1 >= $required_pixman_version $REQUIRED_MODULES])
143.1488 + ABI_VERSION=`$PKG_CONFIG --variable=abi_videodrv xorg-server`
143.1489 ++XSERVER_VERSION=`$PKG_CONFIG --modversion xorg-server`
143.1490 ++PIXMAN_VERSION=`$PKG_CONFIG --modversion pixman-1`
143.1491 + 
143.1492 + if test "x$ONLY_UMS" = "xyes"; then
143.1493 + 	UMS="yes"
143.1494 +@@ -519,7 +542,12 @@ AC_MSG_RESULT([$have_dri1])
143.1495 + AM_CONDITIONAL(DRI1, test "x$have_dri1" != "xno")
143.1496 + if test "x$have_dri1" != "xno"; then
143.1497 +         AC_DEFINE(HAVE_DRI1,1,[Enable DRI1 driver support])
143.1498 +-	dri_msg="$dri_msg DRI1"
143.1499 ++	str="DRI1"
143.1500 ++	if test "x$DRI_DEFAULT" = "x1"; then
143.1501 ++		AC_DEFINE(DEFAULT_DRI_LEVEL,1,[Default DRI level])
143.1502 ++		str="*$str"
143.1503 ++	fi
143.1504 ++	dri_msg="$dri_msg $str"
143.1505 + else
143.1506 +         DRI1_CFLAGS=""
143.1507 +         DRI1_LIBS=""
143.1508 +@@ -576,7 +604,12 @@ AM_CONDITIONAL(DRI2, test "x$have_dri2" != "xno")
143.1509 + AC_MSG_RESULT([$have_dri2])
143.1510 + if test "x$have_dri2" != "xno"; then
143.1511 +         AC_DEFINE(HAVE_DRI2,1,[Enable DRI2 driver support])
143.1512 +-	dri_msg="$dri_msg DRI2"
143.1513 ++	str="DRI2"
143.1514 ++	if test "x$DRI_DEFAULT" = "x2"; then
143.1515 ++		AC_DEFINE(DEFAULT_DRI_LEVEL,2,[Default DRI level])
143.1516 ++		str="*$str"
143.1517 ++	fi
143.1518 ++	dri_msg="$dri_msg $str"
143.1519 + else
143.1520 + 	if test "x$DRI" = "xyes" -a "x$DRI2" != "xno" -a "x$KMS" = "xyes"; then
143.1521 + 		AC_MSG_ERROR([DRI2 requested but prerequisites not found])
143.1522 +@@ -591,13 +624,21 @@ AM_CONDITIONAL(DRI3, test "x$have_dri3" != "xno")
143.1523 + AC_MSG_RESULT([$have_dri3])
143.1524 + if test "x$have_dri3" != "xno"; then
143.1525 +         AC_DEFINE(HAVE_DRI3,1,[Enable DRI3 driver support])
143.1526 +-	dri_msg="$dri_msg DRI3"
143.1527 ++	str="DRI3"
143.1528 ++	if test "x$DRI_DEFAULT" = "x3"; then
143.1529 ++		AC_DEFINE(DEFAULT_DRI_LEVEL,3,[Default DRI level])
143.1530 ++		str="*$str"
143.1531 ++	fi
143.1532 ++	dri_msg="$dri_msg $str"
143.1533 + else
143.1534 + 	if test "x$DRI" = "xyes" -a "x$DRI3" != "xno" -a "x$KMS" = "xyes"; then
143.1535 + 		AC_MSG_ERROR([DRI3 requested but prerequisites not found])
143.1536 + 	fi
143.1537 + fi
143.1538 + 
143.1539 ++AC_MSG_CHECKING([default DRI support])
143.1540 ++AC_MSG_RESULT([$DEFAULT_DRI_DEFAULT])
143.1541 ++
143.1542 + AC_CHECK_HEADERS([X11/extensions/dpmsconst.h])
143.1543 + 
143.1544 + PRESENT="no"
143.1545 +@@ -711,27 +752,6 @@ if test "x$TEARFREE" = "xyes"; then
143.1546 + 	xp_msg="$xp_msg TearFree"
143.1547 + fi
143.1548 + 
143.1549 +-AC_ARG_ENABLE(rendernode,
143.1550 +-	      AS_HELP_STRING([--enable-rendernode],
143.1551 +-			     [Enable use of render nodes (experimental) [default=no]]),
143.1552 +-	      [RENDERNODE="$enableval"],
143.1553 +-	      [RENDERNODE="no"])
143.1554 +-AM_CONDITIONAL(USE_RENDERNODE, test "x$RENDERNODE" = "xyes")
143.1555 +-if test "x$RENDERNODE" = "xyes"; then
143.1556 +-	AC_DEFINE(USE_RENDERNODE,1,[Assume "rendernode" support])
143.1557 +-	xp_msg="$xp_msg rendernode"
143.1558 +-fi
143.1559 +-
143.1560 +-AC_ARG_ENABLE(wc-mmap,
143.1561 +-	      AS_HELP_STRING([--enable-wc-mmap],
143.1562 +-			     [Enable use of WriteCombining mmaps [default=no]]),
143.1563 +-	      [WC_MMAP="$enableval"],
143.1564 +-	      [WC_MMAP="no"])
143.1565 +-if test "x$WC_MMAP" = "xyes"; then
143.1566 +-	AC_DEFINE(USE_WC_MMAP,1,[Enable use of WriteCombining mmaps])
143.1567 +-	xp_msg="$xp_msg mmap(wc)"
143.1568 +-fi
143.1569 +-
143.1570 + AC_ARG_ENABLE(create2,
143.1571 + 	      AS_HELP_STRING([--enable-create2],
143.1572 + 			     [Enable use of create2 ioctl (experimental) [default=no]]),
143.1573 +@@ -848,6 +868,7 @@ AC_CONFIG_FILES([
143.1574 +                 xvmc/shader/mc/Makefile
143.1575 +                 xvmc/shader/vld/Makefile
143.1576 + 		test/Makefile
143.1577 ++		benchmarks/Makefile
143.1578 + 		tools/Makefile
143.1579 + 		tools/org.x.xf86-video-intel.backlight-helper.policy
143.1580 + ])
143.1581 +@@ -855,7 +876,7 @@ AC_OUTPUT
143.1582 + 
143.1583 + echo ""
143.1584 + echo ""
143.1585 +-test -e `pwd $0`/README && cat `pwd $0`/README
143.1586 ++cat $srcdir/README
143.1587 + 
143.1588 + accel_msg=""
143.1589 + if test "x$SNA" != "xno"; then
143.1590 +@@ -895,13 +916,15 @@ fi
143.1591 + 
143.1592 + echo ""
143.1593 + echo "AC_PACKAGE_STRING will be compiled with:"
143.1594 +-echo "  Xorg Video ABI version: $ABI_VERSION"
143.1595 ++echo "  Xorg Video ABI version: $ABI_VERSION (xorg-server-$XSERVER_VERSION)"
143.1596 ++echo "  pixman version: pixman-1-$PIXMAN_VERSION"
143.1597 + echo "  Acceleration backends:$accel_msg"
143.1598 + echo "  Additional debugging support?$debug_msg"
143.1599 + echo "  Support for Kernel Mode Setting? $KMS"
143.1600 + echo "  Support for legacy User Mode Setting (for i810)? $UMS"
143.1601 + echo "  Support for Direct Rendering Infrastructure:$dri_msg"
143.1602 + echo "  Support for Xv motion compensation (XvMC and libXvMC):$xvmc_msg"
143.1603 ++echo "  Support for display hotplug notifications (udev):$udev_msg"
143.1604 + echo "  Build additional tools and utilities?$tools_msg"
143.1605 + if test -n "$xp_msg"; then
143.1606 + echo "  Experimental support:$xp_msg"
143.1607 +diff --git a/libobj/alloca.c b/libobj/alloca.c
143.1608 +new file mode 100644
143.1609 +index 00000000..883e1e9f
143.1610 +--- /dev/null
143.1611 ++++ b/libobj/alloca.c
143.1612 +@@ -0,0 +1,4 @@
143.1613 ++void *alloca(size_t sz)
143.1614 ++{
143.1615 ++	return NULL;
143.1616 ++}
143.1617 +diff --git a/man/intel.man b/man/intel.man
143.1618 +index 17515206..be398fbe 100644
143.1619 +--- a/man/intel.man
143.1620 ++++ b/man/intel.man
143.1621 +@@ -27,9 +27,9 @@ supports the i810, i810-DC100, i810e, i815, i830M, 845G, 852GM, 855GM,
143.1622 + 865G, 915G, 915GM, 945G, 945GM, 965G, 965Q, 946GZ, 965GM, 945GME,
143.1623 + G33, Q33, Q35, G35, GM45, G45, Q45, G43, G41 chipsets, Pineview-M in
143.1624 + Atom N400 series, Pineview-D in Atom D400/D500 series,
143.1625 +-Intel(R) HD Graphics: 2000-6000,
143.1626 +-Intel(R) Iris(TM) Graphics: 5100/6100, and
143.1627 +-Intel(R) Iris(TM) Pro Graphics: 5200/6200/P6300.
143.1628 ++Intel(R) HD Graphics,
143.1629 ++Intel(R) Iris(TM) Graphics,
143.1630 ++Intel(R) Iris(TM) Pro Graphics.
143.1631 + 
143.1632 + .SH CONFIGURATION DETAILS
143.1633 + Please refer to __xconfigfile__(__filemansuffix__) for general configuration
143.1634 +@@ -112,8 +112,8 @@ The default is 8192 if AGP allocable memory is < 128 MB, 16384 if < 192 MB,
143.1635 + 24576 if higher. DRI require at least a value of 16384. Higher values may give
143.1636 + better 3D performance, at expense of available system memory.
143.1637 + .TP
143.1638 +-.BI "Option \*qNoAccel\*q \*q" boolean \*q
143.1639 +-Disable or enable acceleration.
143.1640 ++.BI "Option \*qAccel\*q \*q" boolean \*q
143.1641 ++Enable or disable acceleration.
143.1642 + .IP
143.1643 + Default: acceleration is enabled.
143.1644 + 
143.1645 +@@ -122,8 +122,8 @@ The following driver
143.1646 + .B Options
143.1647 + are supported for the 830M and later chipsets:
143.1648 + .TP
143.1649 +-.BI "Option \*qNoAccel\*q \*q" boolean \*q
143.1650 +-Disable or enable acceleration.
143.1651 ++.BI "Option \*qAccel\*q \*q" boolean \*q
143.1652 ++Enable or disable acceleration.
143.1653 + .IP
143.1654 + Default: acceleration is enabled.
143.1655 + .TP
143.1656 +@@ -201,6 +201,16 @@ that choice by specifying the entry under /sys/class/backlight to use.
143.1657 + .IP
143.1658 + Default: Automatic selection.
143.1659 + .TP
143.1660 ++.BI "Option \*qCustomEDID\*q \*q" string \*q
143.1661 ++Override the probed EDID on particular outputs. Sometimes the manufacturer
143.1662 ++supplied EDID is corrupt or lacking a few usable modes and supplying a
143.1663 ++corrected EDID may be easier than specifying every modeline. This option
143.1664 ++allows to pass the path to load an EDID from per output. The format is a
143.1665 ++comma separated string of output:path pairs, e.g.
143.1666 ++DP1:/path/to/dp1.edid,DP2:/path/to/dp2.edid
143.1667 ++.IP
143.1668 ++Default: No override, use manufacturer supplied EDIDs.
143.1669 ++.TP
143.1670 + .BI "Option \*qFallbackDebug\*q \*q" boolean \*q
143.1671 + Enable printing of debugging information on acceleration fallbacks to the
143.1672 + server log.
143.1673 +@@ -225,6 +235,15 @@ i.e. perform synchronous rendering.
143.1674 + .IP
143.1675 + Default: Disabled
143.1676 + .TP
143.1677 ++.BI "Option \*qHWRotation\*q \*q" boolean \*q
143.1678 ++Override the use of native hardware rotation and force the use of software,
143.1679 ++but GPU accelerated where possible, rotation. On some platforms the hardware
143.1680 ++can scanout directly into a rotated output bypassing the intermediate rendering
143.1681 ++and extra allocations required for software implemented rotation (i.e. native
143.1682 ++rotation uses less resources, is quicker and uses less power). This allows you
143.1683 ++to disable the native rotation in case of errors.
143.1684 ++.IP
143.1685 ++Default: Enabled (use hardware rotation)
143.1686 + .TP
143.1687 + .BI "Option \*qVSync\*q \*q" boolean \*q
143.1688 + This option controls the use of commands to synchronise rendering with the
143.1689 +@@ -324,13 +343,29 @@ Default: 0
143.1690 + .BI "Option \*qZaphodHeads\*q \*q" string \*q
143.1691 + .IP
143.1692 + Specify the randr output(s) to use with zaphod mode for a particular driver
143.1693 +-instance.  If you this option you must use it with all instances of the
143.1694 +-driver
143.1695 ++instance.  If you set this option you must use it with all instances of the
143.1696 ++driver. By default, each head is assigned only one CRTC (which limits
143.1697 ++using multiple outputs with that head to cloned mode). CRTC can be manually
143.1698 ++assigned to individual heads by preceding the output names with a comma
143.1699 ++delimited list of pipe numbers followed by a colon. Note that different pipes
143.1700 ++may be limited in their functionality and some outputs may only work with
143.1701 ++different pipes.
143.1702 + .br
143.1703 + For example:
143.1704 ++
143.1705 ++.RS
143.1706 + .B
143.1707 + Option \*qZaphodHeads\*q \*qLVDS1,VGA1\*q
143.1708 +-will assign xrandr outputs LVDS1 and VGA0 to this instance of the driver.
143.1709 ++
143.1710 ++will assign xrandr outputs LVDS1 and VGA1 to this instance of the driver.
143.1711 ++.RE
143.1712 ++
143.1713 ++.RS
143.1714 ++.B
143.1715 ++Option \*qZaphodHeads\*q \*q0,2:HDMI1,DP2\*q
143.1716 ++
143.1717 ++will assign xrandr outputs HDMI1 and DP2 and CRTCs 0 and 2 to this instance of the driver.
143.1718 ++.RE
143.1719 + 
143.1720 + .SH OUTPUT CONFIGURATION
143.1721 + On 830M and better chipsets, the driver supports runtime configuration of
143.1722 +@@ -431,11 +466,11 @@ First DVI SDVO output
143.1723 + Second DVI SDVO output
143.1724 + 
143.1725 + .SS "TMDS-1", "TMDS-2", "HDMI-1", "HDMI-2"
143.1726 +-DVI/HDMI outputs. Avaliable common properties include:
143.1727 ++DVI/HDMI outputs. Available common properties include:
143.1728 + .TP
143.1729 + \fBBROADCAST_RGB\fP - method used to set RGB color range
143.1730 + Adjusting this property allows you to set RGB color range on each
143.1731 +-channel in order to match HDTV requirment(default 0 for full
143.1732 ++channel in order to match HDTV requirement(default 0 for full
143.1733 + range). Setting 1 means RGB color range is 16-235, 0 means RGB color
143.1734 + range is 0-255 on each channel.  (Full range is 0-255, not 16-235)
143.1735 + 
143.1736 +diff --git a/src/backlight.c b/src/backlight.c
143.1737 +index 9f239867..fcbb279f 100644
143.1738 +--- a/src/backlight.c
143.1739 ++++ b/src/backlight.c
143.1740 +@@ -34,6 +34,12 @@
143.1741 + #include <sys/stat.h>
143.1742 + #include <sys/ioctl.h>
143.1743 + 
143.1744 ++#if MAJOR_IN_MKDEV
143.1745 ++#include <sys/mkdev.h>
143.1746 ++#elif MAJOR_IN_SYSMACROS
143.1747 ++#include <sys/sysmacros.h>
143.1748 ++#endif
143.1749 ++
143.1750 + #include <stdio.h>
143.1751 + #include <stdlib.h>
143.1752 + #include <string.h>
143.1753 +@@ -42,6 +48,7 @@
143.1754 + #include <fcntl.h>
143.1755 + #include <unistd.h>
143.1756 + #include <dirent.h>
143.1757 ++#include <errno.h>
143.1758 + 
143.1759 + #include <xorg-server.h>
143.1760 + #include <xf86.h>
143.1761 +@@ -84,7 +91,7 @@ void backlight_init(struct backlight *b)
143.1762 + 	b->has_power = 0;
143.1763 + }
143.1764 + 
143.1765 +-#ifdef __OpenBSD__
143.1766 ++#ifdef HAVE_DEV_WSCONS_WSCONSIO_H
143.1767 + 
143.1768 + #include <dev/wscons/wsconsio.h>
143.1769 + #include <xf86Priv.h>
143.1770 +@@ -122,6 +129,11 @@ int backlight_get(struct backlight *b)
143.1771 + 	return param.curval;
143.1772 + }
143.1773 + 
143.1774 ++char *backlight_find_for_device(struct pci_device *pci)
143.1775 ++{
143.1776 ++	return NULL;
143.1777 ++}
143.1778 ++
143.1779 + int backlight_open(struct backlight *b, char *iface)
143.1780 + {
143.1781 + 	struct wsdisplay_param param;
143.1782 +@@ -146,12 +158,9 @@ int backlight_open(struct backlight *b, char *iface)
143.1783 + 	return param.curval;
143.1784 + }
143.1785 + 
143.1786 +-enum backlight_type backlight_exists(const char *iface)
143.1787 ++int backlight_exists(const char *iface)
143.1788 + {
143.1789 +-	if (iface != NULL)
143.1790 +-		return BL_NONE;
143.1791 +-
143.1792 +-	return BL_PLATFORM;
143.1793 ++	return iface == NULL;
143.1794 + }
143.1795 + 
143.1796 + int backlight_on(struct backlight *b)
143.1797 +@@ -163,6 +172,7 @@ int backlight_off(struct backlight *b)
143.1798 + {
143.1799 + 	return 0;
143.1800 + }
143.1801 ++
143.1802 + #else
143.1803 + 
143.1804 + static int
143.1805 +@@ -213,6 +223,24 @@ __backlight_read(const char *iface, const char *file)
143.1806 + }
143.1807 + 
143.1808 + static int
143.1809 ++writen(int fd, const char *value, int len)
143.1810 ++{
143.1811 ++	int ret;
143.1812 ++
143.1813 ++	do {
143.1814 ++		ret = write(fd, value, len);
143.1815 ++		if (ret < 0) {
143.1816 ++			if (errno == EAGAIN || errno == EINTR)
143.1817 ++				continue;
143.1818 ++
143.1819 ++			return ret;
143.1820 ++		}
143.1821 ++	} while (value += ret, len -= ret);
143.1822 ++
143.1823 ++	return 0;
143.1824 ++}
143.1825 ++
143.1826 ++static int
143.1827 + __backlight_write(const char *iface, const char *file, const char *value)
143.1828 + {
143.1829 + 	int fd, ret;
143.1830 +@@ -221,7 +249,7 @@ __backlight_write(const char *iface, const char *file, const char *value)
143.1831 + 	if (fd < 0)
143.1832 + 		return -1;
143.1833 + 
143.1834 +-	ret = write(fd, value, strlen(value)+1);
143.1835 ++	ret = writen(fd, value, strlen(value)+1);
143.1836 + 	close(fd);
143.1837 + 
143.1838 + 	return ret;
143.1839 +@@ -244,10 +272,10 @@ static const char *known_interfaces[] = {
143.1840 + 	"intel_backlight",
143.1841 + };
143.1842 + 
143.1843 +-static enum backlight_type __backlight_type(const char *iface)
143.1844 ++static int __backlight_type(const char *iface)
143.1845 + {
143.1846 + 	char buf[1024];
143.1847 +-	int fd, v;
143.1848 ++	int fd, v, i;
143.1849 + 
143.1850 + 	v = -1;
143.1851 + 	fd = __backlight_open(iface, "type", O_RDONLY);
143.1852 +@@ -261,39 +289,41 @@ static enum backlight_type __backlight_type(const char *iface)
143.1853 + 		buf[v] = '\0';
143.1854 + 
143.1855 + 		if (strcmp(buf, "raw") == 0)
143.1856 +-			v = BL_RAW;
143.1857 ++			v = BL_RAW << 8;
143.1858 + 		else if (strcmp(buf, "platform") == 0)
143.1859 +-			v = BL_PLATFORM;
143.1860 ++			v = BL_PLATFORM << 8;
143.1861 + 		else if (strcmp(buf, "firmware") == 0)
143.1862 +-			v = BL_FIRMWARE;
143.1863 ++			v = BL_FIRMWARE << 8;
143.1864 + 		else
143.1865 +-			v = BL_NAMED;
143.1866 ++			v = BL_NAMED << 8;
143.1867 + 	} else
143.1868 +-		v = BL_NAMED;
143.1869 ++		v = BL_NAMED << 8;
143.1870 + 
143.1871 +-	if (v == BL_NAMED) {
143.1872 +-		int i;
143.1873 +-		for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) {
143.1874 +-			if (strcmp(iface, known_interfaces[i]) == 0)
143.1875 +-				break;
143.1876 +-		}
143.1877 +-		v += i;
143.1878 ++	for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) {
143.1879 ++		if (strcmp(iface, known_interfaces[i]) == 0)
143.1880 ++			break;
143.1881 + 	}
143.1882 ++	v += i;
143.1883 + 
143.1884 + 	return v;
143.1885 + }
143.1886 + 
143.1887 +-enum backlight_type backlight_exists(const char *iface)
143.1888 ++static int __backlight_exists(const char *iface)
143.1889 + {
143.1890 + 	if (__backlight_read(iface, "brightness") < 0)
143.1891 +-		return BL_NONE;
143.1892 ++		return -1;
143.1893 + 
143.1894 + 	if (__backlight_read(iface, "max_brightness") <= 0)
143.1895 +-		return BL_NONE;
143.1896 ++		return -1;
143.1897 + 
143.1898 + 	return __backlight_type(iface);
143.1899 + }
143.1900 + 
143.1901 ++int backlight_exists(const char *iface)
143.1902 ++{
143.1903 ++	return __backlight_exists(iface) != -1;
143.1904 ++}
143.1905 ++
143.1906 + static int __backlight_init(struct backlight *b, char *iface, int fd)
143.1907 + {
143.1908 + 	b->fd = fd_move_cloexec(fd_set_nonblock(fd));
143.1909 +@@ -399,7 +429,50 @@ __backlight_find(void)
143.1910 + 			continue;
143.1911 + 
143.1912 + 		/* Fallback to priority list of known iface for old kernels */
143.1913 +-		v = backlight_exists(de->d_name);
143.1914 ++		v = __backlight_exists(de->d_name);
143.1915 ++		if (v < 0)
143.1916 ++			continue;
143.1917 ++
143.1918 ++		if (v < best_type) {
143.1919 ++			char *copy = strdup(de->d_name);
143.1920 ++			if (copy) {
143.1921 ++				free(best_iface);
143.1922 ++				best_iface = copy;
143.1923 ++				best_type = v;
143.1924 ++			}
143.1925 ++		}
143.1926 ++	}
143.1927 ++	closedir(dir);
143.1928 ++
143.1929 ++	return best_iface;
143.1930 ++}
143.1931 ++
143.1932 ++char *backlight_find_for_device(struct pci_device *pci)
143.1933 ++{
143.1934 ++	char path[200];
143.1935 ++	unsigned best_type = INT_MAX;
143.1936 ++	char *best_iface = NULL;
143.1937 ++	DIR *dir;
143.1938 ++	struct dirent *de;
143.1939 ++
143.1940 ++	snprintf(path, sizeof(path),
143.1941 ++		 "/sys/bus/pci/devices/%04x:%02x:%02x.%d/backlight",
143.1942 ++		 pci->domain, pci->bus, pci->dev, pci->func);
143.1943 ++
143.1944 ++	dir = opendir(path);
143.1945 ++	if (dir == NULL)
143.1946 ++		return NULL;
143.1947 ++
143.1948 ++	while ((de = readdir(dir))) {
143.1949 ++		int v;
143.1950 ++
143.1951 ++		if (*de->d_name == '.')
143.1952 ++			continue;
143.1953 ++
143.1954 ++		v = __backlight_exists(de->d_name);
143.1955 ++		if (v < 0)
143.1956 ++			continue;
143.1957 ++
143.1958 + 		if (v < best_type) {
143.1959 + 			char *copy = strdup(de->d_name);
143.1960 + 			if (copy) {
143.1961 +@@ -416,14 +489,17 @@ __backlight_find(void)
143.1962 + 
143.1963 + int backlight_open(struct backlight *b, char *iface)
143.1964 + {
143.1965 +-	int level;
143.1966 ++	int level, type;
143.1967 + 
143.1968 + 	if (iface == NULL)
143.1969 + 		iface = __backlight_find();
143.1970 + 	if (iface == NULL)
143.1971 + 		goto err;
143.1972 + 
143.1973 +-	b->type = __backlight_type(iface);
143.1974 ++	type = __backlight_type(iface);
143.1975 ++	if (type < 0)
143.1976 ++		goto err;
143.1977 ++	b->type = type >> 8;
143.1978 + 
143.1979 + 	b->max = __backlight_read(iface, "max_brightness");
143.1980 + 	if (b->max <= 0)
143.1981 +@@ -447,7 +523,7 @@ err:
143.1982 + int backlight_set(struct backlight *b, int level)
143.1983 + {
143.1984 + 	char val[BACKLIGHT_VALUE_LEN];
143.1985 +-	int len, ret = 0;
143.1986 ++	int len;
143.1987 + 
143.1988 + 	if (b->iface == NULL)
143.1989 + 		return 0;
143.1990 +@@ -456,10 +532,7 @@ int backlight_set(struct backlight *b, int level)
143.1991 + 		level = b->max;
143.1992 + 
143.1993 + 	len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level);
143.1994 +-	if (write(b->fd, val, len) != len)
143.1995 +-		ret = -1;
143.1996 +-
143.1997 +-	return ret;
143.1998 ++	return writen(b->fd, val, len);
143.1999 + }
143.2000 + 
143.2001 + int backlight_get(struct backlight *b)
143.2002 +@@ -517,43 +590,6 @@ void backlight_disable(struct backlight *b)
143.2003 + void backlight_close(struct backlight *b)
143.2004 + {
143.2005 + 	backlight_disable(b);
143.2006 +-	if (b->pid)
143.2007 ++	if (b->pid > 0)
143.2008 + 		waitpid(b->pid, NULL, 0);
143.2009 + }
143.2010 +-
143.2011 +-char *backlight_find_for_device(struct pci_device *pci)
143.2012 +-{
143.2013 +-	char path[200];
143.2014 +-	unsigned best_type = INT_MAX;
143.2015 +-	char *best_iface = NULL;
143.2016 +-	DIR *dir;
143.2017 +-	struct dirent *de;
143.2018 +-
143.2019 +-	snprintf(path, sizeof(path),
143.2020 +-		 "/sys/bus/pci/devices/%04x:%02x:%02x.%d/backlight",
143.2021 +-		 pci->domain, pci->bus, pci->dev, pci->func);
143.2022 +-
143.2023 +-	dir = opendir(path);
143.2024 +-	if (dir == NULL)
143.2025 +-		return NULL;
143.2026 +-
143.2027 +-	while ((de = readdir(dir))) {
143.2028 +-		int v;
143.2029 +-
143.2030 +-		if (*de->d_name == '.')
143.2031 +-			continue;
143.2032 +-
143.2033 +-		v = backlight_exists(de->d_name);
143.2034 +-		if (v < best_type) {
143.2035 +-			char *copy = strdup(de->d_name);
143.2036 +-			if (copy) {
143.2037 +-				free(best_iface);
143.2038 +-				best_iface = copy;
143.2039 +-				best_type = v;
143.2040 +-			}
143.2041 +-		}
143.2042 +-	}
143.2043 +-	closedir(dir);
143.2044 +-
143.2045 +-	return best_iface;
143.2046 +-}
143.2047 +diff --git a/src/backlight.h b/src/backlight.h
143.2048 +index bb0e28bc..ba17755b 100644
143.2049 +--- a/src/backlight.h
143.2050 ++++ b/src/backlight.h
143.2051 +@@ -43,7 +43,7 @@ struct backlight {
143.2052 + 	int pid, fd;
143.2053 + };
143.2054 + 
143.2055 +-enum backlight_type backlight_exists(const char *iface);
143.2056 ++int backlight_exists(const char *iface);
143.2057 + 
143.2058 + void backlight_init(struct backlight *backlight);
143.2059 + int backlight_open(struct backlight *backlight, char *iface);
143.2060 +diff --git a/src/compat-api.h b/src/compat-api.h
143.2061 +index d09e1fb3..05797a08 100644
143.2062 +--- a/src/compat-api.h
143.2063 ++++ b/src/compat-api.h
143.2064 +@@ -30,6 +30,7 @@
143.2065 + 
143.2066 + #include <xorg-server.h>
143.2067 + #include <xorgVersion.h>
143.2068 ++#include <xf86Module.h>
143.2069 + 
143.2070 + #include <picturestr.h>
143.2071 + #ifndef GLYPH_HAS_GLYPH_PICTURE_ACCESSOR
143.2072 +@@ -39,7 +40,17 @@
143.2073 + 
143.2074 + #ifndef XF86_HAS_SCRN_CONV
143.2075 + #define xf86ScreenToScrn(s) xf86Screens[(s)->myNum]
143.2076 ++#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,1,0,0,0)
143.2077 + #define xf86ScrnToScreen(s) screenInfo.screens[(s)->scrnIndex]
143.2078 ++#else
143.2079 ++#define xf86ScrnToScreen(s) ((s)->pScreen)
143.2080 ++#endif
143.2081 ++#else
143.2082 ++#define xf86ScrnToScreen(s) ((s)->pScreen)
143.2083 ++#endif
143.2084 ++
143.2085 ++#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22
143.2086 ++#define HAVE_NOTIFY_FD 1
143.2087 + #endif
143.2088 + 
143.2089 + #ifndef XF86_SCRN_INTERFACE
143.2090 +@@ -131,6 +142,17 @@ region_rects(const RegionRec *r)
143.2091 + 	return r->data ? (const BoxRec *)(r->data + 1) :  &r->extents;
143.2092 + }
143.2093 + 
143.2094 ++inline static void
143.2095 ++region_get_boxes(const RegionRec *r, const BoxRec **s, const BoxRec **e)
143.2096 ++{
143.2097 ++	int n;
143.2098 ++	if (r->data)
143.2099 ++		*s = region_boxptr(r), n = r->data->numRects;
143.2100 ++	else
143.2101 ++		*s = &r->extents, n = 1;
143.2102 ++	*e = *s + n;
143.2103 ++}
143.2104 ++
143.2105 + #ifndef INCLUDE_LEGACY_REGION_DEFINES
143.2106 + #define RegionCreate(r, s) REGION_CREATE(NULL, r, s)
143.2107 + #define RegionBreak(r) REGION_BREAK(NULL, r)
143.2108 +@@ -223,4 +245,19 @@ static inline void FreePixmap(PixmapPtr pixmap)
143.2109 + 			  dstx, dsty)
143.2110 + #endif
143.2111 + 
143.2112 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
143.2113 ++#define isGPU(S) (S)->is_gpu
143.2114 ++#else
143.2115 ++#define isGPU(S) 0
143.2116 ++#endif
143.2117 ++
143.2118 ++#if HAS_DIRTYTRACKING_ROTATION
143.2119 ++#define PixmapSyncDirtyHelper(d, dd) PixmapSyncDirtyHelper(d)
143.2120 ++#endif
143.2121 ++
143.2122 ++#if !HAVE_NOTIFY_FD
143.2123 ++#define SetNotifyFd(fd, cb, mode, data) AddGeneralSocket(fd);
143.2124 ++#define RemoveNotifyFd(fd) RemoveGeneralSocket(fd)
143.2125 ++#endif
143.2126 ++
143.2127 + #endif
143.2128 +diff --git a/src/i915_pciids.h b/src/i915_pciids.h
143.2129 +index 180ad0e6..466c7159 100644
143.2130 +--- a/src/i915_pciids.h
143.2131 ++++ b/src/i915_pciids.h
143.2132 +@@ -134,7 +134,7 @@
143.2133 + #define INTEL_IVB_Q_IDS(info) \
143.2134 + 	INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */
143.2135 + 
143.2136 +-#define INTEL_HSW_D_IDS(info) \
143.2137 ++#define INTEL_HSW_IDS(info) \
143.2138 + 	INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \
143.2139 + 	INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \
143.2140 + 	INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \
143.2141 +@@ -179,9 +179,7 @@
143.2142 + 	INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \
143.2143 + 	INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \
143.2144 + 	INTEL_VGA_DEVICE(0x0D1E, info), /* CRW GT2 reserved */ \
143.2145 +-	INTEL_VGA_DEVICE(0x0D2E, info)  /* CRW GT3 reserved */ \
143.2146 +-
143.2147 +-#define INTEL_HSW_M_IDS(info) \
143.2148 ++	INTEL_VGA_DEVICE(0x0D2E, info),  /* CRW GT3 reserved */ \
143.2149 + 	INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \
143.2150 + 	INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \
143.2151 + 	INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \
143.2152 +@@ -198,60 +196,48 @@
143.2153 + 	INTEL_VGA_DEVICE(0x0D16, info), /* CRW GT2 mobile */ \
143.2154 + 	INTEL_VGA_DEVICE(0x0D26, info)  /* CRW GT3 mobile */
143.2155 + 
143.2156 +-#define INTEL_VLV_M_IDS(info) \
143.2157 ++#define INTEL_VLV_IDS(info) \
143.2158 + 	INTEL_VGA_DEVICE(0x0f30, info), \
143.2159 + 	INTEL_VGA_DEVICE(0x0f31, info), \
143.2160 + 	INTEL_VGA_DEVICE(0x0f32, info), \
143.2161 + 	INTEL_VGA_DEVICE(0x0f33, info), \
143.2162 +-	INTEL_VGA_DEVICE(0x0157, info)
143.2163 +-
143.2164 +-#define INTEL_VLV_D_IDS(info) \
143.2165 ++	INTEL_VGA_DEVICE(0x0157, info), \
143.2166 + 	INTEL_VGA_DEVICE(0x0155, info)
143.2167 + 
143.2168 +-#define _INTEL_BDW_M(gt, id, info) \
143.2169 +-	INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
143.2170 +-#define _INTEL_BDW_D(gt, id, info) \
143.2171 +-	INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
143.2172 +-
143.2173 +-#define _INTEL_BDW_M_IDS(gt, info) \
143.2174 +-	_INTEL_BDW_M(gt, 0x1602, info), /* ULT */ \
143.2175 +-	_INTEL_BDW_M(gt, 0x1606, info), /* ULT */ \
143.2176 +-	_INTEL_BDW_M(gt, 0x160B, info), /* Iris */ \
143.2177 +-	_INTEL_BDW_M(gt, 0x160E, info) /* ULX */
143.2178 +-
143.2179 +-#define _INTEL_BDW_D_IDS(gt, info) \
143.2180 +-	_INTEL_BDW_D(gt, 0x160A, info), /* Server */ \
143.2181 +-	_INTEL_BDW_D(gt, 0x160D, info) /* Workstation */
143.2182 +-
143.2183 +-#define INTEL_BDW_GT12M_IDS(info) \
143.2184 +-	_INTEL_BDW_M_IDS(1, info), \
143.2185 +-	_INTEL_BDW_M_IDS(2, info)
143.2186 +-
143.2187 +-#define INTEL_BDW_GT12D_IDS(info) \
143.2188 +-	_INTEL_BDW_D_IDS(1, info), \
143.2189 +-	_INTEL_BDW_D_IDS(2, info)
143.2190 +-
143.2191 +-#define INTEL_BDW_GT3M_IDS(info) \
143.2192 +-	_INTEL_BDW_M_IDS(3, info)
143.2193 +-
143.2194 +-#define INTEL_BDW_GT3D_IDS(info) \
143.2195 +-	_INTEL_BDW_D_IDS(3, info)
143.2196 +-
143.2197 +-#define INTEL_BDW_RSVDM_IDS(info) \
143.2198 +-	_INTEL_BDW_M_IDS(4, info)
143.2199 +-
143.2200 +-#define INTEL_BDW_RSVDD_IDS(info) \
143.2201 +-	_INTEL_BDW_D_IDS(4, info)
143.2202 +-
143.2203 +-#define INTEL_BDW_M_IDS(info) \
143.2204 +-	INTEL_BDW_GT12M_IDS(info), \
143.2205 +-	INTEL_BDW_GT3M_IDS(info), \
143.2206 +-	INTEL_BDW_RSVDM_IDS(info)
143.2207 +-
143.2208 +-#define INTEL_BDW_D_IDS(info) \
143.2209 +-	INTEL_BDW_GT12D_IDS(info), \
143.2210 +-	INTEL_BDW_GT3D_IDS(info), \
143.2211 +-	INTEL_BDW_RSVDD_IDS(info)
143.2212 ++#define INTEL_BDW_GT12_IDS(info)  \
143.2213 ++	INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \
143.2214 ++	INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
143.2215 ++	INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \
143.2216 ++	INTEL_VGA_DEVICE(0x160E, info), /* GT1 ULX */ \
143.2217 ++	INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \
143.2218 ++	INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \
143.2219 ++	INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \
143.2220 ++	INTEL_VGA_DEVICE(0x161E, info),  /* GT2 ULX */ \
143.2221 ++	INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \
143.2222 ++	INTEL_VGA_DEVICE(0x160D, info), /* GT1 Workstation */ \
143.2223 ++	INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \
143.2224 ++	INTEL_VGA_DEVICE(0x161D, info)  /* GT2 Workstation */
143.2225 ++
143.2226 ++#define INTEL_BDW_GT3_IDS(info) \
143.2227 ++	INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \
143.2228 ++	INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \
143.2229 ++	INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \
143.2230 ++	INTEL_VGA_DEVICE(0x162E, info),  /* ULX */\
143.2231 ++	INTEL_VGA_DEVICE(0x162A, info), /* Server */ \
143.2232 ++	INTEL_VGA_DEVICE(0x162D, info)  /* Workstation */
143.2233 ++
143.2234 ++#define INTEL_BDW_RSVD_IDS(info) \
143.2235 ++	INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \
143.2236 ++	INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \
143.2237 ++	INTEL_VGA_DEVICE(0x163B, info), /* Iris */ \
143.2238 ++	INTEL_VGA_DEVICE(0x163E, info), /* ULX */ \
143.2239 ++	INTEL_VGA_DEVICE(0x163A, info), /* Server */ \
143.2240 ++	INTEL_VGA_DEVICE(0x163D, info)  /* Workstation */
143.2241 ++
143.2242 ++#define INTEL_BDW_IDS(info) \
143.2243 ++	INTEL_BDW_GT12_IDS(info), \
143.2244 ++	INTEL_BDW_GT3_IDS(info), \
143.2245 ++	INTEL_BDW_RSVD_IDS(info)
143.2246 + 
143.2247 + #define INTEL_CHV_IDS(info) \
143.2248 + 	INTEL_VGA_DEVICE(0x22b0, info), \
143.2249 +@@ -259,21 +245,85 @@
143.2250 + 	INTEL_VGA_DEVICE(0x22b2, info), \
143.2251 + 	INTEL_VGA_DEVICE(0x22b3, info)
143.2252 + 
143.2253 +-#define INTEL_SKL_IDS(info) \
143.2254 +-	INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
143.2255 ++#define INTEL_SKL_GT1_IDS(info)	\
143.2256 + 	INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \
143.2257 +-	INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
143.2258 +-	INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
143.2259 + 	INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \
143.2260 ++	INTEL_VGA_DEVICE(0x1902, info), /* DT  GT1 */ \
143.2261 ++	INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
143.2262 ++	INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */
143.2263 ++
143.2264 ++#define INTEL_SKL_GT2_IDS(info)	\
143.2265 ++	INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
143.2266 ++	INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
143.2267 + 	INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \
143.2268 + 	INTEL_VGA_DEVICE(0x1912, info), /* DT  GT2 */ \
143.2269 +-	INTEL_VGA_DEVICE(0x1902, info), /* DT  GT1 */ \
143.2270 + 	INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \
143.2271 +-	INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
143.2272 +-	INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
143.2273 + 	INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \
143.2274 +-	INTEL_VGA_DEVICE(0x192A, info), /* SRV GT3 */ \
143.2275 +-	INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ \
143.2276 + 	INTEL_VGA_DEVICE(0x191D, info)  /* WKS GT2 */
143.2277 + 
143.2278 ++#define INTEL_SKL_GT3_IDS(info) \
143.2279 ++	INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \
143.2280 ++	INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
143.2281 ++	INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ \
143.2282 ++	INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
143.2283 ++	INTEL_VGA_DEVICE(0x192D, info)  /* SRV GT3 */
143.2284 ++
143.2285 ++#define INTEL_SKL_GT4_IDS(info) \
143.2286 ++	INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */ \
143.2287 ++	INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4 */ \
143.2288 ++	INTEL_VGA_DEVICE(0x193D, info), /* WKS GT4 */ \
143.2289 ++	INTEL_VGA_DEVICE(0x192A, info), /* SRV GT4 */ \
143.2290 ++	INTEL_VGA_DEVICE(0x193A, info)  /* SRV GT4e */
143.2291 ++
143.2292 ++#define INTEL_SKL_IDS(info)	 \
143.2293 ++	INTEL_SKL_GT1_IDS(info), \
143.2294 ++	INTEL_SKL_GT2_IDS(info), \
143.2295 ++	INTEL_SKL_GT3_IDS(info), \
143.2296 ++	INTEL_SKL_GT4_IDS(info)
143.2297 ++
143.2298 ++#define INTEL_BXT_IDS(info) \
143.2299 ++	INTEL_VGA_DEVICE(0x0A84, info), \
143.2300 ++	INTEL_VGA_DEVICE(0x1A84, info), \
143.2301 ++	INTEL_VGA_DEVICE(0x1A85, info), \
143.2302 ++	INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ \
143.2303 ++	INTEL_VGA_DEVICE(0x5A85, info)  /* APL HD Graphics 500 */
143.2304 ++
143.2305 ++#define INTEL_GLK_IDS(info) \
143.2306 ++	INTEL_VGA_DEVICE(0x3184, info), \
143.2307 ++	INTEL_VGA_DEVICE(0x3185, info)
143.2308 ++
143.2309 ++#define INTEL_KBL_GT1_IDS(info)	\
143.2310 ++	INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \
143.2311 ++	INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \
143.2312 ++	INTEL_VGA_DEVICE(0x5917, info), /* DT  GT1.5 */ \
143.2313 ++	INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \
143.2314 ++	INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \
143.2315 ++	INTEL_VGA_DEVICE(0x5902, info), /* DT  GT1 */ \
143.2316 ++	INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */ \
143.2317 ++	INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \
143.2318 ++	INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */
143.2319 ++
143.2320 ++#define INTEL_KBL_GT2_IDS(info)	\
143.2321 ++	INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \
143.2322 ++	INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \
143.2323 ++	INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \
143.2324 ++	INTEL_VGA_DEVICE(0x5912, info), /* DT  GT2 */ \
143.2325 ++	INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \
143.2326 ++	INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \
143.2327 ++	INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */
143.2328 ++
143.2329 ++#define INTEL_KBL_GT3_IDS(info) \
143.2330 ++	INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */ \
143.2331 ++	INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \
143.2332 ++	INTEL_VGA_DEVICE(0x5927, info) /* ULT GT3 */
143.2333 ++
143.2334 ++#define INTEL_KBL_GT4_IDS(info) \
143.2335 ++	INTEL_VGA_DEVICE(0x593B, info) /* Halo GT4 */
143.2336 ++
143.2337 ++#define INTEL_KBL_IDS(info) \
143.2338 ++	INTEL_KBL_GT1_IDS(info), \
143.2339 ++	INTEL_KBL_GT2_IDS(info), \
143.2340 ++	INTEL_KBL_GT3_IDS(info), \
143.2341 ++	INTEL_KBL_GT4_IDS(info)
143.2342 ++
143.2343 + #endif /* _I915_PCIIDS_H */
143.2344 +diff --git a/src/intel_device.c b/src/intel_device.c
143.2345 +index 140e1536..c4910cd8 100644
143.2346 +--- a/src/intel_device.c
143.2347 ++++ b/src/intel_device.c
143.2348 +@@ -38,6 +38,12 @@
143.2349 + #include <dirent.h>
143.2350 + #include <errno.h>
143.2351 + 
143.2352 ++#if MAJOR_IN_MKDEV
143.2353 ++#include <sys/mkdev.h>
143.2354 ++#elif MAJOR_IN_SYSMACROS
143.2355 ++#include <sys/sysmacros.h>
143.2356 ++#endif
143.2357 ++
143.2358 + #include <pciaccess.h>
143.2359 + 
143.2360 + #include <xorg-server.h>
143.2361 +@@ -197,9 +203,15 @@ static inline struct intel_device *intel_device(ScrnInfoPtr scrn)
143.2362 + 	return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr;
143.2363 + }
143.2364 + 
143.2365 ++static const char *kernel_module_names[] ={
143.2366 ++	"i915",
143.2367 ++	NULL,
143.2368 ++};
143.2369 ++
143.2370 + static int is_i915_device(int fd)
143.2371 + {
143.2372 + 	drm_version_t version;
143.2373 ++	const char **kn;
143.2374 + 	char name[5] = "";
143.2375 + 
143.2376 + 	memset(&version, 0, sizeof(version));
143.2377 +@@ -209,7 +221,22 @@ static int is_i915_device(int fd)
143.2378 + 	if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
143.2379 + 		return 0;
143.2380 + 
143.2381 +-	return strcmp("i915", name) == 0;
143.2382 ++	for (kn = kernel_module_names; *kn; kn++)
143.2383 ++		if (strcmp(*kn, name) == 0)
143.2384 ++			return 1;
143.2385 ++
143.2386 ++	return 0;
143.2387 ++}
143.2388 ++
143.2389 ++static int load_i915_kernel_module(void)
143.2390 ++{
143.2391 ++	const char **kn;
143.2392 ++
143.2393 ++	for (kn = kernel_module_names; *kn; kn++)
143.2394 ++		if (xf86LoadKernelModule(*kn))
143.2395 ++			return 0;
143.2396 ++
143.2397 ++	return -1;
143.2398 + }
143.2399 + 
143.2400 + static int is_i915_gem(int fd)
143.2401 +@@ -336,7 +363,7 @@ static int __intel_open_device__pci(const struct pci_device *pci)
143.2402 + 
143.2403 + 		sprintf(path + base, "driver");
143.2404 + 		if (stat(path, &st)) {
143.2405 +-			if (xf86LoadKernelModule("i915"))
143.2406 ++			if (load_i915_kernel_module())
143.2407 + 				return -1;
143.2408 + 			(void)xf86LoadKernelModule("fbcon");
143.2409 + 		}
143.2410 +@@ -399,7 +426,7 @@ static int __intel_open_device__legacy(const struct pci_device *pci)
143.2411 + 
143.2412 + 	ret = drmCheckModesettingSupported(id);
143.2413 + 	if (ret) {
143.2414 +-		if (xf86LoadKernelModule("i915"))
143.2415 ++		if (load_i915_kernel_module() == 0)
143.2416 + 			ret = drmCheckModesettingSupported(id);
143.2417 + 		if (ret)
143.2418 + 			return -1;
143.2419 +@@ -461,9 +488,9 @@ static int is_render_node(int fd, struct stat *st)
143.2420 + 
143.2421 + static char *find_render_node(int fd)
143.2422 + {
143.2423 +-#if defined(USE_RENDERNODE)
143.2424 + 	struct stat master, render;
143.2425 + 	char buf[128];
143.2426 ++	int i;
143.2427 + 
143.2428 + 	/* Are we a render-node ourselves? */
143.2429 + 	if (is_render_node(fd, &master))
143.2430 +@@ -472,9 +499,17 @@ static char *find_render_node(int fd)
143.2431 + 	sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf));
143.2432 + 	if (stat(buf, &render) == 0 &&
143.2433 + 	    master.st_mode == render.st_mode &&
143.2434 +-	    render.st_rdev == ((master.st_rdev | 0x80) & 0xbf))
143.2435 ++	    render.st_rdev == (master.st_rdev | 0x80))
143.2436 + 		return strdup(buf);
143.2437 +-#endif
143.2438 ++
143.2439 ++	/* Misaligned card <-> renderD, do a full search */
143.2440 ++	for (i = 0; i < 16; i++) {
143.2441 ++		sprintf(buf, "/dev/dri/renderD%d", i + 128);
143.2442 ++		if (stat(buf, &render) == 0 &&
143.2443 ++		    master.st_mode == render.st_mode &&
143.2444 ++		    render.st_rdev == (master.st_rdev | 0x80))
143.2445 ++			return strdup(buf);
143.2446 ++	}
143.2447 + 
143.2448 + 	return NULL;
143.2449 + }
143.2450 +@@ -608,6 +643,27 @@ err_path:
143.2451 + 	return -1;
143.2452 + }
143.2453 + 
143.2454 ++void intel_close_device(int entity_num)
143.2455 ++{
143.2456 ++	struct intel_device *dev;
143.2457 ++
143.2458 ++	if (intel_device_key == -1)
143.2459 ++		return;
143.2460 ++
143.2461 ++	dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr;
143.2462 ++	xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = NULL;
143.2463 ++	if (!dev)
143.2464 ++		return;
143.2465 ++
143.2466 ++	if (dev->master_count == 0) /* Don't close server-fds */
143.2467 ++		close(dev->fd);
143.2468 ++
143.2469 ++	if (dev->render_node != dev->master_node)
143.2470 ++		free(dev->render_node);
143.2471 ++	free(dev->master_node);
143.2472 ++	free(dev);
143.2473 ++}
143.2474 ++
143.2475 + int __intel_peek_fd(ScrnInfoPtr scrn)
143.2476 + {
143.2477 + 	struct intel_device *dev;
143.2478 +@@ -672,6 +728,12 @@ struct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd)
143.2479 + 	return dev;
143.2480 + }
143.2481 + 
143.2482 ++const char *intel_get_master_name(struct intel_device *dev)
143.2483 ++{
143.2484 ++	assert(dev && dev->master_node);
143.2485 ++	return dev->master_node;
143.2486 ++}
143.2487 ++
143.2488 + const char *intel_get_client_name(struct intel_device *dev)
143.2489 + {
143.2490 + 	assert(dev && dev->render_node);
143.2491 +diff --git a/src/intel_driver.h b/src/intel_driver.h
143.2492 +index 28ed1a0e..bece88a0 100644
143.2493 +--- a/src/intel_driver.h
143.2494 ++++ b/src/intel_driver.h
143.2495 +@@ -124,9 +124,11 @@ int intel_entity_get_devid(int index);
143.2496 + int intel_open_device(int entity_num,
143.2497 + 		      const struct pci_device *pci,
143.2498 + 		      struct xf86_platform_device *dev);
143.2499 ++void intel_close_device(int entity_num);
143.2500 + int __intel_peek_fd(ScrnInfoPtr scrn);
143.2501 + struct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd);
143.2502 + int intel_has_render_node(struct intel_device *dev);
143.2503 ++const char *intel_get_master_name(struct intel_device *dev);
143.2504 + const char *intel_get_client_name(struct intel_device *dev);
143.2505 + int intel_get_client_fd(struct intel_device *dev);
143.2506 + int intel_get_device_id(struct intel_device *dev);
143.2507 +diff --git a/src/intel_list.h b/src/intel_list.h
143.2508 +index 51af825d..c8a3187a 100644
143.2509 +--- a/src/intel_list.h
143.2510 ++++ b/src/intel_list.h
143.2511 +@@ -306,8 +306,7 @@ list_is_empty(const struct list *head)
143.2512 +     list_entry((ptr)->prev, type, member)
143.2513 + 
143.2514 + #define __container_of(ptr, sample, member)				\
143.2515 +-    (void *)((char *)(ptr)						\
143.2516 +-	     - ((char *)&(sample)->member - (char *)(sample)))
143.2517 ++    (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
143.2518 + /**
143.2519 +  * Loop through the list given by head and set pos to struct in the list.
143.2520 +  *
143.2521 +@@ -392,17 +391,50 @@ static inline void list_move_tail(struct list *list, struct list *head)
143.2522 + #define list_last_entry(ptr, type, member) \
143.2523 +     list_entry((ptr)->prev, type, member)
143.2524 + 
143.2525 +-#define list_for_each_entry_reverse(pos, head, member)				\
143.2526 ++#define list_for_each_entry_reverse(pos, head, member)			\
143.2527 +     for (pos = __container_of((head)->prev, pos, member);		\
143.2528 + 	 &pos->member != (head);					\
143.2529 + 	 pos = __container_of(pos->member.prev, pos, member))
143.2530 + 
143.2531 + #endif
143.2532 + 
143.2533 ++#define list_for_each_entry_safe_from(pos, tmp, head, member)		\
143.2534 ++    for (tmp = __container_of(pos->member.next, pos, member);		\
143.2535 ++	 &pos->member != (head);					\
143.2536 ++	 pos = tmp, tmp = __container_of(tmp->member.next, tmp, member))
143.2537 ++
143.2538 + #undef container_of
143.2539 + #define container_of(ptr, type, member) \
143.2540 + 	((type *)((char *)(ptr) - (char *) &((type *)0)->member))
143.2541 + 
143.2542 ++static inline void __list_splice(const struct list *list,
143.2543 ++				 struct list *prev,
143.2544 ++				 struct list *next)
143.2545 ++{
143.2546 ++	struct list *first = list->next;
143.2547 ++	struct list *last = list->prev;
143.2548 ++
143.2549 ++	first->prev = prev;
143.2550 ++	prev->next = first;
143.2551 ++
143.2552 ++	last->next = next;
143.2553 ++	next->prev = last;
143.2554 ++}
143.2555 ++
143.2556 ++static inline void list_splice(const struct list *list,
143.2557 ++			       struct list *head)
143.2558 ++{
143.2559 ++	if (!list_is_empty(list))
143.2560 ++		__list_splice(list, head, head->next);
143.2561 ++}
143.2562 ++
143.2563 ++static inline void list_splice_tail(const struct list *list,
143.2564 ++				    struct list *head)
143.2565 ++{
143.2566 ++	if (!list_is_empty(list))
143.2567 ++		__list_splice(list, head->prev, head);
143.2568 ++}
143.2569 ++
143.2570 + static inline int list_is_singular(const struct list *list)
143.2571 + {
143.2572 + 	return list->next == list->prev;
143.2573 +diff --git a/src/intel_module.c b/src/intel_module.c
143.2574 +index 102d52aa..2e97b5ea 100644
143.2575 +--- a/src/intel_module.c
143.2576 ++++ b/src/intel_module.c
143.2577 +@@ -126,6 +126,17 @@ static const struct intel_device_info intel_skylake_info = {
143.2578 + 	.gen = 0110,
143.2579 + };
143.2580 + 
143.2581 ++static const struct intel_device_info intel_broxton_info = {
143.2582 ++	.gen = 0111,
143.2583 ++};
143.2584 ++
143.2585 ++static const struct intel_device_info intel_kabylake_info = {
143.2586 ++	.gen = 0112,
143.2587 ++};
143.2588 ++
143.2589 ++static const struct intel_device_info intel_geminilake_info = {
143.2590 ++	.gen = 0113,
143.2591 ++};
143.2592 + 
143.2593 + static const SymTabRec intel_chipsets[] = {
143.2594 + 	{PCI_CHIP_I810,				"i810"},
143.2595 +@@ -234,30 +245,63 @@ static const SymTabRec intel_chipsets[] = {
143.2596 + 	{0x0157, "HD Graphics"},
143.2597 + 
143.2598 + 	/* Broadwell Marketing names */
143.2599 +-	{0x1602, "HD graphics"},
143.2600 +-	{0x1606, "HD graphics"},
143.2601 +-	{0x160B, "HD graphics"},
143.2602 +-	{0x160A, "HD graphics"},
143.2603 +-	{0x160D, "HD graphics"},
143.2604 +-	{0x160E, "HD graphics"},
143.2605 +-	{0x1612, "HD graphics 5600"},
143.2606 +-	{0x1616, "HD graphics 5500"},
143.2607 +-	{0x161B, "HD graphics"},
143.2608 +-	{0x161A, "HD graphics"},
143.2609 +-	{0x161D, "HD graphics"},
143.2610 +-	{0x161E, "HD graphics 5300"},
143.2611 +-	{0x1622, "Iris Pro graphics 6200"},
143.2612 +-	{0x1626, "HD graphics 6000"},
143.2613 +-	{0x162B, "Iris graphics 6100"},
143.2614 +-	{0x162A, "Iris Pro graphics P6300"},
143.2615 +-	{0x162D, "HD graphics"},
143.2616 +-	{0x162E, "HD graphics"},
143.2617 +-	{0x1632, "HD graphics"},
143.2618 +-	{0x1636, "HD graphics"},
143.2619 +-	{0x163B, "HD graphics"},
143.2620 +-	{0x163A, "HD graphics"},
143.2621 +-	{0x163D, "HD graphics"},
143.2622 +-	{0x163E, "HD graphics"},
143.2623 ++	{0x1602, "HD Graphics"},
143.2624 ++	{0x1606, "HD Graphics"},
143.2625 ++	{0x160B, "HD Graphics"},
143.2626 ++	{0x160A, "HD Graphics"},
143.2627 ++	{0x160D, "HD Graphics"},
143.2628 ++	{0x160E, "HD Graphics"},
143.2629 ++	{0x1612, "HD Graphics 5600"},
143.2630 ++	{0x1616, "HD Graphics 5500"},
143.2631 ++	{0x161B, "HD Graphics"},
143.2632 ++	{0x161A, "HD Graphics"},
143.2633 ++	{0x161D, "HD Graphics"},
143.2634 ++	{0x161E, "HD Graphics 5300"},
143.2635 ++	{0x1622, "Iris Pro Graphics 6200"},
143.2636 ++	{0x1626, "HD Graphics 6000"},
143.2637 ++	{0x162B, "Iris Graphics 6100"},
143.2638 ++	{0x162A, "Iris Pro Graphics P6300"},
143.2639 ++	{0x162D, "HD Graphics"},
143.2640 ++	{0x162E, "HD Graphics"},
143.2641 ++	{0x1632, "HD Graphics"},
143.2642 ++	{0x1636, "HD Graphics"},
143.2643 ++	{0x163B, "HD Graphics"},
143.2644 ++	{0x163A, "HD Graphics"},
143.2645 ++	{0x163D, "HD Graphics"},
143.2646 ++	{0x163E, "HD Graphics"},
143.2647 ++
143.2648 ++	/* Cherryview (Cherrytrail/Braswell) */
143.2649 ++	{0x22b0, "HD Graphics"},
143.2650 ++	{0x22b1, "HD Graphics"},
143.2651 ++	{0x22b2, "HD Graphics"},
143.2652 ++	{0x22b3, "HD Graphics"},
143.2653 ++
143.2654 ++	/* Skylake */
143.2655 ++	{0x1902, "HD Graphics 510"},
143.2656 ++	{0x1906, "HD Graphics 510"},
143.2657 ++	{0x190B, "HD Graphics 510"},
143.2658 ++	{0x1912, "HD Graphics 530"},
143.2659 ++	{0x1916, "HD Graphics 520"},
143.2660 ++	{0x191B, "HD Graphics 530"},
143.2661 ++	{0x191D, "HD Graphics P530"},
143.2662 ++	{0x191E, "HD Graphics 515"},
143.2663 ++	{0x1921, "HD Graphics 520"},
143.2664 ++	{0x1926, "Iris Graphics 540"},
143.2665 ++	{0x1927, "Iris Graphics 550"},
143.2666 ++	{0x192B, "Iris Graphics 555"},
143.2667 ++	{0x192D, "Iris Graphics P555"},
143.2668 ++	{0x1932, "Iris Pro Graphics 580"},
143.2669 ++	{0x193A, "Iris Pro Graphics P580"},
143.2670 ++	{0x193B, "Iris Pro Graphics 580"},
143.2671 ++	{0x193D, "Iris Pro Graphics P580"},
143.2672 ++
143.2673 ++	/* Broxton (Apollolake) */
143.2674 ++	{0x5A84, "HD Graphics 505"},
143.2675 ++	{0x5A85, "HD Graphics 500"},
143.2676 ++
143.2677 ++	/* Kabylake */
143.2678 ++	{0x5916, "HD Graphics 620"},
143.2679 ++	{0x591E, "HD Graphics 615"},
143.2680 + 
143.2681 + 	/* When adding new identifiers, also update:
143.2682 + 	 * 1. intel_identify()
143.2683 +@@ -305,18 +349,14 @@ static const struct pci_id_match intel_device_match[] = {
143.2684 + 	INTEL_IVB_D_IDS(&intel_ivybridge_info),
143.2685 + 	INTEL_IVB_M_IDS(&intel_ivybridge_info),
143.2686 + 
143.2687 +-	INTEL_HSW_D_IDS(&intel_haswell_info),
143.2688 +-	INTEL_HSW_M_IDS(&intel_haswell_info),
143.2689 +-
143.2690 +-	INTEL_VLV_D_IDS(&intel_valleyview_info),
143.2691 +-	INTEL_VLV_M_IDS(&intel_valleyview_info),
143.2692 +-
143.2693 +-	INTEL_BDW_D_IDS(&intel_broadwell_info),
143.2694 +-	INTEL_BDW_M_IDS(&intel_broadwell_info),
143.2695 +-
143.2696 ++	INTEL_HSW_IDS(&intel_haswell_info),
143.2697 ++	INTEL_VLV_IDS(&intel_valleyview_info),
143.2698 ++	INTEL_BDW_IDS(&intel_broadwell_info),
143.2699 + 	INTEL_CHV_IDS(&intel_cherryview_info),
143.2700 +-
143.2701 + 	INTEL_SKL_IDS(&intel_skylake_info),
143.2702 ++	INTEL_BXT_IDS(&intel_broxton_info),
143.2703 ++	INTEL_KBL_IDS(&intel_kabylake_info),
143.2704 ++	INTEL_GLK_IDS(&intel_geminilake_info),
143.2705 + 
143.2706 + 	INTEL_VGA_DEVICE(PCI_MATCH_ANY, &intel_generic_info),
143.2707 + #endif
143.2708 +@@ -448,9 +488,9 @@ static void intel_identify(int flags)
143.2709 + 	if (unique != stack)
143.2710 + 		free(unique);
143.2711 + 
143.2712 +-	xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) HD Graphics: 2000-6000\n");
143.2713 +-	xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Graphics: 5100, 6100\n");
143.2714 +-	xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Pro Graphics: 5200, 6200, P6300\n");
143.2715 ++	xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) HD Graphics\n");
143.2716 ++	xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Graphics\n");
143.2717 ++	xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Pro Graphics\n");
143.2718 + }
143.2719 + 
143.2720 + static Bool intel_driver_func(ScrnInfoPtr pScrn,
143.2721 +@@ -508,6 +548,9 @@ static enum accel_method { NOACCEL, SNA, UXA } get_accel_method(void)
143.2722 + 	if (hosted())
143.2723 + 		return SNA;
143.2724 + 
143.2725 ++	if (xf86configptr == NULL) /* X -configure */
143.2726 ++		return SNA;
143.2727 ++
143.2728 + 	dev = _xf86findDriver("intel", xf86configptr->conf_device_lst);
143.2729 + 	if (dev && dev->dev_option_lst) {
143.2730 + 		const char *s;
143.2731 +@@ -582,10 +625,17 @@ intel_scrn_create(DriverPtr		driver,
143.2732 + 	case NOACCEL:
143.2733 + #endif
143.2734 + 	case UXA:
143.2735 +-		  return intel_init_scrn(scrn);
143.2736 ++		return intel_init_scrn(scrn);
143.2737 + #endif
143.2738 + 
143.2739 +-	default: break;
143.2740 ++	default:
143.2741 ++#if USE_SNA
143.2742 ++		return sna_init_scrn(scrn, entity_num);
143.2743 ++#elif USE_UXA
143.2744 ++		return intel_init_scrn(scrn);
143.2745 ++#else
143.2746 ++		break;
143.2747 ++#endif
143.2748 + 	}
143.2749 + #endif
143.2750 + 
143.2751 +@@ -604,6 +654,8 @@ static Bool intel_pci_probe(DriverPtr		driver,
143.2752 + 			    struct pci_device	*pci,
143.2753 + 			    intptr_t		match_data)
143.2754 + {
143.2755 ++	Bool ret;
143.2756 ++
143.2757 + 	if (intel_open_device(entity_num, pci, NULL) == -1) {
143.2758 + #if UMS
143.2759 + 		switch (pci->device_id) {
143.2760 +@@ -621,7 +673,11 @@ static Bool intel_pci_probe(DriverPtr		driver,
143.2761 + #endif
143.2762 + 	}
143.2763 + 
143.2764 +-	return intel_scrn_create(driver, entity_num, match_data, 0);
143.2765 ++	ret = intel_scrn_create(driver, entity_num, match_data, 0);
143.2766 ++	if (!ret)
143.2767 ++		intel_close_device(entity_num);
143.2768 ++
143.2769 ++	return ret;
143.2770 + }
143.2771 + 
143.2772 + #ifdef XSERVER_PLATFORM_BUS
143.2773 +@@ -644,9 +700,16 @@ intel_platform_probe(DriverPtr driver,
143.2774 + 
143.2775 + 	/* if we get any flags we don't understand fail to probe for now */
143.2776 + 	if (flags)
143.2777 +-		return FALSE;
143.2778 ++		goto err;
143.2779 ++
143.2780 ++	if (!intel_scrn_create(driver, entity_num, match_data, scrn_flags))
143.2781 ++		goto err;
143.2782 + 
143.2783 +-	return intel_scrn_create(driver, entity_num, match_data, scrn_flags);
143.2784 ++	return TRUE;
143.2785 ++
143.2786 ++err:
143.2787 ++	intel_close_device(entity_num);
143.2788 ++	return FALSE;
143.2789 + }
143.2790 + #endif
143.2791 + 
143.2792 +diff --git a/src/intel_options.c b/src/intel_options.c
143.2793 +index ff8541a4..7f253ac1 100644
143.2794 +--- a/src/intel_options.c
143.2795 ++++ b/src/intel_options.c
143.2796 +@@ -2,18 +2,24 @@
143.2797 + #include "config.h"
143.2798 + #endif
143.2799 + 
143.2800 ++#include <xorg-server.h>
143.2801 ++#include <xorgVersion.h>
143.2802 ++#include <xf86Parser.h>
143.2803 ++
143.2804 + #include "intel_options.h"
143.2805 + 
143.2806 + const OptionInfoRec intel_options[] = {
143.2807 +-	{OPTION_ACCEL_DISABLE,	"NoAccel",	OPTV_BOOLEAN,	{0},	0},
143.2808 ++	{OPTION_ACCEL_ENABLE,	"Accel",	OPTV_BOOLEAN,	{0},	0},
143.2809 + 	{OPTION_ACCEL_METHOD,	"AccelMethod",	OPTV_STRING,	{0},	0},
143.2810 + 	{OPTION_BACKLIGHT,	"Backlight",	OPTV_STRING,	{0},	0},
143.2811 ++	{OPTION_EDID,		"CustomEDID",	OPTV_STRING,	{0},	0},
143.2812 + 	{OPTION_DRI,		"DRI",		OPTV_STRING,	{0},	0},
143.2813 + 	{OPTION_PRESENT,	"Present",	OPTV_BOOLEAN,	{0},	1},
143.2814 + 	{OPTION_COLOR_KEY,	"ColorKey",	OPTV_INTEGER,	{0},	0},
143.2815 + 	{OPTION_VIDEO_KEY,	"VideoKey",	OPTV_INTEGER,	{0},	0},
143.2816 + 	{OPTION_TILING_2D,	"Tiling",	OPTV_BOOLEAN,	{0},	1},
143.2817 + 	{OPTION_TILING_FB,	"LinearFramebuffer",	OPTV_BOOLEAN,	{0},	0},
143.2818 ++	{OPTION_ROTATION,	"HWRotation",	OPTV_BOOLEAN,	{0},	1},
143.2819 + 	{OPTION_VSYNC,		"VSync",	OPTV_BOOLEAN,	{0},	1},
143.2820 + 	{OPTION_PAGEFLIP,	"PageFlip",	OPTV_BOOLEAN,	{0},	1},
143.2821 + 	{OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN,	{0},	1},
143.2822 +@@ -21,7 +27,6 @@ const OptionInfoRec intel_options[] = {
143.2823 + 	{OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, 0},
143.2824 + 	{OPTION_HOTPLUG,	"HotPlug",	OPTV_BOOLEAN,	{0},	1},
143.2825 + 	{OPTION_REPROBE,	"ReprobeOutputs", OPTV_BOOLEAN,	{0},	0},
143.2826 +-	{OPTION_DELETE_DP12,	"DeleteUnusedDP12Displays", OPTV_BOOLEAN,	{0},	0},
143.2827 + #ifdef INTEL_XVMC
143.2828 + 	{OPTION_XVMC,		"XvMC",		OPTV_BOOLEAN,	{0},	1},
143.2829 + #endif
143.2830 +@@ -54,3 +59,85 @@ OptionInfoPtr intel_options_get(ScrnInfoPtr scrn)
143.2831 + 
143.2832 + 	return options;
143.2833 + }
143.2834 ++
143.2835 ++Bool intel_option_cast_to_bool(OptionInfoPtr options, int id, Bool val)
143.2836 ++{
143.2837 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
143.2838 ++	xf86getBoolValue(&val, xf86GetOptValString(options, id));
143.2839 ++#endif
143.2840 ++	return val;
143.2841 ++}
143.2842 ++
143.2843 ++static int
143.2844 ++namecmp(const char *s1, const char *s2)
143.2845 ++{
143.2846 ++	char c1, c2;
143.2847 ++
143.2848 ++	if (!s1 || *s1 == 0) {
143.2849 ++		if (!s2 || *s2 == 0)
143.2850 ++			return 0;
143.2851 ++		else
143.2852 ++			return 1;
143.2853 ++	}
143.2854 ++
143.2855 ++	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
143.2856 ++		s1++;
143.2857 ++
143.2858 ++	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
143.2859 ++		s2++;
143.2860 ++
143.2861 ++	c1 = isupper(*s1) ? tolower(*s1) : *s1;
143.2862 ++	c2 = isupper(*s2) ? tolower(*s2) : *s2;
143.2863 ++	while (c1 == c2) {
143.2864 ++		if (c1 == '\0')
143.2865 ++			return 0;
143.2866 ++
143.2867 ++		s1++;
143.2868 ++		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
143.2869 ++			s1++;
143.2870 ++
143.2871 ++		s2++;
143.2872 ++		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
143.2873 ++			s2++;
143.2874 ++
143.2875 ++		c1 = isupper(*s1) ? tolower(*s1) : *s1;
143.2876 ++		c2 = isupper(*s2) ? tolower(*s2) : *s2;
143.2877 ++	}
143.2878 ++
143.2879 ++	return c1 - c2;
143.2880 ++}
143.2881 ++
143.2882 ++unsigned intel_option_cast_to_unsigned(OptionInfoPtr options, int id, unsigned val)
143.2883 ++{
143.2884 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
143.2885 ++	const char *str = xf86GetOptValString(options, id);
143.2886 ++#else
143.2887 ++	const char *str = NULL;
143.2888 ++#endif
143.2889 ++	unsigned v;
143.2890 ++
143.2891 ++	if (str == NULL || *str == '\0')
143.2892 ++		return val;
143.2893 ++
143.2894 ++	if (namecmp(str, "on") == 0)
143.2895 ++		return val;
143.2896 ++	if (namecmp(str, "true") == 0)
143.2897 ++		return val;
143.2898 ++	if (namecmp(str, "yes") == 0)
143.2899 ++		return val;
143.2900 ++
143.2901 ++	if (namecmp(str, "0") == 0)
143.2902 ++		return 0;
143.2903 ++	if (namecmp(str, "off") == 0)
143.2904 ++		return 0;
143.2905 ++	if (namecmp(str, "false") == 0)
143.2906 ++		return 0;
143.2907 ++	if (namecmp(str, "no") == 0)
143.2908 ++		return 0;
143.2909 ++
143.2910 ++	v = atoi(str);
143.2911 ++	if (v)
143.2912 ++		return v;
143.2913 ++
143.2914 ++	return val;
143.2915 ++}
143.2916 +diff --git a/src/intel_options.h b/src/intel_options.h
143.2917 +index 7e2cbd9b..43635f1f 100644
143.2918 +--- a/src/intel_options.h
143.2919 ++++ b/src/intel_options.h
143.2920 +@@ -12,15 +12,17 @@
143.2921 +  */
143.2922 + 
143.2923 + enum intel_options {
143.2924 +-	OPTION_ACCEL_DISABLE,
143.2925 ++	OPTION_ACCEL_ENABLE,
143.2926 + 	OPTION_ACCEL_METHOD,
143.2927 + 	OPTION_BACKLIGHT,
143.2928 ++	OPTION_EDID,
143.2929 + 	OPTION_DRI,
143.2930 + 	OPTION_PRESENT,
143.2931 + 	OPTION_VIDEO_KEY,
143.2932 + 	OPTION_COLOR_KEY,
143.2933 + 	OPTION_TILING_2D,
143.2934 + 	OPTION_TILING_FB,
143.2935 ++	OPTION_ROTATION,
143.2936 + 	OPTION_VSYNC,
143.2937 + 	OPTION_PAGEFLIP,
143.2938 + 	OPTION_SWAPBUFFERS_WAIT,
143.2939 +@@ -28,7 +30,6 @@ enum intel_options {
143.2940 + 	OPTION_PREFER_OVERLAY,
143.2941 + 	OPTION_HOTPLUG,
143.2942 + 	OPTION_REPROBE,
143.2943 +-	OPTION_DELETE_DP12,
143.2944 + #if defined(XvMCExtension) && defined(ENABLE_XVMC)
143.2945 + 	OPTION_XVMC,
143.2946 + #define INTEL_XVMC 1
143.2947 +@@ -51,5 +52,7 @@ enum intel_options {
143.2948 + 
143.2949 + extern const OptionInfoRec intel_options[];
143.2950 + OptionInfoPtr intel_options_get(ScrnInfoPtr scrn);
143.2951 ++unsigned intel_option_cast_to_unsigned(OptionInfoPtr, int id, unsigned val);
143.2952 ++Bool intel_option_cast_to_bool(OptionInfoPtr, int id, Bool val);
143.2953 + 
143.2954 + #endif /* INTEL_OPTIONS_H */
143.2955 +diff --git a/src/legacy/i810/i810_common.h b/src/legacy/i810/i810_common.h
143.2956 +index 4cc10e8b..8355708c 100644
143.2957 +--- a/src/legacy/i810/i810_common.h
143.2958 ++++ b/src/legacy/i810/i810_common.h
143.2959 +@@ -52,7 +52,7 @@
143.2960 + 
143.2961 + #define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
143.2962 + 
143.2963 +-/* Using usleep() makes things noticably slow. */
143.2964 ++/* Using usleep() makes things noticeably slow. */
143.2965 + #if 0
143.2966 + #define DELAY(x) usleep(x)
143.2967 + #else
143.2968 +@@ -185,7 +185,7 @@ enum {
143.2969 +  *    - zbuffer linear offset and pitch -- also invarient
143.2970 +  *    - drawing origin in back and depth buffers.
143.2971 +  *
143.2972 +- * Keep the depth/back buffer state here to acommodate private buffers
143.2973 ++ * Keep the depth/back buffer state here to accommodate private buffers
143.2974 +  * in the future.
143.2975 +  */
143.2976 + #define I810_DESTREG_DI0  0		/* CMD_OP_DESTBUFFER_INFO (2 dwords) */
143.2977 +diff --git a/src/legacy/i810/i810_hwmc.c b/src/legacy/i810/i810_hwmc.c
143.2978 +index 7cb9c1ab..58661b0a 100644
143.2979 +--- a/src/legacy/i810/i810_hwmc.c
143.2980 ++++ b/src/legacy/i810/i810_hwmc.c
143.2981 +@@ -171,7 +171,7 @@ static XF86MCAdaptorPtr ppAdapt[1] =
143.2982 +  *
143.2983 +  *  I810InitMC
143.2984 +  *
143.2985 +- *  Initialize the hardware motion compenstation extention for this 
143.2986 ++ *  Initialize the hardware motion compensation extension for this
143.2987 +  *  hardware. The initialization routines want the address of the pointers
143.2988 +  *  to the structures, not the address of the structures. This means we
143.2989 +  *  allocate (or create static?) the pointer memory and pass that 
143.2990 +diff --git a/src/legacy/i810/i810_memory.c b/src/legacy/i810/i810_memory.c
143.2991 +index c3de2777..6f274836 100644
143.2992 +--- a/src/legacy/i810/i810_memory.c
143.2993 ++++ b/src/legacy/i810/i810_memory.c
143.2994 +@@ -76,7 +76,7 @@ I810AllocateGARTMemory(ScrnInfoPtr pScrn)
143.2995 +    unsigned long size = pScrn->videoRam * 1024UL;
143.2996 +    I810Ptr pI810 = I810PTR(pScrn);
143.2997 +    int key;
143.2998 +-   long tom = 0;
143.2999 ++   unsigned long tom = 0;
143.3000 +    unsigned long physical;
143.3001 + 
143.3002 +    if (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex)) {
143.3003 +@@ -132,8 +132,8 @@ I810AllocateGARTMemory(ScrnInfoPtr pScrn)
143.3004 +     * Keep it 512K aligned for the sake of tiled regions.
143.3005 +     */
143.3006 + 
143.3007 +-   tom += 0x7ffff;
143.3008 +-   tom &= ~0x7ffff;
143.3009 ++   tom += 0x7ffffUL;
143.3010 ++   tom &= ~0x7ffffUL;
143.3011 + 
143.3012 +    if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 1, NULL)) != -1) {
143.3013 +       pI810->DcacheOffset = tom;
143.3014 +diff --git a/src/legacy/i810/i810_reg.h b/src/legacy/i810/i810_reg.h
143.3015 +index 54faeb3d..fa091c5b 100644
143.3016 +--- a/src/legacy/i810/i810_reg.h
143.3017 ++++ b/src/legacy/i810/i810_reg.h
143.3018 +@@ -245,7 +245,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
143.3019 +  * not sure they refer to local (graphics) memory.
143.3020 +  *
143.3021 +  * These details are for the local memory control registers,
143.3022 +- * (pp301-310).  The test machines are not equiped with local memory,
143.3023 ++ * (pp301-310).  The test machines are not equipped with local memory,
143.3024 +  * so nothing is tested.  Only a single row seems to be supported.
143.3025 +  */
143.3026 + #define DRAM_ROW_TYPE      0x3000
143.3027 +diff --git a/src/legacy/i810/i810_video.c b/src/legacy/i810/i810_video.c
143.3028 +index be49b91d..af683c81 100644
143.3029 +--- a/src/legacy/i810/i810_video.c
143.3030 ++++ b/src/legacy/i810/i810_video.c
143.3031 +@@ -77,7 +77,11 @@ static int I810PutImage( ScrnInfoPtr,
143.3032 + static int I810QueryImageAttributes(ScrnInfoPtr, 
143.3033 + 	int, unsigned short *, unsigned short *,  int *, int *);
143.3034 + 
143.3035 ++#if !HAVE_NOTIFY_FD
143.3036 + static void I810BlockHandler(BLOCKHANDLER_ARGS_DECL);
143.3037 ++#else
143.3038 ++static void I810BlockHandler(void *data, void *_timeout);
143.3039 ++#endif
143.3040 + 
143.3041 + #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
143.3042 + 
143.3043 +@@ -418,8 +422,14 @@ I810SetupImageVideo(ScreenPtr screen)
143.3044 + 
143.3045 +     pI810->adaptor = adapt;
143.3046 + 
143.3047 ++#if !HAVE_NOTIFY_FD
143.3048 +     pI810->BlockHandler = screen->BlockHandler;
143.3049 +     screen->BlockHandler = I810BlockHandler;
143.3050 ++#else
143.3051 ++    RegisterBlockAndWakeupHandlers(I810BlockHandler,
143.3052 ++				   (ServerWakeupHandlerProcPtr)NoopDDA,
143.3053 ++				   pScrn);
143.3054 ++#endif
143.3055 + 
143.3056 +     xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
143.3057 +     xvContrast   = MAKE_ATOM("XV_CONTRAST");
143.3058 +@@ -1135,6 +1145,7 @@ I810QueryImageAttributes(
143.3059 +     return size;
143.3060 + }
143.3061 + 
143.3062 ++#if !HAVE_NOTIFY_FD
143.3063 + static void
143.3064 + I810BlockHandler (BLOCKHANDLER_ARGS_DECL)
143.3065 + {
143.3066 +@@ -1172,6 +1183,38 @@ I810BlockHandler (BLOCKHANDLER_ARGS_DECL)
143.3067 +         }
143.3068 +     }
143.3069 + }
143.3070 ++#else
143.3071 ++static void
143.3072 ++I810BlockHandler(void *data, void *_timeout)
143.3073 ++{
143.3074 ++    ScrnInfoPtr pScrn = data;
143.3075 ++    I810Ptr      pI810 = I810PTR(pScrn);
143.3076 ++    I810PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
143.3077 ++    I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
143.3078 ++
143.3079 ++    if(pPriv->videoStatus & TIMER_MASK) {
143.3080 ++	UpdateCurrentTime();
143.3081 ++	if(pPriv->videoStatus & OFF_TIMER) {
143.3082 ++	    if(pPriv->offTime < currentTime.milliseconds) {
143.3083 ++		/* Turn off the overlay */
143.3084 ++		overlay->OV0CMD &= 0xFFFFFFFE;
143.3085 ++		OVERLAY_UPDATE(pI810->OverlayPhysical);
143.3086 ++
143.3087 ++		pPriv->videoStatus = FREE_TIMER;
143.3088 ++		pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
143.3089 ++	    }
143.3090 ++	} else {  /* FREE_TIMER */
143.3091 ++	    if(pPriv->freeTime < currentTime.milliseconds) {
143.3092 ++		if(pPriv->linear) {
143.3093 ++		   xf86FreeOffscreenLinear(pPriv->linear);
143.3094 ++		   pPriv->linear = NULL;
143.3095 ++		}
143.3096 ++		pPriv->videoStatus = 0;
143.3097 ++	    }
143.3098 ++        }
143.3099 ++    }
143.3100 ++}
143.3101 ++#endif
143.3102 + 
143.3103 + 
143.3104 + /***************************************************************************
143.3105 +@@ -1373,7 +1416,6 @@ I810DisplaySurface(
143.3106 +       UpdateCurrentTime();
143.3107 +       pI810Priv->videoStatus = FREE_TIMER;
143.3108 +       pI810Priv->freeTime = currentTime.milliseconds + FREE_DELAY;
143.3109 +-      pScrn->pScreen->BlockHandler = I810BlockHandler;
143.3110 +     }
143.3111 + 
143.3112 +     return Success;
143.3113 +diff --git a/src/legacy/i810/xvmc/I810XvMC.c b/src/legacy/i810/xvmc/I810XvMC.c
143.3114 +index e6b63d30..a538e999 100644
143.3115 +--- a/src/legacy/i810/xvmc/I810XvMC.c
143.3116 ++++ b/src/legacy/i810/xvmc/I810XvMC.c
143.3117 +@@ -61,7 +61,7 @@ static int event_base;
143.3118 + // Arguments: pI810XvMC private data structure from the current context.
143.3119 + // Notes: We faked the drmMapBufs for the i810's security so now we have
143.3120 + //   to insert an allocated page into the correct spot in the faked
143.3121 +-//   list to keep up appearences.
143.3122 ++//   list to keep up appearances.
143.3123 + //   Concept for this function was taken from Mesa sources.
143.3124 + // Returns: drmBufPtr containing the information about the allocated page.
143.3125 + ***************************************************************************/
143.3126 +@@ -188,7 +188,7 @@ _X_EXPORT Status XvMCCreateContext(Display *display, XvPortID port,
143.3127 + 
143.3128 +   /* Check for drm */
143.3129 +   if(! drmAvailable()) {
143.3130 +-    printf("Direct Rendering is not avilable on this system!\n");
143.3131 ++    printf("Direct Rendering is not available on this system!\n");
143.3132 +     return BadAlloc;
143.3133 +   }
143.3134 + 
143.3135 +@@ -3279,7 +3279,7 @@ _X_EXPORT Status XvMCSyncSurface(Display *display,XvMCSurface *surface) {
143.3136 + //   display - Connection to X server
143.3137 + //   surface - Surface to flush
143.3138 + // Info:
143.3139 +-//   This command is a noop for i810 becuase we always dispatch buffers in
143.3140 ++//   This command is a noop for i810 because we always dispatch buffers in
143.3141 + //   render. There is little gain to be had with 4k buffers.
143.3142 + // Returns: Status
143.3143 + ***************************************************************************/
143.3144 +diff --git a/src/render_program/exa_wm.g4i b/src/render_program/exa_wm.g4i
143.3145 +index 5d3d45b1..587b581c 100644
143.3146 +--- a/src/render_program/exa_wm.g4i
143.3147 ++++ b/src/render_program/exa_wm.g4i
143.3148 +@@ -57,7 +57,7 @@ define(`mask_dw_dy', `g6.4<0,1,0>F')
143.3149 + define(`mask_wo',    `g6.12<0,1,0>F')
143.3150 + 
143.3151 + /*
143.3152 +- * Local variables. Pairs must be aligned on even reg boundry
143.3153 ++ * Local variables. Pairs must be aligned on even reg boundary
143.3154 +  */
143.3155 + 
143.3156 + /* this holds the X dest coordinates */
143.3157 +diff --git a/src/render_program/exa_wm_yuv_rgb.g8a b/src/render_program/exa_wm_yuv_rgb.g8a
143.3158 +index 7def0930..34973ba8 100644
143.3159 +--- a/src/render_program/exa_wm_yuv_rgb.g8a
143.3160 ++++ b/src/render_program/exa_wm_yuv_rgb.g8a
143.3161 +@@ -76,7 +76,7 @@ add (16)    Cbn<1>F		Cb<8,8,1>F	-0.501961F  { compr align1 };
143.3162 +     /* 
143.3163 +      * R = Y + Cr * 1.596
143.3164 +      */
143.3165 +-mov (8)    acc0<1>F		Yn<8,8,1>F		    { compr align1 };
143.3166 ++mov (8)    acc0<1>F		Yn_01<8,8,1>F		    { compr align1 };
143.3167 + mac.sat(8) src_sample_r_01<1>F	Crn_01<8,8,1>F	1.596F	    { compr align1 };
143.3168 +      
143.3169 + mov (8)    acc0<1>F		Yn_23<8,8,1>F		    { compr align1 };
143.3170 +@@ -84,7 +84,7 @@ mac.sat(8) src_sample_r_23<1>F	Crn_23<8,8,1>F	1.596F	    { compr align1 };
143.3171 +     /*
143.3172 +      * G = Crn * -0.813 + Cbn * -0.392 + Y
143.3173 +      */
143.3174 +-mov (8)    acc0<1>F		Yn_23<8,8,1>F		    { compr align1 };
143.3175 ++mov (8)    acc0<1>F		Yn_01<8,8,1>F		    { compr align1 };
143.3176 + mac (8)    acc0<1>F		Crn_01<8,8,1>F    	-0.813F	    { compr align1 };
143.3177 + mac.sat(8) src_sample_g_01<1>F	Cbn_01<8,8,1>F    	-0.392F	    { compr align1 };
143.3178 + 
143.3179 +diff --git a/src/render_program/exa_wm_yuv_rgb.g8b b/src/render_program/exa_wm_yuv_rgb.g8b
143.3180 +index 44949538..2cd6fc44 100644
143.3181 +--- a/src/render_program/exa_wm_yuv_rgb.g8b
143.3182 ++++ b/src/render_program/exa_wm_yuv_rgb.g8b
143.3183 +@@ -6,7 +6,7 @@
143.3184 +    { 0x80600048, 0x21c03ae8, 0x3e8d02c0, 0x3fcc49ba },
143.3185 +    { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
143.3186 +    { 0x80600048, 0x21e03ae8, 0x3e8d02e0, 0x3fcc49ba },
143.3187 +-   { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
143.3188 ++   { 0x00600001, 0x24003ae0, 0x008d0300, 0x00000000 },
143.3189 +    { 0x00600048, 0x24003ae0, 0x3e8d02c0, 0xbf5020c5 },
143.3190 +    { 0x80600048, 0x22003ae8, 0x3e8d0340, 0xbec8b439 },
143.3191 +    { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
143.3192 +diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am
143.3193 +index e09a8d49..adf13963 100644
143.3194 +--- a/src/sna/Makefile.am
143.3195 ++++ b/src/sna/Makefile.am
143.3196 +@@ -107,6 +107,8 @@ libsna_la_SOURCES = \
143.3197 + 	gen8_render.h \
143.3198 + 	gen8_vertex.c \
143.3199 + 	gen8_vertex.h \
143.3200 ++	gen9_render.c \
143.3201 ++	gen9_render.h \
143.3202 + 	xassert.h \
143.3203 + 	$(NULL)
143.3204 + 
143.3205 +diff --git a/src/sna/blt.c b/src/sna/blt.c
143.3206 +index b5bfee69..cb90437a 100644
143.3207 +--- a/src/sna/blt.c
143.3208 ++++ b/src/sna/blt.c
143.3209 +@@ -30,112 +30,608 @@
143.3210 + #endif
143.3211 + 
143.3212 + #include "sna.h"
143.3213 ++#include <pixman.h>
143.3214 + 
143.3215 +-#if __x86_64__
143.3216 +-#define USE_SSE2 1
143.3217 +-#endif
143.3218 +-
143.3219 +-#if USE_SSE2
143.3220 ++#if defined(sse2)
143.3221 ++#pragma GCC push_options
143.3222 ++#pragma GCC target("sse2,inline-all-stringops,fpmath=sse")
143.3223 ++#pragma GCC optimize("Ofast")
143.3224 + #include <xmmintrin.h>
143.3225 + 
143.3226 + #if __x86_64__
143.3227 + #define have_sse2() 1
143.3228 + #else
143.3229 +-enum {
143.3230 +-	MMX = 0x1,
143.3231 +-	MMX_EXTENSIONS = 0x2,
143.3232 +-	SSE = 0x6,
143.3233 +-	SSE2 = 0x8,
143.3234 +-	CMOV = 0x10
143.3235 +-};
143.3236 +-
143.3237 +-#ifdef __GNUC__
143.3238 +-static unsigned int
143.3239 +-detect_cpu_features(void)
143.3240 +-{
143.3241 +-	unsigned int features;
143.3242 +-	unsigned int result = 0;
143.3243 +-
143.3244 +-	char vendor[13];
143.3245 +-	vendor[0] = 0;
143.3246 +-	vendor[12] = 0;
143.3247 +-
143.3248 +-	asm (
143.3249 +-	     "pushf\n"
143.3250 +-	     "pop %%eax\n"
143.3251 +-	     "mov %%eax, %%ecx\n"
143.3252 +-	     "xor $0x00200000, %%eax\n"
143.3253 +-	     "push %%eax\n"
143.3254 +-	     "popf\n"
143.3255 +-	     "pushf\n"
143.3256 +-	     "pop %%eax\n"
143.3257 +-	     "mov $0x0, %%edx\n"
143.3258 +-	     "xor %%ecx, %%eax\n"
143.3259 +-	     "jz 1f\n"
143.3260 +-
143.3261 +-	     "mov $0x00000000, %%eax\n"
143.3262 +-	     "push %%ebx\n"
143.3263 +-	     "cpuid\n"
143.3264 +-	     "mov %%ebx, %%eax\n"
143.3265 +-	     "pop %%ebx\n"
143.3266 +-	     "mov %%eax, %1\n"
143.3267 +-	     "mov %%edx, %2\n"
143.3268 +-	     "mov %%ecx, %3\n"
143.3269 +-	     "mov $0x00000001, %%eax\n"
143.3270 +-	     "push %%ebx\n"
143.3271 +-	     "cpuid\n"
143.3272 +-	     "pop %%ebx\n"
143.3273 +-	     "1:\n"
143.3274 +-	     "mov %%edx, %0\n"
143.3275 +-	     : "=r" (result), "=m" (vendor[0]), "=m" (vendor[4]), "=m" (vendor[8])
143.3276 +-	     :: "%eax", "%ecx", "%edx");
143.3277 +-
143.3278 +-	features = 0;
143.3279 +-	if (result) {
143.3280 +-		/* result now contains the standard feature bits */
143.3281 +-		if (result & (1 << 15))
143.3282 +-			features |= CMOV;
143.3283 +-		if (result & (1 << 23))
143.3284 +-			features |= MMX;
143.3285 +-		if (result & (1 << 25))
143.3286 +-			features |= SSE;
143.3287 +-		if (result & (1 << 26))
143.3288 +-			features |= SSE2;
143.3289 +-	}
143.3290 +-	return features;
143.3291 +-}
143.3292 +-#else
143.3293 +-static unsigned int detect_cpu_features(void) { return 0; }
143.3294 +-#endif
143.3295 +-
143.3296 + static bool have_sse2(void)
143.3297 + {
143.3298 + 	static int sse2_present = -1;
143.3299 + 
143.3300 + 	if (sse2_present == -1)
143.3301 +-		sse2_present = detect_cpu_features() & SSE2;
143.3302 ++		sse2_present = sna_cpu_detect() & SSE2;
143.3303 + 
143.3304 + 	return sse2_present;
143.3305 + }
143.3306 + #endif
143.3307 + 
143.3308 +-static inline __m128i
143.3309 ++static force_inline __m128i
143.3310 + xmm_create_mask_32(uint32_t mask)
143.3311 + {
143.3312 + 	return _mm_set_epi32(mask, mask, mask, mask);
143.3313 + }
143.3314 + 
143.3315 +-static inline __m128i
143.3316 ++static force_inline __m128i
143.3317 ++xmm_load_128(const __m128i *src)
143.3318 ++{
143.3319 ++	return _mm_load_si128(src);
143.3320 ++}
143.3321 ++
143.3322 ++static force_inline __m128i
143.3323 + xmm_load_128u(const __m128i *src)
143.3324 + {
143.3325 + 	return _mm_loadu_si128(src);
143.3326 + }
143.3327 + 
143.3328 +-static inline void
143.3329 ++static force_inline void
143.3330 + xmm_save_128(__m128i *dst, __m128i data)
143.3331 + {
143.3332 + 	_mm_store_si128(dst, data);
143.3333 + }
143.3334 ++
143.3335 ++static force_inline void
143.3336 ++xmm_save_128u(__m128i *dst, __m128i data)
143.3337 ++{
143.3338 ++	_mm_storeu_si128(dst, data);
143.3339 ++}
143.3340 ++
143.3341 ++static force_inline void
143.3342 ++to_sse128xN(uint8_t *dst, const uint8_t *src, int bytes)
143.3343 ++{
143.3344 ++	int i;
143.3345 ++
143.3346 ++	for (i = 0; i < bytes / 128; i++) {
143.3347 ++		__m128i xmm0, xmm1, xmm2, xmm3;
143.3348 ++		__m128i xmm4, xmm5, xmm6, xmm7;
143.3349 ++
143.3350 ++		xmm0 = xmm_load_128u((const __m128i*)src + 0);
143.3351 ++		xmm1 = xmm_load_128u((const __m128i*)src + 1);
143.3352 ++		xmm2 = xmm_load_128u((const __m128i*)src + 2);
143.3353 ++		xmm3 = xmm_load_128u((const __m128i*)src + 3);
143.3354 ++		xmm4 = xmm_load_128u((const __m128i*)src + 4);
143.3355 ++		xmm5 = xmm_load_128u((const __m128i*)src + 5);
143.3356 ++		xmm6 = xmm_load_128u((const __m128i*)src + 6);
143.3357 ++		xmm7 = xmm_load_128u((const __m128i*)src + 7);
143.3358 ++
143.3359 ++		xmm_save_128((__m128i*)dst + 0, xmm0);
143.3360 ++		xmm_save_128((__m128i*)dst + 1, xmm1);
143.3361 ++		xmm_save_128((__m128i*)dst + 2, xmm2);
143.3362 ++		xmm_save_128((__m128i*)dst + 3, xmm3);
143.3363 ++		xmm_save_128((__m128i*)dst + 4, xmm4);
143.3364 ++		xmm_save_128((__m128i*)dst + 5, xmm5);
143.3365 ++		xmm_save_128((__m128i*)dst + 6, xmm6);
143.3366 ++		xmm_save_128((__m128i*)dst + 7, xmm7);
143.3367 ++
143.3368 ++		dst += 128;
143.3369 ++		src += 128;
143.3370 ++	}
143.3371 ++}
143.3372 ++
143.3373 ++static force_inline void
143.3374 ++to_sse64(uint8_t *dst, const uint8_t *src)
143.3375 ++{
143.3376 ++	__m128i xmm1, xmm2, xmm3, xmm4;
143.3377 ++
143.3378 ++	xmm1 = xmm_load_128u((const __m128i*)src + 0);
143.3379 ++	xmm2 = xmm_load_128u((const __m128i*)src + 1);
143.3380 ++	xmm3 = xmm_load_128u((const __m128i*)src + 2);
143.3381 ++	xmm4 = xmm_load_128u((const __m128i*)src + 3);
143.3382 ++
143.3383 ++	xmm_save_128((__m128i*)dst + 0, xmm1);
143.3384 ++	xmm_save_128((__m128i*)dst + 1, xmm2);
143.3385 ++	xmm_save_128((__m128i*)dst + 2, xmm3);
143.3386 ++	xmm_save_128((__m128i*)dst + 3, xmm4);
143.3387 ++}
143.3388 ++
143.3389 ++static force_inline void
143.3390 ++to_sse32(uint8_t *dst, const uint8_t *src)
143.3391 ++{
143.3392 ++	__m128i xmm1, xmm2;
143.3393 ++
143.3394 ++	xmm1 = xmm_load_128u((const __m128i*)src + 0);
143.3395 ++	xmm2 = xmm_load_128u((const __m128i*)src + 1);
143.3396 ++
143.3397 ++	xmm_save_128((__m128i*)dst + 0, xmm1);
143.3398 ++	xmm_save_128((__m128i*)dst + 1, xmm2);
143.3399 ++}
143.3400 ++
143.3401 ++static force_inline void
143.3402 ++to_sse16(uint8_t *dst, const uint8_t *src)
143.3403 ++{
143.3404 ++	xmm_save_128((__m128i*)dst, xmm_load_128u((const __m128i*)src));
143.3405 ++}
143.3406 ++
143.3407 ++static void to_memcpy(uint8_t *dst, const uint8_t *src, unsigned len)
143.3408 ++{
143.3409 ++	assert(len);
143.3410 ++	if ((uintptr_t)dst & 15) {
143.3411 ++		if (len <= 16 - ((uintptr_t)dst & 15)) {
143.3412 ++			memcpy(dst, src, len);
143.3413 ++			return;
143.3414 ++		}
143.3415 ++
143.3416 ++		if ((uintptr_t)dst & 1) {
143.3417 ++			assert(len >= 1);
143.3418 ++			*dst++ = *src++;
143.3419 ++			len--;
143.3420 ++		}
143.3421 ++		if ((uintptr_t)dst & 2) {
143.3422 ++			assert(((uintptr_t)dst & 1) == 0);
143.3423 ++			assert(len >= 2);
143.3424 ++			*(uint16_t *)dst = *(const uint16_t *)src;
143.3425 ++			dst += 2;
143.3426 ++			src += 2;
143.3427 ++			len -= 2;
143.3428 ++		}
143.3429 ++		if ((uintptr_t)dst & 4) {
143.3430 ++			assert(((uintptr_t)dst & 3) == 0);
143.3431 ++			assert(len >= 4);
143.3432 ++			*(uint32_t *)dst = *(const uint32_t *)src;
143.3433 ++			dst += 4;
143.3434 ++			src += 4;
143.3435 ++			len -= 4;
143.3436 ++		}
143.3437 ++		if ((uintptr_t)dst & 8) {
143.3438 ++			assert(((uintptr_t)dst & 7) == 0);
143.3439 ++			assert(len >= 8);
143.3440 ++			*(uint64_t *)dst = *(const uint64_t *)src;
143.3441 ++			dst += 8;
143.3442 ++			src += 8;
143.3443 ++			len -= 8;
143.3444 ++		}
143.3445 ++	}
143.3446 ++
143.3447 ++	assert(((uintptr_t)dst & 15) == 0);
143.3448 ++	while (len >= 64) {
143.3449 ++		to_sse64(dst, src);
143.3450 ++		dst += 64;
143.3451 ++		src += 64;
143.3452 ++		len -= 64;
143.3453 ++	}
143.3454 ++	if (len == 0)
143.3455 ++		return;
143.3456 ++
143.3457 ++	if (len & 32) {
143.3458 ++		to_sse32(dst, src);
143.3459 ++		dst += 32;
143.3460 ++		src += 32;
143.3461 ++	}
143.3462 ++	if (len & 16) {
143.3463 ++		to_sse16(dst, src);
143.3464 ++		dst += 16;
143.3465 ++		src += 16;
143.3466 ++	}
143.3467 ++	if (len & 8) {
143.3468 ++		*(uint64_t *)dst = *(uint64_t *)src;
143.3469 ++		dst += 8;
143.3470 ++		src += 8;
143.3471 ++	}
143.3472 ++	if (len & 4) {
143.3473 ++		*(uint32_t *)dst = *(uint32_t *)src;
143.3474 ++		dst += 4;
143.3475 ++		src += 4;
143.3476 ++	}
143.3477 ++	memcpy(dst, src, len & 3);
143.3478 ++}
143.3479 ++
143.3480 ++static void
143.3481 ++memcpy_to_tiled_x__swizzle_0__sse2(const void *src, void *dst, int bpp,
143.3482 ++				   int32_t src_stride, int32_t dst_stride,
143.3483 ++				   int16_t src_x, int16_t src_y,
143.3484 ++				   int16_t dst_x, int16_t dst_y,
143.3485 ++				   uint16_t width, uint16_t height)
143.3486 ++{
143.3487 ++	const unsigned tile_width = 512;
143.3488 ++	const unsigned tile_height = 8;
143.3489 ++	const unsigned tile_size = 4096;
143.3490 ++
143.3491 ++	const unsigned cpp = bpp / 8;
143.3492 ++	const unsigned tile_pixels = tile_width / cpp;
143.3493 ++	const unsigned tile_shift = ffs(tile_pixels) - 1;
143.3494 ++	const unsigned tile_mask = tile_pixels - 1;
143.3495 ++
143.3496 ++	unsigned offset_x, length_x;
143.3497 ++
143.3498 ++	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.3499 ++	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.3500 ++	assert(src != dst);
143.3501 ++
143.3502 ++	if (src_x | src_y)
143.3503 ++		src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
143.3504 ++	width *= cpp;
143.3505 ++	assert(src_stride >= width);
143.3506 ++
143.3507 ++	if (dst_x & tile_mask) {
143.3508 ++		offset_x = (dst_x & tile_mask) * cpp;
143.3509 ++		length_x = min(tile_width - offset_x, width);
143.3510 ++	} else
143.3511 ++		length_x = 0;
143.3512 ++	dst = (uint8_t *)dst + (dst_x >> tile_shift) * tile_size;
143.3513 ++
143.3514 ++	while (height--) {
143.3515 ++		unsigned w = width;
143.3516 ++		const uint8_t *src_row = src;
143.3517 ++		uint8_t *tile_row = dst;
143.3518 ++
143.3519 ++		src = (const uint8_t *)src + src_stride;
143.3520 ++
143.3521 ++		tile_row += dst_y / tile_height * dst_stride * tile_height;
143.3522 ++		tile_row += (dst_y & (tile_height-1)) * tile_width;
143.3523 ++		dst_y++;
143.3524 ++
143.3525 ++		if (length_x) {
143.3526 ++			to_memcpy(tile_row + offset_x, src_row, length_x);
143.3527 ++
143.3528 ++			tile_row += tile_size;
143.3529 ++			src_row = (const uint8_t *)src_row + length_x;
143.3530 ++			w -= length_x;
143.3531 ++		}
143.3532 ++		while (w >= tile_width) {
143.3533 ++			assert(((uintptr_t)tile_row & (tile_width - 1)) == 0);
143.3534 ++			to_sse128xN(assume_aligned(tile_row, tile_width),
143.3535 ++				    src_row, tile_width);
143.3536 ++			tile_row += tile_size;
143.3537 ++			src_row = (const uint8_t *)src_row + tile_width;
143.3538 ++			w -= tile_width;
143.3539 ++		}
143.3540 ++		if (w) {
143.3541 ++			assert(((uintptr_t)tile_row & (tile_width - 1)) == 0);
143.3542 ++			to_memcpy(assume_aligned(tile_row, tile_width),
143.3543 ++				  src_row, w);
143.3544 ++		}
143.3545 ++	}
143.3546 ++}
143.3547 ++
143.3548 ++static force_inline void
143.3549 ++from_sse128xNu(uint8_t *dst, const uint8_t *src, int bytes)
143.3550 ++{
143.3551 ++	int i;
143.3552 ++
143.3553 ++	assert(((uintptr_t)src & 15) == 0);
143.3554 ++
143.3555 ++	for (i = 0; i < bytes / 128; i++) {
143.3556 ++		__m128i xmm0, xmm1, xmm2, xmm3;
143.3557 ++		__m128i xmm4, xmm5, xmm6, xmm7;
143.3558 ++
143.3559 ++		xmm0 = xmm_load_128((const __m128i*)src + 0);
143.3560 ++		xmm1 = xmm_load_128((const __m128i*)src + 1);
143.3561 ++		xmm2 = xmm_load_128((const __m128i*)src + 2);
143.3562 ++		xmm3 = xmm_load_128((const __m128i*)src + 3);
143.3563 ++		xmm4 = xmm_load_128((const __m128i*)src + 4);
143.3564 ++		xmm5 = xmm_load_128((const __m128i*)src + 5);
143.3565 ++		xmm6 = xmm_load_128((const __m128i*)src + 6);
143.3566 ++		xmm7 = xmm_load_128((const __m128i*)src + 7);
143.3567 ++
143.3568 ++		xmm_save_128u((__m128i*)dst + 0, xmm0);
143.3569 ++		xmm_save_128u((__m128i*)dst + 1, xmm1);
143.3570 ++		xmm_save_128u((__m128i*)dst + 2, xmm2);
143.3571 ++		xmm_save_128u((__m128i*)dst + 3, xmm3);
143.3572 ++		xmm_save_128u((__m128i*)dst + 4, xmm4);
143.3573 ++		xmm_save_128u((__m128i*)dst + 5, xmm5);
143.3574 ++		xmm_save_128u((__m128i*)dst + 6, xmm6);
143.3575 ++		xmm_save_128u((__m128i*)dst + 7, xmm7);
143.3576 ++
143.3577 ++		dst += 128;
143.3578 ++		src += 128;
143.3579 ++	}
143.3580 ++}
143.3581 ++
143.3582 ++static force_inline void
143.3583 ++from_sse128xNa(uint8_t *dst, const uint8_t *src, int bytes)
143.3584 ++{
143.3585 ++	int i;
143.3586 ++
143.3587 ++	assert(((uintptr_t)dst & 15) == 0);
143.3588 ++	assert(((uintptr_t)src & 15) == 0);
143.3589 ++
143.3590 ++	for (i = 0; i < bytes / 128; i++) {
143.3591 ++		__m128i xmm0, xmm1, xmm2, xmm3;
143.3592 ++		__m128i xmm4, xmm5, xmm6, xmm7;
143.3593 ++
143.3594 ++		xmm0 = xmm_load_128((const __m128i*)src + 0);
143.3595 ++		xmm1 = xmm_load_128((const __m128i*)src + 1);
143.3596 ++		xmm2 = xmm_load_128((const __m128i*)src + 2);
143.3597 ++		xmm3 = xmm_load_128((const __m128i*)src + 3);
143.3598 ++		xmm4 = xmm_load_128((const __m128i*)src + 4);
143.3599 ++		xmm5 = xmm_load_128((const __m128i*)src + 5);
143.3600 ++		xmm6 = xmm_load_128((const __m128i*)src + 6);
143.3601 ++		xmm7 = xmm_load_128((const __m128i*)src + 7);
143.3602 ++
143.3603 ++		xmm_save_128((__m128i*)dst + 0, xmm0);
143.3604 ++		xmm_save_128((__m128i*)dst + 1, xmm1);
143.3605 ++		xmm_save_128((__m128i*)dst + 2, xmm2);
143.3606 ++		xmm_save_128((__m128i*)dst + 3, xmm3);
143.3607 ++		xmm_save_128((__m128i*)dst + 4, xmm4);
143.3608 ++		xmm_save_128((__m128i*)dst + 5, xmm5);
143.3609 ++		xmm_save_128((__m128i*)dst + 6, xmm6);
143.3610 ++		xmm_save_128((__m128i*)dst + 7, xmm7);
143.3611 ++
143.3612 ++		dst += 128;
143.3613 ++		src += 128;
143.3614 ++	}
143.3615 ++}
143.3616 ++
143.3617 ++static force_inline void
143.3618 ++from_sse64u(uint8_t *dst, const uint8_t *src)
143.3619 ++{
143.3620 ++	__m128i xmm1, xmm2, xmm3, xmm4;
143.3621 ++
143.3622 ++	assert(((uintptr_t)src & 15) == 0);
143.3623 ++
143.3624 ++	xmm1 = xmm_load_128((const __m128i*)src + 0);
143.3625 ++	xmm2 = xmm_load_128((const __m128i*)src + 1);
143.3626 ++	xmm3 = xmm_load_128((const __m128i*)src + 2);
143.3627 ++	xmm4 = xmm_load_128((const __m128i*)src + 3);
143.3628 ++
143.3629 ++	xmm_save_128u((__m128i*)dst + 0, xmm1);
143.3630 ++	xmm_save_128u((__m128i*)dst + 1, xmm2);
143.3631 ++	xmm_save_128u((__m128i*)dst + 2, xmm3);
143.3632 ++	xmm_save_128u((__m128i*)dst + 3, xmm4);
143.3633 ++}
143.3634 ++
143.3635 ++static force_inline void
143.3636 ++from_sse64a(uint8_t *dst, const uint8_t *src)
143.3637 ++{
143.3638 ++	__m128i xmm1, xmm2, xmm3, xmm4;
143.3639 ++
143.3640 ++	assert(((uintptr_t)dst & 15) == 0);
143.3641 ++	assert(((uintptr_t)src & 15) == 0);
143.3642 ++
143.3643 ++	xmm1 = xmm_load_128((const __m128i*)src + 0);
143.3644 ++	xmm2 = xmm_load_128((const __m128i*)src + 1);
143.3645 ++	xmm3 = xmm_load_128((const __m128i*)src + 2);
143.3646 ++	xmm4 = xmm_load_128((const __m128i*)src + 3);
143.3647 ++
143.3648 ++	xmm_save_128((__m128i*)dst + 0, xmm1);
143.3649 ++	xmm_save_128((__m128i*)dst + 1, xmm2);
143.3650 ++	xmm_save_128((__m128i*)dst + 2, xmm3);
143.3651 ++	xmm_save_128((__m128i*)dst + 3, xmm4);
143.3652 ++}
143.3653 ++
143.3654 ++static force_inline void
143.3655 ++from_sse32u(uint8_t *dst, const uint8_t *src)
143.3656 ++{
143.3657 ++	__m128i xmm1, xmm2;
143.3658 ++
143.3659 ++	xmm1 = xmm_load_128((const __m128i*)src + 0);
143.3660 ++	xmm2 = xmm_load_128((const __m128i*)src + 1);
143.3661 ++
143.3662 ++	xmm_save_128u((__m128i*)dst + 0, xmm1);
143.3663 ++	xmm_save_128u((__m128i*)dst + 1, xmm2);
143.3664 ++}
143.3665 ++
143.3666 ++static force_inline void
143.3667 ++from_sse32a(uint8_t *dst, const uint8_t *src)
143.3668 ++{
143.3669 ++	__m128i xmm1, xmm2;
143.3670 ++
143.3671 ++	assert(((uintptr_t)dst & 15) == 0);
143.3672 ++	assert(((uintptr_t)src & 15) == 0);
143.3673 ++
143.3674 ++	xmm1 = xmm_load_128((const __m128i*)src + 0);
143.3675 ++	xmm2 = xmm_load_128((const __m128i*)src + 1);
143.3676 ++
143.3677 ++	xmm_save_128((__m128i*)dst + 0, xmm1);
143.3678 ++	xmm_save_128((__m128i*)dst + 1, xmm2);
143.3679 ++}
143.3680 ++
143.3681 ++static force_inline void
143.3682 ++from_sse16u(uint8_t *dst, const uint8_t *src)
143.3683 ++{
143.3684 ++	assert(((uintptr_t)src & 15) == 0);
143.3685 ++
143.3686 ++	xmm_save_128u((__m128i*)dst, xmm_load_128((const __m128i*)src));
143.3687 ++}
143.3688 ++
143.3689 ++static force_inline void
143.3690 ++from_sse16a(uint8_t *dst, const uint8_t *src)
143.3691 ++{
143.3692 ++	assert(((uintptr_t)dst & 15) == 0);
143.3693 ++	assert(((uintptr_t)src & 15) == 0);
143.3694 ++
143.3695 ++	xmm_save_128((__m128i*)dst, xmm_load_128((const __m128i*)src));
143.3696 ++}
143.3697 ++
143.3698 ++static void
143.3699 ++memcpy_from_tiled_x__swizzle_0__sse2(const void *src, void *dst, int bpp,
143.3700 ++				     int32_t src_stride, int32_t dst_stride,
143.3701 ++				     int16_t src_x, int16_t src_y,
143.3702 ++				     int16_t dst_x, int16_t dst_y,
143.3703 ++				     uint16_t width, uint16_t height)
143.3704 ++{
143.3705 ++	const unsigned tile_width = 512;
143.3706 ++	const unsigned tile_height = 8;
143.3707 ++	const unsigned tile_size = 4096;
143.3708 ++
143.3709 ++	const unsigned cpp = bpp / 8;
143.3710 ++	const unsigned tile_pixels = tile_width / cpp;
143.3711 ++	const unsigned tile_shift = ffs(tile_pixels) - 1;
143.3712 ++	const unsigned tile_mask = tile_pixels - 1;
143.3713 ++
143.3714 ++	unsigned length_x, offset_x;
143.3715 ++
143.3716 ++	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.3717 ++	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.3718 ++	assert(src != dst);
143.3719 ++
143.3720 ++	if (dst_x | dst_y)
143.3721 ++		dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
143.3722 ++	width *= cpp;
143.3723 ++	assert(dst_stride >= width);
143.3724 ++	if (src_x & tile_mask) {
143.3725 ++		offset_x = (src_x & tile_mask) * cpp;
143.3726 ++		length_x = min(tile_width - offset_x, width);
143.3727 ++		dst_stride -= width;
143.3728 ++		dst_stride += (width - length_x) & 15;
143.3729 ++	} else {
143.3730 ++		offset_x = 0;
143.3731 ++		dst_stride -= width & ~15;
143.3732 ++	}
143.3733 ++	assert(dst_stride >= 0);
143.3734 ++	src = (const uint8_t *)src + (src_x >> tile_shift) * tile_size;
143.3735 ++
143.3736 ++	while (height--) {
143.3737 ++		unsigned w = width;
143.3738 ++		const uint8_t *tile_row = src;
143.3739 ++
143.3740 ++		tile_row += src_y / tile_height * src_stride * tile_height;
143.3741 ++		tile_row += (src_y & (tile_height-1)) * tile_width;
143.3742 ++		src_y++;
143.3743 ++
143.3744 ++		if (offset_x) {
143.3745 ++			memcpy(dst, tile_row + offset_x, length_x);
143.3746 ++			tile_row += tile_size;
143.3747 ++			dst = (uint8_t *)dst + length_x;
143.3748 ++			w -= length_x;
143.3749 ++		}
143.3750 ++
143.3751 ++		if ((uintptr_t)dst & 15) {
143.3752 ++			while (w >= tile_width) {
143.3753 ++				from_sse128xNu(dst,
143.3754 ++					       assume_aligned(tile_row, tile_width),
143.3755 ++					       tile_width);
143.3756 ++				tile_row += tile_size;
143.3757 ++				dst = (uint8_t *)dst + tile_width;
143.3758 ++				w -= tile_width;
143.3759 ++			}
143.3760 ++			while (w >= 64) {
143.3761 ++				from_sse64u(dst, tile_row);
143.3762 ++				tile_row += 64;
143.3763 ++				dst = (uint8_t *)dst + 64;
143.3764 ++				w -= 64;
143.3765 ++			}
143.3766 ++			if (w & 32) {
143.3767 ++				from_sse32u(dst, tile_row);
143.3768 ++				tile_row += 32;
143.3769 ++				dst = (uint8_t *)dst + 32;
143.3770 ++			}
143.3771 ++			if (w & 16) {
143.3772 ++				from_sse16u(dst, tile_row);
143.3773 ++				tile_row += 16;
143.3774 ++				dst = (uint8_t *)dst + 16;
143.3775 ++			}
143.3776 ++			memcpy(dst, assume_aligned(tile_row, 16), w & 15);
143.3777 ++		} else {
143.3778 ++			while (w >= tile_width) {
143.3779 ++				from_sse128xNa(assume_aligned(dst, 16),
143.3780 ++					       assume_aligned(tile_row, tile_width),
143.3781 ++					       tile_width);
143.3782 ++				tile_row += tile_size;
143.3783 ++				dst = (uint8_t *)dst + tile_width;
143.3784 ++				w -= tile_width;
143.3785 ++			}
143.3786 ++			while (w >= 64) {
143.3787 ++				from_sse64a(dst, tile_row);
143.3788 ++				tile_row += 64;
143.3789 ++				dst = (uint8_t *)dst + 64;
143.3790 ++				w -= 64;
143.3791 ++			}
143.3792 ++			if (w & 32) {
143.3793 ++				from_sse32a(dst, tile_row);
143.3794 ++				tile_row += 32;
143.3795 ++				dst = (uint8_t *)dst + 32;
143.3796 ++			}
143.3797 ++			if (w & 16) {
143.3798 ++				from_sse16a(dst, tile_row);
143.3799 ++				tile_row += 16;
143.3800 ++				dst = (uint8_t *)dst + 16;
143.3801 ++			}
143.3802 ++			memcpy(assume_aligned(dst, 16),
143.3803 ++			       assume_aligned(tile_row, 16),
143.3804 ++			       w & 15);
143.3805 ++		}
143.3806 ++		dst = (uint8_t *)dst + dst_stride;
143.3807 ++	}
143.3808 ++}
143.3809 ++
143.3810 ++static void
143.3811 ++memcpy_between_tiled_x__swizzle_0__sse2(const void *src, void *dst, int bpp,
143.3812 ++					int32_t src_stride, int32_t dst_stride,
143.3813 ++					int16_t src_x, int16_t src_y,
143.3814 ++					int16_t dst_x, int16_t dst_y,
143.3815 ++					uint16_t width, uint16_t height)
143.3816 ++{
143.3817 ++	const unsigned tile_width = 512;
143.3818 ++	const unsigned tile_height = 8;
143.3819 ++	const unsigned tile_size = 4096;
143.3820 ++
143.3821 ++	const unsigned cpp = bpp / 8;
143.3822 ++	const unsigned tile_pixels = tile_width / cpp;
143.3823 ++	const unsigned tile_shift = ffs(tile_pixels) - 1;
143.3824 ++	const unsigned tile_mask = tile_pixels - 1;
143.3825 ++
143.3826 ++	unsigned ox, lx;
143.3827 ++
143.3828 ++	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.3829 ++	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.3830 ++	assert(src != dst);
143.3831 ++
143.3832 ++	width *= cpp;
143.3833 ++	dst_stride *= tile_height;
143.3834 ++	src_stride *= tile_height;
143.3835 ++
143.3836 ++	assert((dst_x & tile_mask) == (src_x & tile_mask));
143.3837 ++	if (dst_x & tile_mask) {
143.3838 ++		ox = (dst_x & tile_mask) * cpp;
143.3839 ++		lx = min(tile_width - ox, width);
143.3840 ++		assert(lx != 0);
143.3841 ++	} else
143.3842 ++		lx = 0;
143.3843 ++
143.3844 ++	if (dst_x)
143.3845 ++		dst = (uint8_t *)dst + (dst_x >> tile_shift) * tile_size;
143.3846 ++	if (src_x)
143.3847 ++		src = (const uint8_t *)src + (src_x >> tile_shift) * tile_size;
143.3848 ++
143.3849 ++	while (height--) {
143.3850 ++		const uint8_t *src_row;
143.3851 ++		uint8_t *dst_row;
143.3852 ++		unsigned w = width;
143.3853 ++
143.3854 ++		dst_row = dst;
143.3855 ++		dst_row += dst_y / tile_height * dst_stride;
143.3856 ++		dst_row += (dst_y & (tile_height-1)) * tile_width;
143.3857 ++		dst_y++;
143.3858 ++
143.3859 ++		src_row = src;
143.3860 ++		src_row += src_y / tile_height * src_stride;
143.3861 ++		src_row += (src_y & (tile_height-1)) * tile_width;
143.3862 ++		src_y++;
143.3863 ++
143.3864 ++		if (lx) {
143.3865 ++			to_memcpy(dst_row + ox, src_row + ox, lx);
143.3866 ++			dst_row += tile_size;
143.3867 ++			src_row += tile_size;
143.3868 ++			w -= lx;
143.3869 ++		}
143.3870 ++		while (w >= tile_width) {
143.3871 ++			assert(((uintptr_t)dst_row & (tile_width - 1)) == 0);
143.3872 ++			assert(((uintptr_t)src_row & (tile_width - 1)) == 0);
143.3873 ++			to_sse128xN(assume_aligned(dst_row, tile_width),
143.3874 ++				    assume_aligned(src_row, tile_width),
143.3875 ++				    tile_width);
143.3876 ++			dst_row += tile_size;
143.3877 ++			src_row += tile_size;
143.3878 ++			w -= tile_width;
143.3879 ++		}
143.3880 ++		if (w) {
143.3881 ++			assert(((uintptr_t)dst_row & (tile_width - 1)) == 0);
143.3882 ++			assert(((uintptr_t)src_row & (tile_width - 1)) == 0);
143.3883 ++			to_memcpy(assume_aligned(dst_row, tile_width),
143.3884 ++				  assume_aligned(src_row, tile_width),
143.3885 ++				  w);
143.3886 ++		}
143.3887 ++	}
143.3888 ++}
143.3889 ++
143.3890 ++#pragma GCC push_options
143.3891 + #endif
143.3892 + 
143.3893 + fast void
143.3894 +@@ -257,7 +753,8 @@ memcpy_to_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
143.3895 + 			if (dst_x & tile_mask) {
143.3896 + 				const unsigned x = (dst_x & tile_mask) * cpp;
143.3897 + 				const unsigned len = min(tile_width - x, w);
143.3898 +-				memcpy(tile_row + x, src, len);
143.3899 ++				memcpy(assume_misaligned(tile_row + x, tile_width, x),
143.3900 ++				       src, len);
143.3901 + 
143.3902 + 				tile_row += tile_size;
143.3903 + 				src = (const uint8_t *)src + len;
143.3904 +@@ -265,13 +762,13 @@ memcpy_to_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
143.3905 + 			}
143.3906 + 		}
143.3907 + 		while (w >= tile_width) {
143.3908 +-			memcpy(tile_row, src, tile_width);
143.3909 +-
143.3910 ++			memcpy(assume_aligned(tile_row, tile_width),
143.3911 ++			       src, tile_width);
143.3912 + 			tile_row += tile_size;
143.3913 + 			src = (const uint8_t *)src + tile_width;
143.3914 + 			w -= tile_width;
143.3915 + 		}
143.3916 +-		memcpy(tile_row, src, w);
143.3917 ++		memcpy(assume_aligned(tile_row, tile_width), src, w);
143.3918 + 		src = (const uint8_t *)src + src_stride + w;
143.3919 + 		dst_y++;
143.3920 + 	}
143.3921 +@@ -313,7 +810,7 @@ memcpy_from_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
143.3922 + 			if (src_x & tile_mask) {
143.3923 + 				const unsigned x = (src_x & tile_mask) * cpp;
143.3924 + 				const unsigned len = min(tile_width - x, w);
143.3925 +-				memcpy(dst, tile_row + x, len);
143.3926 ++				memcpy(dst, assume_misaligned(tile_row + x, tile_width, x), len);
143.3927 + 
143.3928 + 				tile_row += tile_size;
143.3929 + 				dst = (uint8_t *)dst + len;
143.3930 +@@ -321,440 +818,371 @@ memcpy_from_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
143.3931 + 			}
143.3932 + 		}
143.3933 + 		while (w >= tile_width) {
143.3934 +-			memcpy(dst, tile_row, tile_width);
143.3935 ++			memcpy(dst,
143.3936 ++			       assume_aligned(tile_row, tile_width),
143.3937 ++			       tile_width);
143.3938 + 
143.3939 + 			tile_row += tile_size;
143.3940 + 			dst = (uint8_t *)dst + tile_width;
143.3941 + 			w -= tile_width;
143.3942 + 		}
143.3943 +-		memcpy(dst, tile_row, w);
143.3944 ++		memcpy(dst, assume_aligned(tile_row, tile_width), w);
143.3945 + 		dst = (uint8_t *)dst + dst_stride + w;
143.3946 + 		src_y++;
143.3947 + 	}
143.3948 + }
143.3949 + 
143.3950 +-fast_memcpy static void
143.3951 +-memcpy_to_tiled_x__swizzle_9(const void *src, void *dst, int bpp,
143.3952 +-			     int32_t src_stride, int32_t dst_stride,
143.3953 +-			     int16_t src_x, int16_t src_y,
143.3954 +-			     int16_t dst_x, int16_t dst_y,
143.3955 +-			     uint16_t width, uint16_t height)
143.3956 ++static fast_memcpy void
143.3957 ++memcpy_between_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
143.3958 ++				  int32_t src_stride, int32_t dst_stride,
143.3959 ++				  int16_t src_x, int16_t src_y,
143.3960 ++				  int16_t dst_x, int16_t dst_y,
143.3961 ++				  uint16_t width, uint16_t height)
143.3962 + {
143.3963 + 	const unsigned tile_width = 512;
143.3964 + 	const unsigned tile_height = 8;
143.3965 + 	const unsigned tile_size = 4096;
143.3966 + 
143.3967 + 	const unsigned cpp = bpp / 8;
143.3968 +-	const unsigned stride_tiles = dst_stride / tile_width;
143.3969 +-	const unsigned swizzle_pixels = 64 / cpp;
143.3970 +-	const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
143.3971 +-	const unsigned tile_mask = (1 << tile_pixels) - 1;
143.3972 +-
143.3973 +-	unsigned x, y;
143.3974 ++	const unsigned tile_pixels = tile_width / cpp;
143.3975 ++	const unsigned tile_shift = ffs(tile_pixels) - 1;
143.3976 ++	const unsigned tile_mask = tile_pixels - 1;
143.3977 + 
143.3978 + 	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.3979 + 	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.3980 ++	assert(src != dst);
143.3981 ++	assert((dst_x & tile_mask) == (src_x & tile_mask));
143.3982 + 
143.3983 +-	src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
143.3984 +-
143.3985 +-	for (y = 0; y < height; ++y) {
143.3986 +-		const uint32_t dy = y + dst_y;
143.3987 +-		const uint32_t tile_row =
143.3988 +-			(dy / tile_height * stride_tiles * tile_size +
143.3989 +-			 (dy & (tile_height-1)) * tile_width);
143.3990 +-		const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
143.3991 +-		uint32_t dx = dst_x, offset;
143.3992 +-
143.3993 +-		x = width * cpp;
143.3994 +-		if (dx & (swizzle_pixels - 1)) {
143.3995 +-			const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
143.3996 +-			const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
143.3997 +-			offset = tile_row +
143.3998 +-				(dx >> tile_pixels) * tile_size +
143.3999 +-				(dx & tile_mask) * cpp;
143.4000 +-			offset ^= (offset >> 3) & 64;
143.4001 +-
143.4002 +-			memcpy((char *)dst + offset, src_row, length * cpp);
143.4003 +-
143.4004 +-			src_row += length * cpp;
143.4005 +-			x -= length * cpp;
143.4006 +-			dx += length;
143.4007 +-		}
143.4008 +-		while (x >= 64) {
143.4009 +-			offset = tile_row +
143.4010 +-				(dx >> tile_pixels) * tile_size +
143.4011 +-				(dx & tile_mask) * cpp;
143.4012 +-			offset ^= (offset >> 3) & 64;
143.4013 +-
143.4014 +-			memcpy((char *)dst + offset, src_row, 64);
143.4015 +-
143.4016 +-			src_row += 64;
143.4017 +-			x -= 64;
143.4018 +-			dx += swizzle_pixels;
143.4019 +-		}
143.4020 +-		if (x) {
143.4021 +-			offset = tile_row +
143.4022 +-				(dx >> tile_pixels) * tile_size +
143.4023 +-				(dx & tile_mask) * cpp;
143.4024 +-			offset ^= (offset >> 3) & 64;
143.4025 +-			memcpy((char *)dst + offset, src_row, x);
143.4026 +-		}
143.4027 +-	}
143.4028 +-}
143.4029 ++	while (height--) {
143.4030 ++		unsigned w = width * cpp;
143.4031 ++		uint8_t *dst_row = dst;
143.4032 ++		const uint8_t *src_row = src;
143.4033 + 
143.4034 +-fast_memcpy static void
143.4035 +-memcpy_from_tiled_x__swizzle_9(const void *src, void *dst, int bpp,
143.4036 +-			       int32_t src_stride, int32_t dst_stride,
143.4037 +-			       int16_t src_x, int16_t src_y,
143.4038 +-			       int16_t dst_x, int16_t dst_y,
143.4039 +-			       uint16_t width, uint16_t height)
143.4040 +-{
143.4041 +-	const unsigned tile_width = 512;
143.4042 +-	const unsigned tile_height = 8;
143.4043 +-	const unsigned tile_size = 4096;
143.4044 ++		dst_row += dst_y / tile_height * dst_stride * tile_height;
143.4045 ++		dst_row += (dst_y & (tile_height-1)) * tile_width;
143.4046 ++		if (dst_x)
143.4047 ++			dst_row += (dst_x >> tile_shift) * tile_size;
143.4048 ++		dst_y++;
143.4049 + 
143.4050 +-	const unsigned cpp = bpp / 8;
143.4051 +-	const unsigned stride_tiles = src_stride / tile_width;
143.4052 +-	const unsigned swizzle_pixels = 64 / cpp;
143.4053 +-	const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
143.4054 +-	const unsigned tile_mask = (1 << tile_pixels) - 1;
143.4055 ++		src_row += src_y / tile_height * src_stride * tile_height;
143.4056 ++		src_row += (src_y & (tile_height-1)) * tile_width;
143.4057 ++		if (src_x)
143.4058 ++			src_row += (src_x >> tile_shift) * tile_size;
143.4059 ++		src_y++;
143.4060 + 
143.4061 +-	unsigned x, y;
143.4062 ++		if (dst_x & tile_mask) {
143.4063 ++			const unsigned x = (dst_x & tile_mask) * cpp;
143.4064 ++			const unsigned len = min(tile_width - x, w);
143.4065 + 
143.4066 +-	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.4067 +-	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.4068 ++			memcpy(assume_misaligned(dst_row + x, tile_width, x),
143.4069 ++			       assume_misaligned(src_row + x, tile_width, x),
143.4070 ++			       len);
143.4071 + 
143.4072 +-	dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
143.4073 +-
143.4074 +-	for (y = 0; y < height; ++y) {
143.4075 +-		const uint32_t sy = y + src_y;
143.4076 +-		const uint32_t tile_row =
143.4077 +-			(sy / tile_height * stride_tiles * tile_size +
143.4078 +-			 (sy & (tile_height-1)) * tile_width);
143.4079 +-		uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
143.4080 +-		uint32_t sx = src_x, offset;
143.4081 +-
143.4082 +-		x = width * cpp;
143.4083 +-		if (sx & (swizzle_pixels - 1)) {
143.4084 +-			const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
143.4085 +-			const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
143.4086 +-			offset = tile_row +
143.4087 +-				(sx >> tile_pixels) * tile_size +
143.4088 +-				(sx & tile_mask) * cpp;
143.4089 +-			offset ^= (offset >> 3) & 64;
143.4090 +-
143.4091 +-			memcpy(dst_row, (const char *)src + offset, length * cpp);
143.4092 +-
143.4093 +-			dst_row += length * cpp;
143.4094 +-			x -= length * cpp;
143.4095 +-			sx += length;
143.4096 ++			dst_row += tile_size;
143.4097 ++			src_row += tile_size;
143.4098 ++			w -= len;
143.4099 + 		}
143.4100 +-		while (x >= 64) {
143.4101 +-			offset = tile_row +
143.4102 +-				(sx >> tile_pixels) * tile_size +
143.4103 +-				(sx & tile_mask) * cpp;
143.4104 +-			offset ^= (offset >> 3) & 64;
143.4105 + 
143.4106 +-			memcpy(dst_row, (const char *)src + offset, 64);
143.4107 +-
143.4108 +-			dst_row += 64;
143.4109 +-			x -= 64;
143.4110 +-			sx += swizzle_pixels;
143.4111 +-		}
143.4112 +-		if (x) {
143.4113 +-			offset = tile_row +
143.4114 +-				(sx >> tile_pixels) * tile_size +
143.4115 +-				(sx & tile_mask) * cpp;
143.4116 +-			offset ^= (offset >> 3) & 64;
143.4117 +-			memcpy(dst_row, (const char *)src + offset, x);
143.4118 ++		while (w >= tile_width) {
143.4119 ++			memcpy(assume_aligned(dst_row, tile_width),
143.4120 ++			       assume_aligned(src_row, tile_width),
143.4121 ++			       tile_width);
143.4122 ++			dst_row += tile_size;
143.4123 ++			src_row += tile_size;
143.4124 ++			w -= tile_width;
143.4125 + 		}
143.4126 ++		memcpy(assume_aligned(dst_row, tile_width),
143.4127 ++		       assume_aligned(src_row, tile_width),
143.4128 ++		       w);
143.4129 + 	}
143.4130 + }
143.4131 + 
143.4132 +-fast_memcpy static void
143.4133 +-memcpy_to_tiled_x__swizzle_9_10(const void *src, void *dst, int bpp,
143.4134 +-				int32_t src_stride, int32_t dst_stride,
143.4135 +-				int16_t src_x, int16_t src_y,
143.4136 +-				int16_t dst_x, int16_t dst_y,
143.4137 +-				uint16_t width, uint16_t height)
143.4138 +-{
143.4139 +-	const unsigned tile_width = 512;
143.4140 +-	const unsigned tile_height = 8;
143.4141 +-	const unsigned tile_size = 4096;
143.4142 +-
143.4143 +-	const unsigned cpp = bpp / 8;
143.4144 +-	const unsigned stride_tiles = dst_stride / tile_width;
143.4145 +-	const unsigned swizzle_pixels = 64 / cpp;
143.4146 +-	const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
143.4147 +-	const unsigned tile_mask = (1 << tile_pixels) - 1;
143.4148 ++#define memcpy_to_tiled_x(swizzle) \
143.4149 ++fast_memcpy static void \
143.4150 ++memcpy_to_tiled_x__##swizzle (const void *src, void *dst, int bpp, \
143.4151 ++			      int32_t src_stride, int32_t dst_stride, \
143.4152 ++			      int16_t src_x, int16_t src_y, \
143.4153 ++			      int16_t dst_x, int16_t dst_y, \
143.4154 ++			      uint16_t width, uint16_t height) \
143.4155 ++{ \
143.4156 ++	const unsigned tile_width = 512; \
143.4157 ++	const unsigned tile_height = 8; \
143.4158 ++	const unsigned tile_size = 4096; \
143.4159 ++	const unsigned cpp = bpp / 8; \
143.4160 ++	const unsigned stride_tiles = dst_stride / tile_width; \
143.4161 ++	const unsigned swizzle_pixels = 64 / cpp; \
143.4162 ++	const unsigned tile_pixels = ffs(tile_width / cpp) - 1; \
143.4163 ++	const unsigned tile_mask = (1 << tile_pixels) - 1; \
143.4164 ++	unsigned x, y; \
143.4165 ++	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n", \
143.4166 ++	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride)); \
143.4167 ++	src = (const uint8_t *)src + src_y * src_stride + src_x * cpp; \
143.4168 ++	for (y = 0; y < height; ++y) { \
143.4169 ++		const uint32_t dy = y + dst_y; \
143.4170 ++		const uint32_t tile_row = \
143.4171 ++			(dy / tile_height * stride_tiles * tile_size + \
143.4172 ++			 (dy & (tile_height-1)) * tile_width); \
143.4173 ++		const uint8_t *src_row = (const uint8_t *)src + src_stride * y; \
143.4174 ++		uint32_t dx = dst_x; \
143.4175 ++		x = width * cpp; \
143.4176 ++		if (dx & (swizzle_pixels - 1)) { \
143.4177 ++			const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels); \
143.4178 ++			const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx; \
143.4179 ++			uint32_t offset = \
143.4180 ++				tile_row + \
143.4181 ++				(dx >> tile_pixels) * tile_size + \
143.4182 ++				(dx & tile_mask) * cpp; \
143.4183 ++			memcpy((char *)dst + swizzle(offset), src_row, length * cpp); \
143.4184 ++			src_row += length * cpp; \
143.4185 ++			x -= length * cpp; \
143.4186 ++			dx += length; \
143.4187 ++		} \
143.4188 ++		while (x >= 64) { \
143.4189 ++			uint32_t offset = \
143.4190 ++				tile_row + \
143.4191 ++				(dx >> tile_pixels) * tile_size + \
143.4192 ++				(dx & tile_mask) * cpp; \
143.4193 ++			memcpy(assume_aligned((char *)dst+swizzle(offset),64), \
143.4194 ++			       src_row, 64); \
143.4195 ++			src_row += 64; \
143.4196 ++			x -= 64; \
143.4197 ++			dx += swizzle_pixels; \
143.4198 ++		} \
143.4199 ++		if (x) { \
143.4200 ++			uint32_t offset = \
143.4201 ++				tile_row + \
143.4202 ++				(dx >> tile_pixels) * tile_size + \
143.4203 ++				(dx & tile_mask) * cpp; \
143.4204 ++			memcpy(assume_aligned((char *)dst + swizzle(offset), 64), src_row, x); \
143.4205 ++		} \
143.4206 ++	} \
143.4207 ++}
143.4208 + 
143.4209 +-	unsigned x, y;
143.4210 ++#define memcpy_from_tiled_x(swizzle) \
143.4211 ++fast_memcpy static void \
143.4212 ++memcpy_from_tiled_x__##swizzle (const void *src, void *dst, int bpp, \
143.4213 ++				int32_t src_stride, int32_t dst_stride, \
143.4214 ++				int16_t src_x, int16_t src_y, \
143.4215 ++				int16_t dst_x, int16_t dst_y, \
143.4216 ++				uint16_t width, uint16_t height) \
143.4217 ++{ \
143.4218 ++	const unsigned tile_width = 512; \
143.4219 ++	const unsigned tile_height = 8; \
143.4220 ++	const unsigned tile_size = 4096; \
143.4221 ++	const unsigned cpp = bpp / 8; \
143.4222 ++	const unsigned stride_tiles = src_stride / tile_width; \
143.4223 ++	const unsigned swizzle_pixels = 64 / cpp; \
143.4224 ++	const unsigned tile_pixels = ffs(tile_width / cpp) - 1; \
143.4225 ++	const unsigned tile_mask = (1 << tile_pixels) - 1; \
143.4226 ++	unsigned x, y; \
143.4227 ++	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n", \
143.4228 ++	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride)); \
143.4229 ++	dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp; \
143.4230 ++	for (y = 0; y < height; ++y) { \
143.4231 ++		const uint32_t sy = y + src_y; \
143.4232 ++		const uint32_t tile_row = \
143.4233 ++			(sy / tile_height * stride_tiles * tile_size + \
143.4234 ++			 (sy & (tile_height-1)) * tile_width); \
143.4235 ++		uint8_t *dst_row = (uint8_t *)dst + dst_stride * y; \
143.4236 ++		uint32_t sx = src_x; \
143.4237 ++		x = width * cpp; \
143.4238 ++		if (sx & (swizzle_pixels - 1)) { \
143.4239 ++			const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels); \
143.4240 ++			const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx; \
143.4241 ++			uint32_t offset = \
143.4242 ++				tile_row + \
143.4243 ++				(sx >> tile_pixels) * tile_size + \
143.4244 ++				(sx & tile_mask) * cpp; \
143.4245 ++			memcpy(dst_row, (const char *)src + swizzle(offset), length * cpp); \
143.4246 ++			dst_row += length * cpp; \
143.4247 ++			x -= length * cpp; \
143.4248 ++			sx += length; \
143.4249 ++		} \
143.4250 ++		while (x >= 64) { \
143.4251 ++			uint32_t offset = \
143.4252 ++				tile_row + \
143.4253 ++				(sx >> tile_pixels) * tile_size + \
143.4254 ++				(sx & tile_mask) * cpp; \
143.4255 ++			memcpy(dst_row, assume_aligned((const char *)src + swizzle(offset), 64), 64); \
143.4256 ++			dst_row += 64; \
143.4257 ++			x -= 64; \
143.4258 ++			sx += swizzle_pixels; \
143.4259 ++		} \
143.4260 ++		if (x) { \
143.4261 ++			uint32_t offset = \
143.4262 ++				tile_row + \
143.4263 ++				(sx >> tile_pixels) * tile_size + \
143.4264 ++				(sx & tile_mask) * cpp; \
143.4265 ++			memcpy(dst_row, assume_aligned((const char *)src + swizzle(offset), 64), x); \
143.4266 ++		} \
143.4267 ++	} \
143.4268 ++}
143.4269 + 
143.4270 +-	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.4271 +-	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.4272 ++#define swizzle_9(X) ((X) ^ (((X) >> 3) & 64))
143.4273 ++memcpy_to_tiled_x(swizzle_9)
143.4274 ++memcpy_from_tiled_x(swizzle_9)
143.4275 ++#undef swizzle_9
143.4276 + 
143.4277 +-	src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
143.4278 +-
143.4279 +-	for (y = 0; y < height; ++y) {
143.4280 +-		const uint32_t dy = y + dst_y;
143.4281 +-		const uint32_t tile_row =
143.4282 +-			(dy / tile_height * stride_tiles * tile_size +
143.4283 +-			 (dy & (tile_height-1)) * tile_width);
143.4284 +-		const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
143.4285 +-		uint32_t dx = dst_x, offset;
143.4286 +-
143.4287 +-		x = width * cpp;
143.4288 +-		if (dx & (swizzle_pixels - 1)) {
143.4289 +-			const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
143.4290 +-			const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
143.4291 +-			offset = tile_row +
143.4292 +-				(dx >> tile_pixels) * tile_size +
143.4293 +-				(dx & tile_mask) * cpp;
143.4294 +-			offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
143.4295 +-
143.4296 +-			memcpy((char *)dst + offset, src_row, length * cpp);
143.4297 +-
143.4298 +-			src_row += length * cpp;
143.4299 +-			x -= length * cpp;
143.4300 +-			dx += length;
143.4301 +-		}
143.4302 +-		while (x >= 64) {
143.4303 +-			offset = tile_row +
143.4304 +-				(dx >> tile_pixels) * tile_size +
143.4305 +-				(dx & tile_mask) * cpp;
143.4306 +-			offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
143.4307 ++#define swizzle_9_10(X) ((X) ^ ((((X) ^ ((X) >> 1)) >> 3) & 64))
143.4308 ++memcpy_to_tiled_x(swizzle_9_10)
143.4309 ++memcpy_from_tiled_x(swizzle_9_10)
143.4310 ++#undef swizzle_9_10
143.4311 + 
143.4312 +-			memcpy((char *)dst + offset, src_row, 64);
143.4313 ++#define swizzle_9_11(X) ((X) ^ ((((X) ^ ((X) >> 2)) >> 3) & 64))
143.4314 ++memcpy_to_tiled_x(swizzle_9_11)
143.4315 ++memcpy_from_tiled_x(swizzle_9_11)
143.4316 ++#undef swizzle_9_11
143.4317 + 
143.4318 +-			src_row += 64;
143.4319 +-			x -= 64;
143.4320 +-			dx += swizzle_pixels;
143.4321 +-		}
143.4322 +-		if (x) {
143.4323 +-			offset = tile_row +
143.4324 +-				(dx >> tile_pixels) * tile_size +
143.4325 +-				(dx & tile_mask) * cpp;
143.4326 +-			offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
143.4327 +-			memcpy((char *)dst + offset, src_row, x);
143.4328 +-		}
143.4329 +-	}
143.4330 +-}
143.4331 ++#define swizzle_9_10_11(X) ((X) ^ ((((X) ^ ((X) >> 1) ^ ((X) >> 2)) >> 3) & 64))
143.4332 ++memcpy_to_tiled_x(swizzle_9_10_11)
143.4333 ++memcpy_from_tiled_x(swizzle_9_10_11)
143.4334 ++#undef swizzle_9_10_11
143.4335 + 
143.4336 +-fast_memcpy static void
143.4337 +-memcpy_from_tiled_x__swizzle_9_10(const void *src, void *dst, int bpp,
143.4338 +-				  int32_t src_stride, int32_t dst_stride,
143.4339 +-				  int16_t src_x, int16_t src_y,
143.4340 +-				  int16_t dst_x, int16_t dst_y,
143.4341 +-				  uint16_t width, uint16_t height)
143.4342 ++static fast_memcpy void
143.4343 ++memcpy_to_tiled_x__gen2(const void *src, void *dst, int bpp,
143.4344 ++			int32_t src_stride, int32_t dst_stride,
143.4345 ++			int16_t src_x, int16_t src_y,
143.4346 ++			int16_t dst_x, int16_t dst_y,
143.4347 ++			uint16_t width, uint16_t height)
143.4348 + {
143.4349 +-	const unsigned tile_width = 512;
143.4350 +-	const unsigned tile_height = 8;
143.4351 +-	const unsigned tile_size = 4096;
143.4352 ++	const unsigned tile_width = 128;
143.4353 ++	const unsigned tile_height = 16;
143.4354 ++	const unsigned tile_size = 2048;
143.4355 + 
143.4356 + 	const unsigned cpp = bpp / 8;
143.4357 +-	const unsigned stride_tiles = src_stride / tile_width;
143.4358 +-	const unsigned swizzle_pixels = 64 / cpp;
143.4359 +-	const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
143.4360 +-	const unsigned tile_mask = (1 << tile_pixels) - 1;
143.4361 +-
143.4362 +-	unsigned x, y;
143.4363 ++	const unsigned tile_pixels = tile_width / cpp;
143.4364 ++	const unsigned tile_shift = ffs(tile_pixels) - 1;
143.4365 ++	const unsigned tile_mask = tile_pixels - 1;
143.4366 + 
143.4367 + 	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.4368 + 	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.4369 ++	assert(src != dst);
143.4370 + 
143.4371 +-	dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
143.4372 +-
143.4373 +-	for (y = 0; y < height; ++y) {
143.4374 +-		const uint32_t sy = y + src_y;
143.4375 +-		const uint32_t tile_row =
143.4376 +-			(sy / tile_height * stride_tiles * tile_size +
143.4377 +-			 (sy & (tile_height-1)) * tile_width);
143.4378 +-		uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
143.4379 +-		uint32_t sx = src_x, offset;
143.4380 +-
143.4381 +-		x = width * cpp;
143.4382 +-		if (sx & (swizzle_pixels - 1)) {
143.4383 +-			const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
143.4384 +-			const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
143.4385 +-			offset = tile_row +
143.4386 +-				(sx >> tile_pixels) * tile_size +
143.4387 +-				(sx & tile_mask) * cpp;
143.4388 +-			offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
143.4389 +-
143.4390 +-			memcpy(dst_row, (const char *)src + offset, length * cpp);
143.4391 +-
143.4392 +-			dst_row += length * cpp;
143.4393 +-			x -= length * cpp;
143.4394 +-			sx += length;
143.4395 +-		}
143.4396 +-		while (x >= 64) {
143.4397 +-			offset = tile_row +
143.4398 +-				(sx >> tile_pixels) * tile_size +
143.4399 +-				(sx & tile_mask) * cpp;
143.4400 +-			offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
143.4401 +-
143.4402 +-			memcpy(dst_row, (const char *)src + offset, 64);
143.4403 +-
143.4404 +-			dst_row += 64;
143.4405 +-			x -= 64;
143.4406 +-			sx += swizzle_pixels;
143.4407 +-		}
143.4408 +-		if (x) {
143.4409 +-			offset = tile_row +
143.4410 +-				(sx >> tile_pixels) * tile_size +
143.4411 +-				(sx & tile_mask) * cpp;
143.4412 +-			offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
143.4413 +-			memcpy(dst_row, (const char *)src + offset, x);
143.4414 +-		}
143.4415 +-	}
143.4416 +-}
143.4417 +-
143.4418 +-fast_memcpy static void
143.4419 +-memcpy_to_tiled_x__swizzle_9_11(const void *src, void *dst, int bpp,
143.4420 +-				int32_t src_stride, int32_t dst_stride,
143.4421 +-				int16_t src_x, int16_t src_y,
143.4422 +-				int16_t dst_x, int16_t dst_y,
143.4423 +-				uint16_t width, uint16_t height)
143.4424 +-{
143.4425 +-	const unsigned tile_width = 512;
143.4426 +-	const unsigned tile_height = 8;
143.4427 +-	const unsigned tile_size = 4096;
143.4428 +-
143.4429 +-	const unsigned cpp = bpp / 8;
143.4430 +-	const unsigned stride_tiles = dst_stride / tile_width;
143.4431 +-	const unsigned swizzle_pixels = 64 / cpp;
143.4432 +-	const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
143.4433 +-	const unsigned tile_mask = (1 << tile_pixels) - 1;
143.4434 ++	if (src_x | src_y)
143.4435 ++		src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
143.4436 ++	assert(src_stride >= width * cpp);
143.4437 ++	src_stride -= width * cpp;
143.4438 + 
143.4439 +-	unsigned x, y;
143.4440 ++	while (height--) {
143.4441 ++		unsigned w = width * cpp;
143.4442 ++		uint8_t *tile_row = dst;
143.4443 + 
143.4444 +-	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.4445 +-	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.4446 ++		tile_row += dst_y / tile_height * dst_stride * tile_height;
143.4447 ++		tile_row += (dst_y & (tile_height-1)) * tile_width;
143.4448 ++		if (dst_x) {
143.4449 ++			tile_row += (dst_x >> tile_shift) * tile_size;
143.4450 ++			if (dst_x & tile_mask) {
143.4451 ++				const unsigned x = (dst_x & tile_mask) * cpp;
143.4452 ++				const unsigned len = min(tile_width - x, w);
143.4453 ++				memcpy(assume_misaligned(tile_row + x, tile_width, x), src, len);
143.4454 + 
143.4455 +-	src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
143.4456 +-
143.4457 +-	for (y = 0; y < height; ++y) {
143.4458 +-		const uint32_t dy = y + dst_y;
143.4459 +-		const uint32_t tile_row =
143.4460 +-			(dy / tile_height * stride_tiles * tile_size +
143.4461 +-			 (dy & (tile_height-1)) * tile_width);
143.4462 +-		const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
143.4463 +-		uint32_t dx = dst_x, offset;
143.4464 +-
143.4465 +-		x = width * cpp;
143.4466 +-		if (dx & (swizzle_pixels - 1)) {
143.4467 +-			const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
143.4468 +-			const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
143.4469 +-			offset = tile_row +
143.4470 +-				(dx >> tile_pixels) * tile_size +
143.4471 +-				(dx & tile_mask) * cpp;
143.4472 +-			offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
143.4473 +-			memcpy((char *)dst + offset, src_row, length * cpp);
143.4474 +-
143.4475 +-			src_row += length * cpp;
143.4476 +-			x -= length * cpp;
143.4477 +-			dx += length;
143.4478 ++				tile_row += tile_size;
143.4479 ++				src = (const uint8_t *)src + len;
143.4480 ++				w -= len;
143.4481 ++			}
143.4482 + 		}
143.4483 +-		while (x >= 64) {
143.4484 +-			offset = tile_row +
143.4485 +-				(dx >> tile_pixels) * tile_size +
143.4486 +-				(dx & tile_mask) * cpp;
143.4487 +-			offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
143.4488 +-
143.4489 +-			memcpy((char *)dst + offset, src_row, 64);
143.4490 ++		while (w >= tile_width) {
143.4491 ++			memcpy(assume_aligned(tile_row, tile_width),
143.4492 ++			       src, tile_width);
143.4493 + 
143.4494 +-			src_row += 64;
143.4495 +-			x -= 64;
143.4496 +-			dx += swizzle_pixels;
143.4497 +-		}
143.4498 +-		if (x) {
143.4499 +-			offset = tile_row +
143.4500 +-				(dx >> tile_pixels) * tile_size +
143.4501 +-				(dx & tile_mask) * cpp;
143.4502 +-			offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
143.4503 +-			memcpy((char *)dst + offset, src_row, x);
143.4504 ++			tile_row += tile_size;
143.4505 ++			src = (const uint8_t *)src + tile_width;
143.4506 ++			w -= tile_width;
143.4507 + 		}
143.4508 ++		memcpy(assume_aligned(tile_row, tile_width), src, w);
143.4509 ++		src = (const uint8_t *)src + src_stride + w;
143.4510 ++		dst_y++;
143.4511 + 	}
143.4512 + }
143.4513 + 
143.4514 +-fast_memcpy static void
143.4515 +-memcpy_from_tiled_x__swizzle_9_11(const void *src, void *dst, int bpp,
143.4516 +-				  int32_t src_stride, int32_t dst_stride,
143.4517 +-				  int16_t src_x, int16_t src_y,
143.4518 +-				  int16_t dst_x, int16_t dst_y,
143.4519 +-				  uint16_t width, uint16_t height)
143.4520 ++static fast_memcpy void
143.4521 ++memcpy_from_tiled_x__gen2(const void *src, void *dst, int bpp,
143.4522 ++			  int32_t src_stride, int32_t dst_stride,
143.4523 ++			  int16_t src_x, int16_t src_y,
143.4524 ++			  int16_t dst_x, int16_t dst_y,
143.4525 ++			  uint16_t width, uint16_t height)
143.4526 + {
143.4527 +-	const unsigned tile_width = 512;
143.4528 +-	const unsigned tile_height = 8;
143.4529 +-	const unsigned tile_size = 4096;
143.4530 ++	const unsigned tile_width = 128;
143.4531 ++	const unsigned tile_height = 16;
143.4532 ++	const unsigned tile_size = 2048;
143.4533 + 
143.4534 + 	const unsigned cpp = bpp / 8;
143.4535 +-	const unsigned stride_tiles = src_stride / tile_width;
143.4536 +-	const unsigned swizzle_pixels = 64 / cpp;
143.4537 +-	const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
143.4538 +-	const unsigned tile_mask = (1 << tile_pixels) - 1;
143.4539 +-
143.4540 +-	unsigned x, y;
143.4541 ++	const unsigned tile_pixels = tile_width / cpp;
143.4542 ++	const unsigned tile_shift = ffs(tile_pixels) - 1;
143.4543 ++	const unsigned tile_mask = tile_pixels - 1;
143.4544 + 
143.4545 + 	DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
143.4546 + 	     __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
143.4547 ++	assert(src != dst);
143.4548 + 
143.4549 +-	dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
143.4550 +-
143.4551 +-	for (y = 0; y < height; ++y) {
143.4552 +-		const uint32_t sy = y + src_y;
143.4553 +-		const uint32_t tile_row =
143.4554 +-			(sy / tile_height * stride_tiles * tile_size +
143.4555 +-			 (sy & (tile_height-1)) * tile_width);
143.4556 +-		uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
143.4557 +-		uint32_t sx = src_x, offset;
143.4558 +-
143.4559 +-		x = width * cpp;
143.4560 +-		if (sx & (swizzle_pixels - 1)) {
143.4561 +-			const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
143.4562 +-			const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
143.4563 +-			offset = tile_row +
143.4564 +-				(sx >> tile_pixels) * tile_size +
143.4565 +-				(sx & tile_mask) * cpp;
143.4566 +-			offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
143.4567 +-			memcpy(dst_row, (const char *)src + offset, length * cpp);
143.4568 +-
143.4569 +-			dst_row += length * cpp;
143.4570 +-			x -= length * cpp;
143.4571 +-			sx += length;
143.4572 +-		}
143.4573 +-		while (x >= 64) {
143.4574 +-			offset = tile_row +
143.4575 +-				(sx >> tile_pixels) * tile_size +
143.4576 +-				(sx & tile_mask) * cpp;
143.4577 +-			offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
143.4578 ++	if (dst_x | dst_y)
143.4579 ++		dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
143.4580 ++	assert(dst_stride >= width * cpp);
143.4581 ++	dst_stride -= width * cpp;
143.4582 ++
143.4583 ++	while (height--) {
143.4584 ++		unsigned w = width * cpp;
143.4585 ++		const uint8_t *tile_row = src;
143.4586 + 
143.4587 +-			memcpy(dst_row, (const char *)src + offset, 64);
143.4588 ++		tile_row += src_y / tile_height * src_stride * tile_height;
143.4589 ++		tile_row += (src_y & (tile_height-1)) * tile_width;
143.4590 ++		if (src_x) {
143.4591 ++			tile_row += (src_x >> tile_shift) * tile_size;
143.4592 ++			if (src_x & tile_mask) {
143.4593 ++				const unsigned x = (src_x & tile_mask) * cpp;
143.4594 ++				const unsigned len = min(tile_width - x, w);
143.4595 ++				memcpy(dst, assume_misaligned(tile_row + x, tile_width, x), len);
143.4596 + 
143.4597 +-			dst_row += 64;
143.4598 +-			x -= 64;
143.4599 +-			sx += swizzle_pixels;
143.4600 ++				tile_row += tile_size;
143.4601 ++				dst = (uint8_t *)dst + len;
143.4602 ++				w -= len;
143.4603 ++			}
143.4604 + 		}
143.4605 +-		if (x) {
143.4606 +-			offset = tile_row +
143.4607 +-				(sx >> tile_pixels) * tile_size +
143.4608 +-				(sx & tile_mask) * cpp;
143.4609 +-			offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
143.4610 +-			memcpy(dst_row, (const char *)src + offset, x);
143.4611 ++		while (w >= tile_width) {
143.4612 ++			memcpy(dst,
143.4613 ++			       assume_aligned(tile_row, tile_width),
143.4614 ++			       tile_width);
143.4615 ++
143.4616 ++			tile_row += tile_size;
143.4617 ++			dst = (uint8_t *)dst + tile_width;
143.4618 ++			w -= tile_width;
143.4619 + 		}
143.4620 ++		memcpy(dst, assume_aligned(tile_row, tile_width), w);
143.4621 ++		dst = (uint8_t *)dst + dst_stride + w;
143.4622 ++		src_y++;
143.4623 + 	}
143.4624 + }
143.4625 + 
143.4626 +-void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling)
143.4627 ++void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling, unsigned cpu)
143.4628 + {
143.4629 ++	if (kgem->gen < 030) {
143.4630 ++		if (swizzling == I915_BIT_6_SWIZZLE_NONE) {
143.4631 ++			DBG(("%s: gen2, no swizzling\n", __FUNCTION__));
143.4632 ++			kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__gen2;
143.4633 ++			kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__gen2;
143.4634 ++		} else
143.4635 ++			DBG(("%s: no detiling with swizzle functions for gen2\n", __FUNCTION__));
143.4636 ++		return;
143.4637 ++	}
143.4638 ++
143.4639 + 	switch (swizzling) {
143.4640 + 	default:
143.4641 + 		DBG(("%s: unknown swizzling, %d\n", __FUNCTION__, swizzling));
143.4642 + 		break;
143.4643 + 	case I915_BIT_6_SWIZZLE_NONE:
143.4644 + 		DBG(("%s: no swizzling\n", __FUNCTION__));
143.4645 +-		kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_0;
143.4646 +-		kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_0;
143.4647 ++#if defined(sse2)
143.4648 ++		if (cpu & SSE2) {
143.4649 ++			kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_0__sse2;
143.4650 ++			kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_0__sse2;
143.4651 ++			kgem->memcpy_between_tiled_x = memcpy_between_tiled_x__swizzle_0__sse2;
143.4652 ++		} else
143.4653 ++#endif
143.4654 ++	       	{
143.4655 ++			kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_0;
143.4656 ++			kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_0;
143.4657 ++			kgem->memcpy_between_tiled_x = memcpy_between_tiled_x__swizzle_0;
143.4658 ++		}
143.4659 + 		break;
143.4660 + 	case I915_BIT_6_SWIZZLE_9:
143.4661 + 		DBG(("%s: 6^9 swizzling\n", __FUNCTION__));
143.4662 +@@ -771,6 +1199,11 @@ void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling)
143.4663 + 		kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_9_11;
143.4664 + 		kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_9_11;
143.4665 + 		break;
143.4666 ++	case I915_BIT_6_SWIZZLE_9_10_11:
143.4667 ++		DBG(("%s: 6^9^10^11 swizzling\n", __FUNCTION__));
143.4668 ++		kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_9_10_11;
143.4669 ++		kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_9_10_11;
143.4670 ++		break;
143.4671 + 	}
143.4672 + }
143.4673 + 
143.4674 +@@ -995,7 +1428,7 @@ memcpy_xor(const void *src, void *dst, int bpp,
143.4675 + 				height = 1;
143.4676 + 			}
143.4677 + 
143.4678 +-#if USE_SSE2
143.4679 ++#if defined(sse2) && __x86_64__
143.4680 + 			if (have_sse2()) {
143.4681 + 				do {
143.4682 + 					uint32_t *d = (uint32_t *)dst_bytes;
143.4683 +@@ -1118,3 +1551,241 @@ memcpy_xor(const void *src, void *dst, int bpp,
143.4684 + 		}
143.4685 + 	}
143.4686 + }
143.4687 ++
143.4688 ++#define BILINEAR_INTERPOLATION_BITS 4
143.4689 ++static inline int
143.4690 ++bilinear_weight(pixman_fixed_t x)
143.4691 ++{
143.4692 ++	return (x >> (16 - BILINEAR_INTERPOLATION_BITS)) &
143.4693 ++		((1 << BILINEAR_INTERPOLATION_BITS) - 1);
143.4694 ++}
143.4695 ++
143.4696 ++#if BILINEAR_INTERPOLATION_BITS <= 4
143.4697 ++/* Inspired by Filter_32_opaque from Skia */
143.4698 ++static inline uint32_t
143.4699 ++bilinear_interpolation(uint32_t tl, uint32_t tr,
143.4700 ++		       uint32_t bl, uint32_t br,
143.4701 ++		       int distx, int disty)
143.4702 ++{
143.4703 ++	int distxy, distxiy, distixy, distixiy;
143.4704 ++	uint32_t lo, hi;
143.4705 ++
143.4706 ++	distx <<= (4 - BILINEAR_INTERPOLATION_BITS);
143.4707 ++	disty <<= (4 - BILINEAR_INTERPOLATION_BITS);
143.4708 ++
143.4709 ++	distxy = distx * disty;
143.4710 ++	distxiy = (distx << 4) - distxy;	/* distx * (16 - disty) */
143.4711 ++	distixy = (disty << 4) - distxy;	/* disty * (16 - distx) */
143.4712 ++	distixiy =
143.4713 ++		16 * 16 - (disty << 4) -
143.4714 ++		(distx << 4) + distxy; /* (16 - distx) * (16 - disty) */
143.4715 ++
143.4716 ++	lo = (tl & 0xff00ff) * distixiy;
143.4717 ++	hi = ((tl >> 8) & 0xff00ff) * distixiy;
143.4718 ++
143.4719 ++	lo += (tr & 0xff00ff) * distxiy;
143.4720 ++	hi += ((tr >> 8) & 0xff00ff) * distxiy;
143.4721 ++
143.4722 ++	lo += (bl & 0xff00ff) * distixy;
143.4723 ++	hi += ((bl >> 8) & 0xff00ff) * distixy;
143.4724 ++
143.4725 ++	lo += (br & 0xff00ff) * distxy;
143.4726 ++	hi += ((br >> 8) & 0xff00ff) * distxy;
143.4727 ++
143.4728 ++	return ((lo >> 8) & 0xff00ff) | (hi & ~0xff00ff);
143.4729 ++}
143.4730 ++#elif SIZEOF_LONG > 4
143.4731 ++static inline uint32_t
143.4732 ++bilinear_interpolation(uint32_t tl, uint32_t tr,
143.4733 ++		       uint32_t bl, uint32_t br,
143.4734 ++		       int distx, int disty)
143.4735 ++{
143.4736 ++	uint64_t distxy, distxiy, distixy, distixiy;
143.4737 ++	uint64_t tl64, tr64, bl64, br64;
143.4738 ++	uint64_t f, r;
143.4739 ++
143.4740 ++	distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
143.4741 ++	disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
143.4742 ++
143.4743 ++	distxy = distx * disty;
143.4744 ++	distxiy = distx * (256 - disty);
143.4745 ++	distixy = (256 - distx) * disty;
143.4746 ++	distixiy = (256 - distx) * (256 - disty);
143.4747 ++
143.4748 ++	/* Alpha and Blue */
143.4749 ++	tl64 = tl & 0xff0000ff;
143.4750 ++	tr64 = tr & 0xff0000ff;
143.4751 ++	bl64 = bl & 0xff0000ff;
143.4752 ++	br64 = br & 0xff0000ff;
143.4753 ++
143.4754 ++	f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
143.4755 ++	r = f & 0x0000ff0000ff0000ull;
143.4756 ++
143.4757 ++	/* Red and Green */
143.4758 ++	tl64 = tl;
143.4759 ++	tl64 = ((tl64 << 16) & 0x000000ff00000000ull) | (tl64 & 0x0000ff00ull);
143.4760 ++
143.4761 ++	tr64 = tr;
143.4762 ++	tr64 = ((tr64 << 16) & 0x000000ff00000000ull) | (tr64 & 0x0000ff00ull);
143.4763 ++
143.4764 ++	bl64 = bl;
143.4765 ++	bl64 = ((bl64 << 16) & 0x000000ff00000000ull) | (bl64 & 0x0000ff00ull);
143.4766 ++
143.4767 ++	br64 = br;
143.4768 ++	br64 = ((br64 << 16) & 0x000000ff00000000ull) | (br64 & 0x0000ff00ull);
143.4769 ++
143.4770 ++	f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
143.4771 ++	r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
143.4772 ++
143.4773 ++	return (uint32_t)(r >> 16);
143.4774 ++}
143.4775 ++#else
143.4776 ++static inline uint32_t
143.4777 ++bilinear_interpolation(uint32_t tl, uint32_t tr,
143.4778 ++		       uint32_t bl, uint32_t br,
143.4779 ++		       int distx, int disty)
143.4780 ++{
143.4781 ++	int distxy, distxiy, distixy, distixiy;
143.4782 ++	uint32_t f, r;
143.4783 ++
143.4784 ++	distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
143.4785 ++	disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
143.4786 ++
143.4787 ++	distxy = distx * disty;
143.4788 ++	distxiy = (distx << 8) - distxy;	/* distx * (256 - disty) */
143.4789 ++	distixy = (disty << 8) - distxy;	/* disty * (256 - distx) */
143.4790 ++	distixiy =
143.4791 ++		256 * 256 - (disty << 8) -
143.4792 ++		(distx << 8) + distxy;		/* (256 - distx) * (256 - disty) */
143.4793 ++
143.4794 ++	/* Blue */
143.4795 ++	r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy +
143.4796 ++	     (bl & 0x000000ff) * distixy  + (br & 0x000000ff) * distxy);
143.4797 ++
143.4798 ++	/* Green */
143.4799 ++	f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy +
143.4800 ++	     (bl & 0x0000ff00) * distixy  + (br & 0x0000ff00) * distxy);
143.4801 ++	r |= f & 0xff000000;
143.4802 ++
143.4803 ++	tl >>= 16;
143.4804 ++	tr >>= 16;
143.4805 ++	bl >>= 16;
143.4806 ++	br >>= 16;
143.4807 ++	r >>= 16;
143.4808 ++
143.4809 ++	/* Red */
143.4810 ++	f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy +
143.4811 ++	     (bl & 0x000000ff) * distixy  + (br & 0x000000ff) * distxy);
143.4812 ++	r |= f & 0x00ff0000;
143.4813 ++
143.4814 ++	/* Alpha */
143.4815 ++	f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy +
143.4816 ++	     (bl & 0x0000ff00) * distixy  + (br & 0x0000ff00) * distxy);
143.4817 ++	r |= f & 0xff000000;
143.4818 ++
143.4819 ++	return r;
143.4820 ++}
143.4821 ++#endif
143.4822 ++
143.4823 ++static inline uint32_t convert_pixel(const uint8_t *p, int x)
143.4824 ++{
143.4825 ++	return ((uint32_t *)p)[x];
143.4826 ++}
143.4827 ++
143.4828 ++fast void
143.4829 ++affine_blt(const void *src, void *dst, int bpp,
143.4830 ++	   int16_t src_x, int16_t src_y,
143.4831 ++	   int16_t src_width, int16_t src_height,
143.4832 ++	   int32_t src_stride,
143.4833 ++	   int16_t dst_x, int16_t dst_y,
143.4834 ++	   uint16_t dst_width, uint16_t dst_height,
143.4835 ++	   int32_t dst_stride,
143.4836 ++	   const struct pixman_f_transform *t)
143.4837 ++{
143.4838 ++	static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
143.4839 ++	const pixman_fixed_t ux = pixman_double_to_fixed(t->m[0][0]);
143.4840 ++	const pixman_fixed_t uy = pixman_double_to_fixed(t->m[1][0]);
143.4841 ++	int i, j;
143.4842 ++
143.4843 ++	assert(bpp == 32);
143.4844 ++
143.4845 ++	for (j = 0; j < dst_height; j++) {
143.4846 ++		pixman_fixed_t x, y;
143.4847 ++		struct pixman_f_vector v;
143.4848 ++		uint32_t *b;
143.4849 ++
143.4850 ++		/* reference point is the center of the pixel */
143.4851 ++		v.v[0] = dst_x + 0.5;
143.4852 ++		v.v[1] = dst_y + j + 0.5;
143.4853 ++		v.v[2] = 1.0;
143.4854 ++
143.4855 ++		pixman_f_transform_point_3d(t, &v);
143.4856 ++
143.4857 ++		x = pixman_double_to_fixed(v.v[0]);
143.4858 ++		x += pixman_int_to_fixed(src_x - dst_x);
143.4859 ++		y = pixman_double_to_fixed(v.v[1]);
143.4860 ++		y +=  pixman_int_to_fixed(src_y - dst_y);
143.4861 ++
143.4862 ++		b = (uint32_t*)((uint8_t *)dst + (dst_y + j) * dst_stride + dst_x * bpp / 8);
143.4863 ++		for (i = 0; i < dst_width; i++) {
143.4864 ++			const uint8_t *row1;
143.4865 ++			const uint8_t *row2;
143.4866 ++			int x1, y1, x2, y2;
143.4867 ++			uint32_t tl, tr, bl, br;
143.4868 ++			int32_t fx, fy;
143.4869 ++
143.4870 ++			x1 = x - pixman_fixed_1/2;
143.4871 ++			y1 = y - pixman_fixed_1/2;
143.4872 ++
143.4873 ++			fx = bilinear_weight(x1);
143.4874 ++			fy = bilinear_weight(y1);
143.4875 ++
143.4876 ++			x1 = pixman_fixed_to_int(x1);
143.4877 ++			x2 = x1 + 1;
143.4878 ++			y1 = pixman_fixed_to_int(y1);
143.4879 ++			y2 = y1 + 1;
143.4880 ++
143.4881 ++			if (x1 >= src_width  || x2 < 0 ||
143.4882 ++			    y1 >= src_height || y2 < 0) {
143.4883 ++				b[i] = 0;
143.4884 ++				goto next;
143.4885 ++			}
143.4886 ++
143.4887 ++			if (y2 == 0) {
143.4888 ++				row1 = zero;
143.4889 ++			} else {
143.4890 ++				row1 = (uint8_t *)src + src_stride * y1;
143.4891 ++				row1 += bpp / 8 * x1;
143.4892 ++			}
143.4893 ++
143.4894 ++			if (y1 == src_height - 1) {
143.4895 ++				row2 = zero;
143.4896 ++			} else {
143.4897 ++				row2 = (uint8_t *)src + src_stride * y2;
143.4898 ++				row2 += bpp / 8 * x1;
143.4899 ++			}
143.4900 ++
143.4901 ++			if (x2 == 0) {
143.4902 ++				tl = 0;
143.4903 ++				bl = 0;
143.4904 ++			} else {
143.4905 ++				tl = convert_pixel(row1, 0);
143.4906 ++				bl = convert_pixel(row2, 0);
143.4907 ++			}
143.4908 ++
143.4909 ++			if (x1 == src_width - 1) {
143.4910 ++				tr = 0;
143.4911 ++				br = 0;
143.4912 ++			} else {
143.4913 ++				tr = convert_pixel(row1, 1);
143.4914 ++				br = convert_pixel(row2, 1);
143.4915 ++			}
143.4916 ++
143.4917 ++			b[i] = bilinear_interpolation(tl, tr, bl, br, fx, fy);
143.4918 ++
143.4919 ++next:
143.4920 ++			x += ux;
143.4921 ++			y += uy;
143.4922 ++		}
143.4923 ++	}
143.4924 ++}
143.4925 +diff --git a/src/sna/brw/brw_eu_emit.c b/src/sna/brw/brw_eu_emit.c
143.4926 +index 00c984d9..154f939a 100644
143.4927 +--- a/src/sna/brw/brw_eu_emit.c
143.4928 ++++ b/src/sna/brw/brw_eu_emit.c
143.4929 +@@ -178,7 +178,7 @@ validate_reg(struct brw_instruction *insn, struct brw_reg reg)
143.4930 + 	}
143.4931 + 
143.4932 + 	if (reg.file == BRW_ARCHITECTURE_REGISTER_FILE &&
143.4933 +-	    reg.file == BRW_ARF_NULL)
143.4934 ++	    reg.nr == BRW_ARF_NULL)
143.4935 + 		return;
143.4936 + 
143.4937 + 	assert(reg.hstride >= 0 && reg.hstride < ARRAY_SIZE(hstride_for_reg));
143.4938 +@@ -700,7 +700,7 @@ push_if_stack(struct brw_compile *p, struct brw_instruction *inst)
143.4939 +  *
143.4940 +  * When the matching 'else' instruction is reached (presumably by
143.4941 +  * countdown of the instruction count patched in by our ELSE/ENDIF
143.4942 +- * functions), the relevent flags are inverted.
143.4943 ++ * functions), the relevant flags are inverted.
143.4944 +  *
143.4945 +  * When the matching 'endif' instruction is reached, the flags are
143.4946 +  * popped off.  If the stack is now empty, normal execution resumes.
143.4947 +diff --git a/src/sna/compiler.h b/src/sna/compiler.h
143.4948 +index ff412179..0f3775ec 100644
143.4949 +--- a/src/sna/compiler.h
143.4950 ++++ b/src/sna/compiler.h
143.4951 +@@ -39,6 +39,7 @@
143.4952 + #define pure __attribute__((pure))
143.4953 + #define tightly_packed __attribute__((__packed__))
143.4954 + #define flatten __attribute__((flatten))
143.4955 ++#define nonnull __attribute__((nonnull))
143.4956 + #define page_aligned __attribute__((aligned(4096)))
143.4957 + #else
143.4958 + #define likely(expr) (expr)
143.4959 +@@ -51,18 +52,15 @@
143.4960 + #define pure
143.4961 + #define tighly_packed
143.4962 + #define flatten
143.4963 ++#define nonnull
143.4964 + #define page_aligned
143.4965 + #endif
143.4966 + 
143.4967 + #define HAS_GCC(major, minor) defined(__GNUC__) && (__GNUC__ > (major) || __GNUC__ == (major) && __GNUC_MINOR__ >= (minor))
143.4968 + 
143.4969 + #if HAS_GCC(4, 5)
143.4970 +-#define sse2 __attribute__((target("sse2,fpmath=sse")))
143.4971 +-#define sse4_2 __attribute__((target("sse4.2,sse2,fpmath=sse")))
143.4972 +-#endif
143.4973 +-
143.4974 +-#if HAS_GCC(4, 7)
143.4975 +-#define avx2 __attribute__((target("avx2,sse4.2,sse2,fpmath=sse")))
143.4976 ++#define sse2 fast __attribute__((target("sse2,fpmath=sse")))
143.4977 ++#define sse4_2 fast __attribute__((target("sse4.2,sse2,fpmath=sse")))
143.4978 + #endif
143.4979 + 
143.4980 + #if HAS_GCC(4, 6) && defined(__OPTIMIZE__)
143.4981 +@@ -71,10 +69,17 @@
143.4982 + #define fast
143.4983 + #endif
143.4984 + 
143.4985 +-#if HAS_GCC(4, 6) && defined(__OPTIMIZE__)
143.4986 +-#define fast_memcpy __attribute__((optimize("Ofast"))) __attribute__((target("inline-all-stringops")))
143.4987 +-#elif HAS_GCC(4, 5) && defined(__OPTIMIZE__)
143.4988 +-#define fast_memcpy __attribute__((target("inline-all-stringops")))
143.4989 ++#if HAS_GCC(4, 7)
143.4990 ++#define avx2 fast __attribute__((target("avx2,avx,sse4.2,sse2,fpmath=sse")))
143.4991 ++#define assume_aligned(ptr, align) __builtin_assume_aligned((ptr), (align))
143.4992 ++#define assume_misaligned(ptr, align, offset) __builtin_assume_aligned((ptr), (align), (offset))
143.4993 ++#else
143.4994 ++#define assume_aligned(ptr, align) (ptr)
143.4995 ++#define assume_misaligned(ptr, align, offset) (ptr)
143.4996 ++#endif
143.4997 ++
143.4998 ++#if HAS_GCC(4, 5) && defined(__OPTIMIZE__)
143.4999 ++#define fast_memcpy fast __attribute__((target("inline-all-stringops")))
143.5000 + #else
143.5001 + #define fast_memcpy
143.5002 + #endif
143.5003 +diff --git a/src/sna/fb/fb.h b/src/sna/fb/fb.h
143.5004 +index 8bf9008a..90431747 100644
143.5005 +--- a/src/sna/fb/fb.h
143.5006 ++++ b/src/sna/fb/fb.h
143.5007 +@@ -24,10 +24,6 @@
143.5008 + #ifndef FB_H
143.5009 + #define FB_H
143.5010 + 
143.5011 +-#ifdef HAVE_CONFIG_H
143.5012 +-#include "config.h"
143.5013 +-#endif
143.5014 +-
143.5015 + #include <xorg-server.h>
143.5016 + #include <servermd.h>
143.5017 + #include <gcstruct.h>
143.5018 +diff --git a/src/sna/fb/fbimage.c b/src/sna/fb/fbimage.c
143.5019 +index 5af23890..cc81c85b 100644
143.5020 +--- a/src/sna/fb/fbimage.c
143.5021 ++++ b/src/sna/fb/fbimage.c
143.5022 +@@ -229,13 +229,19 @@ fbGetImage(DrawablePtr drawable,
143.5023 + 		FbBits pm;
143.5024 + 
143.5025 + 		pm = fbReplicatePixel(planeMask, srcBpp);
143.5026 ++
143.5027 + 		dstStride = PixmapBytePad(w, drawable->depth);
143.5028 +-		if (pm != FB_ALLONES)
143.5029 +-			memset(d, 0, dstStride * h);
143.5030 + 		dstStride /= sizeof(FbStip);
143.5031 ++
143.5032 + 		fbBltStip((FbStip *)(src + (y + srcYoff) * srcStride), srcStride,
143.5033 + 			  (x + srcXoff) * srcBpp,
143.5034 +-			  dst, dstStride, 0, w * srcBpp, h, GXcopy, pm, srcBpp);
143.5035 ++			  dst, dstStride, 0, w * srcBpp, h, GXcopy, FB_ALLONES, srcBpp);
143.5036 ++
143.5037 ++		if (pm != FB_ALLONES) {
143.5038 ++			int i = dstStride * h;
143.5039 ++			while (i--)
143.5040 ++				*dst++ &= pm;
143.5041 ++		}
143.5042 + 	} else {
143.5043 + 		dstStride = BitmapBytePad(w) / sizeof(FbStip);
143.5044 + 		fbBltPlane(src + (y + srcYoff) * srcStride,
143.5045 +diff --git a/src/sna/fb/fbpict.h b/src/sna/fb/fbpict.h
143.5046 +index 932032f9..20877777 100644
143.5047 +--- a/src/sna/fb/fbpict.h
143.5048 ++++ b/src/sna/fb/fbpict.h
143.5049 +@@ -24,10 +24,6 @@
143.5050 + #ifndef FBPICT_H
143.5051 + #define FBPICT_H
143.5052 + 
143.5053 +-#ifdef HAVE_CONFIG_H
143.5054 +-#include "config.h"
143.5055 +-#endif
143.5056 +-
143.5057 + #include <xorg-server.h>
143.5058 + #include <picturestr.h>
143.5059 + 
143.5060 +diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
143.5061 +index 1104f462..49ad16a3 100644
143.5062 +--- a/src/sna/gen2_render.c
143.5063 ++++ b/src/sna/gen2_render.c
143.5064 +@@ -35,6 +35,7 @@
143.5065 + #include "sna_reg.h"
143.5066 + #include "sna_render.h"
143.5067 + #include "sna_render_inline.h"
143.5068 ++#include "sna_video.h"
143.5069 + 
143.5070 + #include "gen2_render.h"
143.5071 + 
143.5072 +@@ -48,6 +49,7 @@
143.5073 + 
143.5074 + #define MAX_3D_SIZE 2048
143.5075 + #define MAX_3D_PITCH 8192
143.5076 ++#define MAX_INLINE (1 << 18)
143.5077 + 
143.5078 + #define BATCH(v) batch_emit(sna, v)
143.5079 + #define BATCH_F(v) batch_emit_float(sna, v)
143.5080 +@@ -596,39 +598,43 @@ gen2_get_batch(struct sna *sna, const struct sna_composite_op *op)
143.5081 + 		gen2_emit_invariant(sna);
143.5082 + }
143.5083 + 
143.5084 +-static void gen2_emit_target(struct sna *sna, const struct sna_composite_op *op)
143.5085 ++static void gen2_emit_target(struct sna *sna,
143.5086 ++			     struct kgem_bo *bo,
143.5087 ++			     int width,
143.5088 ++			     int height,
143.5089 ++			     int format)
143.5090 + {
143.5091 +-	assert(!too_large(op->dst.width, op->dst.height));
143.5092 +-	assert(op->dst.bo->pitch >= 8 && op->dst.bo->pitch <= MAX_3D_PITCH);
143.5093 ++	assert(!too_large(width, height));
143.5094 ++	assert(bo->pitch >= 8 && bo->pitch <= MAX_3D_PITCH);
143.5095 + 	assert(sna->render.vertex_offset == 0);
143.5096 + 
143.5097 +-	assert(op->dst.bo->unique_id);
143.5098 +-	if (sna->render_state.gen2.target == op->dst.bo->unique_id) {
143.5099 +-		kgem_bo_mark_dirty(op->dst.bo);
143.5100 ++	assert(bo->unique_id);
143.5101 ++	if (sna->render_state.gen2.target == bo->unique_id) {
143.5102 ++		kgem_bo_mark_dirty(bo);
143.5103 + 		return;
143.5104 + 	}
143.5105 + 
143.5106 + 	BATCH(_3DSTATE_BUF_INFO_CMD);
143.5107 + 	BATCH(BUF_3D_ID_COLOR_BACK |
143.5108 +-	      gen2_buf_tiling(op->dst.bo->tiling) |
143.5109 +-	      BUF_3D_PITCH(op->dst.bo->pitch));
143.5110 ++	      gen2_buf_tiling(bo->tiling) |
143.5111 ++	      BUF_3D_PITCH(bo->pitch));
143.5112 + 	BATCH(kgem_add_reloc(&sna->kgem, sna->kgem.nbatch,
143.5113 +-			     op->dst.bo,
143.5114 ++			     bo,
143.5115 + 			     I915_GEM_DOMAIN_RENDER << 16 |
143.5116 + 			     I915_GEM_DOMAIN_RENDER,
143.5117 + 			     0));
143.5118 + 
143.5119 + 	BATCH(_3DSTATE_DST_BUF_VARS_CMD);
143.5120 +-	BATCH(gen2_get_dst_format(op->dst.format));
143.5121 ++	BATCH(gen2_get_dst_format(format));
143.5122 + 
143.5123 + 	BATCH(_3DSTATE_DRAW_RECT_CMD);
143.5124 + 	BATCH(0);
143.5125 + 	BATCH(0);	/* ymin, xmin */
143.5126 +-	BATCH(DRAW_YMAX(op->dst.height - 1) |
143.5127 +-	      DRAW_XMAX(op->dst.width - 1));
143.5128 ++	BATCH(DRAW_YMAX(height - 1) |
143.5129 ++	      DRAW_XMAX(width - 1));
143.5130 + 	BATCH(0);	/* yorig, xorig */
143.5131 + 
143.5132 +-	sna->render_state.gen2.target = op->dst.bo->unique_id;
143.5133 ++	sna->render_state.gen2.target = bo->unique_id;
143.5134 + }
143.5135 + 
143.5136 + static void gen2_disable_logic_op(struct sna *sna)
143.5137 +@@ -701,7 +707,11 @@ static void gen2_emit_composite_state(struct sna *sna,
143.5138 + 		kgem_clear_dirty(&sna->kgem);
143.5139 + 	}
143.5140 + 
143.5141 +-	gen2_emit_target(sna, op);
143.5142 ++	gen2_emit_target(sna,
143.5143 ++			 op->dst.bo,
143.5144 ++			 op->dst.width,
143.5145 ++			 op->dst.height,
143.5146 ++			 op->dst.format);
143.5147 + 
143.5148 + 	unwind = sna->kgem.nbatch;
143.5149 + 	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
143.5150 +@@ -1190,7 +1200,13 @@ inline static int gen2_get_rectangles(struct sna *sna,
143.5151 + 			sna->render.vertex_offset = sna->kgem.nbatch;
143.5152 + 			BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST);
143.5153 + 		}
143.5154 +-	}
143.5155 ++
143.5156 ++		need = 0;
143.5157 ++	} else
143.5158 ++		need = sna->kgem.nbatch - sna->render.vertex_offset;
143.5159 ++
143.5160 ++	if (rem > MAX_INLINE - need)
143.5161 ++		rem = MAX_INLINE -need;
143.5162 + 
143.5163 + 	if (want > 1 && want * size > rem)
143.5164 + 		want = rem / size;
143.5165 +@@ -1572,12 +1588,12 @@ gen2_composite_picture(struct sna *sna,
143.5166 + 		if (channel->repeat &&
143.5167 + 		    (x >= 0 &&
143.5168 + 		     y >= 0 &&
143.5169 +-		     x + w < pixmap->drawable.width &&
143.5170 +-		     y + h < pixmap->drawable.height)) {
143.5171 ++		     x + w <= pixmap->drawable.width &&
143.5172 ++		     y + h <= pixmap->drawable.height)) {
143.5173 + 			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.5174 + 			if (priv && priv->clear) {
143.5175 + 				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.5176 +-				return gen2_composite_solid_init(sna, channel, priv->clear_color);
143.5177 ++				return gen2_composite_solid_init(sna, channel, solid_color(picture->format, priv->clear_color));
143.5178 + 			}
143.5179 + 		}
143.5180 + 	} else
143.5181 +@@ -1619,7 +1635,9 @@ gen2_composite_set_target(struct sna *sna,
143.5182 + 	} else
143.5183 + 		sna_render_picture_extents(dst, &box);
143.5184 + 
143.5185 +-	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
143.5186 ++	hint = PREFER_GPU | RENDER_GPU;
143.5187 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.5188 ++		hint |= FORCE_GPU;
143.5189 + 	if (!partial) {
143.5190 + 		hint |= IGNORE_DAMAGE;
143.5191 + 		if (w == op->dst.width && h == op->dst.height)
143.5192 +@@ -2423,7 +2441,11 @@ static void gen2_emit_composite_spans_state(struct sna *sna,
143.5193 + 	uint32_t unwind;
143.5194 + 
143.5195 + 	gen2_get_batch(sna, &op->base);
143.5196 +-	gen2_emit_target(sna, &op->base);
143.5197 ++	gen2_emit_target(sna,
143.5198 ++			 op->base.dst.bo,
143.5199 ++			 op->base.dst.width,
143.5200 ++			 op->base.dst.height,
143.5201 ++			 op->base.dst.format);
143.5202 + 
143.5203 + 	unwind = sna->kgem.nbatch;
143.5204 + 	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
143.5205 +@@ -2706,7 +2728,11 @@ static void gen2_emit_fill_composite_state(struct sna *sna,
143.5206 + 	uint32_t ls1;
143.5207 + 
143.5208 + 	gen2_get_batch(sna, op);
143.5209 +-	gen2_emit_target(sna, op);
143.5210 ++	gen2_emit_target(sna,
143.5211 ++			 op->dst.bo,
143.5212 ++			 op->dst.width,
143.5213 ++			 op->dst.height,
143.5214 ++			 op->dst.format);
143.5215 + 
143.5216 + 	ls1 = sna->kgem.nbatch;
143.5217 + 	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
143.5218 +@@ -2868,7 +2894,11 @@ static void gen2_emit_fill_state(struct sna *sna,
143.5219 + 	uint32_t ls1;
143.5220 + 
143.5221 + 	gen2_get_batch(sna, op);
143.5222 +-	gen2_emit_target(sna, op);
143.5223 ++	gen2_emit_target(sna,
143.5224 ++			 op->dst.bo,
143.5225 ++			 op->dst.width,
143.5226 ++			 op->dst.height,
143.5227 ++			 op->dst.format);
143.5228 + 
143.5229 + 	ls1 = sna->kgem.nbatch;
143.5230 + 	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
143.5231 +@@ -3102,6 +3132,276 @@ gen2_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
143.5232 + }
143.5233 + 
143.5234 + static void
143.5235 ++gen2_emit_video_state(struct sna *sna,
143.5236 ++		      struct sna_video *video,
143.5237 ++		      struct sna_video_frame *frame,
143.5238 ++		      PixmapPtr pixmap,
143.5239 ++		      struct kgem_bo *dst_bo,
143.5240 ++		      int width, int height,
143.5241 ++		      bool bilinear)
143.5242 ++{
143.5243 ++	uint32_t ms1, v, unwind;
143.5244 ++
143.5245 ++	gen2_emit_target(sna, dst_bo, width, height,
143.5246 ++			 sna_format_for_depth(pixmap->drawable.depth));
143.5247 ++
143.5248 ++	unwind = sna->kgem.nbatch;
143.5249 ++	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
143.5250 ++	      I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
143.5251 ++	BATCH(1 << 12);
143.5252 ++	BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
143.5253 ++	BATCH(S8_ENABLE_COLOR_BUFFER_WRITE);
143.5254 ++	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1,
143.5255 ++		   sna->kgem.batch + unwind + 1,
143.5256 ++		   3 * sizeof(uint32_t)) == 0)
143.5257 ++		sna->kgem.nbatch = unwind;
143.5258 ++	else
143.5259 ++		sna->render_state.gen2.ls1 = unwind;
143.5260 ++
143.5261 ++	gen2_disable_logic_op(sna);
143.5262 ++
143.5263 ++	unwind = sna->kgem.nbatch;
143.5264 ++	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
143.5265 ++	      LOAD_TEXTURE_BLEND_STAGE(0) | 1);
143.5266 ++	BATCH(TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OUTPUT_WRITE_CURRENT |
143.5267 ++	      TB0C_OP_ARG1 | TB0C_ARG1_SEL_TEXEL0);
143.5268 ++	BATCH(TB0A_RESULT_SCALE_1X | TB0A_OUTPUT_WRITE_CURRENT |
143.5269 ++	      TB0A_OP_ARG1 | TB0A_ARG1_SEL_ONE);
143.5270 ++	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
143.5271 ++		   sna->kgem.batch + unwind + 1,
143.5272 ++		   2 * sizeof(uint32_t)) == 0)
143.5273 ++		sna->kgem.nbatch = unwind;
143.5274 ++	else
143.5275 ++		sna->render_state.gen2.ls2 = unwind;
143.5276 ++
143.5277 ++	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(0) | 4);
143.5278 ++	BATCH(kgem_add_reloc(&sna->kgem, sna->kgem.nbatch,
143.5279 ++			     frame->bo,
143.5280 ++			     I915_GEM_DOMAIN_SAMPLER << 16,
143.5281 ++			     0));
143.5282 ++	ms1 = MAPSURF_422 | TM0S1_COLORSPACE_CONVERSION;
143.5283 ++	switch (frame->id) {
143.5284 ++	case FOURCC_YUY2:
143.5285 ++		ms1 |= MT_422_YCRCB_NORMAL;
143.5286 ++		break;
143.5287 ++	case FOURCC_UYVY:
143.5288 ++		ms1 |= MT_422_YCRCB_SWAPY;
143.5289 ++		break;
143.5290 ++	}
143.5291 ++	BATCH(((frame->height - 1) << TM0S1_HEIGHT_SHIFT) |
143.5292 ++	      ((frame->width - 1)  << TM0S1_WIDTH_SHIFT) |
143.5293 ++	      ms1 |
143.5294 ++	      gen2_sampler_tiling_bits(frame->bo->tiling));
143.5295 ++	BATCH((frame->pitch[0] / 4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D);
143.5296 ++	if (bilinear)
143.5297 ++		BATCH(FILTER_LINEAR << TM0S3_MAG_FILTER_SHIFT |
143.5298 ++		      FILTER_LINEAR << TM0S3_MIN_FILTER_SHIFT |
143.5299 ++		      MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT);
143.5300 ++	else
143.5301 ++		BATCH(FILTER_NEAREST << TM0S3_MAG_FILTER_SHIFT |
143.5302 ++		      FILTER_NEAREST << TM0S3_MIN_FILTER_SHIFT |
143.5303 ++		      MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT);
143.5304 ++	BATCH(0);	/* default color */
143.5305 ++
143.5306 ++	BATCH(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(0) |
143.5307 ++	      ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL | TEXCOORDTYPE_CARTESIAN |
143.5308 ++	      ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP) |
143.5309 ++	      ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP));
143.5310 ++
143.5311 ++	v = _3DSTATE_VERTEX_FORMAT_2_CMD | TEXCOORDFMT_2D;
143.5312 ++	if (sna->render_state.gen2.vft != v) {
143.5313 ++		BATCH(v);
143.5314 ++		sna->render_state.gen2.vft = v;
143.5315 ++	}
143.5316 ++}
143.5317 ++
143.5318 ++static void
143.5319 ++gen2_video_get_batch(struct sna *sna, struct kgem_bo *bo)
143.5320 ++{
143.5321 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, bo);
143.5322 ++
143.5323 ++	if (!kgem_check_batch(&sna->kgem, 120) ||
143.5324 ++	    !kgem_check_reloc(&sna->kgem, 4) ||
143.5325 ++	    !kgem_check_exec(&sna->kgem, 2)) {
143.5326 ++		_kgem_submit(&sna->kgem);
143.5327 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.5328 ++	}
143.5329 ++
143.5330 ++	if (sna->render_state.gen2.need_invariant)
143.5331 ++		gen2_emit_invariant(sna);
143.5332 ++}
143.5333 ++
143.5334 ++static int
143.5335 ++gen2_get_inline_rectangles(struct sna *sna, int want, int floats_per_vertex)
143.5336 ++{
143.5337 ++	int size = floats_per_vertex * 3;
143.5338 ++	int rem = batch_space(sna) - 1;
143.5339 ++
143.5340 ++	if (rem > MAX_INLINE)
143.5341 ++		rem = MAX_INLINE;
143.5342 ++
143.5343 ++	if (size * want > rem)
143.5344 ++		want = rem / size;
143.5345 ++
143.5346 ++	return want;
143.5347 ++}
143.5348 ++
143.5349 ++static bool
143.5350 ++gen2_render_video(struct sna *sna,
143.5351 ++		  struct sna_video *video,
143.5352 ++		  struct sna_video_frame *frame,
143.5353 ++		  RegionPtr dstRegion,
143.5354 ++		  PixmapPtr pixmap)
143.5355 ++{
143.5356 ++	struct sna_pixmap *priv = sna_pixmap(pixmap);
143.5357 ++	const BoxRec *pbox = region_rects(dstRegion);
143.5358 ++	int nbox = region_num_rects(dstRegion);
143.5359 ++	int dst_width = dstRegion->extents.x2 - dstRegion->extents.x1;
143.5360 ++	int dst_height = dstRegion->extents.y2 - dstRegion->extents.y1;
143.5361 ++	int src_width = frame->src.x2 - frame->src.x1;
143.5362 ++	int src_height = frame->src.y2 - frame->src.y1;
143.5363 ++	float src_offset_x, src_offset_y;
143.5364 ++	float src_scale_x, src_scale_y;
143.5365 ++	int pix_xoff, pix_yoff;
143.5366 ++	struct kgem_bo *dst_bo;
143.5367 ++	bool bilinear;
143.5368 ++	int copy = 0;
143.5369 ++
143.5370 ++	DBG(("%s: src:%dx%d (frame:%dx%d) -> dst:%dx%d\n", __FUNCTION__,
143.5371 ++	     src_width, src_height, frame->width, frame->height, dst_width, dst_height));
143.5372 ++
143.5373 ++	assert(priv->gpu_bo);
143.5374 ++	dst_bo = priv->gpu_bo;
143.5375 ++
143.5376 ++	bilinear = src_width != dst_width || src_height != dst_height;
143.5377 ++
143.5378 ++	src_scale_x = (float)src_width / dst_width / frame->width;
143.5379 ++	src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
143.5380 ++
143.5381 ++	src_scale_y = (float)src_height / dst_height / frame->height;
143.5382 ++	src_offset_y = (float)frame->src.y1 / frame->height - dstRegion->extents.y1 * src_scale_y;
143.5383 ++	DBG(("%s: src offset (%f, %f), scale (%f, %f)\n",
143.5384 ++	     __FUNCTION__, src_offset_x, src_offset_y, src_scale_x, src_scale_y));
143.5385 ++
143.5386 ++	if (too_large(pixmap->drawable.width, pixmap->drawable.height) ||
143.5387 ++	    dst_bo->pitch > MAX_3D_PITCH) {
143.5388 ++		int bpp = pixmap->drawable.bitsPerPixel;
143.5389 ++
143.5390 ++		if (too_large(dst_width, dst_height))
143.5391 ++			return false;
143.5392 ++
143.5393 ++		dst_bo = kgem_create_2d(&sna->kgem,
143.5394 ++					dst_width, dst_height, bpp,
143.5395 ++					kgem_choose_tiling(&sna->kgem,
143.5396 ++							   I915_TILING_X,
143.5397 ++							   dst_width, dst_height, bpp),
143.5398 ++					0);
143.5399 ++		if (!dst_bo)
143.5400 ++			return false;
143.5401 ++
143.5402 ++		pix_xoff = -dstRegion->extents.x1;
143.5403 ++		pix_yoff = -dstRegion->extents.y1;
143.5404 ++		copy = 1;
143.5405 ++	} else {
143.5406 ++		/* Set up the offset for translating from the given region
143.5407 ++		 * (in screen coordinates) to the backing pixmap.
143.5408 ++		 */
143.5409 ++#ifdef COMPOSITE
143.5410 ++		pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.5411 ++		pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.5412 ++#else
143.5413 ++		pix_xoff = 0;
143.5414 ++		pix_yoff = 0;
143.5415 ++#endif
143.5416 ++
143.5417 ++		dst_width  = pixmap->drawable.width;
143.5418 ++		dst_height = pixmap->drawable.height;
143.5419 ++	}
143.5420 ++
143.5421 ++	gen2_video_get_batch(sna, dst_bo);
143.5422 ++	gen2_emit_video_state(sna, video, frame, pixmap,
143.5423 ++			      dst_bo, dst_width, dst_height, bilinear);
143.5424 ++	do {
143.5425 ++		int nbox_this_time = gen2_get_inline_rectangles(sna, nbox, 4);
143.5426 ++		if (nbox_this_time == 0) {
143.5427 ++			gen2_video_get_batch(sna, dst_bo);
143.5428 ++			gen2_emit_video_state(sna, video, frame, pixmap,
143.5429 ++					      dst_bo, dst_width, dst_height, bilinear);
143.5430 ++			nbox_this_time = gen2_get_inline_rectangles(sna, nbox, 4);
143.5431 ++			assert(nbox_this_time);
143.5432 ++		}
143.5433 ++		nbox -= nbox_this_time;
143.5434 ++
143.5435 ++		BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST |
143.5436 ++		      ((12 * nbox_this_time) - 1));
143.5437 ++		do {
143.5438 ++			int box_x1 = pbox->x1;
143.5439 ++			int box_y1 = pbox->y1;
143.5440 ++			int box_x2 = pbox->x2;
143.5441 ++			int box_y2 = pbox->y2;
143.5442 ++
143.5443 ++			pbox++;
143.5444 ++
143.5445 ++			DBG(("%s: dst (%d, %d), (%d, %d) + (%d, %d); src (%f, %f), (%f, %f)\n",
143.5446 ++			     __FUNCTION__, box_x1, box_y1, box_x2, box_y2, pix_xoff, pix_yoff,
143.5447 ++			     box_x1 * src_scale_x + src_offset_x,
143.5448 ++			     box_y1 * src_scale_y + src_offset_y,
143.5449 ++			     box_x2 * src_scale_x + src_offset_x,
143.5450 ++			     box_y2 * src_scale_y + src_offset_y));
143.5451 ++
143.5452 ++			/* bottom right */
143.5453 ++			BATCH_F(box_x2 + pix_xoff);
143.5454 ++			BATCH_F(box_y2 + pix_yoff);
143.5455 ++			BATCH_F(box_x2 * src_scale_x + src_offset_x);
143.5456 ++			BATCH_F(box_y2 * src_scale_y + src_offset_y);
143.5457 ++
143.5458 ++			/* bottom left */
143.5459 ++			BATCH_F(box_x1 + pix_xoff);
143.5460 ++			BATCH_F(box_y2 + pix_yoff);
143.5461 ++			BATCH_F(box_x1 * src_scale_x + src_offset_x);
143.5462 ++			BATCH_F(box_y2 * src_scale_y + src_offset_y);
143.5463 ++
143.5464 ++			/* top left */
143.5465 ++			BATCH_F(box_x1 + pix_xoff);
143.5466 ++			BATCH_F(box_y1 + pix_yoff);
143.5467 ++			BATCH_F(box_x1 * src_scale_x + src_offset_x);
143.5468 ++			BATCH_F(box_y1 * src_scale_y + src_offset_y);
143.5469 ++		} while (--nbox_this_time);
143.5470 ++	} while (nbox);
143.5471 ++
143.5472 ++	if (copy) {
143.5473 ++#ifdef COMPOSITE
143.5474 ++		pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.5475 ++		pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.5476 ++#else
143.5477 ++		pix_xoff = 0;
143.5478 ++		pix_yoff = 0;
143.5479 ++#endif
143.5480 ++		sna_blt_copy_boxes(sna, GXcopy,
143.5481 ++				   dst_bo, -dstRegion->extents.x1, -dstRegion->extents.y1,
143.5482 ++				   priv->gpu_bo, pix_xoff, pix_yoff,
143.5483 ++				   pixmap->drawable.bitsPerPixel,
143.5484 ++				   region_rects(dstRegion),
143.5485 ++				   region_num_rects(dstRegion));
143.5486 ++
143.5487 ++		kgem_bo_destroy(&sna->kgem, dst_bo);
143.5488 ++	}
143.5489 ++
143.5490 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
143.5491 ++		if ((pix_xoff | pix_yoff) == 0) {
143.5492 ++			sna_damage_add(&priv->gpu_damage, dstRegion);
143.5493 ++		} else {
143.5494 ++			sna_damage_add_boxes(&priv->gpu_damage,
143.5495 ++					     region_rects(dstRegion),
143.5496 ++					     region_num_rects(dstRegion),
143.5497 ++					     pix_xoff, pix_yoff);
143.5498 ++		}
143.5499 ++	}
143.5500 ++
143.5501 ++	return true;
143.5502 ++}
143.5503 ++
143.5504 ++static void
143.5505 + gen2_render_copy_setup_source(struct sna_composite_channel *channel,
143.5506 + 			      const DrawableRec *draw,
143.5507 + 			      struct kgem_bo *bo)
143.5508 +@@ -3176,7 +3476,11 @@ static void gen2_emit_copy_state(struct sna *sna, const struct sna_composite_op
143.5509 + 			      PIPELINE_FLUSH_TEXTURE_CACHE);
143.5510 + 		kgem_clear_dirty(&sna->kgem);
143.5511 + 	}
143.5512 +-	gen2_emit_target(sna, op);
143.5513 ++	gen2_emit_target(sna,
143.5514 ++			 op->dst.bo,
143.5515 ++			 op->dst.width,
143.5516 ++			 op->dst.height,
143.5517 ++			 op->dst.format);
143.5518 + 
143.5519 + 	ls1 = sna->kgem.nbatch;
143.5520 + 	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
143.5521 +@@ -3511,7 +3815,7 @@ const char *gen2_render_init(struct sna *sna, const char *backend)
143.5522 + 	render->copy = gen2_render_copy;
143.5523 + 	render->copy_boxes = gen2_render_copy_boxes;
143.5524 + 
143.5525 +-	/* XXX YUV color space conversion for video? */
143.5526 ++	render->video = gen2_render_video;
143.5527 + 
143.5528 + 	render->reset = gen2_render_reset;
143.5529 + 	render->flush = gen2_render_flush;
143.5530 +diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
143.5531 +index 78289f00..4459a562 100644
143.5532 +--- a/src/sna/gen3_render.c
143.5533 ++++ b/src/sna/gen3_render.c
143.5534 +@@ -448,14 +448,14 @@ gen3_emit_composite_boxes_constant(const struct sna_composite_op *op,
143.5535 + 				   float *v)
143.5536 + {
143.5537 + 	do {
143.5538 +-		v[0] = box->x2;
143.5539 +-		v[1] = box->y2;
143.5540 ++		v[0] = box->x2 + op->dst.x;
143.5541 ++		v[1] = box->y2 + op->dst.y;
143.5542 + 
143.5543 +-		v[2] = box->x1;
143.5544 +-		v[3] = box->y2;
143.5545 ++		v[2] = box->x1 + op->dst.x;
143.5546 ++		v[3] = box->y2 + op->dst.y;
143.5547 + 
143.5548 +-		v[4] = box->x1;
143.5549 +-		v[5] = box->y1;
143.5550 ++		v[4] = box->x1 + op->dst.x;
143.5551 ++		v[5] = box->y1 + op->dst.y;
143.5552 + 
143.5553 + 		box++;
143.5554 + 		v += 6;
143.5555 +@@ -494,18 +494,18 @@ gen3_emit_composite_boxes_identity_gradient(const struct sna_composite_op *op,
143.5556 + 					    float *v)
143.5557 + {
143.5558 + 	do {
143.5559 +-		v[0] = box->x2;
143.5560 +-		v[1] = box->y2;
143.5561 ++		v[0] = box->x2 + op->dst.x;
143.5562 ++		v[1] = box->y2 + op->dst.y;
143.5563 + 		v[2] = box->x2 + op->src.offset[0];
143.5564 + 		v[3] = box->y2 + op->src.offset[1];
143.5565 + 
143.5566 +-		v[4] = box->x1;
143.5567 +-		v[5] = box->y2;
143.5568 ++		v[4] = box->x1 + op->dst.x;
143.5569 ++		v[5] = box->y2 + op->dst.y;
143.5570 + 		v[6] = box->x1 + op->src.offset[0];
143.5571 + 		v[7] = box->y2 + op->src.offset[1];
143.5572 + 
143.5573 +-		v[8] = box->x1;
143.5574 +-		v[9] = box->y1;
143.5575 ++		v[8] = box->x1 + op->dst.x;
143.5576 ++		v[9] = box->y1 + op->dst.y;
143.5577 + 		v[10] = box->x1 + op->src.offset[0];
143.5578 + 		v[11] = box->y1 + op->src.offset[1];
143.5579 + 
143.5580 +@@ -531,6 +531,7 @@ gen3_emit_composite_primitive_affine_gradient(struct sna *sna,
143.5581 + 
143.5582 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5583 + 	sna->render.vertex_used += 12;
143.5584 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5585 + 
143.5586 + 	v[0] = dst_x + r->width;
143.5587 + 	v[1] = dst_y + r->height;
143.5588 +@@ -559,22 +560,22 @@ gen3_emit_composite_boxes_affine_gradient(const struct sna_composite_op *op,
143.5589 + 	const PictTransform *transform = op->src.transform;
143.5590 + 
143.5591 + 	do {
143.5592 +-		v[0] = box->x2;
143.5593 +-		v[1] = box->y2;
143.5594 ++		v[0] = box->x2 + op->dst.x;
143.5595 ++		v[1] = box->y2 + op->dst.y;
143.5596 + 		_sna_get_transformed_scaled(box->x2 + op->src.offset[0],
143.5597 + 					    box->y2 + op->src.offset[1],
143.5598 + 					    transform, op->src.scale,
143.5599 + 					    &v[2], &v[3]);
143.5600 + 
143.5601 +-		v[4] = box->x1;
143.5602 +-		v[5] = box->y2;
143.5603 ++		v[4] = box->x1 + op->dst.x;
143.5604 ++		v[5] = box->y2 + op->dst.y;
143.5605 + 		_sna_get_transformed_scaled(box->x1 + op->src.offset[0],
143.5606 + 					    box->y2 + op->src.offset[1],
143.5607 + 					    transform, op->src.scale,
143.5608 + 					    &v[6], &v[7]);
143.5609 + 
143.5610 +-		v[8] = box->x1;
143.5611 +-		v[9] = box->y1;
143.5612 ++		v[8] = box->x1 + op->dst.x;
143.5613 ++		v[9] = box->y1 + op->dst.y;
143.5614 + 		_sna_get_transformed_scaled(box->x1 + op->src.offset[0],
143.5615 + 					    box->y1 + op->src.offset[1],
143.5616 + 					    transform, op->src.scale,
143.5617 +@@ -596,6 +597,7 @@ gen3_emit_composite_primitive_identity_source(struct sna *sna,
143.5618 + 
143.5619 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5620 + 	sna->render.vertex_used += 12;
143.5621 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5622 + 
143.5623 + 	v[8] = v[4] = r->dst.x + op->dst.x;
143.5624 + 	v[0] = v[4] + w;
143.5625 +@@ -643,6 +645,7 @@ gen3_emit_composite_primitive_identity_source_no_offset(struct sna *sna,
143.5626 + 
143.5627 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5628 + 	sna->render.vertex_used += 12;
143.5629 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5630 + 
143.5631 + 	v[8] = v[4] = r->dst.x;
143.5632 + 	v[9] = r->dst.y;
143.5633 +@@ -693,6 +696,7 @@ gen3_emit_composite_primitive_affine_source(struct sna *sna,
143.5634 + 
143.5635 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5636 + 	sna->render.vertex_used += 12;
143.5637 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5638 + 
143.5639 + 	v[0] = dst_x + r->width;
143.5640 + 	v[5] = v[1] = dst_y + r->height;
143.5641 +@@ -720,10 +724,10 @@ gen3_emit_composite_boxes_affine_source(const struct sna_composite_op *op,
143.5642 + 	const PictTransform *transform = op->src.transform;
143.5643 + 
143.5644 + 	do {
143.5645 +-		v[0] = box->x2;
143.5646 +-		v[5] = v[1] = box->y2;
143.5647 +-		v[8] = v[4] = box->x1;
143.5648 +-		v[9] = box->y1;
143.5649 ++		v[0] = box->x2 + op->dst.x;
143.5650 ++		v[5] = v[1] = box->y2 + op->dst.y;
143.5651 ++		v[8] = v[4] = box->x1 + op->dst.x;
143.5652 ++		v[9] = box->y1 + op->dst.y;
143.5653 + 
143.5654 + 		_sna_get_transformed_scaled(box->x2 + op->src.offset[0],
143.5655 + 					    box->y2 + op->src.offset[1],
143.5656 +@@ -756,6 +760,7 @@ gen3_emit_composite_primitive_constant_identity_mask(struct sna *sna,
143.5657 + 
143.5658 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5659 + 	sna->render.vertex_used += 12;
143.5660 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5661 + 
143.5662 + 	v[8] = v[4] = r->dst.x + op->dst.x;
143.5663 + 	v[0] = v[4] + w;
143.5664 +@@ -781,6 +786,7 @@ gen3_emit_composite_primitive_constant_identity_mask_no_offset(struct sna *sna,
143.5665 + 
143.5666 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5667 + 	sna->render.vertex_used += 12;
143.5668 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5669 + 
143.5670 + 	v[8] = v[4] = r->dst.x;
143.5671 + 	v[9] = r->dst.y;
143.5672 +@@ -817,6 +823,7 @@ gen3_emit_composite_primitive_identity_source_mask(struct sna *sna,
143.5673 + 
143.5674 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5675 + 	sna->render.vertex_used += 18;
143.5676 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5677 + 
143.5678 + 	v[0] = dst_x + w;
143.5679 + 	v[1] = dst_y + h;
143.5680 +@@ -862,6 +869,7 @@ gen3_emit_composite_primitive_affine_source_mask(struct sna *sna,
143.5681 + 
143.5682 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5683 + 	sna->render.vertex_used += 18;
143.5684 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5685 + 
143.5686 + 	v[0] = dst_x + w;
143.5687 + 	v[1] = dst_y + h;
143.5688 +@@ -978,6 +986,7 @@ gen3_emit_composite_primitive_constant__sse2(struct sna *sna,
143.5689 + 
143.5690 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5691 + 	sna->render.vertex_used += 6;
143.5692 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5693 + 
143.5694 + 	v[4] = v[2] = r->dst.x + op->dst.x;
143.5695 + 	v[5] = r->dst.y + op->dst.y;
143.5696 +@@ -993,10 +1002,10 @@ gen3_emit_composite_boxes_constant__sse2(const struct sna_composite_op *op,
143.5697 + 					 float *v)
143.5698 + {
143.5699 + 	do {
143.5700 +-		v[0] = box->x2;
143.5701 +-		v[3] = v[1] = box->y2;
143.5702 +-		v[4] = v[2] = box->x1;
143.5703 +-		v[5] = box->y1;
143.5704 ++		v[0] = box->x2 + op->dst.x;
143.5705 ++		v[3] = v[1] = box->y2 + op->dst.y;
143.5706 ++		v[4] = v[2] = box->x1 + op->dst.x;
143.5707 ++		v[5] = box->y1 + op->dst.y;
143.5708 + 
143.5709 + 		box++;
143.5710 + 		v += 6;
143.5711 +@@ -1013,6 +1022,7 @@ gen3_emit_composite_primitive_identity_gradient__sse2(struct sna *sna,
143.5712 + 
143.5713 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5714 + 	sna->render.vertex_used += 12;
143.5715 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5716 + 
143.5717 + 	x = r->dst.x + op->dst.x;
143.5718 + 	y = r->dst.y + op->dst.y;
143.5719 +@@ -1035,10 +1045,10 @@ gen3_emit_composite_boxes_identity_gradient__sse2(const struct sna_composite_op
143.5720 + 						  float *v)
143.5721 + {
143.5722 + 	do {
143.5723 +-		v[0] = box->x2;
143.5724 +-		v[5] = v[1] = box->y2;
143.5725 +-		v[8] = v[4] = box->x1;
143.5726 +-		v[9] = box->y1;
143.5727 ++		v[0] = box->x2 + op->dst.x;
143.5728 ++		v[5] = v[1] = box->y2 + op->dst.y;
143.5729 ++		v[8] = v[4] = box->x1 + op->dst.x;
143.5730 ++		v[9] = box->y1 + op->dst.y;
143.5731 + 
143.5732 + 		v[2] = box->x2 + op->src.offset[0];
143.5733 + 		v[7] = v[3] = box->y2 + op->src.offset[1];
143.5734 +@@ -1067,6 +1077,7 @@ gen3_emit_composite_primitive_affine_gradient__sse2(struct sna *sna,
143.5735 + 
143.5736 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5737 + 	sna->render.vertex_used += 12;
143.5738 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5739 + 
143.5740 + 	v[0] = dst_x + r->width;
143.5741 + 	v[1] = dst_y + r->height;
143.5742 +@@ -1095,22 +1106,22 @@ gen3_emit_composite_boxes_affine_gradient__sse2(const struct sna_composite_op *o
143.5743 + 	const PictTransform *transform = op->src.transform;
143.5744 + 
143.5745 + 	do {
143.5746 +-		v[0] = box->x2;
143.5747 +-		v[1] = box->y2;
143.5748 ++		v[0] = box->x2 + op->dst.x;
143.5749 ++		v[1] = box->y2 + op->dst.y;
143.5750 + 		_sna_get_transformed_scaled(box->x2 + op->src.offset[0],
143.5751 + 					    box->y2 + op->src.offset[1],
143.5752 + 					    transform, op->src.scale,
143.5753 + 					    &v[2], &v[3]);
143.5754 + 
143.5755 +-		v[4] = box->x1;
143.5756 +-		v[5] = box->y2;
143.5757 ++		v[4] = box->x1 + op->dst.x;
143.5758 ++		v[5] = box->y2 + op->dst.y;
143.5759 + 		_sna_get_transformed_scaled(box->x1 + op->src.offset[0],
143.5760 + 					    box->y2 + op->src.offset[1],
143.5761 + 					    transform, op->src.scale,
143.5762 + 					    &v[6], &v[7]);
143.5763 + 
143.5764 +-		v[8] = box->x1;
143.5765 +-		v[9] = box->y1;
143.5766 ++		v[8] = box->x1 + op->dst.x;
143.5767 ++		v[9] = box->y1 + op->dst.y;
143.5768 + 		_sna_get_transformed_scaled(box->x1 + op->src.offset[0],
143.5769 + 					    box->y1 + op->src.offset[1],
143.5770 + 					    transform, op->src.scale,
143.5771 +@@ -1132,6 +1143,7 @@ gen3_emit_composite_primitive_identity_source__sse2(struct sna *sna,
143.5772 + 
143.5773 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5774 + 	sna->render.vertex_used += 12;
143.5775 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5776 + 
143.5777 + 	v[8] = v[4] = r->dst.x + op->dst.x;
143.5778 + 	v[0] = v[4] + w;
143.5779 +@@ -1179,6 +1191,7 @@ gen3_emit_composite_primitive_identity_source_no_offset__sse2(struct sna *sna,
143.5780 + 
143.5781 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5782 + 	sna->render.vertex_used += 12;
143.5783 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5784 + 
143.5785 + 	v[8] = v[4] = r->dst.x;
143.5786 + 	v[9] = r->dst.y;
143.5787 +@@ -1227,8 +1240,12 @@ gen3_emit_composite_primitive_affine_source__sse2(struct sna *sna,
143.5788 + 	int src_y = r->src.y + (int)op->src.offset[1];
143.5789 + 	float *v;
143.5790 + 
143.5791 ++	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n",
143.5792 ++	     __FUNCTION__, src_x, src_y, dst_x, dst_y, r->width, r->height));
143.5793 ++
143.5794 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5795 + 	sna->render.vertex_used += 12;
143.5796 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5797 + 
143.5798 + 	v[0] = dst_x + r->width;
143.5799 + 	v[5] = v[1] = dst_y + r->height;
143.5800 +@@ -1256,10 +1273,13 @@ gen3_emit_composite_boxes_affine_source__sse2(const struct sna_composite_op *op,
143.5801 + 	const PictTransform *transform = op->src.transform;
143.5802 + 
143.5803 + 	do {
143.5804 +-		v[0] = box->x2;
143.5805 +-		v[5] = v[1] = box->y2;
143.5806 +-		v[8] = v[4] = box->x1;
143.5807 +-		v[9] = box->y1;
143.5808 ++		DBG(("%s: box=(%d, %d), (%d, %d), src.offset=(%d, %d)\n",
143.5809 ++		     __FUNCTION__, box->x1, box->y1, box->x2, box->y2, op->src.offset[0], op->src.offset[1]));
143.5810 ++
143.5811 ++		v[0] = box->x2 + op->dst.x;
143.5812 ++		v[5] = v[1] = box->y2 + op->dst.y;
143.5813 ++		v[8] = v[4] = box->x1 + op->dst.x;
143.5814 ++		v[9] = box->y1 + op->dst.y;
143.5815 + 
143.5816 + 		_sna_get_transformed_scaled(box->x2 + op->src.offset[0],
143.5817 + 					    box->y2 + op->src.offset[1],
143.5818 +@@ -1292,6 +1312,7 @@ gen3_emit_composite_primitive_constant_identity_mask__sse2(struct sna *sna,
143.5819 + 
143.5820 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5821 + 	sna->render.vertex_used += 12;
143.5822 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5823 + 
143.5824 + 	v[8] = v[4] = r->dst.x + op->dst.x;
143.5825 + 	v[0] = v[4] + w;
143.5826 +@@ -1317,6 +1338,7 @@ gen3_emit_composite_primitive_constant_identity_mask_no_offset__sse2(struct sna
143.5827 + 
143.5828 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5829 + 	sna->render.vertex_used += 12;
143.5830 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5831 + 
143.5832 + 	v[8] = v[4] = r->dst.x;
143.5833 + 	v[9] = r->dst.y;
143.5834 +@@ -1353,6 +1375,7 @@ gen3_emit_composite_primitive_identity_source_mask__sse2(struct sna *sna,
143.5835 + 
143.5836 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5837 + 	sna->render.vertex_used += 18;
143.5838 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5839 + 
143.5840 + 	v[0] = dst_x + w;
143.5841 + 	v[1] = dst_y + h;
143.5842 +@@ -1398,6 +1421,7 @@ gen3_emit_composite_primitive_affine_source_mask__sse2(struct sna *sna,
143.5843 + 
143.5844 + 	v = sna->render.vertices + sna->render.vertex_used;
143.5845 + 	sna->render.vertex_used += 18;
143.5846 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5847 + 
143.5848 + 	v[0] = dst_x + w;
143.5849 + 	v[1] = dst_y + h;
143.5850 +@@ -2233,6 +2257,7 @@ static void gen3_vertex_flush(struct sna *sna)
143.5851 + static int gen3_vertex_finish(struct sna *sna)
143.5852 + {
143.5853 + 	struct kgem_bo *bo;
143.5854 ++	unsigned hint, size;
143.5855 + 
143.5856 + 	DBG(("%s: used=%d/%d, vbo active? %d\n",
143.5857 + 	     __FUNCTION__, sna->render.vertex_used, sna->render.vertex_size,
143.5858 +@@ -2243,6 +2268,7 @@ static int gen3_vertex_finish(struct sna *sna)
143.5859 + 
143.5860 + 	sna_vertex_wait__locked(&sna->render);
143.5861 + 
143.5862 ++	hint = CREATE_GTT_MAP;
143.5863 + 	bo = sna->render.vbo;
143.5864 + 	if (bo) {
143.5865 + 		DBG(("%s: reloc = %d\n", __FUNCTION__,
143.5866 +@@ -2251,7 +2277,7 @@ static int gen3_vertex_finish(struct sna *sna)
143.5867 + 		if (sna->render.vertex_reloc[0]) {
143.5868 + 			sna->kgem.batch[sna->render.vertex_reloc[0]] =
143.5869 + 				kgem_add_reloc(&sna->kgem, sna->render.vertex_reloc[0],
143.5870 +-					       bo, I915_GEM_DOMAIN_VERTEX << 16, 0);
143.5871 ++					       bo, I915_GEM_DOMAIN_VERTEX << 16 | KGEM_RELOC_FENCED, 0);
143.5872 + 
143.5873 + 			sna->render.vertex_reloc[0] = 0;
143.5874 + 		}
143.5875 +@@ -2260,17 +2286,29 @@ static int gen3_vertex_finish(struct sna *sna)
143.5876 + 		sna->render.vbo = NULL;
143.5877 + 
143.5878 + 		kgem_bo_destroy(&sna->kgem, bo);
143.5879 ++		hint |= CREATE_CACHED | CREATE_NO_THROTTLE;
143.5880 + 	}
143.5881 + 
143.5882 ++	size = 256*1024;
143.5883 + 	sna->render.vertices = NULL;
143.5884 +-	sna->render.vbo = kgem_create_linear(&sna->kgem,
143.5885 +-					     256*1024, CREATE_GTT_MAP);
143.5886 +-	if (sna->render.vbo)
143.5887 ++	sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
143.5888 ++	while (sna->render.vbo == NULL && size > sizeof(sna->render.vertex_data)) {
143.5889 ++		size /= 2;
143.5890 ++		sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
143.5891 ++	}
143.5892 ++	if (sna->render.vbo == NULL)
143.5893 ++		sna->render.vbo = kgem_create_linear(&sna->kgem,
143.5894 ++						     256*1024, CREATE_GTT_MAP);
143.5895 ++	if (sna->render.vbo &&
143.5896 ++	    kgem_check_bo(&sna->kgem, sna->render.vbo, NULL))
143.5897 + 		sna->render.vertices = kgem_bo_map(&sna->kgem, sna->render.vbo);
143.5898 + 	if (sna->render.vertices == NULL) {
143.5899 +-		if (sna->render.vbo)
143.5900 ++		if (sna->render.vbo) {
143.5901 + 			kgem_bo_destroy(&sna->kgem, sna->render.vbo);
143.5902 +-		sna->render.vbo = NULL;
143.5903 ++			sna->render.vbo = NULL;
143.5904 ++		}
143.5905 ++		sna->render.vertices = sna->render.vertex_data;
143.5906 ++		sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
143.5907 + 		return 0;
143.5908 + 	}
143.5909 + 	assert(sna->render.vbo->snoop == false);
143.5910 +@@ -2280,8 +2318,14 @@ static int gen3_vertex_finish(struct sna *sna)
143.5911 + 		       sna->render.vertex_data,
143.5912 + 		       sizeof(float)*sna->render.vertex_used);
143.5913 + 	}
143.5914 +-	sna->render.vertex_size = 64 * 1024 - 1;
143.5915 +-	return sna->render.vertex_size - sna->render.vertex_used;
143.5916 ++
143.5917 ++	size = __kgem_bo_size(sna->render.vbo)/4;
143.5918 ++	if (size >= UINT16_MAX)
143.5919 ++		size = UINT16_MAX - 1;
143.5920 ++	assert(size > sna->render.vertex_used);
143.5921 ++
143.5922 ++	sna->render.vertex_size = size;
143.5923 ++	return size - sna->render.vertex_used;
143.5924 + }
143.5925 + 
143.5926 + static void gen3_vertex_close(struct sna *sna)
143.5927 +@@ -2345,7 +2389,7 @@ static void gen3_vertex_close(struct sna *sna)
143.5928 + 	DBG(("%s: reloc = %d\n", __FUNCTION__, sna->render.vertex_reloc[0]));
143.5929 + 	sna->kgem.batch[sna->render.vertex_reloc[0]] =
143.5930 + 		kgem_add_reloc(&sna->kgem, sna->render.vertex_reloc[0],
143.5931 +-			       bo, I915_GEM_DOMAIN_VERTEX << 16, delta);
143.5932 ++			       bo, I915_GEM_DOMAIN_VERTEX << 16 | KGEM_RELOC_FENCED, delta);
143.5933 + 	sna->render.vertex_reloc[0] = 0;
143.5934 + 
143.5935 + 	if (sna->render.vbo == NULL) {
143.5936 +@@ -2580,6 +2624,7 @@ gen3_render_composite_boxes(struct sna *sna,
143.5937 + 
143.5938 + 		v = sna->render.vertices + sna->render.vertex_used;
143.5939 + 		sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
143.5940 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5941 + 
143.5942 + 		op->emit_boxes(op, box, nbox_this_time, v);
143.5943 + 		box += nbox_this_time;
143.5944 +@@ -2604,6 +2649,7 @@ gen3_render_composite_boxes__thread(struct sna *sna,
143.5945 + 
143.5946 + 		v = sna->render.vertices + sna->render.vertex_used;
143.5947 + 		sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
143.5948 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.5949 + 
143.5950 + 		sna_vertex_acquire__locked(&sna->render);
143.5951 + 		sna_vertex_unlock(&sna->render);
143.5952 +@@ -3065,7 +3111,7 @@ gen3_composite_picture(struct sna *sna,
143.5953 + 
143.5954 + 	if (sna_picture_is_clear(picture, x, y, w, h, &color)) {
143.5955 + 		DBG(("%s: clear drawable [%08x]\n", __FUNCTION__, color));
143.5956 +-		return gen3_init_solid(channel, color_convert(color, picture->format, PICT_a8r8g8b8));
143.5957 ++		return gen3_init_solid(channel, solid_color(picture->format, color));
143.5958 + 	}
143.5959 + 
143.5960 + 	if (!gen3_check_repeat(picture))
143.5961 +@@ -3097,12 +3143,12 @@ gen3_composite_picture(struct sna *sna,
143.5962 + 		if (channel->repeat ||
143.5963 + 		    (x >= 0 &&
143.5964 + 		     y >= 0 &&
143.5965 +-		     x + w < pixmap->drawable.width &&
143.5966 +-		     y + h < pixmap->drawable.height)) {
143.5967 ++		     x + w <= pixmap->drawable.width &&
143.5968 ++		     y + h <= pixmap->drawable.height)) {
143.5969 + 			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.5970 + 			if (priv && priv->clear) {
143.5971 + 				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.5972 +-				return gen3_init_solid(channel, priv->clear_color);
143.5973 ++				return gen3_init_solid(channel, solid_color(picture->format, priv->clear_color));
143.5974 + 			}
143.5975 + 		}
143.5976 + 	} else {
143.5977 +@@ -3182,7 +3228,9 @@ gen3_composite_set_target(struct sna *sna,
143.5978 + 	} else
143.5979 + 		sna_render_picture_extents(dst, &box);
143.5980 + 
143.5981 +-	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
143.5982 ++	hint = PREFER_GPU | RENDER_GPU;
143.5983 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.5984 ++		hint |= FORCE_GPU;
143.5985 + 	if (!partial) {
143.5986 + 		hint |= IGNORE_DAMAGE;
143.5987 + 		if (w == op->dst.width && h == op->dst.height)
143.5988 +@@ -3645,8 +3693,11 @@ gen3_render_composite(struct sna *sna,
143.5989 + 			}
143.5990 + 		}
143.5991 + 	}
143.5992 +-	DBG(("%s: final src/mask type=%d/%d, affine=%d/%d\n", __FUNCTION__,
143.5993 ++	DBG(("%s: final src/mask type=%d/%d [constant? %d/%d], transform? %d/%d, affine=%d/%d\n", __FUNCTION__,
143.5994 + 	     tmp->src.u.gen3.type, tmp->mask.u.gen3.type,
143.5995 ++	     is_constant_ps(tmp->src.u.gen3.type),
143.5996 ++	     is_constant_ps(tmp->mask.u.gen3.type),
143.5997 ++	     !!tmp->src.transform, !!tmp->mask.transform,
143.5998 + 	     tmp->src.is_affine, tmp->mask.is_affine));
143.5999 + 
143.6000 + 	tmp->prim_emit = gen3_emit_composite_primitive;
143.6001 +@@ -3862,6 +3913,7 @@ gen3_emit_composite_spans_primitive_zero(struct sna *sna,
143.6002 + {
143.6003 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6004 + 	sna->render.vertex_used += 6;
143.6005 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6006 + 
143.6007 + 	v[0] = op->base.dst.x + box->x2;
143.6008 + 	v[1] = op->base.dst.y + box->y2;
143.6009 +@@ -3901,6 +3953,7 @@ gen3_emit_composite_spans_primitive_zero_no_offset(struct sna *sna,
143.6010 + {
143.6011 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6012 + 	sna->render.vertex_used += 6;
143.6013 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6014 + 
143.6015 + 	v[0] = box->x2;
143.6016 + 	v[3] = v[1] = box->y2;
143.6017 +@@ -3932,6 +3985,7 @@ gen3_emit_composite_spans_primitive_constant(struct sna *sna,
143.6018 + {
143.6019 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6020 + 	sna->render.vertex_used += 9;
143.6021 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6022 + 
143.6023 + 	v[0] = op->base.dst.x + box->x2;
143.6024 + 	v[6] = v[3] = op->base.dst.x + box->x1;
143.6025 +@@ -3966,6 +4020,7 @@ gen3_emit_composite_spans_primitive_constant_no_offset(struct sna *sna,
143.6026 + {
143.6027 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6028 + 	sna->render.vertex_used += 9;
143.6029 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6030 + 
143.6031 + 	v[0] = box->x2;
143.6032 + 	v[6] = v[3] = box->x1;
143.6033 +@@ -3999,6 +4054,7 @@ gen3_emit_composite_spans_primitive_identity_source(struct sna *sna,
143.6034 + {
143.6035 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6036 + 	sna->render.vertex_used += 15;
143.6037 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6038 + 
143.6039 + 	v[0] = op->base.dst.x + box->x2;
143.6040 + 	v[1] = op->base.dst.y + box->y2;
143.6041 +@@ -4060,6 +4116,7 @@ gen3_emit_composite_spans_primitive_affine_source(struct sna *sna,
143.6042 + 
143.6043 + 	v = sna->render.vertices + sna->render.vertex_used;
143.6044 + 	sna->render.vertex_used += 15;
143.6045 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6046 + 
143.6047 + 	v[0]  = op->base.dst.x + box->x2;
143.6048 + 	v[6]  = v[1] = op->base.dst.y + box->y2;
143.6049 +@@ -4125,6 +4182,7 @@ gen3_emit_composite_spans_primitive_identity_gradient(struct sna *sna,
143.6050 + {
143.6051 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6052 + 	sna->render.vertex_used += 15;
143.6053 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6054 + 
143.6055 + 	v[0] = op->base.dst.x + box->x2;
143.6056 + 	v[1] = op->base.dst.y + box->y2;
143.6057 +@@ -4184,6 +4242,7 @@ gen3_emit_composite_spans_primitive_constant__sse2(struct sna *sna,
143.6058 + {
143.6059 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6060 + 	sna->render.vertex_used += 9;
143.6061 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6062 + 
143.6063 + 	v[0] = op->base.dst.x + box->x2;
143.6064 + 	v[6] = v[3] = op->base.dst.x + box->x1;
143.6065 +@@ -4229,6 +4288,7 @@ gen3_render_composite_spans_constant_box__sse2(struct sna *sna,
143.6066 + 
143.6067 + 	v = sna->render.vertices + sna->render.vertex_used;
143.6068 + 	sna->render.vertex_used += 9;
143.6069 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6070 + 
143.6071 + 	v[0] = box->x2;
143.6072 + 	v[6] = v[3] = box->x1;
143.6073 +@@ -4259,6 +4319,7 @@ gen3_render_composite_spans_constant_thread__sse2__boxes(struct sna *sna,
143.6074 + 
143.6075 + 		v = sna->render.vertices + sna->render.vertex_used;
143.6076 + 		sna->render.vertex_used += nbox_this_time * 9;
143.6077 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6078 + 
143.6079 + 		sna_vertex_acquire__locked(&sna->render);
143.6080 + 		sna_vertex_unlock(&sna->render);
143.6081 +@@ -4287,6 +4348,7 @@ gen3_emit_composite_spans_primitive_constant__sse2__no_offset(struct sna *sna,
143.6082 + {
143.6083 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6084 + 	sna->render.vertex_used += 9;
143.6085 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6086 + 
143.6087 + 	v[0] = box->x2;
143.6088 + 	v[6] = v[3] = box->x1;
143.6089 +@@ -4320,6 +4382,7 @@ gen3_emit_composite_spans_primitive_identity_source__sse2(struct sna *sna,
143.6090 + {
143.6091 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6092 + 	sna->render.vertex_used += 15;
143.6093 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6094 + 
143.6095 + 	v[0] = op->base.dst.x + box->x2;
143.6096 + 	v[1] = op->base.dst.y + box->y2;
143.6097 +@@ -4380,6 +4443,7 @@ gen3_emit_composite_spans_primitive_affine_source__sse2(struct sna *sna,
143.6098 + 
143.6099 + 	v = sna->render.vertices + sna->render.vertex_used;
143.6100 + 	sna->render.vertex_used += 15;
143.6101 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6102 + 
143.6103 + 	v[0]  = op->base.dst.x + box->x2;
143.6104 + 	v[6]  = v[1] = op->base.dst.y + box->y2;
143.6105 +@@ -4445,6 +4509,7 @@ gen3_emit_composite_spans_primitive_identity_gradient__sse2(struct sna *sna,
143.6106 + {
143.6107 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6108 + 	sna->render.vertex_used += 15;
143.6109 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6110 + 
143.6111 + 	v[0] = op->base.dst.x + box->x2;
143.6112 + 	v[1] = op->base.dst.y + box->y2;
143.6113 +@@ -4504,6 +4569,7 @@ gen3_emit_composite_spans_primitive_affine_gradient__sse2(struct sna *sna,
143.6114 + 	PictTransform *transform = op->base.src.transform;
143.6115 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6116 + 	sna->render.vertex_used += 15;
143.6117 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6118 + 
143.6119 + 	v[0] = op->base.dst.x + box->x2;
143.6120 + 	v[1] = op->base.dst.y + box->y2;
143.6121 +@@ -4577,6 +4643,7 @@ gen3_emit_composite_spans_primitive_affine_gradient(struct sna *sna,
143.6122 + 	PictTransform *transform = op->base.src.transform;
143.6123 + 	float *v = sna->render.vertices + sna->render.vertex_used;
143.6124 + 	sna->render.vertex_used += 15;
143.6125 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6126 + 
143.6127 + 	v[0] = op->base.dst.x + box->x2;
143.6128 + 	v[1] = op->base.dst.y + box->y2;
143.6129 +@@ -4676,6 +4743,7 @@ gen3_render_composite_spans_constant_box(struct sna *sna,
143.6130 + 
143.6131 + 	v = sna->render.vertices + sna->render.vertex_used;
143.6132 + 	sna->render.vertex_used += 9;
143.6133 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6134 + 
143.6135 + 	v[0] = box->x2;
143.6136 + 	v[6] = v[3] = box->x1;
143.6137 +@@ -4706,6 +4774,7 @@ gen3_render_composite_spans_constant_thread_boxes(struct sna *sna,
143.6138 + 
143.6139 + 		v = sna->render.vertices + sna->render.vertex_used;
143.6140 + 		sna->render.vertex_used += nbox_this_time * 9;
143.6141 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6142 + 
143.6143 + 		sna_vertex_acquire__locked(&sna->render);
143.6144 + 		sna_vertex_unlock(&sna->render);
143.6145 +@@ -4795,6 +4864,7 @@ gen3_render_composite_spans_boxes__thread(struct sna *sna,
143.6146 + 
143.6147 + 		v = sna->render.vertices + sna->render.vertex_used;
143.6148 + 		sna->render.vertex_used += nbox_this_time * op->base.floats_per_rect;
143.6149 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.6150 + 
143.6151 + 		sna_vertex_acquire__locked(&sna->render);
143.6152 + 		sna_vertex_unlock(&sna->render);
143.6153 +@@ -5436,17 +5506,7 @@ gen3_render_video(struct sna *sna,
143.6154 + 		pix_yoff = -dstRegion->extents.y1;
143.6155 + 		copy = 1;
143.6156 + 	} else {
143.6157 +-		/* Set up the offset for translating from the given region
143.6158 +-		 * (in screen coordinates) to the backing pixmap.
143.6159 +-		 */
143.6160 +-#ifdef COMPOSITE
143.6161 +-		pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.6162 +-		pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.6163 +-#else
143.6164 +-		pix_xoff = 0;
143.6165 +-		pix_yoff = 0;
143.6166 +-#endif
143.6167 +-
143.6168 ++		pix_xoff = pix_yoff = 0;
143.6169 + 		dst_width  = pixmap->drawable.width;
143.6170 + 		dst_height = pixmap->drawable.height;
143.6171 + 	}
143.6172 +@@ -5502,16 +5562,9 @@ gen3_render_video(struct sna *sna,
143.6173 + 	} while (nbox);
143.6174 + 
143.6175 + 	if (copy) {
143.6176 +-#ifdef COMPOSITE
143.6177 +-		pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.6178 +-		pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.6179 +-#else
143.6180 +-		pix_xoff = 0;
143.6181 +-		pix_yoff = 0;
143.6182 +-#endif
143.6183 + 		sna_blt_copy_boxes(sna, GXcopy,
143.6184 + 				   dst_bo, -dstRegion->extents.x1, -dstRegion->extents.y1,
143.6185 +-				   priv->gpu_bo, pix_xoff, pix_yoff,
143.6186 ++				   priv->gpu_bo, 0, 0,
143.6187 + 				   pixmap->drawable.bitsPerPixel,
143.6188 + 				   region_rects(dstRegion),
143.6189 + 				   region_num_rects(dstRegion));
143.6190 +@@ -5519,21 +5572,8 @@ gen3_render_video(struct sna *sna,
143.6191 + 		kgem_bo_destroy(&sna->kgem, dst_bo);
143.6192 + 	}
143.6193 + 
143.6194 +-	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
143.6195 +-		if ((pix_xoff | pix_yoff) == 0) {
143.6196 +-			sna_damage_add(&priv->gpu_damage, dstRegion);
143.6197 +-			sna_damage_subtract(&priv->cpu_damage, dstRegion);
143.6198 +-		} else {
143.6199 +-			sna_damage_add_boxes(&priv->gpu_damage,
143.6200 +-					     region_rects(dstRegion),
143.6201 +-					     region_num_rects(dstRegion),
143.6202 +-					     pix_xoff, pix_yoff);
143.6203 +-			sna_damage_subtract_boxes(&priv->cpu_damage,
143.6204 +-						  region_rects(dstRegion),
143.6205 +-						  region_num_rects(dstRegion),
143.6206 +-						  pix_xoff, pix_yoff);
143.6207 +-		}
143.6208 +-	}
143.6209 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage))
143.6210 ++		sna_damage_add(&priv->gpu_damage, dstRegion);
143.6211 + 
143.6212 + 	return true;
143.6213 + }
143.6214 +diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c
143.6215 +index 6c2d3808..72a98aee 100644
143.6216 +--- a/src/sna/gen4_render.c
143.6217 ++++ b/src/sna/gen4_render.c
143.6218 +@@ -1405,8 +1405,8 @@ gen4_render_video(struct sna *sna,
143.6219 + 	int src_height = frame->src.y2 - frame->src.y1;
143.6220 + 	float src_offset_x, src_offset_y;
143.6221 + 	float src_scale_x, src_scale_y;
143.6222 +-	int nbox, pix_xoff, pix_yoff;
143.6223 + 	const BoxRec *box;
143.6224 ++	int nbox;
143.6225 + 
143.6226 + 	DBG(("%s: %dx%d -> %dx%d\n", __FUNCTION__,
143.6227 + 	     src_width, src_height, dst_width, dst_height));
143.6228 +@@ -1445,17 +1445,6 @@ gen4_render_video(struct sna *sna,
143.6229 + 	gen4_align_vertex(sna, &tmp);
143.6230 + 	gen4_video_bind_surfaces(sna, &tmp);
143.6231 + 
143.6232 +-	/* Set up the offset for translating from the given region (in screen
143.6233 +-	 * coordinates) to the backing pixmap.
143.6234 +-	 */
143.6235 +-#ifdef COMPOSITE
143.6236 +-	pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.6237 +-	pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.6238 +-#else
143.6239 +-	pix_xoff = 0;
143.6240 +-	pix_yoff = 0;
143.6241 +-#endif
143.6242 +-
143.6243 + 	src_scale_x = (float)src_width / dst_width / frame->width;
143.6244 + 	src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
143.6245 + 
143.6246 +@@ -1473,34 +1462,26 @@ gen4_render_video(struct sna *sna,
143.6247 + 		nbox -= n;
143.6248 + 
143.6249 + 		do {
143.6250 +-			BoxRec r;
143.6251 +-
143.6252 +-			r.x1 = box->x1 + pix_xoff;
143.6253 +-			r.x2 = box->x2 + pix_xoff;
143.6254 +-			r.y1 = box->y1 + pix_yoff;
143.6255 +-			r.y2 = box->y2 + pix_yoff;
143.6256 +-
143.6257 +-			OUT_VERTEX(r.x2, r.y2);
143.6258 ++			OUT_VERTEX(box->x2, box->y2);
143.6259 + 			OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
143.6260 + 			OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.6261 + 
143.6262 +-			OUT_VERTEX(r.x1, r.y2);
143.6263 ++			OUT_VERTEX(box->x1, box->y2);
143.6264 + 			OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.6265 + 			OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.6266 + 
143.6267 +-			OUT_VERTEX(r.x1, r.y1);
143.6268 ++			OUT_VERTEX(box->x1, box->y1);
143.6269 + 			OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.6270 + 			OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
143.6271 + 
143.6272 +-			if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
143.6273 +-				sna_damage_add_box(&priv->gpu_damage, &r);
143.6274 +-				sna_damage_subtract_box(&priv->cpu_damage, &r);
143.6275 +-			}
143.6276 + 			box++;
143.6277 + 		} while (--n);
143.6278 + 	} while (nbox);
143.6279 + 	gen4_vertex_flush(sna);
143.6280 + 
143.6281 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage))
143.6282 ++		sna_damage_add(&priv->gpu_damage, dstRegion);
143.6283 ++
143.6284 + 	return true;
143.6285 + }
143.6286 + 
143.6287 +@@ -1585,12 +1566,14 @@ gen4_composite_picture(struct sna *sna,
143.6288 + 		if (channel->repeat &&
143.6289 + 		    (x >= 0 &&
143.6290 + 		     y >= 0 &&
143.6291 +-		     x + w < pixmap->drawable.width &&
143.6292 +-		     y + h < pixmap->drawable.height)) {
143.6293 ++		     x + w <= pixmap->drawable.width &&
143.6294 ++		     y + h <= pixmap->drawable.height)) {
143.6295 + 			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.6296 + 			if (priv && priv->clear) {
143.6297 + 				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.6298 +-				return gen4_channel_init_solid(sna, channel, priv->clear_color);
143.6299 ++				return gen4_channel_init_solid(sna, channel,
143.6300 ++							       solid_color(picture->format,
143.6301 ++									   priv->clear_color));
143.6302 + 			}
143.6303 + 		}
143.6304 + 	} else
143.6305 +@@ -1664,7 +1647,9 @@ gen4_composite_set_target(struct sna *sna,
143.6306 + 	} else
143.6307 + 		sna_render_picture_extents(dst, &box);
143.6308 + 
143.6309 +-	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
143.6310 ++	hint = PREFER_GPU | RENDER_GPU;
143.6311 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.6312 ++		hint |= FORCE_GPU;
143.6313 + 	if (!partial) {
143.6314 + 		hint |= IGNORE_DAMAGE;
143.6315 + 		if (w == op->dst.width && h == op->dst.height)
143.6316 +@@ -2738,6 +2723,20 @@ gen4_render_fill_boxes(struct sna *sna,
143.6317 + 	tmp.dst.format = format;
143.6318 + 	tmp.dst.bo = dst_bo;
143.6319 + 
143.6320 ++	sna_render_composite_redirect_init(&tmp);
143.6321 ++	if (too_large(dst->width, dst->height)) {
143.6322 ++		BoxRec extents;
143.6323 ++
143.6324 ++		boxes_extents(box, n, &extents);
143.6325 ++		if (!sna_render_composite_redirect(sna, &tmp,
143.6326 ++						   extents.x1, extents.y1,
143.6327 ++						   extents.x2 - extents.x1,
143.6328 ++						   extents.y2 - extents.y1,
143.6329 ++						   n > 1))
143.6330 ++			return sna_tiling_fill_boxes(sna, op, format, color,
143.6331 ++						     dst, dst_bo, box, n);
143.6332 ++	}
143.6333 ++
143.6334 + 	gen4_channel_init_solid(sna, &tmp.src, pixel);
143.6335 + 
143.6336 + 	tmp.is_affine = true;
143.6337 +@@ -2748,8 +2747,10 @@ gen4_render_fill_boxes(struct sna *sna,
143.6338 + 
143.6339 + 	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
143.6340 + 		kgem_submit(&sna->kgem);
143.6341 +-		if (!kgem_check_bo(&sna->kgem, dst_bo, NULL))
143.6342 ++		if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
143.6343 ++			kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.6344 + 			return false;
143.6345 ++		}
143.6346 + 	}
143.6347 + 
143.6348 + 	gen4_align_vertex(sna, &tmp);
143.6349 +@@ -2765,6 +2766,7 @@ gen4_render_fill_boxes(struct sna *sna,
143.6350 + 
143.6351 + 	gen4_vertex_flush(sna);
143.6352 + 	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.6353 ++	sna_render_composite_redirect_done(sna, &tmp);
143.6354 + 	return true;
143.6355 + }
143.6356 + 
143.6357 +diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c
143.6358 +index 37cf1ff9..fb3e79bf 100644
143.6359 +--- a/src/sna/gen5_render.c
143.6360 ++++ b/src/sna/gen5_render.c
143.6361 +@@ -1355,8 +1355,8 @@ gen5_render_video(struct sna *sna,
143.6362 + 	int src_height = frame->src.y2 - frame->src.y1;
143.6363 + 	float src_offset_x, src_offset_y;
143.6364 + 	float src_scale_x, src_scale_y;
143.6365 +-	int nbox, pix_xoff, pix_yoff;
143.6366 + 	const BoxRec *box;
143.6367 ++	int nbox;
143.6368 + 
143.6369 + 	DBG(("%s: %dx%d -> %dx%d\n", __FUNCTION__,
143.6370 + 	     src_width, src_height, dst_width, dst_height));
143.6371 +@@ -1395,17 +1395,6 @@ gen5_render_video(struct sna *sna,
143.6372 + 	gen5_align_vertex(sna, &tmp);
143.6373 + 	gen5_video_bind_surfaces(sna, &tmp);
143.6374 + 
143.6375 +-	/* Set up the offset for translating from the given region (in screen
143.6376 +-	 * coordinates) to the backing pixmap.
143.6377 +-	 */
143.6378 +-#ifdef COMPOSITE
143.6379 +-	pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.6380 +-	pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.6381 +-#else
143.6382 +-	pix_xoff = 0;
143.6383 +-	pix_yoff = 0;
143.6384 +-#endif
143.6385 +-
143.6386 + 	src_scale_x = (float)src_width / dst_width / frame->width;
143.6387 + 	src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
143.6388 + 
143.6389 +@@ -1415,35 +1404,27 @@ gen5_render_video(struct sna *sna,
143.6390 + 	box = region_rects(dstRegion);
143.6391 + 	nbox = region_num_rects(dstRegion);
143.6392 + 	while (nbox--) {
143.6393 +-		BoxRec r;
143.6394 +-
143.6395 +-		r.x1 = box->x1 + pix_xoff;
143.6396 +-		r.x2 = box->x2 + pix_xoff;
143.6397 +-		r.y1 = box->y1 + pix_yoff;
143.6398 +-		r.y2 = box->y2 + pix_yoff;
143.6399 +-
143.6400 + 		gen5_get_rectangles(sna, &tmp, 1, gen5_video_bind_surfaces);
143.6401 + 
143.6402 +-		OUT_VERTEX(r.x2, r.y2);
143.6403 ++		OUT_VERTEX(box->x2, box->y2);
143.6404 + 		OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
143.6405 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.6406 + 
143.6407 +-		OUT_VERTEX(r.x1, r.y2);
143.6408 ++		OUT_VERTEX(box->x1, box->y2);
143.6409 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.6410 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.6411 + 
143.6412 +-		OUT_VERTEX(r.x1, r.y1);
143.6413 ++		OUT_VERTEX(box->x1, box->y1);
143.6414 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.6415 + 		OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
143.6416 + 
143.6417 +-		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
143.6418 +-			sna_damage_add_box(&priv->gpu_damage, &r);
143.6419 +-			sna_damage_subtract_box(&priv->cpu_damage, &r);
143.6420 +-		}
143.6421 + 		box++;
143.6422 + 	}
143.6423 +-
143.6424 + 	gen4_vertex_flush(sna);
143.6425 ++
143.6426 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage))
143.6427 ++		sna_damage_add(&priv->gpu_damage, dstRegion);
143.6428 ++
143.6429 + 	return true;
143.6430 + }
143.6431 + 
143.6432 +@@ -1524,12 +1505,12 @@ gen5_composite_picture(struct sna *sna,
143.6433 + 		if (channel->repeat ||
143.6434 + 		    (x >= 0 &&
143.6435 + 		     y >= 0 &&
143.6436 +-		     x + w < pixmap->drawable.width &&
143.6437 +-		     y + h < pixmap->drawable.height)) {
143.6438 ++		     x + w <= pixmap->drawable.width &&
143.6439 ++		     y + h <= pixmap->drawable.height)) {
143.6440 + 			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.6441 + 			if (priv && priv->clear) {
143.6442 + 				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.6443 +-				return gen4_channel_init_solid(sna, channel, priv->clear_color);
143.6444 ++				return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
143.6445 + 			}
143.6446 + 		}
143.6447 + 	} else
143.6448 +@@ -1618,7 +1599,9 @@ gen5_composite_set_target(struct sna *sna,
143.6449 + 	} else
143.6450 + 		sna_render_picture_extents(dst, &box);
143.6451 + 
143.6452 +-	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
143.6453 ++	hint = PREFER_GPU | RENDER_GPU;
143.6454 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.6455 ++		hint |= FORCE_GPU;
143.6456 + 	if (!partial) {
143.6457 + 		hint |= IGNORE_DAMAGE;
143.6458 + 		if (w == op->dst.width && h == op->dst.height)
143.6459 +@@ -2734,6 +2717,19 @@ gen5_render_fill_boxes(struct sna *sna,
143.6460 + 	tmp.dst.format = format;
143.6461 + 	tmp.dst.bo = dst_bo;
143.6462 + 
143.6463 ++	if (too_large(dst->width, dst->height)) {
143.6464 ++		BoxRec extents;
143.6465 ++
143.6466 ++		boxes_extents(box, n, &extents);
143.6467 ++		if (!sna_render_composite_redirect(sna, &tmp,
143.6468 ++						   extents.x1, extents.y1,
143.6469 ++						   extents.x2 - extents.x1,
143.6470 ++						   extents.y2 - extents.y1,
143.6471 ++						   n > 1))
143.6472 ++			return sna_tiling_fill_boxes(sna, op, format, color,
143.6473 ++						     dst, dst_bo, box, n);
143.6474 ++	}
143.6475 ++
143.6476 + 	tmp.src.bo = sna_render_get_solid(sna, pixel);
143.6477 + 	tmp.src.filter = SAMPLER_FILTER_NEAREST;
143.6478 + 	tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
143.6479 +@@ -2780,6 +2776,7 @@ gen5_render_fill_boxes(struct sna *sna,
143.6480 + 
143.6481 + 	gen4_vertex_flush(sna);
143.6482 + 	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.6483 ++	sna_render_composite_redirect_done(sna, &tmp);
143.6484 + 	return true;
143.6485 + }
143.6486 + 
143.6487 +diff --git a/src/sna/gen6_common.h b/src/sna/gen6_common.h
143.6488 +index 6668620b..b53ec0c9 100644
143.6489 +--- a/src/sna/gen6_common.h
143.6490 ++++ b/src/sna/gen6_common.h
143.6491 +@@ -30,8 +30,8 @@
143.6492 + 
143.6493 + #include "sna.h"
143.6494 + 
143.6495 +-#define NO_RING_SWITCH 0
143.6496 +-#define PREFER_RENDER 0
143.6497 ++#define NO_RING_SWITCH(sna) (!(sna)->kgem.has_semaphores)
143.6498 ++#define PREFER_RENDER 0 /* -1 -> BLT, 1 -> RENDER */
143.6499 + 
143.6500 + static inline bool is_uncached(struct sna *sna,
143.6501 + 			       struct kgem_bo *bo)
143.6502 +@@ -46,40 +46,28 @@ inline static bool can_switch_to_blt(struct sna *sna,
143.6503 + 	if (sna->kgem.ring != KGEM_RENDER)
143.6504 + 		return true;
143.6505 + 
143.6506 +-	if (NO_RING_SWITCH)
143.6507 +-		return false;
143.6508 +-
143.6509 +-	if (!sna->kgem.has_semaphores)
143.6510 +-		return false;
143.6511 +-
143.6512 +-	if (flags & COPY_LAST)
143.6513 +-		return true;
143.6514 +-
143.6515 + 	if (bo && RQ_IS_BLT(bo->rq))
143.6516 + 		return true;
143.6517 + 
143.6518 +-	if (sna->render_state.gt < 2)
143.6519 +-		return true;
143.6520 ++	if (bo && bo->tiling == I915_TILING_Y)
143.6521 ++		return false;
143.6522 + 
143.6523 +-	return kgem_ring_is_idle(&sna->kgem, KGEM_BLT);
143.6524 +-}
143.6525 ++	if (bo && !kgem_bo_can_blt(&sna->kgem, bo))
143.6526 ++		return false;
143.6527 + 
143.6528 +-inline static bool can_switch_to_render(struct sna *sna,
143.6529 +-					struct kgem_bo *bo)
143.6530 +-{
143.6531 +-	if (sna->kgem.ring == KGEM_RENDER)
143.6532 ++	if (sna->render_state.gt < 2)
143.6533 + 		return true;
143.6534 + 
143.6535 +-	if (NO_RING_SWITCH)
143.6536 ++	if (bo && RQ_IS_RENDER(bo->rq))
143.6537 + 		return false;
143.6538 + 
143.6539 +-	if (!sna->kgem.has_semaphores)
143.6540 ++	if (NO_RING_SWITCH(sna))
143.6541 + 		return false;
143.6542 + 
143.6543 +-	if (bo && !RQ_IS_BLT(bo->rq) && !is_uncached(sna, bo))
143.6544 ++	if (flags & COPY_LAST)
143.6545 + 		return true;
143.6546 + 
143.6547 +-	return !kgem_ring_is_idle(&sna->kgem, KGEM_RENDER);
143.6548 ++	return kgem_ring_is_idle(&sna->kgem, KGEM_BLT);
143.6549 + }
143.6550 + 
143.6551 + static inline bool untiled_tlb_miss(struct kgem_bo *bo)
143.6552 +@@ -90,57 +78,95 @@ static inline bool untiled_tlb_miss(struct kgem_bo *bo)
143.6553 + 	return bo->tiling == I915_TILING_NONE && bo->pitch >= 4096;
143.6554 + }
143.6555 + 
143.6556 +-static int prefer_blt_bo(struct sna *sna, struct kgem_bo *bo)
143.6557 ++static int prefer_blt_bo(struct sna *sna,
143.6558 ++			 struct kgem_bo *src,
143.6559 ++			 struct kgem_bo *dst)
143.6560 + {
143.6561 ++	assert(dst != NULL);
143.6562 ++
143.6563 + 	if (PREFER_RENDER)
143.6564 + 		return PREFER_RENDER < 0;
143.6565 + 
143.6566 +-	if (bo->rq)
143.6567 +-		return RQ_IS_BLT(bo->rq);
143.6568 ++	if (dst->rq)
143.6569 ++		return RQ_IS_BLT(dst->rq);
143.6570 + 
143.6571 + 	if (sna->flags & SNA_POWERSAVE)
143.6572 + 		return true;
143.6573 + 
143.6574 +-	return bo->tiling == I915_TILING_NONE || is_uncached(sna, bo);
143.6575 +-}
143.6576 ++	if (src) {
143.6577 ++		if (sna->render_state.gt > 1)
143.6578 ++			return false;
143.6579 + 
143.6580 +-inline static bool force_blt_ring(struct sna *sna)
143.6581 +-{
143.6582 +-	if (sna->flags & SNA_POWERSAVE)
143.6583 ++		if (src->rq)
143.6584 ++			return RQ_IS_BLT(src->rq);
143.6585 ++
143.6586 ++		if (src->tiling == I915_TILING_Y)
143.6587 ++			return false;
143.6588 ++        } else {
143.6589 ++                if (sna->render_state.gt > 2)
143.6590 ++                        return false;
143.6591 ++        }
143.6592 ++
143.6593 ++	if (sna->render_state.gt < 2)
143.6594 + 		return true;
143.6595 + 
143.6596 ++	return dst->tiling == I915_TILING_NONE || is_uncached(sna, dst);
143.6597 ++}
143.6598 ++
143.6599 ++inline static bool force_blt_ring(struct sna *sna, struct kgem_bo *bo)
143.6600 ++{
143.6601 + 	if (sna->kgem.mode == KGEM_RENDER)
143.6602 + 		return false;
143.6603 + 
143.6604 ++	if (NO_RING_SWITCH(sna))
143.6605 ++		return sna->kgem.ring == KGEM_BLT;
143.6606 ++
143.6607 ++	if (bo->tiling == I915_TILING_Y)
143.6608 ++		return false;
143.6609 ++
143.6610 ++	if (sna->flags & SNA_POWERSAVE)
143.6611 ++		return true;
143.6612 ++
143.6613 + 	if (sna->render_state.gt < 2)
143.6614 + 		return true;
143.6615 + 
143.6616 + 	return false;
143.6617 + }
143.6618 + 
143.6619 +-inline static bool prefer_blt_ring(struct sna *sna,
143.6620 +-				   struct kgem_bo *bo,
143.6621 +-				   unsigned flags)
143.6622 ++nonnull inline static bool
143.6623 ++prefer_blt_ring(struct sna *sna, struct kgem_bo *bo, unsigned flags)
143.6624 + {
143.6625 + 	if (PREFER_RENDER)
143.6626 + 		return PREFER_RENDER < 0;
143.6627 + 
143.6628 +-	assert(!force_blt_ring(sna));
143.6629 +-	assert(!kgem_bo_is_render(bo));
143.6630 ++	assert(!force_blt_ring(sna, bo));
143.6631 ++	assert(!kgem_bo_is_render(bo) || NO_RING_SWITCH(sna));
143.6632 ++
143.6633 ++	if (kgem_bo_is_blt(bo))
143.6634 ++		return true;
143.6635 + 
143.6636 + 	return can_switch_to_blt(sna, bo, flags);
143.6637 + }
143.6638 + 
143.6639 +-inline static bool prefer_render_ring(struct sna *sna,
143.6640 +-				      struct kgem_bo *bo)
143.6641 ++nonnull inline static bool
143.6642 ++prefer_render_ring(struct sna *sna, struct kgem_bo *bo)
143.6643 + {
143.6644 ++	if (sna->kgem.ring == KGEM_RENDER)
143.6645 ++		return true;
143.6646 ++
143.6647 ++	if (sna->kgem.ring != KGEM_NONE && NO_RING_SWITCH(sna))
143.6648 ++                return false;
143.6649 ++
143.6650 ++	if (kgem_bo_is_render(bo))
143.6651 ++		return true;
143.6652 ++
143.6653 + 	if (sna->flags & SNA_POWERSAVE)
143.6654 + 		return false;
143.6655 + 
143.6656 +-	if (sna->render_state.gt < 2)
143.6657 +-		return false;
143.6658 ++	if (!prefer_blt_bo(sna, NULL, bo))
143.6659 ++		return true;
143.6660 + 
143.6661 +-	return can_switch_to_render(sna, bo);
143.6662 ++	return !kgem_ring_is_idle(&sna->kgem, KGEM_RENDER);
143.6663 + }
143.6664 + 
143.6665 + inline static bool
143.6666 +@@ -153,25 +179,20 @@ prefer_blt_composite(struct sna *sna, struct sna_composite_op *tmp)
143.6667 + 	    untiled_tlb_miss(tmp->src.bo))
143.6668 + 		return true;
143.6669 + 
143.6670 +-	if (force_blt_ring(sna))
143.6671 ++	if (force_blt_ring(sna, tmp->dst.bo))
143.6672 + 		return true;
143.6673 + 
143.6674 +-	if (kgem_bo_is_render(tmp->dst.bo) ||
143.6675 +-	    kgem_bo_is_render(tmp->src.bo))
143.6676 +-		return false;
143.6677 +-
143.6678 + 	if (prefer_render_ring(sna, tmp->dst.bo))
143.6679 + 		return false;
143.6680 + 
143.6681 + 	if (!prefer_blt_ring(sna, tmp->dst.bo, 0))
143.6682 + 		return false;
143.6683 + 
143.6684 +-	return prefer_blt_bo(sna, tmp->dst.bo) || prefer_blt_bo(sna, tmp->src.bo);
143.6685 ++	return prefer_blt_bo(sna, tmp->src.bo, tmp->dst.bo);
143.6686 + }
143.6687 + 
143.6688 +-static inline bool prefer_blt_fill(struct sna *sna,
143.6689 +-				   struct kgem_bo *bo,
143.6690 +-				   unsigned flags)
143.6691 ++nonnull static inline bool
143.6692 ++prefer_blt_fill(struct sna *sna, struct kgem_bo *bo, unsigned flags)
143.6693 + {
143.6694 + 	if (PREFER_RENDER)
143.6695 + 		return PREFER_RENDER < 0;
143.6696 +@@ -179,24 +200,21 @@ static inline bool prefer_blt_fill(struct sna *sna,
143.6697 + 	if (untiled_tlb_miss(bo))
143.6698 + 		return true;
143.6699 + 
143.6700 +-	if (force_blt_ring(sna))
143.6701 ++	if (force_blt_ring(sna, bo))
143.6702 + 		return true;
143.6703 + 
143.6704 + 	if ((flags & (FILL_POINTS | FILL_SPANS)) == 0) {
143.6705 +-		if (kgem_bo_is_render(bo))
143.6706 +-			return false;
143.6707 +-
143.6708 + 		if (prefer_render_ring(sna, bo))
143.6709 + 			return false;
143.6710 + 
143.6711 + 		if (!prefer_blt_ring(sna, bo, 0))
143.6712 + 			return false;
143.6713 + 	} else {
143.6714 +-	    if (can_switch_to_blt(sna, bo, 0))
143.6715 ++	    if (can_switch_to_blt(sna, bo, COPY_LAST))
143.6716 + 		    return true;
143.6717 + 	}
143.6718 + 
143.6719 +-	return prefer_blt_bo(sna, bo);
143.6720 ++	return prefer_blt_bo(sna, NULL, bo);
143.6721 + }
143.6722 + 
143.6723 + void gen6_render_context_switch(struct kgem *kgem, int new_mode);
143.6724 +diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
143.6725 +index 25044685..6b69f216 100644
143.6726 +--- a/src/sna/gen6_render.c
143.6727 ++++ b/src/sna/gen6_render.c
143.6728 +@@ -1633,9 +1633,9 @@ gen6_render_video(struct sna *sna,
143.6729 + 	int src_height = frame->src.y2 - frame->src.y1;
143.6730 + 	float src_offset_x, src_offset_y;
143.6731 + 	float src_scale_x, src_scale_y;
143.6732 +-	int nbox, pix_xoff, pix_yoff;
143.6733 + 	unsigned filter;
143.6734 + 	const BoxRec *box;
143.6735 ++	int nbox;
143.6736 + 
143.6737 + 	DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
143.6738 + 	     __FUNCTION__,
143.6739 +@@ -1686,17 +1686,6 @@ gen6_render_video(struct sna *sna,
143.6740 + 	gen6_align_vertex(sna, &tmp);
143.6741 + 	gen6_emit_video_state(sna, &tmp);
143.6742 + 
143.6743 +-	/* Set up the offset for translating from the given region (in screen
143.6744 +-	 * coordinates) to the backing pixmap.
143.6745 +-	 */
143.6746 +-#ifdef COMPOSITE
143.6747 +-	pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.6748 +-	pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.6749 +-#else
143.6750 +-	pix_xoff = 0;
143.6751 +-	pix_yoff = 0;
143.6752 +-#endif
143.6753 +-
143.6754 + 	src_scale_x = (float)src_width / dst_width / frame->width;
143.6755 + 	src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
143.6756 + 
143.6757 +@@ -1706,35 +1695,27 @@ gen6_render_video(struct sna *sna,
143.6758 + 	box = region_rects(dstRegion);
143.6759 + 	nbox = region_num_rects(dstRegion);
143.6760 + 	while (nbox--) {
143.6761 +-		BoxRec r;
143.6762 +-
143.6763 +-		r.x1 = box->x1 + pix_xoff;
143.6764 +-		r.x2 = box->x2 + pix_xoff;
143.6765 +-		r.y1 = box->y1 + pix_yoff;
143.6766 +-		r.y2 = box->y2 + pix_yoff;
143.6767 +-
143.6768 + 		gen6_get_rectangles(sna, &tmp, 1, gen6_emit_video_state);
143.6769 + 
143.6770 +-		OUT_VERTEX(r.x2, r.y2);
143.6771 ++		OUT_VERTEX(box->x2, box->y2);
143.6772 + 		OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
143.6773 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.6774 + 
143.6775 +-		OUT_VERTEX(r.x1, r.y2);
143.6776 ++		OUT_VERTEX(box->x1, box->y2);
143.6777 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.6778 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.6779 + 
143.6780 +-		OUT_VERTEX(r.x1, r.y1);
143.6781 ++		OUT_VERTEX(box->x1, box->y1);
143.6782 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.6783 + 		OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
143.6784 + 
143.6785 +-		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
143.6786 +-			sna_damage_add_box(&priv->gpu_damage, &r);
143.6787 +-			sna_damage_subtract_box(&priv->cpu_damage, &r);
143.6788 +-		}
143.6789 + 		box++;
143.6790 + 	}
143.6791 +-
143.6792 + 	gen4_vertex_flush(sna);
143.6793 ++
143.6794 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage))
143.6795 ++		sna_damage_add(&priv->gpu_damage, dstRegion);
143.6796 ++
143.6797 + 	return true;
143.6798 + }
143.6799 + 
143.6800 +@@ -1815,12 +1796,12 @@ gen6_composite_picture(struct sna *sna,
143.6801 + 		if (channel->repeat &&
143.6802 + 		    (x >= 0 &&
143.6803 + 		     y >= 0 &&
143.6804 +-		     x + w < pixmap->drawable.width &&
143.6805 +-		     y + h < pixmap->drawable.height)) {
143.6806 ++		     x + w <= pixmap->drawable.width &&
143.6807 ++		     y + h <= pixmap->drawable.height)) {
143.6808 + 			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.6809 + 			if (priv && priv->clear) {
143.6810 + 				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.6811 +-				return gen4_channel_init_solid(sna, channel, priv->clear_color);
143.6812 ++				return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
143.6813 + 			}
143.6814 + 		}
143.6815 + 	} else
143.6816 +@@ -1927,7 +1908,9 @@ gen6_composite_set_target(struct sna *sna,
143.6817 + 	} else
143.6818 + 		sna_render_picture_extents(dst, &box);
143.6819 + 
143.6820 +-	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
143.6821 ++	hint = PREFER_GPU | RENDER_GPU;
143.6822 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.6823 ++		hint |= FORCE_GPU;
143.6824 + 	if (!partial) {
143.6825 + 		hint |= IGNORE_DAMAGE;
143.6826 + 		if (w == op->dst.width && h == op->dst.height)
143.6827 +@@ -1965,46 +1948,77 @@ gen6_composite_set_target(struct sna *sna,
143.6828 + 
143.6829 + static bool
143.6830 + try_blt(struct sna *sna,
143.6831 +-	PicturePtr dst, PicturePtr src,
143.6832 +-	int width, int height)
143.6833 ++	uint8_t op,
143.6834 ++	PicturePtr src,
143.6835 ++	PicturePtr mask,
143.6836 ++	PicturePtr dst,
143.6837 ++	int16_t src_x, int16_t src_y,
143.6838 ++	int16_t msk_x, int16_t msk_y,
143.6839 ++	int16_t dst_x, int16_t dst_y,
143.6840 ++	int16_t width, int16_t height,
143.6841 ++	unsigned flags,
143.6842 ++	struct sna_composite_op *tmp)
143.6843 + {
143.6844 + 	struct kgem_bo *bo;
143.6845 + 
143.6846 + 	if (sna->kgem.mode == KGEM_BLT) {
143.6847 + 		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.6848 +-		return true;
143.6849 ++		goto execute;
143.6850 + 	}
143.6851 + 
143.6852 + 	if (too_large(width, height)) {
143.6853 + 		DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
143.6854 + 		     __FUNCTION__, width, height));
143.6855 +-		return true;
143.6856 ++		goto execute;
143.6857 + 	}
143.6858 + 
143.6859 + 	bo = __sna_drawable_peek_bo(dst->pDrawable);
143.6860 + 	if (bo == NULL)
143.6861 +-		return true;
143.6862 +-	if (bo->rq)
143.6863 +-		return RQ_IS_BLT(bo->rq);
143.6864 ++		goto execute;
143.6865 ++
143.6866 ++	if (untiled_tlb_miss(bo))
143.6867 ++		goto execute;
143.6868 ++
143.6869 ++	if (bo->rq) {
143.6870 ++		if (RQ_IS_BLT(bo->rq))
143.6871 ++			goto execute;
143.6872 ++
143.6873 ++		return false;
143.6874 ++	}
143.6875 ++
143.6876 ++	if (bo->tiling == I915_TILING_Y)
143.6877 ++		goto upload;
143.6878 ++
143.6879 ++	if (src->pDrawable == dst->pDrawable &&
143.6880 ++	    can_switch_to_blt(sna, bo, 0))
143.6881 ++		goto execute;
143.6882 + 
143.6883 + 	if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
143.6884 +-		return true;
143.6885 ++		goto execute;
143.6886 + 
143.6887 + 	if (src->pDrawable) {
143.6888 +-		bo = __sna_drawable_peek_bo(src->pDrawable);
143.6889 +-		if (bo == NULL)
143.6890 +-			return true;
143.6891 ++		struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
143.6892 ++		if (s == NULL)
143.6893 ++			goto execute;
143.6894 + 
143.6895 +-		if (prefer_blt_bo(sna, bo))
143.6896 +-			return true;
143.6897 ++		if (prefer_blt_bo(sna, s, bo))
143.6898 ++			goto execute;
143.6899 + 	}
143.6900 + 
143.6901 + 	if (sna->kgem.ring == KGEM_BLT) {
143.6902 + 		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.6903 +-		return true;
143.6904 ++		goto execute;
143.6905 + 	}
143.6906 + 
143.6907 +-	return false;
143.6908 ++upload:
143.6909 ++	flags |= COMPOSITE_UPLOAD;
143.6910 ++execute:
143.6911 ++	return sna_blt_composite(sna, op,
143.6912 ++				 src, dst,
143.6913 ++				 src_x, src_y,
143.6914 ++				 dst_x, dst_y,
143.6915 ++				 width, height,
143.6916 ++				 flags, tmp);
143.6917 + }
143.6918 + 
143.6919 + static bool
143.6920 +@@ -2234,13 +2248,13 @@ gen6_render_composite(struct sna *sna,
143.6921 + 	     width, height, sna->kgem.ring));
143.6922 + 
143.6923 + 	if (mask == NULL &&
143.6924 +-	    try_blt(sna, dst, src, width, height) &&
143.6925 +-	    sna_blt_composite(sna, op,
143.6926 +-			      src, dst,
143.6927 +-			      src_x, src_y,
143.6928 +-			      dst_x, dst_y,
143.6929 +-			      width, height,
143.6930 +-			      flags, tmp))
143.6931 ++	    try_blt(sna, op,
143.6932 ++		    src, mask, dst,
143.6933 ++		    src_x, src_y,
143.6934 ++		    msk_x, msk_y,
143.6935 ++		    dst_x, dst_y,
143.6936 ++		    width, height,
143.6937 ++		    flags, tmp))
143.6938 + 		return true;
143.6939 + 
143.6940 + 	if (gen6_composite_fallback(sna, src, mask, dst))
143.6941 +@@ -2676,27 +2690,35 @@ static inline bool prefer_blt_copy(struct sna *sna,
143.6942 + 	if (sna->kgem.ring == KGEM_BLT)
143.6943 + 		return true;
143.6944 + 
143.6945 +-	if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
143.6946 ++	if (flags & COPY_DRI && !sna->kgem.has_semaphores)
143.6947 ++		return false;
143.6948 ++
143.6949 ++	if ((flags & COPY_SMALL || src_bo == dst_bo) &&
143.6950 ++	    can_switch_to_blt(sna, dst_bo, flags))
143.6951 + 		return true;
143.6952 + 
143.6953 + 	if (untiled_tlb_miss(src_bo) ||
143.6954 + 	    untiled_tlb_miss(dst_bo))
143.6955 + 		return true;
143.6956 + 
143.6957 +-	if (force_blt_ring(sna))
143.6958 ++	if (force_blt_ring(sna, dst_bo))
143.6959 + 		return true;
143.6960 + 
143.6961 + 	if (kgem_bo_is_render(dst_bo) ||
143.6962 + 	    kgem_bo_is_render(src_bo))
143.6963 + 		return false;
143.6964 + 
143.6965 ++	if (flags & COPY_LAST &&
143.6966 ++            can_switch_to_blt(sna, dst_bo, flags))
143.6967 ++		return true;
143.6968 ++
143.6969 + 	if (prefer_render_ring(sna, dst_bo))
143.6970 + 		return false;
143.6971 + 
143.6972 + 	if (!prefer_blt_ring(sna, dst_bo, flags))
143.6973 + 		return false;
143.6974 + 
143.6975 +-	return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
143.6976 ++	return prefer_blt_bo(sna, src_bo, dst_bo);
143.6977 + }
143.6978 + 
143.6979 + static bool
143.6980 +@@ -2758,8 +2780,7 @@ fallback_blt:
143.6981 + 		assert(src->depth == dst->depth);
143.6982 + 		assert(src->width == dst->width);
143.6983 + 		assert(src->height == dst->height);
143.6984 +-		return sna_render_copy_boxes__overlap(sna, alu,
143.6985 +-						      src, src_bo,
143.6986 ++		return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
143.6987 + 						      src_dx, src_dy,
143.6988 + 						      dst_dx, dst_dy,
143.6989 + 						      box, n, &extents);
143.6990 +diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
143.6991 +index 2ecfd641..aabb8693 100644
143.6992 +--- a/src/sna/gen7_render.c
143.6993 ++++ b/src/sna/gen7_render.c
143.6994 +@@ -60,8 +60,6 @@
143.6995 + #define NO_FILL_ONE 0
143.6996 + #define NO_FILL_CLEAR 0
143.6997 + 
143.6998 +-#define NO_RING_SWITCH 0
143.6999 +-
143.7000 + #define USE_8_PIXEL_DISPATCH 1
143.7001 + #define USE_16_PIXEL_DISPATCH 1
143.7002 + #define USE_32_PIXEL_DISPATCH 0
143.7003 +@@ -149,7 +147,7 @@ static const struct gt_info hsw_gt1_info = {
143.7004 + 	.max_vs_threads = 70,
143.7005 + 	.max_gs_threads = 70,
143.7006 + 	.max_wm_threads =
143.7007 +-		(102 - 1) << HSW_PS_MAX_THREADS_SHIFT |
143.7008 ++		(70 - 1) << HSW_PS_MAX_THREADS_SHIFT |
143.7009 + 		1 << HSW_PS_SAMPLE_MASK_SHIFT,
143.7010 + 	.urb = { 128, 640, 256, 8 },
143.7011 + 	.gt = 1,
143.7012 +@@ -209,6 +207,12 @@ static const uint32_t ps_kernel_planar[][4] = {
143.7013 + #include "exa_wm_write.g7b"
143.7014 + };
143.7015 + 
143.7016 ++static const uint32_t ps_kernel_rgb[][4] = {
143.7017 ++#include "exa_wm_src_affine.g7b"
143.7018 ++#include "exa_wm_src_sample_argb.g7b"
143.7019 ++#include "exa_wm_write.g7b"
143.7020 ++};
143.7021 ++
143.7022 + #define KERNEL(kernel_enum, kernel, num_surfaces) \
143.7023 +     [GEN7_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), num_surfaces}
143.7024 + #define NOKERNEL(kernel_enum, func, num_surfaces) \
143.7025 +@@ -218,7 +222,7 @@ static const struct wm_kernel_info {
143.7026 + 	const void *data;
143.7027 + 	unsigned int size;
143.7028 + 	int num_surfaces;
143.7029 +-} wm_kernels[] = {
143.7030 ++} wm_kernels[GEN7_WM_KERNEL_COUNT] = {
143.7031 + 	NOKERNEL(NOMASK, brw_wm_kernel__affine, 2),
143.7032 + 	NOKERNEL(NOMASK_P, brw_wm_kernel__projective, 2),
143.7033 + 
143.7034 +@@ -236,6 +240,7 @@ static const struct wm_kernel_info {
143.7035 + 
143.7036 + 	KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7),
143.7037 + 	KERNEL(VIDEO_PACKED, ps_kernel_packed, 2),
143.7038 ++	KERNEL(VIDEO_RGB, ps_kernel_rgb, 2),
143.7039 + };
143.7040 + #undef KERNEL
143.7041 + 
143.7042 +@@ -810,7 +815,7 @@ gen7_emit_cc(struct sna *sna, uint32_t blend_offset)
143.7043 + 
143.7044 + 	DBG(("%s: blend = %x\n", __FUNCTION__, blend_offset));
143.7045 + 
143.7046 +-	/* XXX can have upto 8 blend states preload, selectable via
143.7047 ++	/* XXX can have up to 8 blend states preload, selectable via
143.7048 + 	 * Render Target Index. What other side-effects of Render Target Index?
143.7049 + 	 */
143.7050 + 
143.7051 +@@ -1792,7 +1797,9 @@ static void gen7_emit_video_state(struct sna *sna,
143.7052 + 			frame->pitch[0];
143.7053 + 		n_src = 6;
143.7054 + 	} else {
143.7055 +-		if (frame->id == FOURCC_UYVY)
143.7056 ++		if (frame->id == FOURCC_RGB888)
143.7057 ++			src_surf_format = GEN7_SURFACEFORMAT_B8G8R8X8_UNORM;
143.7058 ++		else if (frame->id == FOURCC_UYVY)
143.7059 + 			src_surf_format = GEN7_SURFACEFORMAT_YCRCB_SWAPY;
143.7060 + 		else
143.7061 + 			src_surf_format = GEN7_SURFACEFORMAT_YCRCB_NORMAL;
143.7062 +@@ -1826,6 +1833,23 @@ static void gen7_emit_video_state(struct sna *sna,
143.7063 + 	gen7_emit_state(sna, op, offset | dirty);
143.7064 + }
143.7065 + 
143.7066 ++static unsigned select_video_kernel(const struct sna_video_frame *frame)
143.7067 ++{
143.7068 ++	switch (frame->id) {
143.7069 ++	case FOURCC_YV12:
143.7070 ++	case FOURCC_I420:
143.7071 ++	case FOURCC_XVMC:
143.7072 ++		return GEN7_WM_KERNEL_VIDEO_PLANAR;
143.7073 ++
143.7074 ++	case FOURCC_RGB888:
143.7075 ++	case FOURCC_RGB565:
143.7076 ++		return GEN7_WM_KERNEL_VIDEO_RGB;
143.7077 ++
143.7078 ++	default:
143.7079 ++		return GEN7_WM_KERNEL_VIDEO_PACKED;
143.7080 ++	}
143.7081 ++}
143.7082 ++
143.7083 + static bool
143.7084 + gen7_render_video(struct sna *sna,
143.7085 + 		  struct sna_video *video,
143.7086 +@@ -1841,9 +1865,9 @@ gen7_render_video(struct sna *sna,
143.7087 + 	int src_height = frame->src.y2 - frame->src.y1;
143.7088 + 	float src_offset_x, src_offset_y;
143.7089 + 	float src_scale_x, src_scale_y;
143.7090 +-	int nbox, pix_xoff, pix_yoff;
143.7091 + 	unsigned filter;
143.7092 + 	const BoxRec *box;
143.7093 ++	int nbox;
143.7094 + 
143.7095 + 	DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
143.7096 + 	     __FUNCTION__,
143.7097 +@@ -1878,9 +1902,7 @@ gen7_render_video(struct sna *sna,
143.7098 + 		GEN7_SET_FLAGS(SAMPLER_OFFSET(filter, SAMPLER_EXTEND_PAD,
143.7099 + 					      SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE),
143.7100 + 			       NO_BLEND,
143.7101 +-			       is_planar_fourcc(frame->id) ?
143.7102 +-			       GEN7_WM_KERNEL_VIDEO_PLANAR :
143.7103 +-			       GEN7_WM_KERNEL_VIDEO_PACKED,
143.7104 ++			       select_video_kernel(frame),
143.7105 + 			       2);
143.7106 + 	tmp.priv = frame;
143.7107 + 
143.7108 +@@ -1896,17 +1918,6 @@ gen7_render_video(struct sna *sna,
143.7109 + 	gen7_align_vertex(sna, &tmp);
143.7110 + 	gen7_emit_video_state(sna, &tmp);
143.7111 + 
143.7112 +-	/* Set up the offset for translating from the given region (in screen
143.7113 +-	 * coordinates) to the backing pixmap.
143.7114 +-	 */
143.7115 +-#ifdef COMPOSITE
143.7116 +-	pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.7117 +-	pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.7118 +-#else
143.7119 +-	pix_xoff = 0;
143.7120 +-	pix_yoff = 0;
143.7121 +-#endif
143.7122 +-
143.7123 + 	DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
143.7124 + 	     __FUNCTION__,
143.7125 + 	     frame->src.x1, frame->src.y1,
143.7126 +@@ -1928,45 +1939,36 @@ gen7_render_video(struct sna *sna,
143.7127 + 	box = region_rects(dstRegion);
143.7128 + 	nbox = region_num_rects(dstRegion);
143.7129 + 	while (nbox--) {
143.7130 +-		BoxRec r;
143.7131 +-
143.7132 +-		DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
143.7133 ++		DBG(("%s: dst=(%d, %d), (%d, %d); src=(%f, %f), (%f, %f)\n",
143.7134 + 		     __FUNCTION__,
143.7135 + 		     box->x1, box->y1,
143.7136 + 		     box->x2, box->y2,
143.7137 +-		     pix_xoff, pix_yoff,
143.7138 + 		     box->x1 * src_scale_x + src_offset_x,
143.7139 + 		     box->y1 * src_scale_y + src_offset_y,
143.7140 + 		     box->x2 * src_scale_x + src_offset_x,
143.7141 + 		     box->y2 * src_scale_y + src_offset_y));
143.7142 + 
143.7143 +-		r.x1 = box->x1 + pix_xoff;
143.7144 +-		r.x2 = box->x2 + pix_xoff;
143.7145 +-		r.y1 = box->y1 + pix_yoff;
143.7146 +-		r.y2 = box->y2 + pix_yoff;
143.7147 +-
143.7148 + 		gen7_get_rectangles(sna, &tmp, 1, gen7_emit_video_state);
143.7149 + 
143.7150 +-		OUT_VERTEX(r.x2, r.y2);
143.7151 ++		OUT_VERTEX(box->x2, box->y2);
143.7152 + 		OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
143.7153 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.7154 + 
143.7155 +-		OUT_VERTEX(r.x1, r.y2);
143.7156 ++		OUT_VERTEX(box->x1, box->y2);
143.7157 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.7158 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.7159 + 
143.7160 +-		OUT_VERTEX(r.x1, r.y1);
143.7161 ++		OUT_VERTEX(box->x1, box->y1);
143.7162 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.7163 + 		OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
143.7164 + 
143.7165 +-		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
143.7166 +-			sna_damage_add_box(&priv->gpu_damage, &r);
143.7167 +-			sna_damage_subtract_box(&priv->cpu_damage, &r);
143.7168 +-		}
143.7169 + 		box++;
143.7170 + 	}
143.7171 +-
143.7172 + 	gen4_vertex_flush(sna);
143.7173 ++
143.7174 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage))
143.7175 ++		sna_damage_add(&priv->gpu_damage, dstRegion);
143.7176 ++
143.7177 + 	return true;
143.7178 + }
143.7179 + 
143.7180 +@@ -2048,12 +2050,13 @@ gen7_composite_picture(struct sna *sna,
143.7181 + 		if (channel->repeat ||
143.7182 + 		    (x >= 0 &&
143.7183 + 		     y >= 0 &&
143.7184 +-		     x + w < pixmap->drawable.width &&
143.7185 +-		     y + h < pixmap->drawable.height)) {
143.7186 ++		     x + w <= pixmap->drawable.width &&
143.7187 ++		     y + h <= pixmap->drawable.height)) {
143.7188 + 			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.7189 + 			if (priv && priv->clear) {
143.7190 + 				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.7191 +-				return gen4_channel_init_solid(sna, channel, priv->clear_color);
143.7192 ++				return gen4_channel_init_solid(sna, channel,
143.7193 ++							       solid_color(picture->format, priv->clear_color));
143.7194 + 			}
143.7195 + 		}
143.7196 + 	} else
143.7197 +@@ -2147,7 +2150,9 @@ gen7_composite_set_target(struct sna *sna,
143.7198 + 	} else
143.7199 + 		sna_render_picture_extents(dst, &box);
143.7200 + 
143.7201 +-	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
143.7202 ++	hint = PREFER_GPU | RENDER_GPU;
143.7203 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.7204 ++		hint |= FORCE_GPU;
143.7205 + 	if (!partial) {
143.7206 + 		hint |= IGNORE_DAMAGE;
143.7207 + 		if (w == op->dst.width && h == op->dst.height)
143.7208 +@@ -2185,46 +2190,78 @@ gen7_composite_set_target(struct sna *sna,
143.7209 + 
143.7210 + static bool
143.7211 + try_blt(struct sna *sna,
143.7212 +-	PicturePtr dst, PicturePtr src,
143.7213 +-	int width, int height)
143.7214 ++	uint8_t op,
143.7215 ++	PicturePtr src,
143.7216 ++	PicturePtr mask,
143.7217 ++	PicturePtr dst,
143.7218 ++	int16_t src_x, int16_t src_y,
143.7219 ++	int16_t msk_x, int16_t msk_y,
143.7220 ++	int16_t dst_x, int16_t dst_y,
143.7221 ++	int16_t width, int16_t height,
143.7222 ++	unsigned flags,
143.7223 ++	struct sna_composite_op *tmp)
143.7224 + {
143.7225 + 	struct kgem_bo *bo;
143.7226 + 
143.7227 + 	if (sna->kgem.mode == KGEM_BLT) {
143.7228 + 		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.7229 +-		return true;
143.7230 ++		goto execute;
143.7231 + 	}
143.7232 + 
143.7233 + 	if (too_large(width, height)) {
143.7234 + 		DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
143.7235 + 		     __FUNCTION__, width, height));
143.7236 +-		return true;
143.7237 ++		goto execute;
143.7238 + 	}
143.7239 + 
143.7240 + 	bo = __sna_drawable_peek_bo(dst->pDrawable);
143.7241 + 	if (bo == NULL)
143.7242 +-		return true;
143.7243 +-	if (bo->rq)
143.7244 +-		return RQ_IS_BLT(bo->rq);
143.7245 ++		goto execute;
143.7246 ++
143.7247 ++	if (untiled_tlb_miss(bo))
143.7248 ++		goto execute;
143.7249 ++
143.7250 ++	if (bo->rq) {
143.7251 ++		if (RQ_IS_BLT(bo->rq))
143.7252 ++			goto execute;
143.7253 ++
143.7254 ++		return false;
143.7255 ++	}
143.7256 ++
143.7257 ++	if (bo->tiling == I915_TILING_Y)
143.7258 ++		goto upload;
143.7259 ++
143.7260 ++	if (src->pDrawable == dst->pDrawable &&
143.7261 ++	    (sna->render_state.gt < 3 || width*height < 1024) &&
143.7262 ++	    can_switch_to_blt(sna, bo, 0))
143.7263 ++		goto execute;
143.7264 + 
143.7265 + 	if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
143.7266 +-		return true;
143.7267 ++		goto execute;
143.7268 + 
143.7269 + 	if (src->pDrawable) {
143.7270 +-		bo = __sna_drawable_peek_bo(src->pDrawable);
143.7271 +-		if (bo == NULL)
143.7272 +-			return true;
143.7273 ++		struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
143.7274 ++		if (s == NULL)
143.7275 ++			goto upload;
143.7276 + 
143.7277 +-		if (prefer_blt_bo(sna, bo))
143.7278 +-			return true;
143.7279 ++		if (prefer_blt_bo(sna, s, bo))
143.7280 ++			goto execute;
143.7281 + 	}
143.7282 + 
143.7283 + 	if (sna->kgem.ring == KGEM_BLT) {
143.7284 + 		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.7285 +-		return true;
143.7286 ++		goto execute;
143.7287 + 	}
143.7288 + 
143.7289 +-	return false;
143.7290 ++upload:
143.7291 ++	flags |= COMPOSITE_UPLOAD;
143.7292 ++execute:
143.7293 ++	return sna_blt_composite(sna, op,
143.7294 ++				 src, dst,
143.7295 ++				 src_x, src_y,
143.7296 ++				 dst_x, dst_y,
143.7297 ++				 width, height,
143.7298 ++				 flags, tmp);
143.7299 + }
143.7300 + 
143.7301 + static bool
143.7302 +@@ -2454,13 +2491,13 @@ gen7_render_composite(struct sna *sna,
143.7303 + 	     width, height, sna->kgem.mode, sna->kgem.ring));
143.7304 + 
143.7305 + 	if (mask == NULL &&
143.7306 +-	    try_blt(sna, dst, src, width, height) &&
143.7307 +-	    sna_blt_composite(sna, op,
143.7308 +-			      src, dst,
143.7309 +-			      src_x, src_y,
143.7310 +-			      dst_x, dst_y,
143.7311 +-			      width, height,
143.7312 +-			      flags, tmp))
143.7313 ++	    try_blt(sna, op,
143.7314 ++		    src, mask, dst,
143.7315 ++		    src_x, src_y,
143.7316 ++		    msk_x, msk_y,
143.7317 ++		    dst_x, dst_y,
143.7318 ++		    width, height,
143.7319 ++		    flags, tmp))
143.7320 + 		return true;
143.7321 + 
143.7322 + 	if (gen7_composite_fallback(sna, src, mask, dst))
143.7323 +@@ -2878,27 +2915,37 @@ prefer_blt_copy(struct sna *sna,
143.7324 + 
143.7325 + 	assert((flags & COPY_SYNC) == 0);
143.7326 + 
143.7327 +-	if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
143.7328 +-		return true;
143.7329 +-
143.7330 + 	if (untiled_tlb_miss(src_bo) ||
143.7331 + 	    untiled_tlb_miss(dst_bo))
143.7332 + 		return true;
143.7333 + 
143.7334 +-	if (force_blt_ring(sna))
143.7335 ++	if (flags & COPY_DRI && !sna->kgem.has_semaphores)
143.7336 ++		return false;
143.7337 ++
143.7338 ++	if (force_blt_ring(sna, dst_bo))
143.7339 ++		return true;
143.7340 ++
143.7341 ++	if ((flags & COPY_SMALL ||
143.7342 ++	     (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
143.7343 ++            can_switch_to_blt(sna, dst_bo, flags))
143.7344 + 		return true;
143.7345 + 
143.7346 + 	if (kgem_bo_is_render(dst_bo) ||
143.7347 + 	    kgem_bo_is_render(src_bo))
143.7348 + 		return false;
143.7349 + 
143.7350 ++	if (flags & COPY_LAST &&
143.7351 ++	    sna->render_state.gt < 3 &&
143.7352 ++            can_switch_to_blt(sna, dst_bo, flags))
143.7353 ++		return true;
143.7354 ++
143.7355 + 	if (prefer_render_ring(sna, dst_bo))
143.7356 + 		return false;
143.7357 + 
143.7358 + 	if (!prefer_blt_ring(sna, dst_bo, flags))
143.7359 + 		return false;
143.7360 + 
143.7361 +-	return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
143.7362 ++	return prefer_blt_bo(sna, src_bo, dst_bo);
143.7363 + }
143.7364 + 
143.7365 + static bool
143.7366 +@@ -2946,7 +2993,7 @@ fallback_blt:
143.7367 + 		     &extents)) {
143.7368 + 		bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
143.7369 + 
143.7370 +-		if ((big || can_switch_to_blt(sna, dst_bo, flags)) &&
143.7371 ++		if ((big || !prefer_render_ring(sna, dst_bo)) &&
143.7372 + 		    sna_blt_copy_boxes(sna, alu,
143.7373 + 				       src_bo, src_dx, src_dy,
143.7374 + 				       dst_bo, dst_dx, dst_dy,
143.7375 +@@ -2961,8 +3008,7 @@ fallback_blt:
143.7376 + 		assert(src->depth == dst->depth);
143.7377 + 		assert(src->width == dst->width);
143.7378 + 		assert(src->height == dst->height);
143.7379 +-		return sna_render_copy_boxes__overlap(sna, alu,
143.7380 +-						      src, src_bo,
143.7381 ++		return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
143.7382 + 						      src_dx, src_dy,
143.7383 + 						      dst_dx, dst_dy,
143.7384 + 						      box, n, &extents);
143.7385 +diff --git a/src/sna/gen8_render.c b/src/sna/gen8_render.c
143.7386 +index 6eb11452..445983b1 100644
143.7387 +--- a/src/sna/gen8_render.c
143.7388 ++++ b/src/sna/gen8_render.c
143.7389 +@@ -106,6 +106,12 @@ static const uint32_t ps_kernel_planar[][4] = {
143.7390 + #include "exa_wm_yuv_rgb.g8b"
143.7391 + #include "exa_wm_write.g8b"
143.7392 + };
143.7393 ++
143.7394 ++static const uint32_t ps_kernel_rgb[][4] = {
143.7395 ++#include "exa_wm_src_affine.g8b"
143.7396 ++#include "exa_wm_src_sample_argb.g8b"
143.7397 ++#include "exa_wm_write.g8b"
143.7398 ++};
143.7399 + #endif
143.7400 + 
143.7401 + #define SURFACE_DW (64 / sizeof(uint32_t));
143.7402 +@@ -119,7 +125,7 @@ static const struct wm_kernel_info {
143.7403 + 	const void *data;
143.7404 + 	unsigned int size;
143.7405 + 	int num_surfaces;
143.7406 +-} wm_kernels[] = {
143.7407 ++} wm_kernels[GEN8_WM_KERNEL_COUNT] = {
143.7408 + 	NOKERNEL(NOMASK, gen8_wm_kernel__affine, 2),
143.7409 + 	NOKERNEL(NOMASK_P, gen8_wm_kernel__projective, 2),
143.7410 + 
143.7411 +@@ -138,6 +144,7 @@ static const struct wm_kernel_info {
143.7412 + #if !NO_VIDEO
143.7413 + 	KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7),
143.7414 + 	KERNEL(VIDEO_PACKED, ps_kernel_packed, 2),
143.7415 ++	KERNEL(VIDEO_RGB, ps_kernel_rgb, 2),
143.7416 + #endif
143.7417 + };
143.7418 + #undef KERNEL
143.7419 +@@ -205,6 +212,33 @@ static const struct blendinfo {
143.7420 + #define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
143.7421 + #define OUT_VERTEX_F(v) vertex_emit(sna, v)
143.7422 + 
143.7423 ++struct gt_info {
143.7424 ++	const char *name;
143.7425 ++	struct {
143.7426 ++		int max_vs_entries;
143.7427 ++	} urb;
143.7428 ++};
143.7429 ++
143.7430 ++static const struct gt_info bdw_gt_info = {
143.7431 ++	.name = "Broadwell (gen8)",
143.7432 ++	.urb = { .max_vs_entries = 960 },
143.7433 ++};
143.7434 ++
143.7435 ++static bool is_bdw(struct sna *sna)
143.7436 ++{
143.7437 ++	return sna->kgem.gen == 0100;
143.7438 ++}
143.7439 ++
143.7440 ++static const struct gt_info chv_gt_info = {
143.7441 ++	.name = "Cherryview (gen8)",
143.7442 ++	.urb = { .max_vs_entries = 640 },
143.7443 ++};
143.7444 ++
143.7445 ++static bool is_chv(struct sna *sna)
143.7446 ++{
143.7447 ++	return sna->kgem.gen == 0101;
143.7448 ++}
143.7449 ++
143.7450 + static inline bool too_large(int width, int height)
143.7451 + {
143.7452 + 	return width > GEN8_MAX_SIZE || height > GEN8_MAX_SIZE;
143.7453 +@@ -462,7 +496,7 @@ gen8_emit_urb(struct sna *sna)
143.7454 + {
143.7455 + 	/* num of VS entries must be divisible by 8 if size < 9 */
143.7456 + 	OUT_BATCH(GEN8_3DSTATE_URB_VS | (2 - 2));
143.7457 +-	OUT_BATCH(960 << URB_ENTRY_NUMBER_SHIFT |
143.7458 ++	OUT_BATCH(sna->render_state.gen8.info->urb.max_vs_entries << URB_ENTRY_NUMBER_SHIFT |
143.7459 + 		  (2 - 1) << URB_ENTRY_SIZE_SHIFT |
143.7460 + 		  4 << URB_STARTING_ADDRESS_SHIFT);
143.7461 + 
143.7462 +@@ -873,7 +907,7 @@ gen8_emit_cc(struct sna *sna, uint32_t blend)
143.7463 + 	assert(blend / GEN8_BLENDFACTOR_COUNT > 0);
143.7464 + 	assert(blend % GEN8_BLENDFACTOR_COUNT > 0);
143.7465 + 
143.7466 +-	/* XXX can have upto 8 blend states preload, selectable via
143.7467 ++	/* XXX can have up to 8 blend states preload, selectable via
143.7468 + 	 * Render Target Index. What other side-effects of Render Target Index?
143.7469 + 	 */
143.7470 + 
143.7471 +@@ -1167,6 +1201,7 @@ gen8_emit_pipe_stall(struct sna *sna)
143.7472 + {
143.7473 + 	OUT_BATCH(GEN8_PIPE_CONTROL | (6 - 2));
143.7474 + 	OUT_BATCH(PIPE_CONTROL_CS_STALL |
143.7475 ++		  PIPE_CONTROL_FLUSH |
143.7476 + 		  PIPE_CONTROL_STALL_AT_SCOREBOARD);
143.7477 + 	OUT_BATCH64(0);
143.7478 + 	OUT_BATCH64(0);
143.7479 +@@ -1876,12 +1911,12 @@ gen8_composite_picture(struct sna *sna,
143.7480 + 		if (channel->repeat ||
143.7481 + 		    (x >= 0 &&
143.7482 + 		     y >= 0 &&
143.7483 +-		     x + w < pixmap->drawable.width &&
143.7484 +-		     y + h < pixmap->drawable.height)) {
143.7485 ++		     x + w <= pixmap->drawable.width &&
143.7486 ++		     y + h <= pixmap->drawable.height)) {
143.7487 + 			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.7488 + 			if (priv && priv->clear) {
143.7489 + 				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.7490 +-				return gen4_channel_init_solid(sna, channel, priv->clear_color);
143.7491 ++				return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
143.7492 + 			}
143.7493 + 		}
143.7494 + 	} else
143.7495 +@@ -1961,7 +1996,9 @@ gen8_composite_set_target(struct sna *sna,
143.7496 + 	} else
143.7497 + 		sna_render_picture_extents(dst, &box);
143.7498 + 
143.7499 +-	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
143.7500 ++	hint = PREFER_GPU | RENDER_GPU;
143.7501 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.7502 ++		hint |= FORCE_GPU;
143.7503 + 	if (!partial) {
143.7504 + 		hint |= IGNORE_DAMAGE;
143.7505 + 		if (w == op->dst.width && h == op->dst.height)
143.7506 +@@ -2002,46 +2039,78 @@ gen8_composite_set_target(struct sna *sna,
143.7507 + 
143.7508 + static bool
143.7509 + try_blt(struct sna *sna,
143.7510 +-	PicturePtr dst, PicturePtr src,
143.7511 +-	int width, int height)
143.7512 ++	uint8_t op,
143.7513 ++	PicturePtr src,
143.7514 ++	PicturePtr mask,
143.7515 ++	PicturePtr dst,
143.7516 ++	int16_t src_x, int16_t src_y,
143.7517 ++	int16_t msk_x, int16_t msk_y,
143.7518 ++	int16_t dst_x, int16_t dst_y,
143.7519 ++	int16_t width, int16_t height,
143.7520 ++	unsigned flags,
143.7521 ++	struct sna_composite_op *tmp)
143.7522 + {
143.7523 + 	struct kgem_bo *bo;
143.7524 + 
143.7525 + 	if (sna->kgem.mode == KGEM_BLT) {
143.7526 + 		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.7527 +-		return true;
143.7528 ++		goto execute;
143.7529 + 	}
143.7530 + 
143.7531 + 	if (too_large(width, height)) {
143.7532 + 		DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
143.7533 + 		     __FUNCTION__, width, height));
143.7534 +-		return true;
143.7535 ++		goto execute;
143.7536 + 	}
143.7537 + 
143.7538 + 	bo = __sna_drawable_peek_bo(dst->pDrawable);
143.7539 + 	if (bo == NULL)
143.7540 +-		return true;
143.7541 +-	if (bo->rq)
143.7542 +-		return RQ_IS_BLT(bo->rq);
143.7543 ++		goto execute;
143.7544 ++
143.7545 ++	if (untiled_tlb_miss(bo))
143.7546 ++		goto execute;
143.7547 ++
143.7548 ++	if (bo->rq) {
143.7549 ++		if (RQ_IS_BLT(bo->rq))
143.7550 ++			goto execute;
143.7551 ++
143.7552 ++		return false;
143.7553 ++	}
143.7554 ++
143.7555 ++	if (bo->tiling == I915_TILING_Y)
143.7556 ++		goto upload;
143.7557 + 
143.7558 + 	if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
143.7559 +-		return true;
143.7560 ++		goto execute;
143.7561 ++
143.7562 ++	if (src->pDrawable == dst->pDrawable &&
143.7563 ++	    (sna->render_state.gt < 3 || width*height < 1024) &&
143.7564 ++	    can_switch_to_blt(sna, bo, 0))
143.7565 ++		goto execute;
143.7566 + 
143.7567 + 	if (src->pDrawable) {
143.7568 +-		bo = __sna_drawable_peek_bo(src->pDrawable);
143.7569 +-		if (bo == NULL)
143.7570 +-			return true;
143.7571 ++		struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
143.7572 ++		if (s == NULL)
143.7573 ++			goto upload;
143.7574 + 
143.7575 +-		if (prefer_blt_bo(sna, bo))
143.7576 +-			return RQ_IS_BLT(bo->rq);
143.7577 ++		if (prefer_blt_bo(sna, s, bo))
143.7578 ++			goto execute;
143.7579 + 	}
143.7580 + 
143.7581 + 	if (sna->kgem.ring == KGEM_BLT) {
143.7582 + 		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.7583 +-		return true;
143.7584 ++		goto execute;
143.7585 + 	}
143.7586 + 
143.7587 +-	return false;
143.7588 ++upload:
143.7589 ++	flags |= COMPOSITE_UPLOAD;
143.7590 ++execute:
143.7591 ++	return sna_blt_composite(sna, op,
143.7592 ++				 src, dst,
143.7593 ++				 src_x, src_y,
143.7594 ++				 dst_x, dst_y,
143.7595 ++				 width, height,
143.7596 ++				 flags, tmp);
143.7597 + }
143.7598 + 
143.7599 + static bool
143.7600 +@@ -2271,13 +2340,13 @@ gen8_render_composite(struct sna *sna,
143.7601 + 	     width, height, sna->kgem.mode, sna->kgem.ring));
143.7602 + 
143.7603 + 	if (mask == NULL &&
143.7604 +-	    try_blt(sna, dst, src, width, height) &&
143.7605 +-	    sna_blt_composite(sna, op,
143.7606 +-			      src, dst,
143.7607 +-			      src_x, src_y,
143.7608 +-			      dst_x, dst_y,
143.7609 +-			      width, height,
143.7610 +-			      flags, tmp))
143.7611 ++	    try_blt(sna, op,
143.7612 ++		    src, mask, dst,
143.7613 ++		    src_x, src_y,
143.7614 ++		    msk_x, msk_y,
143.7615 ++		    dst_x, dst_y,
143.7616 ++		    width, height,
143.7617 ++		    flags, tmp))
143.7618 + 		return true;
143.7619 + 
143.7620 + 	if (gen8_composite_fallback(sna, src, mask, dst))
143.7621 +@@ -2700,27 +2769,37 @@ prefer_blt_copy(struct sna *sna,
143.7622 + 
143.7623 + 	assert((flags & COPY_SYNC) == 0);
143.7624 + 
143.7625 +-	if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
143.7626 +-		return true;
143.7627 +-
143.7628 + 	if (untiled_tlb_miss(src_bo) ||
143.7629 + 	    untiled_tlb_miss(dst_bo))
143.7630 + 		return true;
143.7631 + 
143.7632 +-	if (force_blt_ring(sna))
143.7633 ++	if (flags & COPY_DRI && !sna->kgem.has_semaphores)
143.7634 ++		return false;
143.7635 ++
143.7636 ++	if (force_blt_ring(sna, dst_bo))
143.7637 ++		return true;
143.7638 ++
143.7639 ++	if ((flags & COPY_SMALL ||
143.7640 ++	     (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
143.7641 ++	    can_switch_to_blt(sna, dst_bo, flags))
143.7642 + 		return true;
143.7643 + 
143.7644 + 	if (kgem_bo_is_render(dst_bo) ||
143.7645 + 	    kgem_bo_is_render(src_bo))
143.7646 + 		return false;
143.7647 + 
143.7648 ++	if (flags & COPY_LAST &&
143.7649 ++	    sna->render_state.gt < 3 &&
143.7650 ++            can_switch_to_blt(sna, dst_bo, flags))
143.7651 ++		return true;
143.7652 ++
143.7653 + 	if (prefer_render_ring(sna, dst_bo))
143.7654 + 		return false;
143.7655 + 
143.7656 + 	if (!prefer_blt_ring(sna, dst_bo, flags))
143.7657 + 		return false;
143.7658 + 
143.7659 +-	return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
143.7660 ++	return prefer_blt_bo(sna, src_bo, dst_bo);
143.7661 + }
143.7662 + 
143.7663 + static bool
143.7664 +@@ -2770,7 +2849,7 @@ fallback_blt:
143.7665 + 		     &extents)) {
143.7666 + 		bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
143.7667 + 
143.7668 +-		if ((big || can_switch_to_blt(sna, dst_bo, flags)) &&
143.7669 ++		if ((big || !prefer_render_ring(sna, dst_bo)) &&
143.7670 + 		    sna_blt_copy_boxes(sna, alu,
143.7671 + 				       src_bo, src_dx, src_dy,
143.7672 + 				       dst_bo, dst_dx, dst_dy,
143.7673 +@@ -2785,8 +2864,7 @@ fallback_blt:
143.7674 + 		assert(src->depth == dst->depth);
143.7675 + 		assert(src->width == dst->width);
143.7676 + 		assert(src->height == dst->height);
143.7677 +-		return sna_render_copy_boxes__overlap(sna, alu,
143.7678 +-						      src, src_bo,
143.7679 ++		return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
143.7680 + 						      src_dx, src_dy,
143.7681 + 						      dst_dx, dst_dy,
143.7682 + 						      box, n, &extents);
143.7683 +@@ -3665,7 +3743,9 @@ static void gen8_emit_video_state(struct sna *sna,
143.7684 + 			frame->pitch[0];
143.7685 + 		n_src = 6;
143.7686 + 	} else {
143.7687 +-		if (frame->id == FOURCC_UYVY)
143.7688 ++		if (frame->id == FOURCC_RGB888)
143.7689 ++			src_surf_format = SURFACEFORMAT_B8G8R8X8_UNORM;
143.7690 ++		else if (frame->id == FOURCC_UYVY)
143.7691 + 			src_surf_format = SURFACEFORMAT_YCRCB_SWAPY;
143.7692 + 		else
143.7693 + 			src_surf_format = SURFACEFORMAT_YCRCB_NORMAL;
143.7694 +@@ -3697,6 +3777,23 @@ static void gen8_emit_video_state(struct sna *sna,
143.7695 + 	gen8_emit_state(sna, op, offset);
143.7696 + }
143.7697 + 
143.7698 ++static unsigned select_video_kernel(const struct sna_video_frame *frame)
143.7699 ++{
143.7700 ++	switch (frame->id) {
143.7701 ++	case FOURCC_YV12:
143.7702 ++	case FOURCC_I420:
143.7703 ++	case FOURCC_XVMC:
143.7704 ++		return GEN8_WM_KERNEL_VIDEO_PLANAR;
143.7705 ++
143.7706 ++	case FOURCC_RGB888:
143.7707 ++	case FOURCC_RGB565:
143.7708 ++		return GEN8_WM_KERNEL_VIDEO_RGB;
143.7709 ++
143.7710 ++	default:
143.7711 ++		return GEN8_WM_KERNEL_VIDEO_PACKED;
143.7712 ++	}
143.7713 ++}
143.7714 ++
143.7715 + static bool
143.7716 + gen8_render_video(struct sna *sna,
143.7717 + 		  struct sna_video *video,
143.7718 +@@ -3712,9 +3809,9 @@ gen8_render_video(struct sna *sna,
143.7719 + 	int src_height = frame->src.y2 - frame->src.y1;
143.7720 + 	float src_offset_x, src_offset_y;
143.7721 + 	float src_scale_x, src_scale_y;
143.7722 +-	int nbox, pix_xoff, pix_yoff;
143.7723 + 	unsigned filter;
143.7724 + 	const BoxRec *box;
143.7725 ++	int nbox;
143.7726 + 
143.7727 + 	DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
143.7728 + 	     __FUNCTION__,
143.7729 +@@ -3743,6 +3840,11 @@ gen8_render_video(struct sna *sna,
143.7730 + 	tmp.floats_per_vertex = 3;
143.7731 + 	tmp.floats_per_rect = 9;
143.7732 + 
143.7733 ++	DBG(("%s: scaling?=%d, planar?=%d [%x]\n",
143.7734 ++	     __FUNCTION__,
143.7735 ++	     src_width != dst_width || src_height != dst_height,
143.7736 ++	     is_planar_fourcc(frame->id), frame->id));
143.7737 ++
143.7738 + 	if (src_width == dst_width && src_height == dst_height)
143.7739 + 		filter = SAMPLER_FILTER_NEAREST;
143.7740 + 	else
143.7741 +@@ -3752,9 +3854,7 @@ gen8_render_video(struct sna *sna,
143.7742 + 		GEN8_SET_FLAGS(SAMPLER_OFFSET(filter, SAMPLER_EXTEND_PAD,
143.7743 + 					      SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE),
143.7744 + 			       NO_BLEND,
143.7745 +-			       is_planar_fourcc(frame->id) ?
143.7746 +-			       GEN8_WM_KERNEL_VIDEO_PLANAR :
143.7747 +-			       GEN8_WM_KERNEL_VIDEO_PACKED,
143.7748 ++			       select_video_kernel(frame),
143.7749 + 			       2);
143.7750 + 	tmp.priv = frame;
143.7751 + 
143.7752 +@@ -3770,17 +3870,6 @@ gen8_render_video(struct sna *sna,
143.7753 + 	gen8_align_vertex(sna, &tmp);
143.7754 + 	gen8_emit_video_state(sna, &tmp);
143.7755 + 
143.7756 +-	/* Set up the offset for translating from the given region (in screen
143.7757 +-	 * coordinates) to the backing pixmap.
143.7758 +-	 */
143.7759 +-#ifdef COMPOSITE
143.7760 +-	pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
143.7761 +-	pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
143.7762 +-#else
143.7763 +-	pix_xoff = 0;
143.7764 +-	pix_yoff = 0;
143.7765 +-#endif
143.7766 +-
143.7767 + 	DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
143.7768 + 	     __FUNCTION__,
143.7769 + 	     frame->src.x1, frame->src.y1,
143.7770 +@@ -3802,45 +3891,36 @@ gen8_render_video(struct sna *sna,
143.7771 + 	box = region_rects(dstRegion);
143.7772 + 	nbox = region_num_rects(dstRegion);
143.7773 + 	while (nbox--) {
143.7774 +-		BoxRec r;
143.7775 +-
143.7776 + 		DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
143.7777 + 		     __FUNCTION__,
143.7778 + 		     box->x1, box->y1,
143.7779 + 		     box->x2, box->y2,
143.7780 +-		     pix_xoff, pix_yoff,
143.7781 + 		     box->x1 * src_scale_x + src_offset_x,
143.7782 + 		     box->y1 * src_scale_y + src_offset_y,
143.7783 + 		     box->x2 * src_scale_x + src_offset_x,
143.7784 + 		     box->y2 * src_scale_y + src_offset_y));
143.7785 + 
143.7786 +-		r.x1 = box->x1 + pix_xoff;
143.7787 +-		r.x2 = box->x2 + pix_xoff;
143.7788 +-		r.y1 = box->y1 + pix_yoff;
143.7789 +-		r.y2 = box->y2 + pix_yoff;
143.7790 +-
143.7791 + 		gen8_get_rectangles(sna, &tmp, 1, gen8_emit_video_state);
143.7792 + 
143.7793 +-		OUT_VERTEX(r.x2, r.y2);
143.7794 ++		OUT_VERTEX(box->x2, box->y2);
143.7795 + 		OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
143.7796 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.7797 + 
143.7798 +-		OUT_VERTEX(r.x1, r.y2);
143.7799 ++		OUT_VERTEX(box->x1, box->y2);
143.7800 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.7801 + 		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.7802 + 
143.7803 +-		OUT_VERTEX(r.x1, r.y1);
143.7804 ++		OUT_VERTEX(box->x1, box->y1);
143.7805 + 		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.7806 + 		OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
143.7807 + 
143.7808 +-		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
143.7809 +-			sna_damage_add_box(&priv->gpu_damage, &r);
143.7810 +-			sna_damage_subtract_box(&priv->cpu_damage, &r);
143.7811 +-		}
143.7812 + 		box++;
143.7813 + 	}
143.7814 +-
143.7815 + 	gen8_vertex_flush(sna);
143.7816 ++
143.7817 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage))
143.7818 ++		sna_damage_add(&priv->gpu_damage, dstRegion);
143.7819 ++
143.7820 + 	return true;
143.7821 + }
143.7822 + #endif
143.7823 +@@ -3896,6 +3976,13 @@ static bool gen8_render_setup(struct sna *sna)
143.7824 + 		state->gt = ((devid >> 4) & 0xf) + 1;
143.7825 + 	DBG(("%s: gt=%d\n", __FUNCTION__, state->gt));
143.7826 + 
143.7827 ++	if (is_bdw(sna))
143.7828 ++		state->info = &bdw_gt_info;
143.7829 ++	else if (is_chv(sna))
143.7830 ++		state->info = &chv_gt_info;
143.7831 ++	else
143.7832 ++		return false;
143.7833 ++
143.7834 + 	sna_static_stream_init(&general);
143.7835 + 
143.7836 + 	/* Zero pad the start. If you see an offset of 0x0 in the batchbuffer
143.7837 +@@ -4007,5 +4094,5 @@ const char *gen8_render_init(struct sna *sna, const char *backend)
143.7838 + 
143.7839 + 	sna->render.max_3d_size = GEN8_MAX_SIZE;
143.7840 + 	sna->render.max_3d_pitch = 1 << 18;
143.7841 +-	return "Broadwell";
143.7842 ++	return sna->render_state.gen8.info->name;
143.7843 + }
143.7844 +diff --git a/src/sna/gen8_render.h b/src/sna/gen8_render.h
143.7845 +index eb4928e7..e6a8dc55 100644
143.7846 +--- a/src/sna/gen8_render.h
143.7847 ++++ b/src/sna/gen8_render.h
143.7848 +@@ -335,6 +335,7 @@
143.7849 + #define PIPE_CONTROL_IS_FLUSH      (1 << 11)
143.7850 + #define PIPE_CONTROL_TC_FLUSH      (1 << 10)
143.7851 + #define PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
143.7852 ++#define PIPE_CONTROL_FLUSH         (1 << 7)
143.7853 + #define PIPE_CONTROL_GLOBAL_GTT    (1 << 2)
143.7854 + #define PIPE_CONTROL_LOCAL_PGTT    (0 << 2)
143.7855 + #define PIPE_CONTROL_STALL_AT_SCOREBOARD   (1 << 1)
143.7856 +diff --git a/src/sna/gen9_render.c b/src/sna/gen9_render.c
143.7857 +new file mode 100644
143.7858 +index 00000000..e5f12c72
143.7859 +--- /dev/null
143.7860 ++++ b/src/sna/gen9_render.c
143.7861 +@@ -0,0 +1,4156 @@
143.7862 ++/*
143.7863 ++ * Copyright © 2012,2013 Intel Corporation
143.7864 ++ *
143.7865 ++ * Permission is hereby granted, free of charge, to any person obtaining a
143.7866 ++ * copy of this software and associated documentation files (the "Software"),
143.7867 ++ * to deal in the Software without restriction, including without limitation
143.7868 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
143.7869 ++ * and/or sell copies of the Software, and to permit persons to whom the
143.7870 ++ * Software is furnished to do so, subject to the following conditions:
143.7871 ++ *
143.7872 ++ * The above copyright notice and this permission notice (including the next
143.7873 ++ * paragraph) shall be included in all copies or substantial portions of the
143.7874 ++ * Software.
143.7875 ++ *
143.7876 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
143.7877 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
143.7878 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
143.7879 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143.7880 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
143.7881 ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
143.7882 ++ * SOFTWARE.
143.7883 ++ *
143.7884 ++ * Authors:
143.7885 ++ *    Chris Wilson <chris@chris-wilson.co.uk>
143.7886 ++ *
143.7887 ++ */
143.7888 ++
143.7889 ++#ifdef HAVE_CONFIG_H
143.7890 ++#include "config.h"
143.7891 ++#endif
143.7892 ++
143.7893 ++#include "sna.h"
143.7894 ++#include "sna_reg.h"
143.7895 ++#include "sna_render.h"
143.7896 ++#include "sna_render_inline.h"
143.7897 ++#include "sna_video.h"
143.7898 ++
143.7899 ++#include "gen9_render.h"
143.7900 ++#include "gen8_eu.h"
143.7901 ++#include "gen4_common.h"
143.7902 ++#include "gen4_source.h"
143.7903 ++#include "gen4_vertex.h"
143.7904 ++#include "gen6_common.h"
143.7905 ++#include "gen8_vertex.h"
143.7906 ++
143.7907 ++#define SIM 1
143.7908 ++
143.7909 ++#define ALWAYS_INVALIDATE 0
143.7910 ++#define ALWAYS_FLUSH 0
143.7911 ++#define ALWAYS_STALL 0
143.7912 ++
143.7913 ++#define NO_COMPOSITE 0
143.7914 ++#define NO_COMPOSITE_SPANS 0
143.7915 ++#define NO_COPY 0
143.7916 ++#define NO_COPY_BOXES 0
143.7917 ++#define NO_FILL 0
143.7918 ++#define NO_FILL_BOXES 0
143.7919 ++#define NO_FILL_ONE 0
143.7920 ++#define NO_FILL_CLEAR 0
143.7921 ++#define NO_VIDEO 0
143.7922 ++
143.7923 ++#define USE_8_PIXEL_DISPATCH 1
143.7924 ++#define USE_16_PIXEL_DISPATCH 1
143.7925 ++#define USE_32_PIXEL_DISPATCH 0
143.7926 ++
143.7927 ++#if !USE_8_PIXEL_DISPATCH && !USE_16_PIXEL_DISPATCH && !USE_32_PIXEL_DISPATCH
143.7928 ++#error "Must select at least 8, 16 or 32 pixel dispatch"
143.7929 ++#endif
143.7930 ++
143.7931 ++#define GEN9_MAX_SIZE 16384
143.7932 ++#define GEN9_GT_BIAS 1 /* Each GT is bigger than previous gen */
143.7933 ++
143.7934 ++/* XXX Todo
143.7935 ++ *
143.7936 ++ * STR (software tiled rendering) mode. No, really.
143.7937 ++ * 64x32 pixel blocks align with the rendering cache. Worth considering.
143.7938 ++ */
143.7939 ++
143.7940 ++#define is_aligned(x, y) (((x) & ((y) - 1)) == 0)
143.7941 ++
143.7942 ++/* Pipeline stages:
143.7943 ++ *  1. Command Streamer (CS)
143.7944 ++ *  2. Vertex Fetch (VF)
143.7945 ++ *  3. Vertex Shader (VS)
143.7946 ++ *  4. Hull Shader (HS)
143.7947 ++ *  5. Tesselation Engine (TE)
143.7948 ++ *  6. Domain Shader (DS)
143.7949 ++ *  7. Geometry Shader (GS)
143.7950 ++ *  8. Stream Output Logic (SOL)
143.7951 ++ *  9. Clipper (CLIP)
143.7952 ++ * 10. Strip/Fan (SF)
143.7953 ++ * 11. Windower/Masker (WM)
143.7954 ++ * 12. Color Calculator (CC)
143.7955 ++ */
143.7956 ++
143.7957 ++#if !NO_VIDEO
143.7958 ++static const uint32_t ps_kernel_packed[][4] = {
143.7959 ++#include "exa_wm_src_affine.g8b"
143.7960 ++#include "exa_wm_src_sample_argb.g8b"
143.7961 ++#include "exa_wm_yuv_rgb.g8b"
143.7962 ++#include "exa_wm_write.g8b"
143.7963 ++};
143.7964 ++
143.7965 ++static const uint32_t ps_kernel_planar[][4] = {
143.7966 ++#include "exa_wm_src_affine.g8b"
143.7967 ++#include "exa_wm_src_sample_planar.g8b"
143.7968 ++#include "exa_wm_yuv_rgb.g8b"
143.7969 ++#include "exa_wm_write.g8b"
143.7970 ++};
143.7971 ++
143.7972 ++static const uint32_t ps_kernel_rgb[][4] = {
143.7973 ++#include "exa_wm_src_affine.g8b"
143.7974 ++#include "exa_wm_src_sample_argb.g8b"
143.7975 ++#include "exa_wm_write.g8b"
143.7976 ++};
143.7977 ++#endif
143.7978 ++
143.7979 ++#define SURFACE_DW (64 / sizeof(uint32_t));
143.7980 ++
143.7981 ++#define KERNEL(kernel_enum, kernel, num_surfaces) \
143.7982 ++    [GEN9_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), num_surfaces}
143.7983 ++#define NOKERNEL(kernel_enum, func, num_surfaces) \
143.7984 ++    [GEN9_WM_KERNEL_##kernel_enum] = {#kernel_enum, (void *)func, 0, num_surfaces}
143.7985 ++static const struct wm_kernel_info {
143.7986 ++	const char *name;
143.7987 ++	const void *data;
143.7988 ++	unsigned int size;
143.7989 ++	int num_surfaces;
143.7990 ++} wm_kernels[] = {
143.7991 ++	NOKERNEL(NOMASK, gen8_wm_kernel__affine, 2),
143.7992 ++	NOKERNEL(NOMASK_P, gen8_wm_kernel__projective, 2),
143.7993 ++
143.7994 ++	NOKERNEL(MASK, gen8_wm_kernel__affine_mask, 3),
143.7995 ++	NOKERNEL(MASK_P, gen8_wm_kernel__projective_mask, 3),
143.7996 ++
143.7997 ++	NOKERNEL(MASKCA, gen8_wm_kernel__affine_mask_ca, 3),
143.7998 ++	NOKERNEL(MASKCA_P, gen8_wm_kernel__projective_mask_ca, 3),
143.7999 ++
143.8000 ++	NOKERNEL(MASKSA, gen8_wm_kernel__affine_mask_sa, 3),
143.8001 ++	NOKERNEL(MASKSA_P, gen8_wm_kernel__projective_mask_sa, 3),
143.8002 ++
143.8003 ++	NOKERNEL(OPACITY, gen8_wm_kernel__affine_opacity, 2),
143.8004 ++	NOKERNEL(OPACITY_P, gen8_wm_kernel__projective_opacity, 2),
143.8005 ++
143.8006 ++#if !NO_VIDEO
143.8007 ++	KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7),
143.8008 ++	KERNEL(VIDEO_PACKED, ps_kernel_packed, 2),
143.8009 ++	KERNEL(VIDEO_RGB, ps_kernel_rgb, 2),
143.8010 ++#endif
143.8011 ++};
143.8012 ++#undef KERNEL
143.8013 ++
143.8014 ++static const struct blendinfo {
143.8015 ++	uint8_t src_alpha;
143.8016 ++	uint8_t src_blend;
143.8017 ++	uint8_t dst_blend;
143.8018 ++} gen9_blend_op[] = {
143.8019 ++	/* Clear */	{0, BLENDFACTOR_ZERO, BLENDFACTOR_ZERO},
143.8020 ++	/* Src */	{0, BLENDFACTOR_ONE, BLENDFACTOR_ZERO},
143.8021 ++	/* Dst */	{0, BLENDFACTOR_ZERO, BLENDFACTOR_ONE},
143.8022 ++	/* Over */	{1, BLENDFACTOR_ONE, BLENDFACTOR_INV_SRC_ALPHA},
143.8023 ++	/* OverReverse */ {0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ONE},
143.8024 ++	/* In */	{0, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_ZERO},
143.8025 ++	/* InReverse */	{1, BLENDFACTOR_ZERO, BLENDFACTOR_SRC_ALPHA},
143.8026 ++	/* Out */	{0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ZERO},
143.8027 ++	/* OutReverse */ {1, BLENDFACTOR_ZERO, BLENDFACTOR_INV_SRC_ALPHA},
143.8028 ++	/* Atop */	{1, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
143.8029 ++	/* AtopReverse */ {1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_SRC_ALPHA},
143.8030 ++	/* Xor */	{1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
143.8031 ++	/* Add */	{0, BLENDFACTOR_ONE, BLENDFACTOR_ONE},
143.8032 ++};
143.8033 ++
143.8034 ++/**
143.8035 ++ * Highest-valued BLENDFACTOR used in gen9_blend_op.
143.8036 ++ *
143.8037 ++ * This leaves out GEN9_BLENDFACTOR_INV_DST_COLOR,
143.8038 ++ * GEN9_BLENDFACTOR_INV_CONST_{COLOR,ALPHA},
143.8039 ++ * GEN9_BLENDFACTOR_INV_SRC1_{COLOR,ALPHA}
143.8040 ++ */
143.8041 ++#define GEN9_BLENDFACTOR_COUNT (BLENDFACTOR_INV_DST_ALPHA + 1)
143.8042 ++
143.8043 ++#define GEN9_BLEND_STATE_PADDED_SIZE	ALIGN(sizeof(struct gen9_blend_state), 64)
143.8044 ++
143.8045 ++#define BLEND_OFFSET(s, d) \
143.8046 ++	((d != BLENDFACTOR_ZERO) << 15 | ((s) * GEN9_BLENDFACTOR_COUNT + (d)) << 4)
143.8047 ++
143.8048 ++#define NO_BLEND BLEND_OFFSET(BLENDFACTOR_ONE, BLENDFACTOR_ZERO)
143.8049 ++#define CLEAR BLEND_OFFSET(BLENDFACTOR_ZERO, BLENDFACTOR_ZERO)
143.8050 ++
143.8051 ++#define SAMPLER_OFFSET(sf, se, mf, me) \
143.8052 ++	(((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me)) + 2)
143.8053 ++
143.8054 ++#define VERTEX_2s2s 0
143.8055 ++
143.8056 ++#define COPY_SAMPLER 0
143.8057 ++#define COPY_VERTEX VERTEX_2s2s
143.8058 ++#define COPY_FLAGS(a) GEN9_SET_FLAGS(COPY_SAMPLER, (a) == GXcopy ? NO_BLEND : CLEAR, GEN9_WM_KERNEL_NOMASK, COPY_VERTEX)
143.8059 ++
143.8060 ++#define FILL_SAMPLER 1
143.8061 ++#define FILL_VERTEX VERTEX_2s2s
143.8062 ++#define FILL_FLAGS(op, format) GEN9_SET_FLAGS(FILL_SAMPLER, gen9_get_blend((op), false, (format)), GEN9_WM_KERNEL_NOMASK, FILL_VERTEX)
143.8063 ++#define FILL_FLAGS_NOBLEND GEN9_SET_FLAGS(FILL_SAMPLER, NO_BLEND, GEN9_WM_KERNEL_NOMASK, FILL_VERTEX)
143.8064 ++
143.8065 ++#define GEN9_SAMPLER(f) (((f) >> 20) & 0xfff)
143.8066 ++#define GEN9_BLEND(f) (((f) >> 4) & 0x7ff)
143.8067 ++#define GEN9_READS_DST(f) (((f) >> 15) & 1)
143.8068 ++#define GEN9_KERNEL(f) (((f) >> 16) & 0xf)
143.8069 ++#define GEN9_VERTEX(f) (((f) >> 0) & 0xf)
143.8070 ++#define GEN9_SET_FLAGS(S, B, K, V)  ((S) << 20 | (K) << 16 | (B) | (V))
143.8071 ++
143.8072 ++#define OUT_BATCH(v) batch_emit(sna, v)
143.8073 ++#define OUT_BATCH64(v) batch_emit64(sna, v)
143.8074 ++#define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
143.8075 ++#define OUT_VERTEX_F(v) vertex_emit(sna, v)
143.8076 ++
143.8077 ++struct gt_info {
143.8078 ++	const char *name;
143.8079 ++	struct {
143.8080 ++		int max_vs_entries;
143.8081 ++	} urb;
143.8082 ++};
143.8083 ++
143.8084 ++static const struct gt_info min_gt_info = {
143.8085 ++	.name = "Skylake (gen9)",
143.8086 ++	.urb = { .max_vs_entries = 240 },
143.8087 ++};
143.8088 ++
143.8089 ++static const struct gt_info skl_gt_info = {
143.8090 ++	.name = "Skylake (gen9)",
143.8091 ++	.urb = { .max_vs_entries = 960 },
143.8092 ++};
143.8093 ++
143.8094 ++static const struct gt_info bxt_gt_info = {
143.8095 ++	.name = "Broxton (gen9)",
143.8096 ++	.urb = { .max_vs_entries = 320 },
143.8097 ++};
143.8098 ++
143.8099 ++static const struct gt_info kbl_gt_info = {
143.8100 ++	.name = "Kabylake (gen9)",
143.8101 ++	.urb = { .max_vs_entries = 960 },
143.8102 ++};
143.8103 ++
143.8104 ++static const struct gt_info glk_gt_info = {
143.8105 ++	.name = "Geminilake (gen9)",
143.8106 ++	.urb = { .max_vs_entries = 320 },
143.8107 ++};
143.8108 ++
143.8109 ++static bool is_skl(struct sna *sna)
143.8110 ++{
143.8111 ++	return sna->kgem.gen == 0110;
143.8112 ++}
143.8113 ++
143.8114 ++static bool is_bxt(struct sna *sna)
143.8115 ++{
143.8116 ++	return sna->kgem.gen == 0111;
143.8117 ++}
143.8118 ++
143.8119 ++static bool is_kbl(struct sna *sna)
143.8120 ++{
143.8121 ++	return sna->kgem.gen == 0112;
143.8122 ++}
143.8123 ++
143.8124 ++static bool is_glk(struct sna *sna)
143.8125 ++{
143.8126 ++	return sna->kgem.gen == 0113;
143.8127 ++}
143.8128 ++
143.8129 ++
143.8130 ++static inline bool too_large(int width, int height)
143.8131 ++{
143.8132 ++	return width > GEN9_MAX_SIZE || height > GEN9_MAX_SIZE;
143.8133 ++}
143.8134 ++
143.8135 ++static inline bool unaligned(struct kgem_bo *bo, int bpp)
143.8136 ++{
143.8137 ++	/* XXX What exactly do we need to meet H_ALIGN and V_ALIGN? */
143.8138 ++#if 0
143.8139 ++	int x, y;
143.8140 ++
143.8141 ++	if (bo->proxy == NULL)
143.8142 ++		return false;
143.8143 ++
143.8144 ++	/* Assume that all tiled proxies are constructed correctly. */
143.8145 ++	if (bo->tiling)
143.8146 ++		return false;
143.8147 ++
143.8148 ++	DBG(("%s: checking alignment of a linear proxy, offset=%d, pitch=%d, bpp=%d: => (%d, %d)\n",
143.8149 ++	     __FUNCTION__, bo->delta, bo->pitch, bpp,
143.8150 ++	     8 * (bo->delta % bo->pitch) / bpp, bo->delta / bo->pitch));
143.8151 ++
143.8152 ++	/* This may be a random userptr map, check that it meets the
143.8153 ++	 * render alignment of SURFACE_VALIGN_4 | SURFACE_HALIGN_4.
143.8154 ++	 */
143.8155 ++	y = bo->delta / bo->pitch;
143.8156 ++	if (y & 3)
143.8157 ++		return true;
143.8158 ++
143.8159 ++	x = 8 * (bo->delta - y * bo->pitch);
143.8160 ++	if (x & (4*bpp - 1))
143.8161 ++	    return true;
143.8162 ++
143.8163 ++	return false;
143.8164 ++#else
143.8165 ++	return false;
143.8166 ++#endif
143.8167 ++}
143.8168 ++
143.8169 ++static uint32_t gen9_get_blend(int op,
143.8170 ++			       bool has_component_alpha,
143.8171 ++			       uint32_t dst_format)
143.8172 ++{
143.8173 ++	uint32_t src, dst;
143.8174 ++
143.8175 ++	COMPILE_TIME_ASSERT(BLENDFACTOR_INV_DST_ALPHA*GEN9_BLENDFACTOR_COUNT + BLENDFACTOR_INV_DST_ALPHA <= 0x7ff);
143.8176 ++
143.8177 ++	src = gen9_blend_op[op].src_blend;
143.8178 ++	dst = gen9_blend_op[op].dst_blend;
143.8179 ++
143.8180 ++	/* If there's no dst alpha channel, adjust the blend op so that
143.8181 ++	 * we'll treat it always as 1.
143.8182 ++	 */
143.8183 ++	if (PICT_FORMAT_A(dst_format) == 0) {
143.8184 ++		if (src == BLENDFACTOR_DST_ALPHA)
143.8185 ++			src = BLENDFACTOR_ONE;
143.8186 ++		else if (src == BLENDFACTOR_INV_DST_ALPHA)
143.8187 ++			src = BLENDFACTOR_ZERO;
143.8188 ++	}
143.8189 ++
143.8190 ++	/* If the source alpha is being used, then we should only be in a
143.8191 ++	 * case where the source blend factor is 0, and the source blend
143.8192 ++	 * value is the mask channels multiplied by the source picture's alpha.
143.8193 ++	 */
143.8194 ++	if (has_component_alpha && gen9_blend_op[op].src_alpha) {
143.8195 ++		if (dst == BLENDFACTOR_SRC_ALPHA)
143.8196 ++			dst = BLENDFACTOR_SRC_COLOR;
143.8197 ++		else if (dst == BLENDFACTOR_INV_SRC_ALPHA)
143.8198 ++			dst = BLENDFACTOR_INV_SRC_COLOR;
143.8199 ++	}
143.8200 ++
143.8201 ++	DBG(("blend op=%d, dst=%x [A=%d] => src=%d, dst=%d => offset=%x\n",
143.8202 ++	     op, dst_format, PICT_FORMAT_A(dst_format),
143.8203 ++	     src, dst, (int)(BLEND_OFFSET(src, dst)>>4)));
143.8204 ++	assert(BLEND_OFFSET(src, dst) >> 4 <= 0xfff);
143.8205 ++	return BLEND_OFFSET(src, dst);
143.8206 ++}
143.8207 ++
143.8208 ++static uint32_t gen9_get_card_format(PictFormat format)
143.8209 ++{
143.8210 ++	switch (format) {
143.8211 ++	default:
143.8212 ++		return -1;
143.8213 ++	case PICT_a8r8g8b8:
143.8214 ++		return SURFACEFORMAT_B8G8R8A8_UNORM;
143.8215 ++	case PICT_x8r8g8b8:
143.8216 ++		return SURFACEFORMAT_B8G8R8X8_UNORM;
143.8217 ++	case PICT_a8b8g8r8:
143.8218 ++		return SURFACEFORMAT_R8G8B8A8_UNORM;
143.8219 ++	case PICT_x8b8g8r8:
143.8220 ++		return SURFACEFORMAT_R8G8B8X8_UNORM;
143.8221 ++#ifdef PICT_a2r10g10b10
143.8222 ++	case PICT_a2r10g10b10:
143.8223 ++		return SURFACEFORMAT_B10G10R10A2_UNORM;
143.8224 ++	case PICT_x2r10g10b10:
143.8225 ++		return SURFACEFORMAT_B10G10R10X2_UNORM;
143.8226 ++#endif
143.8227 ++	case PICT_r8g8b8:
143.8228 ++		return SURFACEFORMAT_R8G8B8_UNORM;
143.8229 ++	case PICT_r5g6b5:
143.8230 ++		return SURFACEFORMAT_B5G6R5_UNORM;
143.8231 ++	case PICT_a1r5g5b5:
143.8232 ++		return SURFACEFORMAT_B5G5R5A1_UNORM;
143.8233 ++	case PICT_a8:
143.8234 ++		return SURFACEFORMAT_A8_UNORM;
143.8235 ++	case PICT_a4r4g4b4:
143.8236 ++		return SURFACEFORMAT_B4G4R4A4_UNORM;
143.8237 ++	}
143.8238 ++}
143.8239 ++
143.8240 ++static uint32_t gen9_get_dest_format(PictFormat format)
143.8241 ++{
143.8242 ++	switch (format) {
143.8243 ++	default:
143.8244 ++		return -1;
143.8245 ++	case PICT_a8r8g8b8:
143.8246 ++	case PICT_x8r8g8b8:
143.8247 ++		return SURFACEFORMAT_B8G8R8A8_UNORM;
143.8248 ++	case PICT_a8b8g8r8:
143.8249 ++	case PICT_x8b8g8r8:
143.8250 ++		return SURFACEFORMAT_R8G8B8A8_UNORM;
143.8251 ++#ifdef PICT_a2r10g10b10
143.8252 ++	case PICT_a2r10g10b10:
143.8253 ++	case PICT_x2r10g10b10:
143.8254 ++		return SURFACEFORMAT_B10G10R10A2_UNORM;
143.8255 ++#endif
143.8256 ++	case PICT_r5g6b5:
143.8257 ++		return SURFACEFORMAT_B5G6R5_UNORM;
143.8258 ++	case PICT_x1r5g5b5:
143.8259 ++	case PICT_a1r5g5b5:
143.8260 ++		return SURFACEFORMAT_B5G5R5A1_UNORM;
143.8261 ++	case PICT_a8:
143.8262 ++		return SURFACEFORMAT_A8_UNORM;
143.8263 ++	case PICT_a4r4g4b4:
143.8264 ++	case PICT_x4r4g4b4:
143.8265 ++		return SURFACEFORMAT_B4G4R4A4_UNORM;
143.8266 ++	}
143.8267 ++}
143.8268 ++
143.8269 ++static bool gen9_check_dst_format(PictFormat format)
143.8270 ++{
143.8271 ++	if (gen9_get_dest_format(format) != -1)
143.8272 ++		return true;
143.8273 ++
143.8274 ++	DBG(("%s: unhandled format: %x\n", __FUNCTION__, (int)format));
143.8275 ++	return false;
143.8276 ++}
143.8277 ++
143.8278 ++static bool gen9_check_format(uint32_t format)
143.8279 ++{
143.8280 ++	if (gen9_get_card_format(format) != -1)
143.8281 ++		return true;
143.8282 ++
143.8283 ++	DBG(("%s: unhandled format: %x\n", __FUNCTION__, (int)format));
143.8284 ++	return false;
143.8285 ++}
143.8286 ++
143.8287 ++static uint32_t gen9_filter(uint32_t filter)
143.8288 ++{
143.8289 ++	switch (filter) {
143.8290 ++	default:
143.8291 ++		assert(0);
143.8292 ++	case PictFilterNearest:
143.8293 ++		return SAMPLER_FILTER_NEAREST;
143.8294 ++	case PictFilterBilinear:
143.8295 ++		return SAMPLER_FILTER_BILINEAR;
143.8296 ++	}
143.8297 ++}
143.8298 ++
143.8299 ++static uint32_t gen9_check_filter(PicturePtr picture)
143.8300 ++{
143.8301 ++	switch (picture->filter) {
143.8302 ++	case PictFilterNearest:
143.8303 ++	case PictFilterBilinear:
143.8304 ++		return true;
143.8305 ++	default:
143.8306 ++		return false;
143.8307 ++	}
143.8308 ++}
143.8309 ++
143.8310 ++static uint32_t gen9_repeat(uint32_t repeat)
143.8311 ++{
143.8312 ++	switch (repeat) {
143.8313 ++	default:
143.8314 ++		assert(0);
143.8315 ++	case RepeatNone:
143.8316 ++		return SAMPLER_EXTEND_NONE;
143.8317 ++	case RepeatNormal:
143.8318 ++		return SAMPLER_EXTEND_REPEAT;
143.8319 ++	case RepeatPad:
143.8320 ++		return SAMPLER_EXTEND_PAD;
143.8321 ++	case RepeatReflect:
143.8322 ++		return SAMPLER_EXTEND_REFLECT;
143.8323 ++	}
143.8324 ++}
143.8325 ++
143.8326 ++static bool gen9_check_repeat(PicturePtr picture)
143.8327 ++{
143.8328 ++	if (!picture->repeat)
143.8329 ++		return true;
143.8330 ++
143.8331 ++	switch (picture->repeatType) {
143.8332 ++	case RepeatNone:
143.8333 ++	case RepeatNormal:
143.8334 ++	case RepeatPad:
143.8335 ++	case RepeatReflect:
143.8336 ++		return true;
143.8337 ++	default:
143.8338 ++		return false;
143.8339 ++	}
143.8340 ++}
143.8341 ++
143.8342 ++static int
143.8343 ++gen9_choose_composite_kernel(int op, bool has_mask, bool is_ca, bool is_affine)
143.8344 ++{
143.8345 ++	int base;
143.8346 ++
143.8347 ++	if (has_mask) {
143.8348 ++		if (is_ca) {
143.8349 ++			if (gen9_blend_op[op].src_alpha)
143.8350 ++				base = GEN9_WM_KERNEL_MASKSA;
143.8351 ++			else
143.8352 ++				base = GEN9_WM_KERNEL_MASKCA;
143.8353 ++		} else
143.8354 ++			base = GEN9_WM_KERNEL_MASK;
143.8355 ++	} else
143.8356 ++		base = GEN9_WM_KERNEL_NOMASK;
143.8357 ++
143.8358 ++	return base + !is_affine;
143.8359 ++}
143.8360 ++
143.8361 ++static void
143.8362 ++gen9_emit_push_constants(struct sna *sna)
143.8363 ++{
143.8364 ++#if SIM
143.8365 ++	OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_VS | (2 - 2));
143.8366 ++	OUT_BATCH(0);
143.8367 ++
143.8368 ++	OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_HS | (2 - 2));
143.8369 ++	OUT_BATCH(0);
143.8370 ++
143.8371 ++	OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_DS | (2 - 2));
143.8372 ++	OUT_BATCH(0);
143.8373 ++
143.8374 ++	OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_GS | (2 - 2));
143.8375 ++	OUT_BATCH(0);
143.8376 ++
143.8377 ++	OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_PS | (2 - 2));
143.8378 ++	OUT_BATCH(0);
143.8379 ++#endif
143.8380 ++}
143.8381 ++
143.8382 ++static void
143.8383 ++gen9_emit_urb(struct sna *sna)
143.8384 ++{
143.8385 ++	/* num of VS entries must be divisible by 8 if size < 9 */
143.8386 ++	OUT_BATCH(GEN9_3DSTATE_URB_VS | (2 - 2));
143.8387 ++	OUT_BATCH(sna->render_state.gen9.info->urb.max_vs_entries << URB_ENTRY_NUMBER_SHIFT |
143.8388 ++		  (2 - 1) << URB_ENTRY_SIZE_SHIFT |
143.8389 ++		  4 << URB_STARTING_ADDRESS_SHIFT);
143.8390 ++
143.8391 ++	OUT_BATCH(GEN9_3DSTATE_URB_HS | (2 - 2));
143.8392 ++	OUT_BATCH(0 << URB_ENTRY_SIZE_SHIFT |
143.8393 ++		  4 << URB_STARTING_ADDRESS_SHIFT);
143.8394 ++
143.8395 ++	OUT_BATCH(GEN9_3DSTATE_URB_DS | (2 - 2));
143.8396 ++	OUT_BATCH(0 << URB_ENTRY_SIZE_SHIFT |
143.8397 ++		  4 << URB_STARTING_ADDRESS_SHIFT);
143.8398 ++
143.8399 ++	OUT_BATCH(GEN9_3DSTATE_URB_GS | (2 - 2));
143.8400 ++	OUT_BATCH(0 << URB_ENTRY_SIZE_SHIFT |
143.8401 ++		  4 << URB_STARTING_ADDRESS_SHIFT);
143.8402 ++}
143.8403 ++
143.8404 ++static void
143.8405 ++gen9_emit_state_base_address(struct sna *sna)
143.8406 ++{
143.8407 ++	uint32_t num_pages;
143.8408 ++
143.8409 ++	assert(sna->kgem.surface - sna->kgem.nbatch <= 16384);
143.8410 ++
143.8411 ++	/* WaBindlessSurfaceStateModifyEnable:skl,bxt */
143.8412 ++	OUT_BATCH(GEN9_STATE_BASE_ADDRESS | (19 - 1 - 2));
143.8413 ++	OUT_BATCH64(0); /* general */
143.8414 ++	OUT_BATCH(0); /* stateless dataport */
143.8415 ++	OUT_BATCH64(kgem_add_reloc64(&sna->kgem, /* surface */
143.8416 ++				     sna->kgem.nbatch,
143.8417 ++				     NULL,
143.8418 ++				     I915_GEM_DOMAIN_INSTRUCTION << 16,
143.8419 ++				     BASE_ADDRESS_MODIFY));
143.8420 ++	OUT_BATCH64(kgem_add_reloc64(&sna->kgem, /* dynamic */
143.8421 ++				     sna->kgem.nbatch,
143.8422 ++				     sna->render_state.gen9.general_bo,
143.8423 ++				     I915_GEM_DOMAIN_INSTRUCTION << 16,
143.8424 ++				     BASE_ADDRESS_MODIFY));
143.8425 ++	OUT_BATCH64(0); /* indirect */
143.8426 ++	OUT_BATCH64(kgem_add_reloc64(&sna->kgem, /* instruction */
143.8427 ++				     sna->kgem.nbatch,
143.8428 ++				     sna->render_state.gen9.general_bo,
143.8429 ++				     I915_GEM_DOMAIN_INSTRUCTION << 16,
143.8430 ++				     BASE_ADDRESS_MODIFY));
143.8431 ++	/* upper bounds */
143.8432 ++	num_pages = sna->render_state.gen9.general_bo->size.pages.count;
143.8433 ++	OUT_BATCH(0); /* general */
143.8434 ++	OUT_BATCH(num_pages << 12 | 1); /* dynamic */
143.8435 ++	OUT_BATCH(0); /* indirect */
143.8436 ++	OUT_BATCH(num_pages << 12 | 1); /* instruction */
143.8437 ++
143.8438 ++	/* Bindless */
143.8439 ++	OUT_BATCH(0);
143.8440 ++	OUT_BATCH(0);
143.8441 ++	OUT_BATCH(0);
143.8442 ++}
143.8443 ++
143.8444 ++static void
143.8445 ++gen9_emit_vs_invariant(struct sna *sna)
143.8446 ++{
143.8447 ++	OUT_BATCH(GEN9_3DSTATE_VS | (9 - 2));
143.8448 ++	OUT_BATCH64(0); /* no VS kernel */
143.8449 ++	OUT_BATCH(0);
143.8450 ++	OUT_BATCH64(0); /* scratch */
143.8451 ++	OUT_BATCH(0);
143.8452 ++	OUT_BATCH(1 << 1); /* pass-through */
143.8453 ++	OUT_BATCH(1 << 16 | 1 << 21); /* urb write to SBE */
143.8454 ++
143.8455 ++#if SIM
143.8456 ++	OUT_BATCH(GEN9_3DSTATE_CONSTANT_VS | (11 - 2));
143.8457 ++	OUT_BATCH(0);
143.8458 ++	OUT_BATCH(0);
143.8459 ++	OUT_BATCH64(0);
143.8460 ++	OUT_BATCH64(0);
143.8461 ++	OUT_BATCH64(0);
143.8462 ++	OUT_BATCH64(0);
143.8463 ++
143.8464 ++	OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_VS | (2 - 2));
143.8465 ++	OUT_BATCH(0);
143.8466 ++
143.8467 ++	OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_VS | (2 - 2));
143.8468 ++	OUT_BATCH(0);
143.8469 ++#endif
143.8470 ++}
143.8471 ++
143.8472 ++static void
143.8473 ++gen9_emit_hs_invariant(struct sna *sna)
143.8474 ++{
143.8475 ++	OUT_BATCH(GEN9_3DSTATE_HS | (9 - 2));
143.8476 ++	OUT_BATCH(0);
143.8477 ++	OUT_BATCH(0);
143.8478 ++	OUT_BATCH64(0); /* no HS kernel */
143.8479 ++	OUT_BATCH64(0); /* scratch */
143.8480 ++	OUT_BATCH(0);
143.8481 ++	OUT_BATCH(0); /* pass-through */
143.8482 ++
143.8483 ++#if SIM
143.8484 ++	OUT_BATCH(GEN9_3DSTATE_CONSTANT_HS | (11 - 2));
143.8485 ++	OUT_BATCH(0);
143.8486 ++	OUT_BATCH(0);
143.8487 ++	OUT_BATCH64(0);
143.8488 ++	OUT_BATCH64(0);
143.8489 ++	OUT_BATCH64(0);
143.8490 ++	OUT_BATCH64(0);
143.8491 ++
143.8492 ++#if 1
143.8493 ++	OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_HS | (2 - 2));
143.8494 ++	OUT_BATCH(0);
143.8495 ++
143.8496 ++	OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_HS | (2 - 2));
143.8497 ++	OUT_BATCH(0);
143.8498 ++#endif
143.8499 ++#endif
143.8500 ++}
143.8501 ++
143.8502 ++static void
143.8503 ++gen9_emit_te_invariant(struct sna *sna)
143.8504 ++{
143.8505 ++	OUT_BATCH(GEN9_3DSTATE_TE | (4 - 2));
143.8506 ++	OUT_BATCH(0);
143.8507 ++	OUT_BATCH(0);
143.8508 ++	OUT_BATCH(0);
143.8509 ++}
143.8510 ++
143.8511 ++static void
143.8512 ++gen9_emit_ds_invariant(struct sna *sna)
143.8513 ++{
143.8514 ++	OUT_BATCH(GEN9_3DSTATE_DS | (11 - 2));
143.8515 ++	OUT_BATCH64(0); /* no kernel */
143.8516 ++	OUT_BATCH(0);
143.8517 ++	OUT_BATCH64(0); /* scratch */
143.8518 ++	OUT_BATCH(0);
143.8519 ++	OUT_BATCH(0);
143.8520 ++	OUT_BATCH(0);
143.8521 ++	OUT_BATCH(0);
143.8522 ++	OUT_BATCH(0);
143.8523 ++
143.8524 ++#if SIM
143.8525 ++	OUT_BATCH(GEN9_3DSTATE_CONSTANT_DS | (11 - 2));
143.8526 ++	OUT_BATCH(0);
143.8527 ++	OUT_BATCH(0);
143.8528 ++	OUT_BATCH64(0);
143.8529 ++	OUT_BATCH64(0);
143.8530 ++	OUT_BATCH64(0);
143.8531 ++	OUT_BATCH64(0);
143.8532 ++
143.8533 ++#if 1
143.8534 ++	OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_DS | (2 - 2));
143.8535 ++	OUT_BATCH(0);
143.8536 ++
143.8537 ++	OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_DS | (2 - 2));
143.8538 ++	OUT_BATCH(0);
143.8539 ++#endif
143.8540 ++#endif
143.8541 ++}
143.8542 ++
143.8543 ++static void
143.8544 ++gen9_emit_gs_invariant(struct sna *sna)
143.8545 ++{
143.8546 ++	OUT_BATCH(GEN9_3DSTATE_GS | (10 - 2));
143.8547 ++	OUT_BATCH64(0); /* no GS kernel */
143.8548 ++	OUT_BATCH(0);
143.8549 ++	OUT_BATCH64(0); /* scratch */
143.8550 ++	OUT_BATCH(0);
143.8551 ++	OUT_BATCH(0); /* pass-through */
143.8552 ++	OUT_BATCH(0);
143.8553 ++	OUT_BATCH(0);
143.8554 ++
143.8555 ++#if SIM
143.8556 ++	OUT_BATCH(GEN9_3DSTATE_CONSTANT_GS | (11 - 2));
143.8557 ++	OUT_BATCH(0);
143.8558 ++	OUT_BATCH(0);
143.8559 ++	OUT_BATCH64(0);
143.8560 ++	OUT_BATCH64(0);
143.8561 ++	OUT_BATCH64(0);
143.8562 ++	OUT_BATCH64(0);
143.8563 ++
143.8564 ++#if 1
143.8565 ++	OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_GS | (2 - 2));
143.8566 ++	OUT_BATCH(0);
143.8567 ++
143.8568 ++	OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_GS | (2 - 2));
143.8569 ++	OUT_BATCH(0);
143.8570 ++#endif
143.8571 ++#endif
143.8572 ++}
143.8573 ++
143.8574 ++static void
143.8575 ++gen9_emit_sol_invariant(struct sna *sna)
143.8576 ++{
143.8577 ++	OUT_BATCH(GEN9_3DSTATE_STREAMOUT | (5 - 2));
143.8578 ++	OUT_BATCH(0);
143.8579 ++	OUT_BATCH(0);
143.8580 ++	OUT_BATCH(0);
143.8581 ++	OUT_BATCH(0);
143.8582 ++}
143.8583 ++
143.8584 ++static void
143.8585 ++gen9_emit_sf_invariant(struct sna *sna)
143.8586 ++{
143.8587 ++	OUT_BATCH(GEN9_3DSTATE_SF | (4 - 2));
143.8588 ++	OUT_BATCH(0);
143.8589 ++	OUT_BATCH(0);
143.8590 ++	OUT_BATCH(0);
143.8591 ++}
143.8592 ++
143.8593 ++static void
143.8594 ++gen9_emit_clip_invariant(struct sna *sna)
143.8595 ++{
143.8596 ++	OUT_BATCH(GEN9_3DSTATE_CLIP | (4 - 2));
143.8597 ++	OUT_BATCH(0);
143.8598 ++	OUT_BATCH(0); /* pass-through */
143.8599 ++	OUT_BATCH(0);
143.8600 ++
143.8601 ++	OUT_BATCH(GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP | (2 - 2));
143.8602 ++	OUT_BATCH(0);
143.8603 ++
143.8604 ++	OUT_BATCH(GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_CC | (2 - 2));
143.8605 ++	OUT_BATCH(0);
143.8606 ++}
143.8607 ++
143.8608 ++static void
143.8609 ++gen9_emit_null_depth_buffer(struct sna *sna)
143.8610 ++{
143.8611 ++	OUT_BATCH(GEN9_3DSTATE_DEPTH_BUFFER | (8 - 2));
143.8612 ++#if 1
143.8613 ++	OUT_BATCH(SURFACE_NULL << DEPTH_BUFFER_TYPE_SHIFT |
143.8614 ++		  DEPTHFORMAT_D32_FLOAT << DEPTH_BUFFER_FORMAT_SHIFT);
143.8615 ++#else
143.8616 ++	OUT_BATCH(SURFACE_2D << DEPTH_BUFFER_TYPE_SHIFT |
143.8617 ++		  DEPTHFORMAT_D16_UNORM << DEPTH_BUFFER_FORMAT_SHIFT);
143.8618 ++#endif
143.8619 ++	OUT_BATCH64(0);
143.8620 ++	OUT_BATCH(0);
143.8621 ++	OUT_BATCH(0);
143.8622 ++	OUT_BATCH(0);
143.8623 ++	OUT_BATCH(0);
143.8624 ++
143.8625 ++#if SIM
143.8626 ++	OUT_BATCH(GEN9_3DSTATE_HIER_DEPTH_BUFFER | (5 - 2));
143.8627 ++	OUT_BATCH(0);
143.8628 ++	OUT_BATCH64(0);
143.8629 ++	OUT_BATCH(0);
143.8630 ++#endif
143.8631 ++
143.8632 ++#if SIM
143.8633 ++	OUT_BATCH(GEN9_3DSTATE_STENCIL_BUFFER | (5 - 2));
143.8634 ++	OUT_BATCH(0);
143.8635 ++	OUT_BATCH64(0);
143.8636 ++	OUT_BATCH(0);
143.8637 ++#endif
143.8638 ++
143.8639 ++#if SIM
143.8640 ++	OUT_BATCH(GEN9_3DSTATE_WM_DEPTH_STENCIL | (4 - 2));
143.8641 ++	OUT_BATCH(0);
143.8642 ++	OUT_BATCH(0);
143.8643 ++	OUT_BATCH(0);
143.8644 ++#endif
143.8645 ++
143.8646 ++#if SIM
143.8647 ++	OUT_BATCH(GEN9_3DSTATE_CLEAR_PARAMS | (3 - 2));
143.8648 ++	OUT_BATCH(0);
143.8649 ++	OUT_BATCH(0);
143.8650 ++#endif
143.8651 ++}
143.8652 ++
143.8653 ++static void
143.8654 ++gen9_emit_wm_invariant(struct sna *sna)
143.8655 ++{
143.8656 ++	gen9_emit_null_depth_buffer(sna);
143.8657 ++
143.8658 ++#if SIM
143.8659 ++	OUT_BATCH(GEN9_3DSTATE_SCISSOR_STATE_POINTERS | (2 - 2));
143.8660 ++	OUT_BATCH(0);
143.8661 ++#endif
143.8662 ++
143.8663 ++	OUT_BATCH(GEN9_3DSTATE_WM | (2 - 2));
143.8664 ++	//OUT_BATCH(WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC); /* XXX */
143.8665 ++	OUT_BATCH(WM_PERSPECTIVE_PIXEL_BARYCENTRIC);
143.8666 ++
143.8667 ++#if SIM
143.8668 ++	OUT_BATCH(GEN9_3DSTATE_WM_CHROMAKEY | (2 - 2));
143.8669 ++	OUT_BATCH(0);
143.8670 ++#endif
143.8671 ++
143.8672 ++#if 0
143.8673 ++	OUT_BATCH(GEN9_3DSTATE_WM_HZ_OP | (5 - 2));
143.8674 ++	OUT_BATCH(0);
143.8675 ++	OUT_BATCH(0);
143.8676 ++	OUT_BATCH(0);
143.8677 ++	OUT_BATCH(0);
143.8678 ++#endif
143.8679 ++
143.8680 ++	OUT_BATCH(GEN9_3DSTATE_PS_EXTRA | (2 - 2));
143.8681 ++	OUT_BATCH(PSX_PIXEL_SHADER_VALID |
143.8682 ++		  PSX_ATTRIBUTE_ENABLE);
143.8683 ++
143.8684 ++	OUT_BATCH(GEN9_3DSTATE_RASTER | (5 - 2));
143.8685 ++	OUT_BATCH(RASTER_FRONT_WINDING_CCW |
143.8686 ++		  RASTER_CULL_NONE);
143.8687 ++	OUT_BATCH(0);
143.8688 ++	OUT_BATCH(0);
143.8689 ++	OUT_BATCH(0);
143.8690 ++
143.8691 ++	OUT_BATCH(GEN9_3DSTATE_SBE_SWIZ | (11 - 2));
143.8692 ++	OUT_BATCH(0);
143.8693 ++	OUT_BATCH(0);
143.8694 ++	OUT_BATCH(0);
143.8695 ++	OUT_BATCH(0);
143.8696 ++	OUT_BATCH(0);
143.8697 ++	OUT_BATCH(0);
143.8698 ++	OUT_BATCH(0);
143.8699 ++	OUT_BATCH(0);
143.8700 ++	OUT_BATCH(0);
143.8701 ++	OUT_BATCH(0);
143.8702 ++
143.8703 ++#if SIM
143.8704 ++	OUT_BATCH(GEN9_3DSTATE_CONSTANT_PS | (11 - 2));
143.8705 ++	OUT_BATCH(0);
143.8706 ++	OUT_BATCH(0);
143.8707 ++	OUT_BATCH64(0);
143.8708 ++	OUT_BATCH64(0);
143.8709 ++	OUT_BATCH64(0);
143.8710 ++	OUT_BATCH64(0);
143.8711 ++#endif
143.8712 ++}
143.8713 ++
143.8714 ++static void
143.8715 ++gen9_emit_cc_invariant(struct sna *sna)
143.8716 ++{
143.8717 ++}
143.8718 ++
143.8719 ++static void
143.8720 ++gen9_emit_vf_invariant(struct sna *sna)
143.8721 ++{
143.8722 ++	int n;
143.8723 ++
143.8724 ++#if 1
143.8725 ++	OUT_BATCH(GEN9_3DSTATE_VF | (2 - 2));
143.8726 ++	OUT_BATCH(0);
143.8727 ++#endif
143.8728 ++
143.8729 ++	OUT_BATCH(GEN9_3DSTATE_VF_SGVS | (2 - 2));
143.8730 ++	OUT_BATCH(0);
143.8731 ++
143.8732 ++	OUT_BATCH(GEN9_3DSTATE_VF_TOPOLOGY | (2 - 2));
143.8733 ++	OUT_BATCH(RECTLIST);
143.8734 ++
143.8735 ++	OUT_BATCH(GEN9_3DSTATE_VF_STATISTICS | 0);
143.8736 ++
143.8737 ++	for (n = 1; n <= 3; n++) {
143.8738 ++		OUT_BATCH(GEN9_3DSTATE_VF_INSTANCING | (3 - 2));
143.8739 ++		OUT_BATCH(n);
143.8740 ++		OUT_BATCH(0);
143.8741 ++	}
143.8742 ++}
143.8743 ++
143.8744 ++static void
143.8745 ++gen9_emit_invariant(struct sna *sna)
143.8746 ++{
143.8747 ++	OUT_BATCH(GEN9_PIPELINE_SELECT |
143.8748 ++		  PIPELINE_SELECTION_MASK |
143.8749 ++		  PIPELINE_SELECT_3D);
143.8750 ++
143.8751 ++#if SIM
143.8752 ++	OUT_BATCH(GEN9_STATE_SIP | (3 - 2));
143.8753 ++	OUT_BATCH64(0);
143.8754 ++#endif
143.8755 ++
143.8756 ++	OUT_BATCH(GEN9_3DSTATE_MULTISAMPLE | (2 - 2));
143.8757 ++	OUT_BATCH(MULTISAMPLE_PIXEL_LOCATION_CENTER |
143.8758 ++		  MULTISAMPLE_NUMSAMPLES_1); /* 1 sample/pixel */
143.8759 ++
143.8760 ++	OUT_BATCH(GEN9_3DSTATE_SAMPLE_MASK | (2 - 2));
143.8761 ++	OUT_BATCH(1);
143.8762 ++
143.8763 ++#if SIM
143.8764 ++	OUT_BATCH(GEN9_3DSTATE_SAMPLE_PATTERN | (5 - 2));
143.8765 ++	OUT_BATCH(0);
143.8766 ++	OUT_BATCH(0);
143.8767 ++	OUT_BATCH(0);
143.8768 ++	//OUT_BATCH(8<<20 | 8<<16);
143.8769 ++	OUT_BATCH(0);
143.8770 ++#endif
143.8771 ++
143.8772 ++	gen9_emit_push_constants(sna);
143.8773 ++	gen9_emit_urb(sna);
143.8774 ++
143.8775 ++	gen9_emit_state_base_address(sna);
143.8776 ++
143.8777 ++	gen9_emit_vf_invariant(sna);
143.8778 ++	gen9_emit_vs_invariant(sna);
143.8779 ++	gen9_emit_hs_invariant(sna);
143.8780 ++	gen9_emit_te_invariant(sna);
143.8781 ++	gen9_emit_ds_invariant(sna);
143.8782 ++	gen9_emit_gs_invariant(sna);
143.8783 ++	gen9_emit_sol_invariant(sna);
143.8784 ++	gen9_emit_clip_invariant(sna);
143.8785 ++	gen9_emit_sf_invariant(sna);
143.8786 ++	gen9_emit_wm_invariant(sna);
143.8787 ++	gen9_emit_cc_invariant(sna);
143.8788 ++
143.8789 ++	sna->render_state.gen9.needs_invariant = false;
143.8790 ++}
143.8791 ++
143.8792 ++static void
143.8793 ++gen9_emit_cc(struct sna *sna, uint32_t blend)
143.8794 ++{
143.8795 ++	struct gen9_render_state *render = &sna->render_state.gen9;
143.8796 ++
143.8797 ++	if (render->blend == blend)
143.8798 ++		return;
143.8799 ++
143.8800 ++	DBG(("%s: blend=%x (current=%x), src=%d, dst=%d\n",
143.8801 ++	     __FUNCTION__, blend, render->blend,
143.8802 ++	     blend / GEN9_BLENDFACTOR_COUNT,
143.8803 ++	     blend % GEN9_BLENDFACTOR_COUNT));
143.8804 ++
143.8805 ++	assert(blend < GEN9_BLENDFACTOR_COUNT * GEN9_BLENDFACTOR_COUNT);
143.8806 ++	assert(blend / GEN9_BLENDFACTOR_COUNT > 0);
143.8807 ++	assert(blend % GEN9_BLENDFACTOR_COUNT > 0);
143.8808 ++
143.8809 ++	/* XXX can have up to 8 blend states preload, selectable via
143.8810 ++	 * Render Target Index. What other side-effects of Render Target Index?
143.8811 ++	 */
143.8812 ++
143.8813 ++	OUT_BATCH(GEN9_3DSTATE_PS_BLEND | (2 - 2));
143.8814 ++	if (blend != GEN9_BLEND(NO_BLEND)) {
143.8815 ++		uint32_t src = blend / GEN9_BLENDFACTOR_COUNT;
143.8816 ++		uint32_t dst = blend % GEN9_BLENDFACTOR_COUNT;
143.8817 ++		OUT_BATCH(PS_BLEND_HAS_WRITEABLE_RT |
143.8818 ++			  PS_BLEND_COLOR_BLEND_ENABLE |
143.8819 ++			  src << PS_BLEND_SRC_ALPHA_SHIFT |
143.8820 ++			  dst << PS_BLEND_DST_ALPHA_SHIFT |
143.8821 ++			  src << PS_BLEND_SRC_SHIFT |
143.8822 ++			  dst << PS_BLEND_DST_SHIFT);
143.8823 ++	} else
143.8824 ++		OUT_BATCH(PS_BLEND_HAS_WRITEABLE_RT);
143.8825 ++
143.8826 ++	assert(is_aligned(render->cc_blend + blend * GEN9_BLEND_STATE_PADDED_SIZE, 64));
143.8827 ++	OUT_BATCH(GEN9_3DSTATE_BLEND_STATE_POINTERS | (2 - 2));
143.8828 ++	OUT_BATCH((render->cc_blend + blend * GEN9_BLEND_STATE_PADDED_SIZE) | 1);
143.8829 ++
143.8830 ++	/* Force a CC_STATE pointer change to improve blend performance */
143.8831 ++	OUT_BATCH(GEN9_3DSTATE_CC_STATE_POINTERS | (2 - 2));
143.8832 ++	OUT_BATCH(0);
143.8833 ++
143.8834 ++	render->blend = blend;
143.8835 ++}
143.8836 ++
143.8837 ++static void
143.8838 ++gen9_emit_sampler(struct sna *sna, uint32_t state)
143.8839 ++{
143.8840 ++	if (sna->render_state.gen9.samplers == state)
143.8841 ++		return;
143.8842 ++
143.8843 ++	sna->render_state.gen9.samplers = state;
143.8844 ++
143.8845 ++	DBG(("%s: sampler = %x\n", __FUNCTION__, state));
143.8846 ++
143.8847 ++	assert(2 * sizeof(struct gen9_sampler_state) == 32);
143.8848 ++	OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_PS | (2 - 2));
143.8849 ++	OUT_BATCH(sna->render_state.gen9.wm_state + state * 2 * sizeof(struct gen9_sampler_state));
143.8850 ++}
143.8851 ++
143.8852 ++static void
143.8853 ++gen9_emit_sf(struct sna *sna, bool has_mask)
143.8854 ++{
143.8855 ++	int num_sf_outputs = has_mask ? 2 : 1;
143.8856 ++
143.8857 ++	if (sna->render_state.gen9.num_sf_outputs == num_sf_outputs)
143.8858 ++		return;
143.8859 ++
143.8860 ++	DBG(("%s: num_sf_outputs=%d\n", __FUNCTION__, num_sf_outputs));
143.8861 ++
143.8862 ++	sna->render_state.gen9.num_sf_outputs = num_sf_outputs;
143.8863 ++
143.8864 ++	OUT_BATCH(GEN9_3DSTATE_SBE | (6 - 2));
143.8865 ++	OUT_BATCH(num_sf_outputs << SBE_NUM_OUTPUTS_SHIFT |
143.8866 ++		  SBE_FORCE_VERTEX_URB_READ_LENGTH | /* forced is faster */
143.8867 ++		  SBE_FORCE_VERTEX_URB_READ_OFFSET |
143.8868 ++		  1 << SBE_URB_ENTRY_READ_LENGTH_SHIFT |
143.8869 ++		  1 << SBE_URB_ENTRY_READ_OFFSET_SHIFT);
143.8870 ++	OUT_BATCH(0);
143.8871 ++	OUT_BATCH(0);
143.8872 ++        OUT_BATCH(SBE_ACTIVE_COMPONENT_XYZW << 0 |
143.8873 ++		  SBE_ACTIVE_COMPONENT_XYZW << 1);
143.8874 ++        OUT_BATCH(0);
143.8875 ++}
143.8876 ++
143.8877 ++static void
143.8878 ++gen9_emit_wm(struct sna *sna, int kernel)
143.8879 ++{
143.8880 ++	const uint32_t *kernels;
143.8881 ++
143.8882 ++	assert(kernel < ARRAY_SIZE(wm_kernels));
143.8883 ++	if (sna->render_state.gen9.kernel == kernel)
143.8884 ++		return;
143.8885 ++
143.8886 ++	sna->render_state.gen9.kernel = kernel;
143.8887 ++	kernels = sna->render_state.gen9.wm_kernel[kernel];
143.8888 ++
143.8889 ++	DBG(("%s: switching to %s, num_surfaces=%d (8-wide? %d, 16-wide? %d, 32-wide? %d)\n",
143.8890 ++	     __FUNCTION__,
143.8891 ++	     wm_kernels[kernel].name,
143.8892 ++	     wm_kernels[kernel].num_surfaces,
143.8893 ++	     kernels[0], kernels[1], kernels[2]));
143.8894 ++	assert(is_aligned(kernels[0], 64));
143.8895 ++	assert(is_aligned(kernels[1], 64));
143.8896 ++	assert(is_aligned(kernels[2], 64));
143.8897 ++
143.8898 ++	OUT_BATCH(GEN9_3DSTATE_PS | (12 - 2));
143.8899 ++	OUT_BATCH64(kernels[0] ?: kernels[1] ?: kernels[2]);
143.8900 ++	OUT_BATCH(1 << PS_SAMPLER_COUNT_SHIFT |
143.8901 ++		  PS_VECTOR_MASK_ENABLE |
143.8902 ++		  wm_kernels[kernel].num_surfaces << PS_BINDING_TABLE_ENTRY_COUNT_SHIFT);
143.8903 ++	OUT_BATCH64(0); /* scratch address */
143.8904 ++	OUT_BATCH(PS_MAX_THREADS |
143.8905 ++		  (kernels[0] ? PS_8_DISPATCH_ENABLE : 0) |
143.8906 ++		  (kernels[1] ? PS_16_DISPATCH_ENABLE : 0) |
143.8907 ++		  (kernels[2] ? PS_32_DISPATCH_ENABLE : 0));
143.8908 ++	OUT_BATCH((kernels[0] ? 4 : kernels[1] ? 6 : 8) << PS_DISPATCH_START_GRF_SHIFT_0 |
143.8909 ++		  8 << PS_DISPATCH_START_GRF_SHIFT_1 |
143.8910 ++		  6 << PS_DISPATCH_START_GRF_SHIFT_2);
143.8911 ++	OUT_BATCH64(kernels[2]);
143.8912 ++	OUT_BATCH64(kernels[1]);
143.8913 ++}
143.8914 ++
143.8915 ++static bool
143.8916 ++gen9_emit_binding_table(struct sna *sna, uint16_t offset)
143.8917 ++{
143.8918 ++	if (sna->render_state.gen9.surface_table == offset)
143.8919 ++		return false;
143.8920 ++
143.8921 ++	/* Binding table pointers */
143.8922 ++	assert(is_aligned(4*offset, 32));
143.8923 ++	OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_PS | (2 - 2));
143.8924 ++	OUT_BATCH(offset*4);
143.8925 ++
143.8926 ++	sna->render_state.gen9.surface_table = offset;
143.8927 ++	return true;
143.8928 ++}
143.8929 ++
143.8930 ++static bool
143.8931 ++gen9_emit_drawing_rectangle(struct sna *sna,
143.8932 ++			    const struct sna_composite_op *op)
143.8933 ++{
143.8934 ++	uint32_t limit = (op->dst.height - 1) << 16 | (op->dst.width - 1);
143.8935 ++	uint32_t offset = (uint16_t)op->dst.y << 16 | (uint16_t)op->dst.x;
143.8936 ++
143.8937 ++	assert(!too_large(abs(op->dst.x), abs(op->dst.y)));
143.8938 ++	assert(!too_large(op->dst.width, op->dst.height));
143.8939 ++
143.8940 ++	if (sna->render_state.gen9.drawrect_limit == limit &&
143.8941 ++	    sna->render_state.gen9.drawrect_offset == offset)
143.8942 ++		return true;
143.8943 ++
143.8944 ++	sna->render_state.gen9.drawrect_offset = offset;
143.8945 ++	sna->render_state.gen9.drawrect_limit = limit;
143.8946 ++
143.8947 ++	OUT_BATCH(GEN9_3DSTATE_DRAWING_RECTANGLE | (4 - 2));
143.8948 ++	OUT_BATCH(0);
143.8949 ++	OUT_BATCH(limit);
143.8950 ++	OUT_BATCH(offset);
143.8951 ++	return false;
143.8952 ++}
143.8953 ++
143.8954 ++static void
143.8955 ++gen9_emit_vertex_elements(struct sna *sna,
143.8956 ++			  const struct sna_composite_op *op)
143.8957 ++{
143.8958 ++	/*
143.8959 ++	 * vertex data in vertex buffer
143.8960 ++	 *    position: (x, y)
143.8961 ++	 *    texture coordinate 0: (u0, v0) if (is_affine is true) else (u0, v0, w0)
143.8962 ++	 *    texture coordinate 1 if (has_mask is true): same as above
143.8963 ++	 */
143.8964 ++	struct gen9_render_state *render = &sna->render_state.gen9;
143.8965 ++	uint32_t src_format, dw;
143.8966 ++	int id = GEN9_VERTEX(op->u.gen9.flags);
143.8967 ++	bool has_mask;
143.8968 ++
143.8969 ++	DBG(("%s: setup id=%d\n", __FUNCTION__, id));
143.8970 ++
143.8971 ++	if (render->ve_id == id)
143.8972 ++		return;
143.8973 ++	render->ve_id = id;
143.8974 ++
143.8975 ++	if (render->ve_dirty) {
143.8976 ++		/* dummy primitive to flush vertex before change? */
143.8977 ++		OUT_BATCH(GEN9_3DPRIMITIVE | (7 - 2));
143.8978 ++		OUT_BATCH(0); /* ignored, see VF_TOPOLOGY */
143.8979 ++		OUT_BATCH(0);
143.8980 ++		OUT_BATCH(0);
143.8981 ++		OUT_BATCH(1);	/* single instance */
143.8982 ++		OUT_BATCH(0);	/* start instance location */
143.8983 ++		OUT_BATCH(0);	/* index buffer offset, ignored */
143.8984 ++	}
143.8985 ++
143.8986 ++	/* The VUE layout
143.8987 ++	 *    dword 0-3: pad (0.0, 0.0, 0.0. 0.0)
143.8988 ++	 *    dword 4-7: position (x, y, 1.0, 1.0),
143.8989 ++	 *    dword 8-11: texture coordinate 0 (u0, v0, w0, 1.0)
143.8990 ++	 *    dword 12-15: texture coordinate 1 (u1, v1, w1, 1.0)
143.8991 ++	 *
143.8992 ++	 * dword 4-15 are fetched from vertex buffer
143.8993 ++	 */
143.8994 ++	has_mask = (id >> 2) != 0;
143.8995 ++	OUT_BATCH(GEN9_3DSTATE_VERTEX_ELEMENTS |
143.8996 ++		((2 * (3 + has_mask)) + 1 - 2));
143.8997 ++
143.8998 ++	OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
143.8999 ++		  SURFACEFORMAT_R32G32B32A32_FLOAT << VE_FORMAT_SHIFT |
143.9000 ++		  0 << VE_OFFSET_SHIFT);
143.9001 ++	OUT_BATCH(COMPONENT_STORE_0 << VE_COMPONENT_0_SHIFT |
143.9002 ++		  COMPONENT_STORE_0 << VE_COMPONENT_1_SHIFT |
143.9003 ++		  COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT |
143.9004 ++		  COMPONENT_STORE_0 << VE_COMPONENT_3_SHIFT);
143.9005 ++
143.9006 ++	/* x,y */
143.9007 ++	OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
143.9008 ++		  SURFACEFORMAT_R16G16_SSCALED << VE_FORMAT_SHIFT |
143.9009 ++		  0 << VE_OFFSET_SHIFT);
143.9010 ++	OUT_BATCH(COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT |
143.9011 ++		  COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT |
143.9012 ++		  COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT |
143.9013 ++		  COMPONENT_STORE_1_FLT << VE_COMPONENT_3_SHIFT);
143.9014 ++
143.9015 ++	/* u0, v0, w0 */
143.9016 ++	DBG(("%s: first channel %d floats, offset=4\n", __FUNCTION__, id & 3));
143.9017 ++	dw = COMPONENT_STORE_1_FLT << VE_COMPONENT_3_SHIFT;
143.9018 ++	switch (id & 3) {
143.9019 ++	default:
143.9020 ++		assert(0);
143.9021 ++	case 0:
143.9022 ++		src_format = SURFACEFORMAT_R16G16_SSCALED;
143.9023 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
143.9024 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
143.9025 ++		dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
143.9026 ++		break;
143.9027 ++	case 1:
143.9028 ++		src_format = SURFACEFORMAT_R32_FLOAT;
143.9029 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
143.9030 ++		dw |= COMPONENT_STORE_0 << VE_COMPONENT_1_SHIFT;
143.9031 ++		dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
143.9032 ++		break;
143.9033 ++	case 2:
143.9034 ++		src_format = SURFACEFORMAT_R32G32_FLOAT;
143.9035 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
143.9036 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
143.9037 ++		dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
143.9038 ++		break;
143.9039 ++	case 3:
143.9040 ++		src_format = SURFACEFORMAT_R32G32B32_FLOAT;
143.9041 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
143.9042 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
143.9043 ++		dw |= COMPONENT_STORE_SRC << VE_COMPONENT_2_SHIFT;
143.9044 ++		break;
143.9045 ++	}
143.9046 ++	OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
143.9047 ++		  src_format << VE_FORMAT_SHIFT |
143.9048 ++		  4 << VE_OFFSET_SHIFT);
143.9049 ++	OUT_BATCH(dw);
143.9050 ++
143.9051 ++	/* u1, v1, w1 */
143.9052 ++	if (has_mask) {
143.9053 ++		unsigned offset = 4 + ((id & 3) ?: 1) * sizeof(float);
143.9054 ++		DBG(("%s: second channel %d floats, offset=%d\n", __FUNCTION__, (id >> 2) & 3, offset));
143.9055 ++		dw = COMPONENT_STORE_1_FLT << VE_COMPONENT_3_SHIFT;
143.9056 ++		switch (id >> 2) {
143.9057 ++		case 1:
143.9058 ++			src_format = SURFACEFORMAT_R32_FLOAT;
143.9059 ++			dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
143.9060 ++			dw |= COMPONENT_STORE_0 << VE_COMPONENT_1_SHIFT;
143.9061 ++			dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
143.9062 ++			break;
143.9063 ++		default:
143.9064 ++			assert(0);
143.9065 ++		case 2:
143.9066 ++			src_format = SURFACEFORMAT_R32G32_FLOAT;
143.9067 ++			dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
143.9068 ++			dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
143.9069 ++			dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
143.9070 ++			break;
143.9071 ++		case 3:
143.9072 ++			src_format = SURFACEFORMAT_R32G32B32_FLOAT;
143.9073 ++			dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
143.9074 ++			dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
143.9075 ++			dw |= COMPONENT_STORE_SRC << VE_COMPONENT_2_SHIFT;
143.9076 ++			break;
143.9077 ++		}
143.9078 ++		OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
143.9079 ++			  src_format << VE_FORMAT_SHIFT |
143.9080 ++			  offset << VE_OFFSET_SHIFT);
143.9081 ++		OUT_BATCH(dw);
143.9082 ++	}
143.9083 ++
143.9084 ++	render->ve_dirty = true;
143.9085 ++}
143.9086 ++
143.9087 ++inline static void
143.9088 ++gen9_emit_pipe_invalidate(struct sna *sna)
143.9089 ++{
143.9090 ++	OUT_BATCH(GEN9_PIPE_CONTROL | (6 - 2));
143.9091 ++	OUT_BATCH(PIPE_CONTROL_WC_FLUSH |
143.9092 ++		  PIPE_CONTROL_TC_FLUSH |
143.9093 ++		  PIPE_CONTROL_CS_STALL);
143.9094 ++	OUT_BATCH64(0);
143.9095 ++	OUT_BATCH64(0);
143.9096 ++}
143.9097 ++
143.9098 ++inline static void
143.9099 ++gen9_emit_pipe_flush(struct sna *sna, bool need_stall)
143.9100 ++{
143.9101 ++	unsigned stall;
143.9102 ++
143.9103 ++	stall = 0;
143.9104 ++	if (need_stall)
143.9105 ++		stall = (PIPE_CONTROL_CS_STALL |
143.9106 ++			 PIPE_CONTROL_STALL_AT_SCOREBOARD);
143.9107 ++
143.9108 ++	OUT_BATCH(GEN9_PIPE_CONTROL | (6 - 2));
143.9109 ++	OUT_BATCH(PIPE_CONTROL_WC_FLUSH | stall);
143.9110 ++	OUT_BATCH64(0);
143.9111 ++	OUT_BATCH64(0);
143.9112 ++}
143.9113 ++
143.9114 ++inline static void
143.9115 ++gen9_emit_pipe_stall(struct sna *sna)
143.9116 ++{
143.9117 ++	OUT_BATCH(GEN9_PIPE_CONTROL | (6 - 2));
143.9118 ++	OUT_BATCH(PIPE_CONTROL_CS_STALL |
143.9119 ++		  PIPE_CONTROL_FLUSH |
143.9120 ++		  PIPE_CONTROL_STALL_AT_SCOREBOARD);
143.9121 ++	OUT_BATCH64(0);
143.9122 ++	OUT_BATCH64(0);
143.9123 ++}
143.9124 ++
143.9125 ++static void
143.9126 ++gen9_emit_state(struct sna *sna,
143.9127 ++		const struct sna_composite_op *op,
143.9128 ++		uint16_t wm_binding_table)
143.9129 ++{
143.9130 ++	bool need_invalidate;
143.9131 ++	bool need_flush;
143.9132 ++	bool need_stall;
143.9133 ++
143.9134 ++	assert(op->dst.bo->exec);
143.9135 ++
143.9136 ++	need_flush = wm_binding_table & 1 ||
143.9137 ++		(sna->render_state.gen9.emit_flush && GEN9_READS_DST(op->u.gen9.flags));
143.9138 ++	if (ALWAYS_FLUSH)
143.9139 ++		need_flush = true;
143.9140 ++
143.9141 ++	wm_binding_table &= ~1;
143.9142 ++
143.9143 ++	need_stall = sna->render_state.gen9.surface_table != wm_binding_table;
143.9144 ++
143.9145 ++	need_invalidate = kgem_bo_is_dirty(op->src.bo) || kgem_bo_is_dirty(op->mask.bo);
143.9146 ++	if (ALWAYS_INVALIDATE)
143.9147 ++		need_invalidate = true;
143.9148 ++
143.9149 ++	need_stall &= gen9_emit_drawing_rectangle(sna, op);
143.9150 ++	if (ALWAYS_STALL)
143.9151 ++		need_stall = true;
143.9152 ++
143.9153 ++	if (need_invalidate) {
143.9154 ++		gen9_emit_pipe_invalidate(sna);
143.9155 ++		kgem_clear_dirty(&sna->kgem);
143.9156 ++		assert(op->dst.bo->exec);
143.9157 ++		kgem_bo_mark_dirty(op->dst.bo);
143.9158 ++
143.9159 ++		need_flush = false;
143.9160 ++		need_stall = false;
143.9161 ++	}
143.9162 ++	if (need_flush) {
143.9163 ++		gen9_emit_pipe_flush(sna, need_stall);
143.9164 ++		need_stall = false;
143.9165 ++	}
143.9166 ++	if (need_stall)
143.9167 ++		gen9_emit_pipe_stall(sna);
143.9168 ++
143.9169 ++	gen9_emit_cc(sna, GEN9_BLEND(op->u.gen9.flags));
143.9170 ++	gen9_emit_sampler(sna, GEN9_SAMPLER(op->u.gen9.flags));
143.9171 ++	gen9_emit_sf(sna, GEN9_VERTEX(op->u.gen9.flags) >> 2);
143.9172 ++	gen9_emit_wm(sna, GEN9_KERNEL(op->u.gen9.flags));
143.9173 ++	gen9_emit_vertex_elements(sna, op);
143.9174 ++	gen9_emit_binding_table(sna, wm_binding_table);
143.9175 ++
143.9176 ++	sna->render_state.gen9.emit_flush = GEN9_READS_DST(op->u.gen9.flags);
143.9177 ++}
143.9178 ++
143.9179 ++static bool gen9_magic_ca_pass(struct sna *sna,
143.9180 ++			       const struct sna_composite_op *op)
143.9181 ++{
143.9182 ++	struct gen9_render_state *state = &sna->render_state.gen9;
143.9183 ++
143.9184 ++	if (!op->need_magic_ca_pass)
143.9185 ++		return false;
143.9186 ++
143.9187 ++	DBG(("%s: CA fixup (%d -> %d)\n", __FUNCTION__,
143.9188 ++	     sna->render.vertex_start, sna->render.vertex_index));
143.9189 ++
143.9190 ++	gen9_emit_pipe_stall(sna);
143.9191 ++
143.9192 ++	gen9_emit_cc(sna,
143.9193 ++		     GEN9_BLEND(gen9_get_blend(PictOpAdd, true,
143.9194 ++					       op->dst.format)));
143.9195 ++	gen9_emit_wm(sna,
143.9196 ++		     gen9_choose_composite_kernel(PictOpAdd,
143.9197 ++						  true, true,
143.9198 ++						  op->is_affine));
143.9199 ++
143.9200 ++	OUT_BATCH(GEN9_3DPRIMITIVE | (7 - 2));
143.9201 ++	OUT_BATCH(0); /* ignored, see VF_TOPOLOGY */
143.9202 ++	OUT_BATCH(sna->render.vertex_index - sna->render.vertex_start);
143.9203 ++	OUT_BATCH(sna->render.vertex_start);
143.9204 ++	OUT_BATCH(1);	/* single instance */
143.9205 ++	OUT_BATCH(0);	/* start instance location */
143.9206 ++	OUT_BATCH(0);	/* index buffer offset, ignored */
143.9207 ++
143.9208 ++	state->last_primitive = sna->kgem.nbatch;
143.9209 ++	state->ve_dirty = false;
143.9210 ++	return true;
143.9211 ++}
143.9212 ++
143.9213 ++static void null_create(struct sna_static_stream *stream)
143.9214 ++{
143.9215 ++	/* A bunch of zeros useful for legacy border color and depth-stencil */
143.9216 ++	sna_static_stream_map(stream, 64, 64);
143.9217 ++}
143.9218 ++
143.9219 ++static void
143.9220 ++sampler_state_init(struct gen9_sampler_state *sampler_state,
143.9221 ++		   sampler_filter_t filter,
143.9222 ++		   sampler_extend_t extend)
143.9223 ++{
143.9224 ++	COMPILE_TIME_ASSERT(sizeof(*sampler_state) == 4*sizeof(uint32_t));
143.9225 ++
143.9226 ++	sampler_state->ss0.lod_preclamp = 2;	/* GL mode */
143.9227 ++	sampler_state->ss0.default_color_mode = 1;
143.9228 ++
143.9229 ++	switch (filter) {
143.9230 ++	default:
143.9231 ++	case SAMPLER_FILTER_NEAREST:
143.9232 ++		sampler_state->ss0.min_filter = MAPFILTER_NEAREST;
143.9233 ++		sampler_state->ss0.mag_filter = MAPFILTER_NEAREST;
143.9234 ++		break;
143.9235 ++	case SAMPLER_FILTER_BILINEAR:
143.9236 ++		sampler_state->ss0.min_filter = MAPFILTER_LINEAR;
143.9237 ++		sampler_state->ss0.mag_filter = MAPFILTER_LINEAR;
143.9238 ++		break;
143.9239 ++	}
143.9240 ++
143.9241 ++	/* XXX bicubic filter using MAPFILTER_FLEXIBLE */
143.9242 ++
143.9243 ++	switch (extend) {
143.9244 ++	default:
143.9245 ++	case SAMPLER_EXTEND_NONE:
143.9246 ++		sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
143.9247 ++		sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
143.9248 ++		sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
143.9249 ++		break;
143.9250 ++	case SAMPLER_EXTEND_REPEAT:
143.9251 ++		sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_WRAP;
143.9252 ++		sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_WRAP;
143.9253 ++		sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_WRAP;
143.9254 ++		break;
143.9255 ++	case SAMPLER_EXTEND_PAD:
143.9256 ++		sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_CLAMP;
143.9257 ++		sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_CLAMP;
143.9258 ++		sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_CLAMP;
143.9259 ++		break;
143.9260 ++	case SAMPLER_EXTEND_REFLECT:
143.9261 ++		sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_MIRROR;
143.9262 ++		sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_MIRROR;
143.9263 ++		sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_MIRROR;
143.9264 ++		break;
143.9265 ++	}
143.9266 ++}
143.9267 ++
143.9268 ++static void
143.9269 ++sampler_copy_init(struct gen9_sampler_state *ss)
143.9270 ++{
143.9271 ++	sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
143.9272 ++	ss->ss3.non_normalized_coord = 1;
143.9273 ++
143.9274 ++	sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
143.9275 ++}
143.9276 ++
143.9277 ++static void
143.9278 ++sampler_fill_init(struct gen9_sampler_state *ss)
143.9279 ++{
143.9280 ++	sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_REPEAT);
143.9281 ++	ss->ss3.non_normalized_coord = 1;
143.9282 ++
143.9283 ++	sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
143.9284 ++}
143.9285 ++
143.9286 ++static uint32_t
143.9287 ++gen9_tiling_bits(uint32_t tiling)
143.9288 ++{
143.9289 ++	switch (tiling) {
143.9290 ++	default: assert(0);
143.9291 ++	case I915_TILING_NONE: return 0;
143.9292 ++	case I915_TILING_X: return SURFACE_TILED;
143.9293 ++	case I915_TILING_Y: return SURFACE_TILED | SURFACE_TILED_Y;
143.9294 ++	}
143.9295 ++}
143.9296 ++
143.9297 ++#define MOCS_PTE (1 << 1)
143.9298 ++#define MOCS_WB (2 << 1)
143.9299 ++
143.9300 ++/**
143.9301 ++ * Sets up the common fields for a surface state buffer for the given
143.9302 ++ * picture in the given surface state buffer.
143.9303 ++ */
143.9304 ++static uint32_t
143.9305 ++gen9_bind_bo(struct sna *sna,
143.9306 ++	     struct kgem_bo *bo,
143.9307 ++	     uint32_t width,
143.9308 ++	     uint32_t height,
143.9309 ++	     uint32_t format,
143.9310 ++	     bool is_dst)
143.9311 ++{
143.9312 ++	uint32_t *ss;
143.9313 ++	uint32_t domains;
143.9314 ++	int offset;
143.9315 ++	uint32_t is_scanout = is_dst && bo->scanout;
143.9316 ++
143.9317 ++	/* After the first bind, we manage the cache domains within the batch */
143.9318 ++	offset = kgem_bo_get_binding(bo, format | is_dst << 30 | is_scanout << 31);
143.9319 ++	if (offset) {
143.9320 ++		if (is_dst)
143.9321 ++			kgem_bo_mark_dirty(bo);
143.9322 ++		assert(offset >= sna->kgem.surface);
143.9323 ++		return offset * sizeof(uint32_t);
143.9324 ++	}
143.9325 ++
143.9326 ++	offset = sna->kgem.surface -= SURFACE_DW;
143.9327 ++	ss = sna->kgem.batch + offset;
143.9328 ++	ss[0] = (SURFACE_2D << SURFACE_TYPE_SHIFT |
143.9329 ++		 gen9_tiling_bits(bo->tiling) |
143.9330 ++		 format << SURFACE_FORMAT_SHIFT |
143.9331 ++		 SURFACE_VALIGN_4 | SURFACE_HALIGN_4);
143.9332 ++	if (is_dst) {
143.9333 ++		ss[0] |= SURFACE_RC_READ_WRITE;
143.9334 ++		domains = I915_GEM_DOMAIN_RENDER << 16 |I915_GEM_DOMAIN_RENDER;
143.9335 ++	} else
143.9336 ++		domains = I915_GEM_DOMAIN_SAMPLER << 16;
143.9337 ++	ss[1] = (is_scanout || (is_dst && is_uncached(sna, bo))) ? MOCS_PTE << 24 : MOCS_WB << 24;
143.9338 ++	ss[2] = ((width - 1)  << SURFACE_WIDTH_SHIFT |
143.9339 ++		 (height - 1) << SURFACE_HEIGHT_SHIFT);
143.9340 ++	ss[3] = (bo->pitch - 1) << SURFACE_PITCH_SHIFT;
143.9341 ++	ss[4] = 0;
143.9342 ++	ss[5] = 0;
143.9343 ++	ss[6] = 0;
143.9344 ++	ss[7] = SURFACE_SWIZZLE(RED, GREEN, BLUE, ALPHA);
143.9345 ++	*(uint64_t *)(ss+8) = kgem_add_reloc64(&sna->kgem, offset + 8, bo, domains, 0);
143.9346 ++	ss[10] = 0;
143.9347 ++	ss[11] = 0;
143.9348 ++	ss[12] = 0;
143.9349 ++	ss[13] = 0;
143.9350 ++	ss[14] = 0;
143.9351 ++	ss[15] = 0;
143.9352 ++
143.9353 ++	kgem_bo_set_binding(bo, format | is_dst << 30 | is_scanout << 31, offset);
143.9354 ++
143.9355 ++	DBG(("[%x] bind bo(handle=%d, addr=%lx), format=%d, width=%d, height=%d, pitch=%d, tiling=%d -> %s\n",
143.9356 ++	     offset, bo->handle, *(uint64_t *)(ss+8),
143.9357 ++	     format, width, height, bo->pitch, bo->tiling,
143.9358 ++	     domains & 0xffff ? "render" : "sampler"));
143.9359 ++
143.9360 ++	return offset * sizeof(uint32_t);
143.9361 ++}
143.9362 ++
143.9363 ++static void gen9_emit_vertex_buffer(struct sna *sna,
143.9364 ++				    const struct sna_composite_op *op)
143.9365 ++{
143.9366 ++	int id = GEN9_VERTEX(op->u.gen9.flags);
143.9367 ++
143.9368 ++	OUT_BATCH(GEN9_3DSTATE_VERTEX_BUFFERS | (5 - 2));
143.9369 ++	OUT_BATCH(id << VB_INDEX_SHIFT | VB_MODIFY_ENABLE |
143.9370 ++		  4*op->floats_per_vertex);
143.9371 ++	sna->render.vertex_reloc[sna->render.nvertex_reloc++] = sna->kgem.nbatch;
143.9372 ++	OUT_BATCH64(0);
143.9373 ++	OUT_BATCH(~0); /* buffer size: disabled */
143.9374 ++
143.9375 ++	sna->render.vb_id |= 1 << id;
143.9376 ++}
143.9377 ++
143.9378 ++static void gen9_emit_primitive(struct sna *sna)
143.9379 ++{
143.9380 ++	if (sna->kgem.nbatch == sna->render_state.gen9.last_primitive) {
143.9381 ++		sna->render.vertex_offset = sna->kgem.nbatch - 5;
143.9382 ++		return;
143.9383 ++	}
143.9384 ++
143.9385 ++	OUT_BATCH(GEN9_3DPRIMITIVE | (7 - 2));
143.9386 ++	OUT_BATCH(0); /* ignored, see VF_TOPOLOGY */
143.9387 ++	sna->render.vertex_offset = sna->kgem.nbatch;
143.9388 ++	OUT_BATCH(0);	/* vertex count, to be filled in later */
143.9389 ++	OUT_BATCH(sna->render.vertex_index);
143.9390 ++	OUT_BATCH(1);	/* single instance */
143.9391 ++	OUT_BATCH(0);	/* start instance location */
143.9392 ++	OUT_BATCH(0);	/* index buffer offset, ignored */
143.9393 ++	sna->render.vertex_start = sna->render.vertex_index;
143.9394 ++
143.9395 ++	sna->render_state.gen9.last_primitive = sna->kgem.nbatch;
143.9396 ++	sna->render_state.gen9.ve_dirty = false;
143.9397 ++}
143.9398 ++
143.9399 ++static bool gen9_rectangle_begin(struct sna *sna,
143.9400 ++				 const struct sna_composite_op *op)
143.9401 ++{
143.9402 ++	int id = 1 << GEN9_VERTEX(op->u.gen9.flags);
143.9403 ++	int ndwords;
143.9404 ++
143.9405 ++	if (sna_vertex_wait__locked(&sna->render) && sna->render.vertex_offset)
143.9406 ++		return true;
143.9407 ++
143.9408 ++	ndwords = op->need_magic_ca_pass ? 60 : 6;
143.9409 ++	if ((sna->render.vb_id & id) == 0)
143.9410 ++		ndwords += 5;
143.9411 ++	if (!kgem_check_batch(&sna->kgem, ndwords))
143.9412 ++		return false;
143.9413 ++
143.9414 ++	if ((sna->render.vb_id & id) == 0)
143.9415 ++		gen9_emit_vertex_buffer(sna, op);
143.9416 ++
143.9417 ++	gen9_emit_primitive(sna);
143.9418 ++	return true;
143.9419 ++}
143.9420 ++
143.9421 ++static int gen9_get_rectangles__flush(struct sna *sna,
143.9422 ++				      const struct sna_composite_op *op)
143.9423 ++{
143.9424 ++	/* Preventing discarding new vbo after lock contention */
143.9425 ++	if (sna_vertex_wait__locked(&sna->render)) {
143.9426 ++		int rem = vertex_space(sna);
143.9427 ++		if (rem > op->floats_per_rect)
143.9428 ++			return rem;
143.9429 ++	}
143.9430 ++
143.9431 ++	if (!kgem_check_batch(&sna->kgem, op->need_magic_ca_pass ? 65 : 6))
143.9432 ++		return 0;
143.9433 ++	if (!kgem_check_reloc_and_exec(&sna->kgem, 2))
143.9434 ++		return 0;
143.9435 ++
143.9436 ++	if (sna->render.vertex_offset) {
143.9437 ++		gen8_vertex_flush(sna);
143.9438 ++		if (gen9_magic_ca_pass(sna, op)) {
143.9439 ++			gen9_emit_pipe_invalidate(sna);
143.9440 ++			gen9_emit_cc(sna, GEN9_BLEND(op->u.gen9.flags));
143.9441 ++			gen9_emit_wm(sna, GEN9_KERNEL(op->u.gen9.flags));
143.9442 ++		}
143.9443 ++	}
143.9444 ++
143.9445 ++	return gen8_vertex_finish(sna);
143.9446 ++}
143.9447 ++
143.9448 ++inline static int gen9_get_rectangles(struct sna *sna,
143.9449 ++				      const struct sna_composite_op *op,
143.9450 ++				      int want,
143.9451 ++				      void (*emit_state)(struct sna *sna, const struct sna_composite_op *op))
143.9452 ++{
143.9453 ++	int rem;
143.9454 ++
143.9455 ++	assert(want);
143.9456 ++
143.9457 ++start:
143.9458 ++	rem = vertex_space(sna);
143.9459 ++	if (unlikely(rem < op->floats_per_rect)) {
143.9460 ++		DBG(("flushing vbo for %s: %d < %d\n",
143.9461 ++		     __FUNCTION__, rem, op->floats_per_rect));
143.9462 ++		rem = gen9_get_rectangles__flush(sna, op);
143.9463 ++		if (unlikely(rem == 0))
143.9464 ++			goto flush;
143.9465 ++	}
143.9466 ++
143.9467 ++	if (unlikely(sna->render.vertex_offset == 0)) {
143.9468 ++		if (!gen9_rectangle_begin(sna, op))
143.9469 ++			goto flush;
143.9470 ++		else
143.9471 ++			goto start;
143.9472 ++	}
143.9473 ++
143.9474 ++	assert(rem <= vertex_space(sna));
143.9475 ++	assert(op->floats_per_rect <= rem);
143.9476 ++	if (want > 1 && want * op->floats_per_rect > rem)
143.9477 ++		want = rem / op->floats_per_rect;
143.9478 ++
143.9479 ++	assert(want > 0);
143.9480 ++	sna->render.vertex_index += 3*want;
143.9481 ++	return want;
143.9482 ++
143.9483 ++flush:
143.9484 ++	if (sna->render.vertex_offset) {
143.9485 ++		gen8_vertex_flush(sna);
143.9486 ++		gen9_magic_ca_pass(sna, op);
143.9487 ++	}
143.9488 ++	sna_vertex_wait__locked(&sna->render);
143.9489 ++	_kgem_submit(&sna->kgem);
143.9490 ++	emit_state(sna, op);
143.9491 ++	goto start;
143.9492 ++}
143.9493 ++
143.9494 ++inline static uint32_t *gen9_composite_get_binding_table(struct sna *sna,
143.9495 ++							 uint16_t *offset)
143.9496 ++{
143.9497 ++	uint32_t *table;
143.9498 ++
143.9499 ++	assert(sna->kgem.surface <= 16384);
143.9500 ++	sna->kgem.surface -= SURFACE_DW;
143.9501 ++	/* Clear all surplus entries to zero in case of prefetch */
143.9502 ++	table = memset(sna->kgem.batch + sna->kgem.surface, 0, 64);
143.9503 ++
143.9504 ++	DBG(("%s(%x)\n", __FUNCTION__, 4*sna->kgem.surface));
143.9505 ++
143.9506 ++	*offset = sna->kgem.surface;
143.9507 ++	return table;
143.9508 ++}
143.9509 ++
143.9510 ++static void
143.9511 ++gen9_get_batch(struct sna *sna, const struct sna_composite_op *op)
143.9512 ++{
143.9513 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, op->dst.bo);
143.9514 ++
143.9515 ++	if (!kgem_check_batch_with_surfaces(&sna->kgem, 150, 2*(1+3))) {
143.9516 ++		DBG(("%s: flushing batch: %d < %d+%d\n",
143.9517 ++		     __FUNCTION__, sna->kgem.surface - sna->kgem.nbatch,
143.9518 ++		     150, 4*8*2));
143.9519 ++		_kgem_submit(&sna->kgem);
143.9520 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.9521 ++	}
143.9522 ++
143.9523 ++	assert(sna->kgem.mode == KGEM_RENDER);
143.9524 ++	assert(sna->kgem.ring == KGEM_RENDER);
143.9525 ++
143.9526 ++	if (sna->render_state.gen9.needs_invariant)
143.9527 ++		gen9_emit_invariant(sna);
143.9528 ++}
143.9529 ++
143.9530 ++static void gen9_emit_composite_state(struct sna *sna,
143.9531 ++				      const struct sna_composite_op *op)
143.9532 ++{
143.9533 ++	uint32_t *binding_table;
143.9534 ++	uint16_t offset, dirty;
143.9535 ++
143.9536 ++	gen9_get_batch(sna, op);
143.9537 ++
143.9538 ++	binding_table = gen9_composite_get_binding_table(sna, &offset);
143.9539 ++
143.9540 ++	dirty = kgem_bo_is_dirty(op->dst.bo);
143.9541 ++
143.9542 ++	binding_table[0] =
143.9543 ++		gen9_bind_bo(sna,
143.9544 ++			    op->dst.bo, op->dst.width, op->dst.height,
143.9545 ++			    gen9_get_dest_format(op->dst.format),
143.9546 ++			    true);
143.9547 ++	binding_table[1] =
143.9548 ++		gen9_bind_bo(sna,
143.9549 ++			     op->src.bo, op->src.width, op->src.height,
143.9550 ++			     op->src.card_format,
143.9551 ++			     false);
143.9552 ++	if (op->mask.bo) {
143.9553 ++		binding_table[2] =
143.9554 ++			gen9_bind_bo(sna,
143.9555 ++				     op->mask.bo,
143.9556 ++				     op->mask.width,
143.9557 ++				     op->mask.height,
143.9558 ++				     op->mask.card_format,
143.9559 ++				     false);
143.9560 ++	}
143.9561 ++
143.9562 ++	if (sna->kgem.surface == offset &&
143.9563 ++	    *(uint64_t *)(sna->kgem.batch + sna->render_state.gen9.surface_table) == *(uint64_t*)binding_table &&
143.9564 ++	    (op->mask.bo == NULL ||
143.9565 ++	     sna->kgem.batch[sna->render_state.gen9.surface_table+2] == binding_table[2])) {
143.9566 ++		sna->kgem.surface += SURFACE_DW;
143.9567 ++		offset = sna->render_state.gen9.surface_table;
143.9568 ++	}
143.9569 ++
143.9570 ++	if (sna->kgem.batch[sna->render_state.gen9.surface_table] == binding_table[0])
143.9571 ++		dirty = 0;
143.9572 ++
143.9573 ++	gen9_emit_state(sna, op, offset | dirty);
143.9574 ++}
143.9575 ++
143.9576 ++static void
143.9577 ++gen9_align_vertex(struct sna *sna, const struct sna_composite_op *op)
143.9578 ++{
143.9579 ++	if (op->floats_per_vertex != sna->render_state.gen9.floats_per_vertex) {
143.9580 ++		DBG(("aligning vertex: was %d, now %d floats per vertex\n",
143.9581 ++		     sna->render_state.gen9.floats_per_vertex, op->floats_per_vertex));
143.9582 ++		gen8_vertex_align(sna, op);
143.9583 ++		sna->render_state.gen9.floats_per_vertex = op->floats_per_vertex;
143.9584 ++	}
143.9585 ++}
143.9586 ++
143.9587 ++fastcall static void
143.9588 ++gen9_render_composite_blt(struct sna *sna,
143.9589 ++			  const struct sna_composite_op *op,
143.9590 ++			  const struct sna_composite_rectangles *r)
143.9591 ++{
143.9592 ++	gen9_get_rectangles(sna, op, 1, gen9_emit_composite_state);
143.9593 ++	op->prim_emit(sna, op, r);
143.9594 ++}
143.9595 ++
143.9596 ++fastcall static void
143.9597 ++gen9_render_composite_box(struct sna *sna,
143.9598 ++			  const struct sna_composite_op *op,
143.9599 ++			  const BoxRec *box)
143.9600 ++{
143.9601 ++	struct sna_composite_rectangles r;
143.9602 ++
143.9603 ++	gen9_get_rectangles(sna, op, 1, gen9_emit_composite_state);
143.9604 ++
143.9605 ++	DBG(("  %s: (%d, %d), (%d, %d)\n",
143.9606 ++	     __FUNCTION__,
143.9607 ++	     box->x1, box->y1, box->x2, box->y2));
143.9608 ++
143.9609 ++	r.dst.x = box->x1;
143.9610 ++	r.dst.y = box->y1;
143.9611 ++	r.width  = box->x2 - box->x1;
143.9612 ++	r.height = box->y2 - box->y1;
143.9613 ++	r.src = r.mask = r.dst;
143.9614 ++
143.9615 ++	op->prim_emit(sna, op, &r);
143.9616 ++}
143.9617 ++
143.9618 ++static void
143.9619 ++gen9_render_composite_boxes__blt(struct sna *sna,
143.9620 ++				 const struct sna_composite_op *op,
143.9621 ++				 const BoxRec *box, int nbox)
143.9622 ++{
143.9623 ++	DBG(("composite_boxes(%d)\n", nbox));
143.9624 ++
143.9625 ++	do {
143.9626 ++		int nbox_this_time;
143.9627 ++
143.9628 ++		nbox_this_time = gen9_get_rectangles(sna, op, nbox,
143.9629 ++						     gen9_emit_composite_state);
143.9630 ++		nbox -= nbox_this_time;
143.9631 ++
143.9632 ++		do {
143.9633 ++			struct sna_composite_rectangles r;
143.9634 ++
143.9635 ++			DBG(("  %s: (%d, %d), (%d, %d)\n",
143.9636 ++			     __FUNCTION__,
143.9637 ++			     box->x1, box->y1, box->x2, box->y2));
143.9638 ++
143.9639 ++			r.dst.x = box->x1;
143.9640 ++			r.dst.y = box->y1;
143.9641 ++			r.width  = box->x2 - box->x1;
143.9642 ++			r.height = box->y2 - box->y1;
143.9643 ++			r.src = r.mask = r.dst;
143.9644 ++
143.9645 ++			op->prim_emit(sna, op, &r);
143.9646 ++			box++;
143.9647 ++		} while (--nbox_this_time);
143.9648 ++	} while (nbox);
143.9649 ++}
143.9650 ++
143.9651 ++static void
143.9652 ++gen9_render_composite_boxes(struct sna *sna,
143.9653 ++			    const struct sna_composite_op *op,
143.9654 ++			    const BoxRec *box, int nbox)
143.9655 ++{
143.9656 ++	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
143.9657 ++
143.9658 ++	do {
143.9659 ++		int nbox_this_time;
143.9660 ++		float *v;
143.9661 ++
143.9662 ++		nbox_this_time = gen9_get_rectangles(sna, op, nbox,
143.9663 ++						     gen9_emit_composite_state);
143.9664 ++		assert(nbox_this_time);
143.9665 ++		nbox -= nbox_this_time;
143.9666 ++
143.9667 ++		v = sna->render.vertices + sna->render.vertex_used;
143.9668 ++		sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
143.9669 ++
143.9670 ++		op->emit_boxes(op, box, nbox_this_time, v);
143.9671 ++		box += nbox_this_time;
143.9672 ++	} while (nbox);
143.9673 ++}
143.9674 ++
143.9675 ++static void
143.9676 ++gen9_render_composite_boxes__thread(struct sna *sna,
143.9677 ++				    const struct sna_composite_op *op,
143.9678 ++				    const BoxRec *box, int nbox)
143.9679 ++{
143.9680 ++	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
143.9681 ++
143.9682 ++	sna_vertex_lock(&sna->render);
143.9683 ++	do {
143.9684 ++		int nbox_this_time;
143.9685 ++		float *v;
143.9686 ++
143.9687 ++		nbox_this_time = gen9_get_rectangles(sna, op, nbox,
143.9688 ++						     gen9_emit_composite_state);
143.9689 ++		assert(nbox_this_time);
143.9690 ++		nbox -= nbox_this_time;
143.9691 ++
143.9692 ++		v = sna->render.vertices + sna->render.vertex_used;
143.9693 ++		sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
143.9694 ++
143.9695 ++		sna_vertex_acquire__locked(&sna->render);
143.9696 ++		sna_vertex_unlock(&sna->render);
143.9697 ++
143.9698 ++		op->emit_boxes(op, box, nbox_this_time, v);
143.9699 ++		box += nbox_this_time;
143.9700 ++
143.9701 ++		sna_vertex_lock(&sna->render);
143.9702 ++		sna_vertex_release__locked(&sna->render);
143.9703 ++	} while (nbox);
143.9704 ++	sna_vertex_unlock(&sna->render);
143.9705 ++}
143.9706 ++
143.9707 ++static uint32_t
143.9708 ++gen9_create_blend_state(struct sna_static_stream *stream)
143.9709 ++{
143.9710 ++	char *base, *ptr;
143.9711 ++	int src, dst;
143.9712 ++
143.9713 ++	COMPILE_TIME_ASSERT(((GEN9_BLENDFACTOR_COUNT * GEN9_BLENDFACTOR_COUNT << 4) & (1 << 15)) == 0);
143.9714 ++
143.9715 ++	base = sna_static_stream_map(stream,
143.9716 ++				     GEN9_BLENDFACTOR_COUNT * GEN9_BLENDFACTOR_COUNT * GEN9_BLEND_STATE_PADDED_SIZE,
143.9717 ++				     64);
143.9718 ++
143.9719 ++	ptr = base;
143.9720 ++	for (src = 0; src < GEN9_BLENDFACTOR_COUNT; src++) {
143.9721 ++		for (dst = 0; dst < GEN9_BLENDFACTOR_COUNT; dst++) {
143.9722 ++			struct gen9_blend_state *blend =
143.9723 ++				(struct gen9_blend_state *)ptr;
143.9724 ++
143.9725 ++			assert(((ptr - base) & 63) == 0);
143.9726 ++			COMPILE_TIME_ASSERT(sizeof(blend->common) == 4);
143.9727 ++			COMPILE_TIME_ASSERT(sizeof(blend->rt) == 8);
143.9728 ++			COMPILE_TIME_ASSERT((char *)&blend->rt - (char *)blend == 4);
143.9729 ++
143.9730 ++			blend->rt.post_blend_clamp = 1;
143.9731 ++			blend->rt.pre_blend_clamp = 1;
143.9732 ++
143.9733 ++			blend->rt.color_blend =
143.9734 ++				!(dst == BLENDFACTOR_ZERO && src == BLENDFACTOR_ONE);
143.9735 ++			blend->rt.dest_blend_factor = dst;
143.9736 ++			blend->rt.source_blend_factor = src;
143.9737 ++			blend->rt.color_blend_function = BLENDFUNCTION_ADD;
143.9738 ++
143.9739 ++			blend->rt.dest_alpha_blend_factor = dst;
143.9740 ++			blend->rt.source_alpha_blend_factor = src;
143.9741 ++			blend->rt.alpha_blend_function = BLENDFUNCTION_ADD;
143.9742 ++
143.9743 ++			ptr += GEN9_BLEND_STATE_PADDED_SIZE;
143.9744 ++		}
143.9745 ++	}
143.9746 ++
143.9747 ++	return sna_static_stream_offsetof(stream, base);
143.9748 ++}
143.9749 ++
143.9750 ++static int
143.9751 ++gen9_composite_picture(struct sna *sna,
143.9752 ++		       PicturePtr picture,
143.9753 ++		       struct sna_composite_channel *channel,
143.9754 ++		       int x, int y,
143.9755 ++		       int w, int h,
143.9756 ++		       int dst_x, int dst_y,
143.9757 ++		       bool precise)
143.9758 ++{
143.9759 ++	PixmapPtr pixmap;
143.9760 ++	uint32_t color;
143.9761 ++	int16_t dx, dy;
143.9762 ++
143.9763 ++	DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
143.9764 ++	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
143.9765 ++
143.9766 ++	channel->is_solid = false;
143.9767 ++	channel->card_format = -1;
143.9768 ++
143.9769 ++	if (sna_picture_is_solid(picture, &color))
143.9770 ++		return gen4_channel_init_solid(sna, channel, color);
143.9771 ++
143.9772 ++	if (picture->pDrawable == NULL) {
143.9773 ++		int ret;
143.9774 ++
143.9775 ++		if (picture->pSourcePict->type == SourcePictTypeLinear)
143.9776 ++			return gen4_channel_init_linear(sna, picture, channel,
143.9777 ++							x, y,
143.9778 ++							w, h,
143.9779 ++							dst_x, dst_y);
143.9780 ++
143.9781 ++		DBG(("%s -- fixup, gradient\n", __FUNCTION__));
143.9782 ++		ret = -1;
143.9783 ++		if (!precise)
143.9784 ++			ret = sna_render_picture_approximate_gradient(sna, picture, channel,
143.9785 ++								      x, y, w, h, dst_x, dst_y);
143.9786 ++		if (ret == -1)
143.9787 ++			ret = sna_render_picture_fixup(sna, picture, channel,
143.9788 ++						       x, y, w, h, dst_x, dst_y);
143.9789 ++		return ret;
143.9790 ++	}
143.9791 ++
143.9792 ++	if (picture->alphaMap) {
143.9793 ++		DBG(("%s -- fallback, alphamap\n", __FUNCTION__));
143.9794 ++		return sna_render_picture_fixup(sna, picture, channel,
143.9795 ++						x, y, w, h, dst_x, dst_y);
143.9796 ++	}
143.9797 ++
143.9798 ++	if (!gen9_check_repeat(picture))
143.9799 ++		return sna_render_picture_fixup(sna, picture, channel,
143.9800 ++						x, y, w, h, dst_x, dst_y);
143.9801 ++
143.9802 ++	if (!gen9_check_filter(picture))
143.9803 ++		return sna_render_picture_fixup(sna, picture, channel,
143.9804 ++						x, y, w, h, dst_x, dst_y);
143.9805 ++
143.9806 ++	channel->repeat = picture->repeat ? picture->repeatType : RepeatNone;
143.9807 ++	channel->filter = picture->filter;
143.9808 ++
143.9809 ++	pixmap = get_drawable_pixmap(picture->pDrawable);
143.9810 ++	get_drawable_deltas(picture->pDrawable, pixmap, &dx, &dy);
143.9811 ++
143.9812 ++	x += dx + picture->pDrawable->x;
143.9813 ++	y += dy + picture->pDrawable->y;
143.9814 ++
143.9815 ++	channel->is_affine = sna_transform_is_affine(picture->transform);
143.9816 ++	if (sna_transform_is_imprecise_integer_translation(picture->transform, picture->filter, precise, &dx, &dy)) {
143.9817 ++		DBG(("%s: integer translation (%d, %d), removing\n",
143.9818 ++		     __FUNCTION__, dx, dy));
143.9819 ++		x += dx;
143.9820 ++		y += dy;
143.9821 ++		channel->transform = NULL;
143.9822 ++		channel->filter = PictFilterNearest;
143.9823 ++
143.9824 ++		if (channel->repeat ||
143.9825 ++		    (x >= 0 &&
143.9826 ++		     y >= 0 &&
143.9827 ++		     x + w <= pixmap->drawable.width &&
143.9828 ++		     y + h <= pixmap->drawable.height)) {
143.9829 ++			struct sna_pixmap *priv = sna_pixmap(pixmap);
143.9830 ++			if (priv && priv->clear) {
143.9831 ++				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
143.9832 ++				return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
143.9833 ++			}
143.9834 ++		}
143.9835 ++	} else
143.9836 ++		channel->transform = picture->transform;
143.9837 ++
143.9838 ++	channel->pict_format = picture->format;
143.9839 ++	channel->card_format = gen9_get_card_format(picture->format);
143.9840 ++	if (channel->card_format == (unsigned)-1)
143.9841 ++		return sna_render_picture_convert(sna, picture, channel, pixmap,
143.9842 ++						  x, y, w, h, dst_x, dst_y,
143.9843 ++						  false);
143.9844 ++
143.9845 ++	if (too_large(pixmap->drawable.width, pixmap->drawable.height)) {
143.9846 ++		DBG(("%s: extracting from pixmap %dx%d\n", __FUNCTION__,
143.9847 ++		     pixmap->drawable.width, pixmap->drawable.height));
143.9848 ++		return sna_render_picture_extract(sna, picture, channel,
143.9849 ++						  x, y, w, h, dst_x, dst_y);
143.9850 ++	}
143.9851 ++
143.9852 ++	return sna_render_pixmap_bo(sna, channel, pixmap,
143.9853 ++				    x, y, w, h, dst_x, dst_y);
143.9854 ++}
143.9855 ++
143.9856 ++inline static bool gen9_composite_channel_convert(struct sna_composite_channel *channel)
143.9857 ++{
143.9858 ++	if (unaligned(channel->bo, PICT_FORMAT_BPP(channel->pict_format)))
143.9859 ++		return false;
143.9860 ++
143.9861 ++	channel->repeat = gen9_repeat(channel->repeat);
143.9862 ++	channel->filter = gen9_filter(channel->filter);
143.9863 ++	if (channel->card_format == (unsigned)-1)
143.9864 ++		channel->card_format = gen9_get_card_format(channel->pict_format);
143.9865 ++	assert(channel->card_format != (unsigned)-1);
143.9866 ++
143.9867 ++	return true;
143.9868 ++}
143.9869 ++
143.9870 ++static void gen9_render_composite_done(struct sna *sna,
143.9871 ++				       const struct sna_composite_op *op)
143.9872 ++{
143.9873 ++	if (sna->render.vertex_offset) {
143.9874 ++		gen8_vertex_flush(sna);
143.9875 ++		gen9_magic_ca_pass(sna, op);
143.9876 ++	}
143.9877 ++
143.9878 ++	if (op->mask.bo)
143.9879 ++		kgem_bo_destroy(&sna->kgem, op->mask.bo);
143.9880 ++	if (op->src.bo)
143.9881 ++		kgem_bo_destroy(&sna->kgem, op->src.bo);
143.9882 ++
143.9883 ++	sna_render_composite_redirect_done(sna, op);
143.9884 ++}
143.9885 ++
143.9886 ++inline static bool
143.9887 ++gen9_composite_set_target(struct sna *sna,
143.9888 ++			  struct sna_composite_op *op,
143.9889 ++			  PicturePtr dst,
143.9890 ++			  int x, int y, int w, int h,
143.9891 ++			  bool partial)
143.9892 ++{
143.9893 ++	BoxRec box;
143.9894 ++	unsigned int hint;
143.9895 ++
143.9896 ++	DBG(("%s: (%d, %d)x(%d, %d), partial?=%d\n", __FUNCTION__, x, y, w, h, partial));
143.9897 ++
143.9898 ++	op->dst.pixmap = get_drawable_pixmap(dst->pDrawable);
143.9899 ++	op->dst.format = dst->format;
143.9900 ++	op->dst.width  = op->dst.pixmap->drawable.width;
143.9901 ++	op->dst.height = op->dst.pixmap->drawable.height;
143.9902 ++
143.9903 ++	if (w | h) {
143.9904 ++		assert(w && h);
143.9905 ++		box.x1 = x;
143.9906 ++		box.y1 = y;
143.9907 ++		box.x2 = x + w;
143.9908 ++		box.y2 = y + h;
143.9909 ++	} else
143.9910 ++		sna_render_picture_extents(dst, &box);
143.9911 ++
143.9912 ++	hint = PREFER_GPU | RENDER_GPU;
143.9913 ++	if (!need_tiling(sna, op->dst.width, op->dst.height))
143.9914 ++		hint |= FORCE_GPU;
143.9915 ++	if (!partial) {
143.9916 ++		hint |= IGNORE_DAMAGE;
143.9917 ++		if (w == op->dst.width && h == op->dst.height)
143.9918 ++			hint |= REPLACES;
143.9919 ++	}
143.9920 ++
143.9921 ++	op->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint, &box, &op->damage);
143.9922 ++	if (op->dst.bo == NULL)
143.9923 ++		return false;
143.9924 ++
143.9925 ++	assert(!op->damage || !DAMAGE_IS_ALL(*op->damage));
143.9926 ++
143.9927 ++	if (unaligned(op->dst.bo, dst->pDrawable->bitsPerPixel))
143.9928 ++		return false;
143.9929 ++
143.9930 ++	if (hint & REPLACES) {
143.9931 ++		struct sna_pixmap *priv = sna_pixmap(op->dst.pixmap);
143.9932 ++		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
143.9933 ++	}
143.9934 ++
143.9935 ++	get_drawable_deltas(dst->pDrawable, op->dst.pixmap,
143.9936 ++			    &op->dst.x, &op->dst.y);
143.9937 ++
143.9938 ++	DBG(("%s: pixmap=%ld, format=%08x, size=%dx%d, pitch=%d, delta=(%d,%d),damage=%p\n",
143.9939 ++	     __FUNCTION__,
143.9940 ++	     op->dst.pixmap->drawable.serialNumber, (int)op->dst.format,
143.9941 ++	     op->dst.width, op->dst.height,
143.9942 ++	     op->dst.bo->pitch,
143.9943 ++	     op->dst.x, op->dst.y,
143.9944 ++	     op->damage ? *op->damage : (void *)-1));
143.9945 ++
143.9946 ++	assert(op->dst.bo->proxy == NULL);
143.9947 ++
143.9948 ++	if (too_large(op->dst.width, op->dst.height) &&
143.9949 ++	    !sna_render_composite_redirect(sna, op, x, y, w, h, partial))
143.9950 ++		return false;
143.9951 ++
143.9952 ++	return true;
143.9953 ++}
143.9954 ++
143.9955 ++static bool
143.9956 ++try_blt(struct sna *sna,
143.9957 ++	uint8_t op,
143.9958 ++	PicturePtr src,
143.9959 ++	PicturePtr mask,
143.9960 ++	PicturePtr dst,
143.9961 ++	int16_t src_x, int16_t src_y,
143.9962 ++	int16_t msk_x, int16_t msk_y,
143.9963 ++	int16_t dst_x, int16_t dst_y,
143.9964 ++	int16_t width, int16_t height,
143.9965 ++	unsigned flags,
143.9966 ++	struct sna_composite_op *tmp)
143.9967 ++{
143.9968 ++	struct kgem_bo *bo;
143.9969 ++
143.9970 ++	if (sna->kgem.mode == KGEM_BLT) {
143.9971 ++		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.9972 ++		goto execute;
143.9973 ++	}
143.9974 ++
143.9975 ++	if (too_large(width, height)) {
143.9976 ++		DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
143.9977 ++		     __FUNCTION__, width, height));
143.9978 ++		goto execute;
143.9979 ++	}
143.9980 ++
143.9981 ++	bo = __sna_drawable_peek_bo(dst->pDrawable);
143.9982 ++	if (bo == NULL)
143.9983 ++		goto execute;
143.9984 ++
143.9985 ++	if (untiled_tlb_miss(bo))
143.9986 ++		goto execute;
143.9987 ++
143.9988 ++	if (bo->rq) {
143.9989 ++		if (RQ_IS_BLT(bo->rq))
143.9990 ++			goto execute;
143.9991 ++
143.9992 ++		return false;
143.9993 ++	}
143.9994 ++
143.9995 ++	if (bo->tiling == I915_TILING_Y)
143.9996 ++		goto upload;
143.9997 ++
143.9998 ++	if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
143.9999 ++		goto execute;
143.10000 ++
143.10001 ++	if (src->pDrawable == dst->pDrawable &&
143.10002 ++	    (sna->render_state.gt < 3 || width*height < 1024) &&
143.10003 ++	    can_switch_to_blt(sna, bo, 0))
143.10004 ++		goto execute;
143.10005 ++
143.10006 ++	if (src->pDrawable) {
143.10007 ++		struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
143.10008 ++		if (s == NULL)
143.10009 ++			goto upload;
143.10010 ++
143.10011 ++		if (prefer_blt_bo(sna, s, bo))
143.10012 ++			goto execute;
143.10013 ++	}
143.10014 ++
143.10015 ++	if (sna->kgem.ring == KGEM_BLT) {
143.10016 ++		DBG(("%s: already performing BLT\n", __FUNCTION__));
143.10017 ++		goto execute;
143.10018 ++	}
143.10019 ++
143.10020 ++upload:
143.10021 ++	flags |= COMPOSITE_UPLOAD;
143.10022 ++execute:
143.10023 ++	return sna_blt_composite(sna, op,
143.10024 ++				 src, dst,
143.10025 ++				 src_x, src_y,
143.10026 ++				 dst_x, dst_y,
143.10027 ++				 width, height,
143.10028 ++				 flags, tmp);
143.10029 ++}
143.10030 ++
143.10031 ++static bool
143.10032 ++check_gradient(PicturePtr picture, bool precise)
143.10033 ++{
143.10034 ++	if (picture->pDrawable)
143.10035 ++		return false;
143.10036 ++
143.10037 ++	switch (picture->pSourcePict->type) {
143.10038 ++	case SourcePictTypeSolidFill:
143.10039 ++	case SourcePictTypeLinear:
143.10040 ++		return false;
143.10041 ++	default:
143.10042 ++		return precise;
143.10043 ++	}
143.10044 ++}
143.10045 ++
143.10046 ++static bool
143.10047 ++has_alphamap(PicturePtr p)
143.10048 ++{
143.10049 ++	return p->alphaMap != NULL;
143.10050 ++}
143.10051 ++
143.10052 ++static bool
143.10053 ++need_upload(PicturePtr p)
143.10054 ++{
143.10055 ++	return p->pDrawable && unattached(p->pDrawable) && untransformed(p);
143.10056 ++}
143.10057 ++
143.10058 ++static bool
143.10059 ++source_is_busy(PixmapPtr pixmap)
143.10060 ++{
143.10061 ++	struct sna_pixmap *priv = sna_pixmap(pixmap);
143.10062 ++	if (priv == NULL || priv->clear)
143.10063 ++		return false;
143.10064 ++
143.10065 ++	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo))
143.10066 ++		return true;
143.10067 ++
143.10068 ++	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
143.10069 ++		return true;
143.10070 ++
143.10071 ++	return priv->gpu_damage && !priv->cpu_damage;
143.10072 ++}
143.10073 ++
143.10074 ++static bool
143.10075 ++source_fallback(PicturePtr p, PixmapPtr pixmap, bool precise)
143.10076 ++{
143.10077 ++	if (sna_picture_is_solid(p, NULL))
143.10078 ++		return false;
143.10079 ++
143.10080 ++	if (p->pSourcePict)
143.10081 ++		return check_gradient(p, precise);
143.10082 ++
143.10083 ++	if (!gen9_check_repeat(p) || !gen9_check_format(p->format))
143.10084 ++		return true;
143.10085 ++
143.10086 ++	if (pixmap && source_is_busy(pixmap))
143.10087 ++		return false;
143.10088 ++
143.10089 ++	return has_alphamap(p) || !gen9_check_filter(p) || need_upload(p);
143.10090 ++}
143.10091 ++
143.10092 ++static bool
143.10093 ++gen9_composite_fallback(struct sna *sna,
143.10094 ++			PicturePtr src,
143.10095 ++			PicturePtr mask,
143.10096 ++			PicturePtr dst)
143.10097 ++{
143.10098 ++	PixmapPtr src_pixmap;
143.10099 ++	PixmapPtr mask_pixmap;
143.10100 ++	PixmapPtr dst_pixmap;
143.10101 ++	bool src_fallback, mask_fallback;
143.10102 ++
143.10103 ++	if (!gen9_check_dst_format(dst->format)) {
143.10104 ++		DBG(("%s: unknown destination format: %d\n",
143.10105 ++		     __FUNCTION__, dst->format));
143.10106 ++		return true;
143.10107 ++	}
143.10108 ++
143.10109 ++	dst_pixmap = get_drawable_pixmap(dst->pDrawable);
143.10110 ++
143.10111 ++	src_pixmap = src->pDrawable ? get_drawable_pixmap(src->pDrawable) : NULL;
143.10112 ++	src_fallback = source_fallback(src, src_pixmap,
143.10113 ++				       dst->polyMode == PolyModePrecise);
143.10114 ++
143.10115 ++	if (mask) {
143.10116 ++		mask_pixmap = mask->pDrawable ? get_drawable_pixmap(mask->pDrawable) : NULL;
143.10117 ++		mask_fallback = source_fallback(mask, mask_pixmap,
143.10118 ++						dst->polyMode == PolyModePrecise);
143.10119 ++	} else {
143.10120 ++		mask_pixmap = NULL;
143.10121 ++		mask_fallback = false;
143.10122 ++	}
143.10123 ++
143.10124 ++	/* If we are using the destination as a source and need to
143.10125 ++	 * readback in order to upload the source, do it all
143.10126 ++	 * on the cpu.
143.10127 ++	 */
143.10128 ++	if (src_pixmap == dst_pixmap && src_fallback) {
143.10129 ++		DBG(("%s: src is dst and will fallback\n",__FUNCTION__));
143.10130 ++		return true;
143.10131 ++	}
143.10132 ++	if (mask_pixmap == dst_pixmap && mask_fallback) {
143.10133 ++		DBG(("%s: mask is dst and will fallback\n",__FUNCTION__));
143.10134 ++		return true;
143.10135 ++	}
143.10136 ++
143.10137 ++	/* If anything is on the GPU, push everything out to the GPU */
143.10138 ++	if (dst_use_gpu(dst_pixmap)) {
143.10139 ++		DBG(("%s: dst is already on the GPU, try to use GPU\n",
143.10140 ++		     __FUNCTION__));
143.10141 ++		return false;
143.10142 ++	}
143.10143 ++
143.10144 ++	if (src_pixmap && !src_fallback) {
143.10145 ++		DBG(("%s: src is already on the GPU, try to use GPU\n",
143.10146 ++		     __FUNCTION__));
143.10147 ++		return false;
143.10148 ++	}
143.10149 ++	if (mask_pixmap && !mask_fallback) {
143.10150 ++		DBG(("%s: mask is already on the GPU, try to use GPU\n",
143.10151 ++		     __FUNCTION__));
143.10152 ++		return false;
143.10153 ++	}
143.10154 ++
143.10155 ++	/* However if the dst is not on the GPU and we need to
143.10156 ++	 * render one of the sources using the CPU, we may
143.10157 ++	 * as well do the entire operation in place onthe CPU.
143.10158 ++	 */
143.10159 ++	if (src_fallback) {
143.10160 ++		DBG(("%s: dst is on the CPU and src will fallback\n",
143.10161 ++		     __FUNCTION__));
143.10162 ++		return true;
143.10163 ++	}
143.10164 ++
143.10165 ++	if (mask && mask_fallback) {
143.10166 ++		DBG(("%s: dst is on the CPU and mask will fallback\n",
143.10167 ++		     __FUNCTION__));
143.10168 ++		return true;
143.10169 ++	}
143.10170 ++
143.10171 ++	if (too_large(dst_pixmap->drawable.width,
143.10172 ++		      dst_pixmap->drawable.height) &&
143.10173 ++	    dst_is_cpu(dst_pixmap)) {
143.10174 ++		DBG(("%s: dst is on the CPU and too large\n", __FUNCTION__));
143.10175 ++		return true;
143.10176 ++	}
143.10177 ++
143.10178 ++	DBG(("%s: dst is not on the GPU and the operation should not fallback\n",
143.10179 ++	     __FUNCTION__));
143.10180 ++	return dst_use_cpu(dst_pixmap);
143.10181 ++}
143.10182 ++
143.10183 ++static int
143.10184 ++reuse_source(struct sna *sna,
143.10185 ++	     PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y,
143.10186 ++	     PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y)
143.10187 ++{
143.10188 ++	uint32_t color;
143.10189 ++
143.10190 ++	if (src_x != msk_x || src_y != msk_y)
143.10191 ++		return false;
143.10192 ++
143.10193 ++	if (src == mask) {
143.10194 ++		DBG(("%s: mask is source\n", __FUNCTION__));
143.10195 ++		*mc = *sc;
143.10196 ++		mc->bo = kgem_bo_reference(mc->bo);
143.10197 ++		return true;
143.10198 ++	}
143.10199 ++
143.10200 ++	if (sna_picture_is_solid(mask, &color))
143.10201 ++		return gen4_channel_init_solid(sna, mc, color);
143.10202 ++
143.10203 ++	if (sc->is_solid)
143.10204 ++		return false;
143.10205 ++
143.10206 ++	if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable)
143.10207 ++		return false;
143.10208 ++
143.10209 ++	DBG(("%s: mask reuses source drawable\n", __FUNCTION__));
143.10210 ++
143.10211 ++	if (!sna_transform_equal(src->transform, mask->transform))
143.10212 ++		return false;
143.10213 ++
143.10214 ++	if (!sna_picture_alphamap_equal(src, mask))
143.10215 ++		return false;
143.10216 ++
143.10217 ++	if (!gen9_check_repeat(mask))
143.10218 ++		return false;
143.10219 ++
143.10220 ++	if (!gen9_check_filter(mask))
143.10221 ++		return false;
143.10222 ++
143.10223 ++	if (!gen9_check_format(mask->format))
143.10224 ++		return false;
143.10225 ++
143.10226 ++	DBG(("%s: reusing source channel for mask with a twist\n",
143.10227 ++	     __FUNCTION__));
143.10228 ++
143.10229 ++	*mc = *sc;
143.10230 ++	mc->repeat = gen9_repeat(mask->repeat ? mask->repeatType : RepeatNone);
143.10231 ++	mc->filter = gen9_filter(mask->filter);
143.10232 ++	mc->pict_format = mask->format;
143.10233 ++	mc->card_format = gen9_get_card_format(mask->format);
143.10234 ++	mc->bo = kgem_bo_reference(mc->bo);
143.10235 ++	return true;
143.10236 ++}
143.10237 ++
143.10238 ++static bool
143.10239 ++gen9_render_composite(struct sna *sna,
143.10240 ++		      uint8_t op,
143.10241 ++		      PicturePtr src,
143.10242 ++		      PicturePtr mask,
143.10243 ++		      PicturePtr dst,
143.10244 ++		      int16_t src_x, int16_t src_y,
143.10245 ++		      int16_t msk_x, int16_t msk_y,
143.10246 ++		      int16_t dst_x, int16_t dst_y,
143.10247 ++		      int16_t width, int16_t height,
143.10248 ++		      unsigned flags,
143.10249 ++		      struct sna_composite_op *tmp)
143.10250 ++{
143.10251 ++	if (op >= ARRAY_SIZE(gen9_blend_op))
143.10252 ++		return false;
143.10253 ++
143.10254 ++	DBG(("%s: %dx%d, current mode=%d/%d\n", __FUNCTION__,
143.10255 ++	     width, height, sna->kgem.mode, sna->kgem.ring));
143.10256 ++
143.10257 ++	if (mask == NULL &&
143.10258 ++	    try_blt(sna, op,
143.10259 ++		    src, mask, dst,
143.10260 ++		    src_x, src_y,
143.10261 ++		    msk_x, msk_y,
143.10262 ++		    dst_x, dst_y,
143.10263 ++		    width, height,
143.10264 ++		    flags, tmp))
143.10265 ++		return true;
143.10266 ++
143.10267 ++	if (gen9_composite_fallback(sna, src, mask, dst))
143.10268 ++		goto fallback;
143.10269 ++
143.10270 ++	if (need_tiling(sna, width, height))
143.10271 ++		return sna_tiling_composite(op, src, mask, dst,
143.10272 ++					    src_x, src_y,
143.10273 ++					    msk_x, msk_y,
143.10274 ++					    dst_x, dst_y,
143.10275 ++					    width, height,
143.10276 ++					    tmp);
143.10277 ++
143.10278 ++	if (op == PictOpClear && src == sna->clear)
143.10279 ++		op = PictOpSrc;
143.10280 ++	tmp->op = op;
143.10281 ++	if (!gen9_composite_set_target(sna, tmp, dst,
143.10282 ++				       dst_x, dst_y, width, height,
143.10283 ++				       flags & COMPOSITE_PARTIAL || op > PictOpSrc))
143.10284 ++		goto fallback;
143.10285 ++
143.10286 ++	switch (gen9_composite_picture(sna, src, &tmp->src,
143.10287 ++				       src_x, src_y,
143.10288 ++				       width, height,
143.10289 ++				       dst_x, dst_y,
143.10290 ++				       dst->polyMode == PolyModePrecise)) {
143.10291 ++	case -1:
143.10292 ++		goto cleanup_dst;
143.10293 ++	case 0:
143.10294 ++		if (!gen4_channel_init_solid(sna, &tmp->src, 0))
143.10295 ++			goto cleanup_dst;
143.10296 ++		/* fall through to fixup */
143.10297 ++	case 1:
143.10298 ++		/* Did we just switch rings to prepare the source? */
143.10299 ++		if (mask == NULL &&
143.10300 ++		    (prefer_blt_composite(sna, tmp) ||
143.10301 ++		     unaligned(tmp->src.bo, PICT_FORMAT_BPP(tmp->src.pict_format))) &&
143.10302 ++		    sna_blt_composite__convert(sna,
143.10303 ++					       dst_x, dst_y, width, height,
143.10304 ++					       tmp))
143.10305 ++			return true;
143.10306 ++
143.10307 ++		if (!gen9_composite_channel_convert(&tmp->src))
143.10308 ++			goto cleanup_src;
143.10309 ++
143.10310 ++		break;
143.10311 ++	}
143.10312 ++
143.10313 ++	tmp->is_affine = tmp->src.is_affine;
143.10314 ++	tmp->has_component_alpha = false;
143.10315 ++	tmp->need_magic_ca_pass = false;
143.10316 ++
143.10317 ++	tmp->mask.bo = NULL;
143.10318 ++	tmp->mask.filter = SAMPLER_FILTER_NEAREST;
143.10319 ++	tmp->mask.repeat = SAMPLER_EXTEND_NONE;
143.10320 ++
143.10321 ++	if (mask) {
143.10322 ++		if (mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) {
143.10323 ++			tmp->has_component_alpha = true;
143.10324 ++
143.10325 ++			/* Check if it's component alpha that relies on a source alpha and on
143.10326 ++			 * the source value.  We can only get one of those into the single
143.10327 ++			 * source value that we get to blend with.
143.10328 ++			 */
143.10329 ++			if (gen9_blend_op[op].src_alpha &&
143.10330 ++			    (gen9_blend_op[op].src_blend != BLENDFACTOR_ZERO)) {
143.10331 ++				if (op != PictOpOver)
143.10332 ++					goto cleanup_src;
143.10333 ++
143.10334 ++				tmp->need_magic_ca_pass = true;
143.10335 ++				tmp->op = PictOpOutReverse;
143.10336 ++			}
143.10337 ++		}
143.10338 ++
143.10339 ++		if (!reuse_source(sna,
143.10340 ++				  src, &tmp->src, src_x, src_y,
143.10341 ++				  mask, &tmp->mask, msk_x, msk_y)) {
143.10342 ++			switch (gen9_composite_picture(sna, mask, &tmp->mask,
143.10343 ++						       msk_x, msk_y,
143.10344 ++						       width, height,
143.10345 ++						       dst_x, dst_y,
143.10346 ++						       dst->polyMode == PolyModePrecise)) {
143.10347 ++			case -1:
143.10348 ++				goto cleanup_src;
143.10349 ++			case 0:
143.10350 ++				if (!gen4_channel_init_solid(sna, &tmp->mask, 0))
143.10351 ++					goto cleanup_src;
143.10352 ++				/* fall through to fixup */
143.10353 ++			case 1:
143.10354 ++				if (!gen9_composite_channel_convert(&tmp->mask))
143.10355 ++					goto cleanup_mask;
143.10356 ++				break;
143.10357 ++			}
143.10358 ++		}
143.10359 ++
143.10360 ++		tmp->is_affine &= tmp->mask.is_affine;
143.10361 ++	}
143.10362 ++
143.10363 ++	tmp->u.gen9.flags =
143.10364 ++		GEN9_SET_FLAGS(SAMPLER_OFFSET(tmp->src.filter,
143.10365 ++					      tmp->src.repeat,
143.10366 ++					      tmp->mask.filter,
143.10367 ++					      tmp->mask.repeat),
143.10368 ++			       gen9_get_blend(tmp->op,
143.10369 ++					      tmp->has_component_alpha,
143.10370 ++					      tmp->dst.format),
143.10371 ++			       gen9_choose_composite_kernel(tmp->op,
143.10372 ++							    tmp->mask.bo != NULL,
143.10373 ++							    tmp->has_component_alpha,
143.10374 ++							    tmp->is_affine),
143.10375 ++			       gen4_choose_composite_emitter(sna, tmp));
143.10376 ++
143.10377 ++	tmp->blt   = gen9_render_composite_blt;
143.10378 ++	tmp->box   = gen9_render_composite_box;
143.10379 ++	tmp->boxes = gen9_render_composite_boxes__blt;
143.10380 ++	if (tmp->emit_boxes){
143.10381 ++		tmp->boxes = gen9_render_composite_boxes;
143.10382 ++		tmp->thread_boxes = gen9_render_composite_boxes__thread;
143.10383 ++	}
143.10384 ++	tmp->done  = gen9_render_composite_done;
143.10385 ++
143.10386 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp->dst.bo);
143.10387 ++	if (!kgem_check_bo(&sna->kgem,
143.10388 ++			   tmp->dst.bo, tmp->src.bo, tmp->mask.bo,
143.10389 ++			   NULL)) {
143.10390 ++		kgem_submit(&sna->kgem);
143.10391 ++		if (!kgem_check_bo(&sna->kgem,
143.10392 ++				   tmp->dst.bo, tmp->src.bo, tmp->mask.bo,
143.10393 ++				   NULL))
143.10394 ++			goto cleanup_mask;
143.10395 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.10396 ++	}
143.10397 ++
143.10398 ++	gen9_align_vertex(sna, tmp);
143.10399 ++	gen9_emit_composite_state(sna, tmp);
143.10400 ++	return true;
143.10401 ++
143.10402 ++cleanup_mask:
143.10403 ++	if (tmp->mask.bo) {
143.10404 ++		kgem_bo_destroy(&sna->kgem, tmp->mask.bo);
143.10405 ++		tmp->mask.bo = NULL;
143.10406 ++	}
143.10407 ++cleanup_src:
143.10408 ++	if (tmp->src.bo) {
143.10409 ++		kgem_bo_destroy(&sna->kgem, tmp->src.bo);
143.10410 ++		tmp->src.bo = NULL;
143.10411 ++	}
143.10412 ++cleanup_dst:
143.10413 ++	if (tmp->redirect.real_bo) {
143.10414 ++		kgem_bo_destroy(&sna->kgem, tmp->dst.bo);
143.10415 ++		tmp->redirect.real_bo = NULL;
143.10416 ++	}
143.10417 ++fallback:
143.10418 ++	return (mask == NULL &&
143.10419 ++		sna_blt_composite(sna, op,
143.10420 ++				  src, dst,
143.10421 ++				  src_x, src_y,
143.10422 ++				  dst_x, dst_y,
143.10423 ++				  width, height,
143.10424 ++				  flags | COMPOSITE_FALLBACK, tmp));
143.10425 ++}
143.10426 ++
143.10427 ++#if !NO_COMPOSITE_SPANS
143.10428 ++fastcall static void
143.10429 ++gen9_render_composite_spans_box(struct sna *sna,
143.10430 ++				const struct sna_composite_spans_op *op,
143.10431 ++				const BoxRec *box, float opacity)
143.10432 ++{
143.10433 ++	DBG(("%s: src=+(%d, %d), opacity=%f, dst=+(%d, %d), box=(%d, %d) x (%d, %d)\n",
143.10434 ++	     __FUNCTION__,
143.10435 ++	     op->base.src.offset[0], op->base.src.offset[1],
143.10436 ++	     opacity,
143.10437 ++	     op->base.dst.x, op->base.dst.y,
143.10438 ++	     box->x1, box->y1,
143.10439 ++	     box->x2 - box->x1,
143.10440 ++	     box->y2 - box->y1));
143.10441 ++
143.10442 ++	gen9_get_rectangles(sna, &op->base, 1, gen9_emit_composite_state);
143.10443 ++	op->prim_emit(sna, op, box, opacity);
143.10444 ++}
143.10445 ++
143.10446 ++static void
143.10447 ++gen9_render_composite_spans_boxes(struct sna *sna,
143.10448 ++				  const struct sna_composite_spans_op *op,
143.10449 ++				  const BoxRec *box, int nbox,
143.10450 ++				  float opacity)
143.10451 ++{
143.10452 ++	DBG(("%s: nbox=%d, src=+(%d, %d), opacity=%f, dst=+(%d, %d)\n",
143.10453 ++	     __FUNCTION__, nbox,
143.10454 ++	     op->base.src.offset[0], op->base.src.offset[1],
143.10455 ++	     opacity,
143.10456 ++	     op->base.dst.x, op->base.dst.y));
143.10457 ++
143.10458 ++	do {
143.10459 ++		int nbox_this_time;
143.10460 ++
143.10461 ++		nbox_this_time = gen9_get_rectangles(sna, &op->base, nbox,
143.10462 ++						     gen9_emit_composite_state);
143.10463 ++		nbox -= nbox_this_time;
143.10464 ++
143.10465 ++		do {
143.10466 ++			DBG(("  %s: (%d, %d) x (%d, %d)\n", __FUNCTION__,
143.10467 ++			     box->x1, box->y1,
143.10468 ++			     box->x2 - box->x1,
143.10469 ++			     box->y2 - box->y1));
143.10470 ++
143.10471 ++			op->prim_emit(sna, op, box++, opacity);
143.10472 ++		} while (--nbox_this_time);
143.10473 ++	} while (nbox);
143.10474 ++}
143.10475 ++
143.10476 ++fastcall static void
143.10477 ++gen9_render_composite_spans_boxes__thread(struct sna *sna,
143.10478 ++					  const struct sna_composite_spans_op *op,
143.10479 ++					  const struct sna_opacity_box *box,
143.10480 ++					  int nbox)
143.10481 ++{
143.10482 ++	DBG(("%s: nbox=%d, src=+(%d, %d), dst=+(%d, %d)\n",
143.10483 ++	     __FUNCTION__, nbox,
143.10484 ++	     op->base.src.offset[0], op->base.src.offset[1],
143.10485 ++	     op->base.dst.x, op->base.dst.y));
143.10486 ++
143.10487 ++	sna_vertex_lock(&sna->render);
143.10488 ++	do {
143.10489 ++		int nbox_this_time;
143.10490 ++		float *v;
143.10491 ++
143.10492 ++		nbox_this_time = gen9_get_rectangles(sna, &op->base, nbox,
143.10493 ++						     gen9_emit_composite_state);
143.10494 ++		assert(nbox_this_time);
143.10495 ++		nbox -= nbox_this_time;
143.10496 ++
143.10497 ++		v = sna->render.vertices + sna->render.vertex_used;
143.10498 ++		sna->render.vertex_used += nbox_this_time * op->base.floats_per_rect;
143.10499 ++
143.10500 ++		sna_vertex_acquire__locked(&sna->render);
143.10501 ++		sna_vertex_unlock(&sna->render);
143.10502 ++
143.10503 ++		op->emit_boxes(op, box, nbox_this_time, v);
143.10504 ++		box += nbox_this_time;
143.10505 ++
143.10506 ++		sna_vertex_lock(&sna->render);
143.10507 ++		sna_vertex_release__locked(&sna->render);
143.10508 ++	} while (nbox);
143.10509 ++	sna_vertex_unlock(&sna->render);
143.10510 ++}
143.10511 ++
143.10512 ++fastcall static void
143.10513 ++gen9_render_composite_spans_done(struct sna *sna,
143.10514 ++				 const struct sna_composite_spans_op *op)
143.10515 ++{
143.10516 ++	if (sna->render.vertex_offset)
143.10517 ++		gen8_vertex_flush(sna);
143.10518 ++
143.10519 ++	DBG(("%s()\n", __FUNCTION__));
143.10520 ++
143.10521 ++	if (op->base.src.bo)
143.10522 ++		kgem_bo_destroy(&sna->kgem, op->base.src.bo);
143.10523 ++
143.10524 ++	sna_render_composite_redirect_done(sna, &op->base);
143.10525 ++}
143.10526 ++
143.10527 ++static bool
143.10528 ++gen9_check_composite_spans(struct sna *sna,
143.10529 ++			   uint8_t op, PicturePtr src, PicturePtr dst,
143.10530 ++			   int16_t width, int16_t height, unsigned flags)
143.10531 ++{
143.10532 ++	if (op >= ARRAY_SIZE(gen9_blend_op))
143.10533 ++		return false;
143.10534 ++
143.10535 ++	if (gen9_composite_fallback(sna, src, NULL, dst))
143.10536 ++		return false;
143.10537 ++
143.10538 ++	if (need_tiling(sna, width, height) &&
143.10539 ++	    !is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) {
143.10540 ++		DBG(("%s: fallback, tiled operation not on GPU\n",
143.10541 ++		     __FUNCTION__));
143.10542 ++		return false;
143.10543 ++	}
143.10544 ++
143.10545 ++	return true;
143.10546 ++}
143.10547 ++
143.10548 ++static bool
143.10549 ++gen9_render_composite_spans(struct sna *sna,
143.10550 ++			    uint8_t op,
143.10551 ++			    PicturePtr src,
143.10552 ++			    PicturePtr dst,
143.10553 ++			    int16_t src_x,  int16_t src_y,
143.10554 ++			    int16_t dst_x,  int16_t dst_y,
143.10555 ++			    int16_t width,  int16_t height,
143.10556 ++			    unsigned flags,
143.10557 ++			    struct sna_composite_spans_op *tmp)
143.10558 ++{
143.10559 ++	DBG(("%s: %dx%d with flags=%x, current mode=%d\n", __FUNCTION__,
143.10560 ++	     width, height, flags, sna->kgem.ring));
143.10561 ++
143.10562 ++	assert(gen9_check_composite_spans(sna, op, src, dst, width, height, flags));
143.10563 ++
143.10564 ++	if (need_tiling(sna, width, height)) {
143.10565 ++		DBG(("%s: tiling, operation (%dx%d) too wide for pipeline\n",
143.10566 ++		     __FUNCTION__, width, height));
143.10567 ++		return sna_tiling_composite_spans(op, src, dst,
143.10568 ++						  src_x, src_y, dst_x, dst_y,
143.10569 ++						  width, height, flags, tmp);
143.10570 ++	}
143.10571 ++
143.10572 ++	tmp->base.op = op;
143.10573 ++	if (!gen9_composite_set_target(sna, &tmp->base, dst,
143.10574 ++				       dst_x, dst_y, width, height, true))
143.10575 ++		return false;
143.10576 ++
143.10577 ++	switch (gen9_composite_picture(sna, src, &tmp->base.src,
143.10578 ++				       src_x, src_y,
143.10579 ++				       width, height,
143.10580 ++				       dst_x, dst_y,
143.10581 ++				       dst->polyMode == PolyModePrecise)) {
143.10582 ++	case -1:
143.10583 ++		goto cleanup_dst;
143.10584 ++	case 0:
143.10585 ++		if (!gen4_channel_init_solid(sna, &tmp->base.src, 0))
143.10586 ++			goto cleanup_dst;
143.10587 ++		/* fall through to fixup */
143.10588 ++	case 1:
143.10589 ++		if (!gen9_composite_channel_convert(&tmp->base.src))
143.10590 ++			goto cleanup_src;
143.10591 ++		break;
143.10592 ++	}
143.10593 ++	tmp->base.mask.bo = NULL;
143.10594 ++
143.10595 ++	tmp->base.is_affine = tmp->base.src.is_affine;
143.10596 ++	tmp->base.need_magic_ca_pass = false;
143.10597 ++
143.10598 ++	tmp->base.u.gen9.flags =
143.10599 ++		GEN9_SET_FLAGS(SAMPLER_OFFSET(tmp->base.src.filter,
143.10600 ++					      tmp->base.src.repeat,
143.10601 ++					      SAMPLER_FILTER_NEAREST,
143.10602 ++					      SAMPLER_EXTEND_PAD),
143.10603 ++			       gen9_get_blend(tmp->base.op, false, tmp->base.dst.format),
143.10604 ++			       GEN9_WM_KERNEL_OPACITY | !tmp->base.is_affine,
143.10605 ++			       gen4_choose_spans_emitter(sna, tmp));
143.10606 ++
143.10607 ++	tmp->box   = gen9_render_composite_spans_box;
143.10608 ++	tmp->boxes = gen9_render_composite_spans_boxes;
143.10609 ++	if (tmp->emit_boxes)
143.10610 ++		tmp->thread_boxes = gen9_render_composite_spans_boxes__thread;
143.10611 ++	tmp->done  = gen9_render_composite_spans_done;
143.10612 ++
143.10613 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp->base.dst.bo);
143.10614 ++	if (!kgem_check_bo(&sna->kgem,
143.10615 ++			   tmp->base.dst.bo, tmp->base.src.bo,
143.10616 ++			   NULL)) {
143.10617 ++		kgem_submit(&sna->kgem);
143.10618 ++		if (!kgem_check_bo(&sna->kgem,
143.10619 ++				   tmp->base.dst.bo, tmp->base.src.bo,
143.10620 ++				   NULL))
143.10621 ++			goto cleanup_src;
143.10622 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.10623 ++	}
143.10624 ++
143.10625 ++	gen9_align_vertex(sna, &tmp->base);
143.10626 ++	gen9_emit_composite_state(sna, &tmp->base);
143.10627 ++	return true;
143.10628 ++
143.10629 ++cleanup_src:
143.10630 ++	if (tmp->base.src.bo)
143.10631 ++		kgem_bo_destroy(&sna->kgem, tmp->base.src.bo);
143.10632 ++cleanup_dst:
143.10633 ++	if (tmp->base.redirect.real_bo)
143.10634 ++		kgem_bo_destroy(&sna->kgem, tmp->base.dst.bo);
143.10635 ++	return false;
143.10636 ++}
143.10637 ++#endif
143.10638 ++
143.10639 ++static void
143.10640 ++gen9_emit_copy_state(struct sna *sna,
143.10641 ++		     const struct sna_composite_op *op)
143.10642 ++{
143.10643 ++	uint32_t *binding_table;
143.10644 ++	uint16_t offset, dirty;
143.10645 ++
143.10646 ++	gen9_get_batch(sna, op);
143.10647 ++
143.10648 ++	binding_table = gen9_composite_get_binding_table(sna, &offset);
143.10649 ++
143.10650 ++	dirty = kgem_bo_is_dirty(op->dst.bo);
143.10651 ++
143.10652 ++	binding_table[0] =
143.10653 ++		gen9_bind_bo(sna,
143.10654 ++			     op->dst.bo, op->dst.width, op->dst.height,
143.10655 ++			     gen9_get_dest_format(op->dst.format),
143.10656 ++			     true);
143.10657 ++	binding_table[1] =
143.10658 ++		gen9_bind_bo(sna,
143.10659 ++			     op->src.bo, op->src.width, op->src.height,
143.10660 ++			     op->src.card_format,
143.10661 ++			     false);
143.10662 ++
143.10663 ++	if (sna->kgem.surface == offset &&
143.10664 ++	    *(uint64_t *)(sna->kgem.batch + sna->render_state.gen9.surface_table) == *(uint64_t*)binding_table) {
143.10665 ++		sna->kgem.surface += SURFACE_DW;
143.10666 ++		offset = sna->render_state.gen9.surface_table;
143.10667 ++	}
143.10668 ++
143.10669 ++	if (sna->kgem.batch[sna->render_state.gen9.surface_table] == binding_table[0])
143.10670 ++		dirty = 0;
143.10671 ++
143.10672 ++	assert(!GEN9_READS_DST(op->u.gen9.flags));
143.10673 ++	gen9_emit_state(sna, op, offset | dirty);
143.10674 ++}
143.10675 ++
143.10676 ++static inline bool
143.10677 ++prefer_blt_copy(struct sna *sna,
143.10678 ++		struct kgem_bo *src_bo,
143.10679 ++		struct kgem_bo *dst_bo,
143.10680 ++		unsigned flags)
143.10681 ++{
143.10682 ++	if (sna->kgem.mode == KGEM_BLT)
143.10683 ++		return true;
143.10684 ++
143.10685 ++	assert((flags & COPY_SYNC) == 0);
143.10686 ++
143.10687 ++	if (untiled_tlb_miss(src_bo) ||
143.10688 ++	    untiled_tlb_miss(dst_bo))
143.10689 ++		return true;
143.10690 ++
143.10691 ++	if (flags & COPY_DRI && !sna->kgem.has_semaphores)
143.10692 ++		return false;
143.10693 ++
143.10694 ++	if (force_blt_ring(sna, dst_bo))
143.10695 ++		return true;
143.10696 ++
143.10697 ++	if ((flags & COPY_SMALL ||
143.10698 ++	     (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
143.10699 ++	    can_switch_to_blt(sna, dst_bo, flags))
143.10700 ++		return true;
143.10701 ++
143.10702 ++	if (kgem_bo_is_render(dst_bo) ||
143.10703 ++	    kgem_bo_is_render(src_bo))
143.10704 ++		return false;
143.10705 ++
143.10706 ++	if (flags & COPY_LAST &&
143.10707 ++	    sna->render_state.gt < 3 &&
143.10708 ++            can_switch_to_blt(sna, dst_bo, flags))
143.10709 ++		return true;
143.10710 ++
143.10711 ++	if (prefer_render_ring(sna, dst_bo))
143.10712 ++		return false;
143.10713 ++
143.10714 ++	if (!prefer_blt_ring(sna, dst_bo, flags))
143.10715 ++		return false;
143.10716 ++
143.10717 ++	return prefer_blt_bo(sna, src_bo, dst_bo);
143.10718 ++}
143.10719 ++
143.10720 ++static bool
143.10721 ++gen9_render_copy_boxes(struct sna *sna, uint8_t alu,
143.10722 ++		       const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
143.10723 ++		       const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
143.10724 ++		       const BoxRec *box, int n, unsigned flags)
143.10725 ++{
143.10726 ++	struct sna_composite_op tmp;
143.10727 ++	BoxRec extents;
143.10728 ++
143.10729 ++	DBG(("%s (%d, %d)->(%d, %d) x %d, alu=%x, flags=%x, self-copy=%d, overlaps? %d\n",
143.10730 ++	     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, n, alu, flags,
143.10731 ++	     src_bo == dst_bo,
143.10732 ++	     overlaps(sna,
143.10733 ++		      src_bo, src_dx, src_dy,
143.10734 ++		      dst_bo, dst_dx, dst_dy,
143.10735 ++		      box, n, flags, &extents)));
143.10736 ++
143.10737 ++	if (prefer_blt_copy(sna, src_bo, dst_bo, flags) &&
143.10738 ++	    sna_blt_compare_depth(src, dst) &&
143.10739 ++	    sna_blt_copy_boxes(sna, alu,
143.10740 ++			       src_bo, src_dx, src_dy,
143.10741 ++			       dst_bo, dst_dx, dst_dy,
143.10742 ++			       dst->bitsPerPixel,
143.10743 ++			       box, n))
143.10744 ++		return true;
143.10745 ++
143.10746 ++	if (!(alu == GXcopy || alu == GXclear) ||
143.10747 ++	    unaligned(src_bo, src->bitsPerPixel) ||
143.10748 ++	    unaligned(dst_bo, dst->bitsPerPixel)) {
143.10749 ++fallback_blt:
143.10750 ++		DBG(("%s: fallback blt\n", __FUNCTION__));
143.10751 ++		if (!sna_blt_compare_depth(src, dst))
143.10752 ++			return false;
143.10753 ++
143.10754 ++		return sna_blt_copy_boxes_fallback(sna, alu,
143.10755 ++						   src, src_bo, src_dx, src_dy,
143.10756 ++						   dst, dst_bo, dst_dx, dst_dy,
143.10757 ++						   box, n);
143.10758 ++	}
143.10759 ++
143.10760 ++	if (overlaps(sna,
143.10761 ++		     src_bo, src_dx, src_dy,
143.10762 ++		     dst_bo, dst_dx, dst_dy,
143.10763 ++		     box, n, flags,
143.10764 ++		     &extents)) {
143.10765 ++		bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
143.10766 ++
143.10767 ++		if ((big || !prefer_render_ring(sna, dst_bo)) &&
143.10768 ++		    sna_blt_copy_boxes(sna, alu,
143.10769 ++				       src_bo, src_dx, src_dy,
143.10770 ++				       dst_bo, dst_dx, dst_dy,
143.10771 ++				       dst->bitsPerPixel,
143.10772 ++				       box, n))
143.10773 ++			return true;
143.10774 ++
143.10775 ++		if (big)
143.10776 ++			goto fallback_blt;
143.10777 ++
143.10778 ++		assert(src_bo == dst_bo);
143.10779 ++		assert(src->depth == dst->depth);
143.10780 ++		assert(src->width == dst->width);
143.10781 ++		assert(src->height == dst->height);
143.10782 ++		return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
143.10783 ++						      src_dx, src_dy,
143.10784 ++						      dst_dx, dst_dy,
143.10785 ++						      box, n, &extents);
143.10786 ++	}
143.10787 ++
143.10788 ++	if (dst->depth == src->depth) {
143.10789 ++		tmp.dst.format = sna_render_format_for_depth(dst->depth);
143.10790 ++		tmp.src.pict_format = tmp.dst.format;
143.10791 ++	} else {
143.10792 ++		tmp.dst.format = sna_format_for_depth(dst->depth);
143.10793 ++		tmp.src.pict_format = sna_format_for_depth(src->depth);
143.10794 ++	}
143.10795 ++	if (!gen9_check_format(tmp.src.pict_format))
143.10796 ++		goto fallback_blt;
143.10797 ++
143.10798 ++	tmp.dst.pixmap = (PixmapPtr)dst;
143.10799 ++	tmp.dst.width  = dst->width;
143.10800 ++	tmp.dst.height = dst->height;
143.10801 ++	tmp.dst.bo = dst_bo;
143.10802 ++	tmp.dst.x = tmp.dst.y = 0;
143.10803 ++	tmp.damage = NULL;
143.10804 ++
143.10805 ++	sna_render_composite_redirect_init(&tmp);
143.10806 ++	if (too_large(tmp.dst.width, tmp.dst.height)) {
143.10807 ++		int i;
143.10808 ++
143.10809 ++		extents = box[0];
143.10810 ++		for (i = 1; i < n; i++) {
143.10811 ++			if (box[i].x1 < extents.x1)
143.10812 ++				extents.x1 = box[i].x1;
143.10813 ++			if (box[i].y1 < extents.y1)
143.10814 ++				extents.y1 = box[i].y1;
143.10815 ++
143.10816 ++			if (box[i].x2 > extents.x2)
143.10817 ++				extents.x2 = box[i].x2;
143.10818 ++			if (box[i].y2 > extents.y2)
143.10819 ++				extents.y2 = box[i].y2;
143.10820 ++		}
143.10821 ++
143.10822 ++		if (!sna_render_composite_redirect(sna, &tmp,
143.10823 ++						   extents.x1 + dst_dx,
143.10824 ++						   extents.y1 + dst_dy,
143.10825 ++						   extents.x2 - extents.x1,
143.10826 ++						   extents.y2 - extents.y1,
143.10827 ++						   n > 1))
143.10828 ++			goto fallback_tiled;
143.10829 ++	}
143.10830 ++
143.10831 ++	tmp.src.card_format = gen9_get_card_format(tmp.src.pict_format);
143.10832 ++	if (too_large(src->width, src->height)) {
143.10833 ++		int i;
143.10834 ++
143.10835 ++		extents = box[0];
143.10836 ++		for (i = 1; i < n; i++) {
143.10837 ++			if (box[i].x1 < extents.x1)
143.10838 ++				extents.x1 = box[i].x1;
143.10839 ++			if (box[i].y1 < extents.y1)
143.10840 ++				extents.y1 = box[i].y1;
143.10841 ++
143.10842 ++			if (box[i].x2 > extents.x2)
143.10843 ++				extents.x2 = box[i].x2;
143.10844 ++			if (box[i].y2 > extents.y2)
143.10845 ++				extents.y2 = box[i].y2;
143.10846 ++		}
143.10847 ++
143.10848 ++		if (!sna_render_pixmap_partial(sna, src, src_bo, &tmp.src,
143.10849 ++					       extents.x1 + src_dx,
143.10850 ++					       extents.y1 + src_dy,
143.10851 ++					       extents.x2 - extents.x1,
143.10852 ++					       extents.y2 - extents.y1))
143.10853 ++			goto fallback_tiled_dst;
143.10854 ++	} else {
143.10855 ++		tmp.src.bo = src_bo;
143.10856 ++		tmp.src.width  = src->width;
143.10857 ++		tmp.src.height = src->height;
143.10858 ++		tmp.src.offset[0] = tmp.src.offset[1] = 0;
143.10859 ++	}
143.10860 ++
143.10861 ++	tmp.mask.bo = NULL;
143.10862 ++
143.10863 ++	tmp.floats_per_vertex = 2;
143.10864 ++	tmp.floats_per_rect = 6;
143.10865 ++	tmp.need_magic_ca_pass = 0;
143.10866 ++
143.10867 ++	tmp.u.gen9.flags = COPY_FLAGS(alu);
143.10868 ++
143.10869 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp.dst.bo);
143.10870 ++	if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL)) {
143.10871 ++		kgem_submit(&sna->kgem);
143.10872 ++		if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL)) {
143.10873 ++			if (tmp.src.bo != src_bo)
143.10874 ++				kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.10875 ++			if (tmp.redirect.real_bo)
143.10876 ++				kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
143.10877 ++			goto fallback_blt;
143.10878 ++		}
143.10879 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.10880 ++	}
143.10881 ++
143.10882 ++	src_dx += tmp.src.offset[0];
143.10883 ++	src_dy += tmp.src.offset[1];
143.10884 ++
143.10885 ++	dst_dx += tmp.dst.x;
143.10886 ++	dst_dy += tmp.dst.y;
143.10887 ++
143.10888 ++	tmp.dst.x = tmp.dst.y = 0;
143.10889 ++
143.10890 ++	gen9_align_vertex(sna, &tmp);
143.10891 ++	gen9_emit_copy_state(sna, &tmp);
143.10892 ++
143.10893 ++	do {
143.10894 ++		int16_t *v;
143.10895 ++		int n_this_time;
143.10896 ++
143.10897 ++		n_this_time = gen9_get_rectangles(sna, &tmp, n,
143.10898 ++						  gen9_emit_copy_state);
143.10899 ++		n -= n_this_time;
143.10900 ++
143.10901 ++		v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
143.10902 ++		sna->render.vertex_used += 6 * n_this_time;
143.10903 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.10904 ++		do {
143.10905 ++
143.10906 ++			DBG(("	(%d, %d) -> (%d, %d) + (%d, %d)\n",
143.10907 ++			     box->x1 + src_dx, box->y1 + src_dy,
143.10908 ++			     box->x1 + dst_dx, box->y1 + dst_dy,
143.10909 ++			     box->x2 - box->x1, box->y2 - box->y1));
143.10910 ++			v[0] = box->x2 + dst_dx;
143.10911 ++			v[2] = box->x2 + src_dx;
143.10912 ++			v[1]  = v[5] = box->y2 + dst_dy;
143.10913 ++			v[3]  = v[7] = box->y2 + src_dy;
143.10914 ++			v[8]  = v[4] = box->x1 + dst_dx;
143.10915 ++			v[10] = v[6] = box->x1 + src_dx;
143.10916 ++			v[9]  = box->y1 + dst_dy;
143.10917 ++			v[11] = box->y1 + src_dy;
143.10918 ++			v += 12; box++;
143.10919 ++		} while (--n_this_time);
143.10920 ++	} while (n);
143.10921 ++
143.10922 ++	gen8_vertex_flush(sna);
143.10923 ++	sna_render_composite_redirect_done(sna, &tmp);
143.10924 ++	if (tmp.src.bo != src_bo)
143.10925 ++		kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.10926 ++	return true;
143.10927 ++
143.10928 ++fallback_tiled_dst:
143.10929 ++	if (tmp.redirect.real_bo)
143.10930 ++		kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
143.10931 ++fallback_tiled:
143.10932 ++	DBG(("%s: fallback tiled\n", __FUNCTION__));
143.10933 ++	if (sna_blt_compare_depth(src, dst) &&
143.10934 ++	    sna_blt_copy_boxes(sna, alu,
143.10935 ++			       src_bo, src_dx, src_dy,
143.10936 ++			       dst_bo, dst_dx, dst_dy,
143.10937 ++			       dst->bitsPerPixel,
143.10938 ++			       box, n))
143.10939 ++		return true;
143.10940 ++
143.10941 ++	return sna_tiling_copy_boxes(sna, alu,
143.10942 ++				     src, src_bo, src_dx, src_dy,
143.10943 ++				     dst, dst_bo, dst_dx, dst_dy,
143.10944 ++				     box, n);
143.10945 ++}
143.10946 ++
143.10947 ++static void
143.10948 ++gen9_render_copy_blt(struct sna *sna,
143.10949 ++		     const struct sna_copy_op *op,
143.10950 ++		     int16_t sx, int16_t sy,
143.10951 ++		     int16_t w,  int16_t h,
143.10952 ++		     int16_t dx, int16_t dy)
143.10953 ++{
143.10954 ++	int16_t *v;
143.10955 ++
143.10956 ++	gen9_get_rectangles(sna, &op->base, 1, gen9_emit_copy_state);
143.10957 ++
143.10958 ++	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
143.10959 ++	sna->render.vertex_used += 6;
143.10960 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.10961 ++
143.10962 ++	v[0]  = dx+w; v[1]  = dy+h;
143.10963 ++	v[2]  = sx+w; v[3]  = sy+h;
143.10964 ++	v[4]  = dx;   v[5]  = dy+h;
143.10965 ++	v[6]  = sx;   v[7]  = sy+h;
143.10966 ++	v[8]  = dx;   v[9]  = dy;
143.10967 ++	v[10] = sx;   v[11] = sy;
143.10968 ++}
143.10969 ++
143.10970 ++static void
143.10971 ++gen9_render_copy_done(struct sna *sna, const struct sna_copy_op *op)
143.10972 ++{
143.10973 ++	if (sna->render.vertex_offset)
143.10974 ++		gen8_vertex_flush(sna);
143.10975 ++}
143.10976 ++
143.10977 ++static bool
143.10978 ++gen9_render_copy(struct sna *sna, uint8_t alu,
143.10979 ++		 PixmapPtr src, struct kgem_bo *src_bo,
143.10980 ++		 PixmapPtr dst, struct kgem_bo *dst_bo,
143.10981 ++		 struct sna_copy_op *op)
143.10982 ++{
143.10983 ++	DBG(("%s (alu=%d, src=(%dx%d), dst=(%dx%d))\n",
143.10984 ++	     __FUNCTION__, alu,
143.10985 ++	     src->drawable.width, src->drawable.height,
143.10986 ++	     dst->drawable.width, dst->drawable.height));
143.10987 ++
143.10988 ++	if (prefer_blt_copy(sna, src_bo, dst_bo, 0) &&
143.10989 ++	    sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
143.10990 ++	    sna_blt_copy(sna, alu,
143.10991 ++			 src_bo, dst_bo,
143.10992 ++			 dst->drawable.bitsPerPixel,
143.10993 ++			 op))
143.10994 ++		return true;
143.10995 ++
143.10996 ++	if (!(alu == GXcopy || alu == GXclear) || src_bo == dst_bo ||
143.10997 ++	    too_large(src->drawable.width, src->drawable.height) ||
143.10998 ++	    too_large(dst->drawable.width, dst->drawable.height) ||
143.10999 ++	    unaligned(src_bo, src->drawable.bitsPerPixel) ||
143.11000 ++	    unaligned(dst_bo, dst->drawable.bitsPerPixel)) {
143.11001 ++fallback:
143.11002 ++		if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
143.11003 ++			return false;
143.11004 ++
143.11005 ++		return sna_blt_copy(sna, alu, src_bo, dst_bo,
143.11006 ++				    dst->drawable.bitsPerPixel,
143.11007 ++				    op);
143.11008 ++	}
143.11009 ++
143.11010 ++	if (dst->drawable.depth == src->drawable.depth) {
143.11011 ++		op->base.dst.format = sna_render_format_for_depth(dst->drawable.depth);
143.11012 ++		op->base.src.pict_format = op->base.dst.format;
143.11013 ++	} else {
143.11014 ++		op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
143.11015 ++		op->base.src.pict_format = sna_format_for_depth(src->drawable.depth);
143.11016 ++	}
143.11017 ++	if (!gen9_check_format(op->base.src.pict_format))
143.11018 ++		goto fallback;
143.11019 ++
143.11020 ++	op->base.dst.pixmap = dst;
143.11021 ++	op->base.dst.width  = dst->drawable.width;
143.11022 ++	op->base.dst.height = dst->drawable.height;
143.11023 ++	op->base.dst.bo = dst_bo;
143.11024 ++
143.11025 ++	op->base.src.bo = src_bo;
143.11026 ++	op->base.src.card_format =
143.11027 ++		gen9_get_card_format(op->base.src.pict_format);
143.11028 ++	op->base.src.width  = src->drawable.width;
143.11029 ++	op->base.src.height = src->drawable.height;
143.11030 ++
143.11031 ++	op->base.mask.bo = NULL;
143.11032 ++
143.11033 ++	op->base.floats_per_vertex = 2;
143.11034 ++	op->base.floats_per_rect = 6;
143.11035 ++
143.11036 ++	op->base.u.gen9.flags = COPY_FLAGS(alu);
143.11037 ++
143.11038 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, dst_bo);
143.11039 ++	if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
143.11040 ++		kgem_submit(&sna->kgem);
143.11041 ++		if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL))
143.11042 ++			goto fallback;
143.11043 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.11044 ++	}
143.11045 ++
143.11046 ++	gen9_align_vertex(sna, &op->base);
143.11047 ++	gen9_emit_copy_state(sna, &op->base);
143.11048 ++
143.11049 ++	op->blt  = gen9_render_copy_blt;
143.11050 ++	op->done = gen9_render_copy_done;
143.11051 ++	return true;
143.11052 ++}
143.11053 ++
143.11054 ++static void
143.11055 ++gen9_emit_fill_state(struct sna *sna, const struct sna_composite_op *op)
143.11056 ++{
143.11057 ++	uint32_t *binding_table;
143.11058 ++	uint16_t offset, dirty;
143.11059 ++
143.11060 ++	/* XXX Render Target Fast Clear
143.11061 ++	 * Set RTFC Enable in PS and render a rectangle.
143.11062 ++	 * Limited to a clearing the full MSC surface only with a
143.11063 ++	 * specific kernel.
143.11064 ++	 */
143.11065 ++
143.11066 ++	gen9_get_batch(sna, op);
143.11067 ++
143.11068 ++	binding_table = gen9_composite_get_binding_table(sna, &offset);
143.11069 ++
143.11070 ++	dirty = kgem_bo_is_dirty(op->dst.bo);
143.11071 ++
143.11072 ++	binding_table[0] =
143.11073 ++		gen9_bind_bo(sna,
143.11074 ++			     op->dst.bo, op->dst.width, op->dst.height,
143.11075 ++			     gen9_get_dest_format(op->dst.format),
143.11076 ++			     true);
143.11077 ++	binding_table[1] =
143.11078 ++		gen9_bind_bo(sna,
143.11079 ++			     op->src.bo, 1, 1,
143.11080 ++			     SURFACEFORMAT_B8G8R8A8_UNORM,
143.11081 ++			     false);
143.11082 ++
143.11083 ++	if (sna->kgem.surface == offset &&
143.11084 ++	    *(uint64_t *)(sna->kgem.batch + sna->render_state.gen9.surface_table) == *(uint64_t*)binding_table) {
143.11085 ++		sna->kgem.surface += SURFACE_DW;
143.11086 ++		offset = sna->render_state.gen9.surface_table;
143.11087 ++	}
143.11088 ++
143.11089 ++	if (sna->kgem.batch[sna->render_state.gen9.surface_table] == binding_table[0])
143.11090 ++		dirty = 0;
143.11091 ++
143.11092 ++	gen9_emit_state(sna, op, offset | dirty);
143.11093 ++}
143.11094 ++
143.11095 ++static bool
143.11096 ++gen9_render_fill_boxes(struct sna *sna,
143.11097 ++		       CARD8 op,
143.11098 ++		       PictFormat format,
143.11099 ++		       const xRenderColor *color,
143.11100 ++		       const DrawableRec *dst, struct kgem_bo *dst_bo,
143.11101 ++		       const BoxRec *box, int n)
143.11102 ++{
143.11103 ++	struct sna_composite_op tmp;
143.11104 ++	uint32_t pixel;
143.11105 ++
143.11106 ++	DBG(("%s (op=%d, color=(%04x, %04x, %04x, %04x) [%08x])\n",
143.11107 ++	     __FUNCTION__, op,
143.11108 ++	     color->red, color->green, color->blue, color->alpha, (int)format));
143.11109 ++
143.11110 ++	if (op >= ARRAY_SIZE(gen9_blend_op)) {
143.11111 ++		DBG(("%s: fallback due to unhandled blend op: %d\n",
143.11112 ++		     __FUNCTION__, op));
143.11113 ++		return false;
143.11114 ++	}
143.11115 ++
143.11116 ++	if (prefer_blt_fill(sna, dst_bo, FILL_BOXES) ||
143.11117 ++	    !gen9_check_dst_format(format) ||
143.11118 ++	    unaligned(dst_bo, PICT_FORMAT_BPP(format))) {
143.11119 ++		uint8_t alu = GXinvalid;
143.11120 ++
143.11121 ++		if (op <= PictOpSrc) {
143.11122 ++			pixel = 0;
143.11123 ++			if (op == PictOpClear)
143.11124 ++				alu = GXclear;
143.11125 ++			else if (sna_get_pixel_from_rgba(&pixel,
143.11126 ++							 color->red,
143.11127 ++							 color->green,
143.11128 ++							 color->blue,
143.11129 ++							 color->alpha,
143.11130 ++							 format))
143.11131 ++				alu = GXcopy;
143.11132 ++		}
143.11133 ++
143.11134 ++		if (alu != GXinvalid &&
143.11135 ++		    sna_blt_fill_boxes(sna, alu,
143.11136 ++				       dst_bo, dst->bitsPerPixel,
143.11137 ++				       pixel, box, n))
143.11138 ++			return true;
143.11139 ++
143.11140 ++		if (!gen9_check_dst_format(format))
143.11141 ++			return false;
143.11142 ++	}
143.11143 ++
143.11144 ++	if (op == PictOpClear) {
143.11145 ++		pixel = 0;
143.11146 ++		op = PictOpSrc;
143.11147 ++	} else if (!sna_get_pixel_from_rgba(&pixel,
143.11148 ++					    color->red,
143.11149 ++					    color->green,
143.11150 ++					    color->blue,
143.11151 ++					    color->alpha,
143.11152 ++					    PICT_a8r8g8b8))
143.11153 ++		return false;
143.11154 ++
143.11155 ++	DBG(("%s(%08x x %d [(%d, %d), (%d, %d) ...])\n",
143.11156 ++	     __FUNCTION__, pixel, n,
143.11157 ++	     box[0].x1, box[0].y1, box[0].x2, box[0].y2));
143.11158 ++
143.11159 ++	tmp.dst.pixmap = (PixmapPtr)dst;
143.11160 ++	tmp.dst.width  = dst->width;
143.11161 ++	tmp.dst.height = dst->height;
143.11162 ++	tmp.dst.format = format;
143.11163 ++	tmp.dst.bo = dst_bo;
143.11164 ++	tmp.dst.x = tmp.dst.y = 0;
143.11165 ++	tmp.damage = NULL;
143.11166 ++
143.11167 ++	sna_render_composite_redirect_init(&tmp);
143.11168 ++	if (too_large(dst->width, dst->height)) {
143.11169 ++		BoxRec extents;
143.11170 ++
143.11171 ++		boxes_extents(box, n, &extents);
143.11172 ++		if (!sna_render_composite_redirect(sna, &tmp,
143.11173 ++						   extents.x1, extents.y1,
143.11174 ++						   extents.x2 - extents.x1,
143.11175 ++						   extents.y2 - extents.y1,
143.11176 ++						   n > 1))
143.11177 ++			return sna_tiling_fill_boxes(sna, op, format, color,
143.11178 ++						     dst, dst_bo, box, n);
143.11179 ++	}
143.11180 ++
143.11181 ++	tmp.src.bo = sna_render_get_solid(sna, pixel);
143.11182 ++	tmp.mask.bo = NULL;
143.11183 ++
143.11184 ++	tmp.floats_per_vertex = 2;
143.11185 ++	tmp.floats_per_rect = 6;
143.11186 ++	tmp.need_magic_ca_pass = false;
143.11187 ++
143.11188 ++	tmp.u.gen9.flags = FILL_FLAGS(op, format);
143.11189 ++
143.11190 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, dst_bo);
143.11191 ++	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
143.11192 ++		kgem_submit(&sna->kgem);
143.11193 ++		if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
143.11194 ++			kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.11195 ++			tmp.src.bo = NULL;
143.11196 ++
143.11197 ++			if (tmp.redirect.real_bo) {
143.11198 ++				kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
143.11199 ++				tmp.redirect.real_bo = NULL;
143.11200 ++			}
143.11201 ++
143.11202 ++			return false;
143.11203 ++		}
143.11204 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.11205 ++	}
143.11206 ++
143.11207 ++	gen9_align_vertex(sna, &tmp);
143.11208 ++	gen9_emit_fill_state(sna, &tmp);
143.11209 ++
143.11210 ++	do {
143.11211 ++		int n_this_time;
143.11212 ++		int16_t *v;
143.11213 ++
143.11214 ++		n_this_time = gen9_get_rectangles(sna, &tmp, n,
143.11215 ++						  gen9_emit_fill_state);
143.11216 ++		n -= n_this_time;
143.11217 ++
143.11218 ++		v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
143.11219 ++		sna->render.vertex_used += 6 * n_this_time;
143.11220 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.11221 ++		do {
143.11222 ++			DBG(("	(%d, %d), (%d, %d)\n",
143.11223 ++			     box->x1, box->y1, box->x2, box->y2));
143.11224 ++
143.11225 ++			v[0] = box->x2;
143.11226 ++			v[5] = v[1] = box->y2;
143.11227 ++			v[8] = v[4] = box->x1;
143.11228 ++			v[9] = box->y1;
143.11229 ++			v[2] = v[3]  = v[7]  = 1;
143.11230 ++			v[6] = v[10] = v[11] = 0;
143.11231 ++			v += 12; box++;
143.11232 ++		} while (--n_this_time);
143.11233 ++	} while (n);
143.11234 ++
143.11235 ++	gen8_vertex_flush(sna);
143.11236 ++	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.11237 ++	sna_render_composite_redirect_done(sna, &tmp);
143.11238 ++	return true;
143.11239 ++}
143.11240 ++
143.11241 ++static void
143.11242 ++gen9_render_fill_op_blt(struct sna *sna,
143.11243 ++			const struct sna_fill_op *op,
143.11244 ++			int16_t x, int16_t y, int16_t w, int16_t h)
143.11245 ++{
143.11246 ++	int16_t *v;
143.11247 ++
143.11248 ++	DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
143.11249 ++
143.11250 ++	gen9_get_rectangles(sna, &op->base, 1, gen9_emit_fill_state);
143.11251 ++
143.11252 ++	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
143.11253 ++	sna->render.vertex_used += 6;
143.11254 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.11255 ++
143.11256 ++	v[0] = x+w;
143.11257 ++	v[4] = v[8] = x;
143.11258 ++	v[1] = v[5] = y+h;
143.11259 ++	v[9] = y;
143.11260 ++
143.11261 ++	v[2] = v[3]  = v[7]  = 1;
143.11262 ++	v[6] = v[10] = v[11] = 0;
143.11263 ++}
143.11264 ++
143.11265 ++fastcall static void
143.11266 ++gen9_render_fill_op_box(struct sna *sna,
143.11267 ++			const struct sna_fill_op *op,
143.11268 ++			const BoxRec *box)
143.11269 ++{
143.11270 ++	int16_t *v;
143.11271 ++
143.11272 ++	DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
143.11273 ++	     box->x1, box->y1, box->x2, box->y2));
143.11274 ++
143.11275 ++	gen9_get_rectangles(sna, &op->base, 1, gen9_emit_fill_state);
143.11276 ++
143.11277 ++	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
143.11278 ++	sna->render.vertex_used += 6;
143.11279 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.11280 ++
143.11281 ++	v[0] = box->x2;
143.11282 ++	v[8] = v[4] = box->x1;
143.11283 ++	v[5] = v[1] = box->y2;
143.11284 ++	v[9] = box->y1;
143.11285 ++
143.11286 ++	v[7] = v[2]  = v[3]  = 1;
143.11287 ++	v[6] = v[10] = v[11] = 0;
143.11288 ++}
143.11289 ++
143.11290 ++fastcall static void
143.11291 ++gen9_render_fill_op_boxes(struct sna *sna,
143.11292 ++			  const struct sna_fill_op *op,
143.11293 ++			  const BoxRec *box,
143.11294 ++			  int nbox)
143.11295 ++{
143.11296 ++	DBG(("%s: (%d, %d),(%d, %d)... x %d\n", __FUNCTION__,
143.11297 ++	     box->x1, box->y1, box->x2, box->y2, nbox));
143.11298 ++
143.11299 ++	do {
143.11300 ++		int nbox_this_time;
143.11301 ++		int16_t *v;
143.11302 ++
143.11303 ++		nbox_this_time = gen9_get_rectangles(sna, &op->base, nbox,
143.11304 ++						     gen9_emit_fill_state);
143.11305 ++		nbox -= nbox_this_time;
143.11306 ++
143.11307 ++		v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
143.11308 ++		sna->render.vertex_used += 6 * nbox_this_time;
143.11309 ++		assert(sna->render.vertex_used <= sna->render.vertex_size);
143.11310 ++
143.11311 ++		do {
143.11312 ++			v[0] = box->x2;
143.11313 ++			v[8] = v[4] = box->x1;
143.11314 ++			v[5] = v[1] = box->y2;
143.11315 ++			v[9] = box->y1;
143.11316 ++			v[7] = v[2]  = v[3]  = 1;
143.11317 ++			v[6] = v[10] = v[11] = 0;
143.11318 ++			box++; v += 12;
143.11319 ++		} while (--nbox_this_time);
143.11320 ++	} while (nbox);
143.11321 ++}
143.11322 ++
143.11323 ++static void
143.11324 ++gen9_render_fill_op_done(struct sna *sna, const struct sna_fill_op *op)
143.11325 ++{
143.11326 ++	if (sna->render.vertex_offset)
143.11327 ++		gen8_vertex_flush(sna);
143.11328 ++	kgem_bo_destroy(&sna->kgem, op->base.src.bo);
143.11329 ++}
143.11330 ++
143.11331 ++static bool
143.11332 ++gen9_render_fill(struct sna *sna, uint8_t alu,
143.11333 ++		 PixmapPtr dst, struct kgem_bo *dst_bo,
143.11334 ++		 uint32_t color, unsigned flags,
143.11335 ++		 struct sna_fill_op *op)
143.11336 ++{
143.11337 ++	DBG(("%s: (alu=%d, color=%x)\n", __FUNCTION__, alu, color));
143.11338 ++
143.11339 ++	if (prefer_blt_fill(sna, dst_bo, flags) &&
143.11340 ++	    sna_blt_fill(sna, alu,
143.11341 ++			 dst_bo, dst->drawable.bitsPerPixel,
143.11342 ++			 color,
143.11343 ++			 op))
143.11344 ++		return true;
143.11345 ++
143.11346 ++	if (!(alu == GXcopy || alu == GXclear) ||
143.11347 ++	    too_large(dst->drawable.width, dst->drawable.height) ||
143.11348 ++	    unaligned(dst_bo, dst->drawable.bitsPerPixel))
143.11349 ++		return sna_blt_fill(sna, alu,
143.11350 ++				    dst_bo, dst->drawable.bitsPerPixel,
143.11351 ++				    color,
143.11352 ++				    op);
143.11353 ++
143.11354 ++	if (alu == GXclear)
143.11355 ++		color = 0;
143.11356 ++
143.11357 ++	op->base.dst.pixmap = dst;
143.11358 ++	op->base.dst.width  = dst->drawable.width;
143.11359 ++	op->base.dst.height = dst->drawable.height;
143.11360 ++	op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
143.11361 ++	op->base.dst.bo = dst_bo;
143.11362 ++	op->base.dst.x = op->base.dst.y = 0;
143.11363 ++
143.11364 ++	op->base.src.bo =
143.11365 ++		sna_render_get_solid(sna,
143.11366 ++				     sna_rgba_for_color(color,
143.11367 ++							dst->drawable.depth));
143.11368 ++	op->base.mask.bo = NULL;
143.11369 ++
143.11370 ++	op->base.need_magic_ca_pass = false;
143.11371 ++	op->base.floats_per_vertex = 2;
143.11372 ++	op->base.floats_per_rect = 6;
143.11373 ++
143.11374 ++	op->base.u.gen9.flags = FILL_FLAGS_NOBLEND;
143.11375 ++
143.11376 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, dst_bo);
143.11377 ++	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
143.11378 ++		kgem_submit(&sna->kgem);
143.11379 ++		if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
143.11380 ++			kgem_bo_destroy(&sna->kgem, op->base.src.bo);
143.11381 ++			return false;
143.11382 ++		}
143.11383 ++
143.11384 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.11385 ++	}
143.11386 ++
143.11387 ++	gen9_align_vertex(sna, &op->base);
143.11388 ++	gen9_emit_fill_state(sna, &op->base);
143.11389 ++
143.11390 ++	op->blt   = gen9_render_fill_op_blt;
143.11391 ++	op->box   = gen9_render_fill_op_box;
143.11392 ++	op->boxes = gen9_render_fill_op_boxes;
143.11393 ++	op->points = NULL;
143.11394 ++	op->done  = gen9_render_fill_op_done;
143.11395 ++	return true;
143.11396 ++}
143.11397 ++
143.11398 ++static bool
143.11399 ++gen9_render_fill_one_try_blt(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
143.11400 ++			     uint32_t color,
143.11401 ++			     int16_t x1, int16_t y1, int16_t x2, int16_t y2,
143.11402 ++			     uint8_t alu)
143.11403 ++{
143.11404 ++	BoxRec box;
143.11405 ++
143.11406 ++	box.x1 = x1;
143.11407 ++	box.y1 = y1;
143.11408 ++	box.x2 = x2;
143.11409 ++	box.y2 = y2;
143.11410 ++
143.11411 ++	return sna_blt_fill_boxes(sna, alu,
143.11412 ++				  bo, dst->drawable.bitsPerPixel,
143.11413 ++				  color, &box, 1);
143.11414 ++}
143.11415 ++
143.11416 ++static bool
143.11417 ++gen9_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
143.11418 ++		     uint32_t color,
143.11419 ++		     int16_t x1, int16_t y1,
143.11420 ++		     int16_t x2, int16_t y2,
143.11421 ++		     uint8_t alu)
143.11422 ++{
143.11423 ++	struct sna_composite_op tmp;
143.11424 ++	int16_t *v;
143.11425 ++
143.11426 ++	/* Prefer to use the BLT if already engaged */
143.11427 ++	if (prefer_blt_fill(sna, bo, FILL_BOXES) &&
143.11428 ++	    gen9_render_fill_one_try_blt(sna, dst, bo, color,
143.11429 ++					 x1, y1, x2, y2, alu))
143.11430 ++		return true;
143.11431 ++
143.11432 ++	/* Must use the BLT if we can't RENDER... */
143.11433 ++	if (!(alu == GXcopy || alu == GXclear) ||
143.11434 ++	    too_large(dst->drawable.width, dst->drawable.height) ||
143.11435 ++	    unaligned(bo, dst->drawable.bitsPerPixel))
143.11436 ++		return gen9_render_fill_one_try_blt(sna, dst, bo, color,
143.11437 ++						    x1, y1, x2, y2, alu);
143.11438 ++
143.11439 ++	if (alu == GXclear)
143.11440 ++		color = 0;
143.11441 ++
143.11442 ++	tmp.dst.pixmap = dst;
143.11443 ++	tmp.dst.width  = dst->drawable.width;
143.11444 ++	tmp.dst.height = dst->drawable.height;
143.11445 ++	tmp.dst.format = sna_format_for_depth(dst->drawable.depth);
143.11446 ++	tmp.dst.bo = bo;
143.11447 ++	tmp.dst.x = tmp.dst.y = 0;
143.11448 ++
143.11449 ++	tmp.src.bo =
143.11450 ++		sna_render_get_solid(sna,
143.11451 ++				     sna_rgba_for_color(color,
143.11452 ++							dst->drawable.depth));
143.11453 ++	tmp.mask.bo = NULL;
143.11454 ++
143.11455 ++	tmp.floats_per_vertex = 2;
143.11456 ++	tmp.floats_per_rect = 6;
143.11457 ++	tmp.need_magic_ca_pass = false;
143.11458 ++
143.11459 ++	tmp.u.gen9.flags = FILL_FLAGS_NOBLEND;
143.11460 ++
143.11461 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, bo);
143.11462 ++	if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
143.11463 ++		kgem_submit(&sna->kgem);
143.11464 ++		if (kgem_check_bo(&sna->kgem, bo, NULL)) {
143.11465 ++			kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.11466 ++			return false;
143.11467 ++		}
143.11468 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.11469 ++	}
143.11470 ++
143.11471 ++	gen9_align_vertex(sna, &tmp);
143.11472 ++	gen9_emit_fill_state(sna, &tmp);
143.11473 ++
143.11474 ++	gen9_get_rectangles(sna, &tmp, 1, gen9_emit_fill_state);
143.11475 ++
143.11476 ++	DBG(("	(%d, %d), (%d, %d)\n", x1, y1, x2, y2));
143.11477 ++
143.11478 ++	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
143.11479 ++	sna->render.vertex_used += 6;
143.11480 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.11481 ++
143.11482 ++	v[0] = x2;
143.11483 ++	v[8] = v[4] = x1;
143.11484 ++	v[5] = v[1] = y2;
143.11485 ++	v[9] = y1;
143.11486 ++	v[7] = v[2]  = v[3]  = 1;
143.11487 ++	v[6] = v[10] = v[11] = 0;
143.11488 ++
143.11489 ++	gen8_vertex_flush(sna);
143.11490 ++	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.11491 ++
143.11492 ++	return true;
143.11493 ++}
143.11494 ++
143.11495 ++static bool
143.11496 ++gen9_render_clear_try_blt(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
143.11497 ++{
143.11498 ++	BoxRec box;
143.11499 ++
143.11500 ++	box.x1 = 0;
143.11501 ++	box.y1 = 0;
143.11502 ++	box.x2 = dst->drawable.width;
143.11503 ++	box.y2 = dst->drawable.height;
143.11504 ++
143.11505 ++	return sna_blt_fill_boxes(sna, GXclear,
143.11506 ++				  bo, dst->drawable.bitsPerPixel,
143.11507 ++				  0, &box, 1);
143.11508 ++}
143.11509 ++
143.11510 ++static bool
143.11511 ++gen9_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
143.11512 ++{
143.11513 ++	struct sna_composite_op tmp;
143.11514 ++	int16_t *v;
143.11515 ++
143.11516 ++	DBG(("%s: %dx%d\n",
143.11517 ++	     __FUNCTION__,
143.11518 ++	     dst->drawable.width,
143.11519 ++	     dst->drawable.height));
143.11520 ++
143.11521 ++	/* Prefer to use the BLT if already engaged */
143.11522 ++	if (sna->kgem.mode == KGEM_BLT &&
143.11523 ++	    gen9_render_clear_try_blt(sna, dst, bo))
143.11524 ++		return true;
143.11525 ++
143.11526 ++	/* Must use the BLT if we can't RENDER... */
143.11527 ++	if (too_large(dst->drawable.width, dst->drawable.height) ||
143.11528 ++	    unaligned(bo, dst->drawable.bitsPerPixel))
143.11529 ++		return gen9_render_clear_try_blt(sna, dst, bo);
143.11530 ++
143.11531 ++	tmp.dst.pixmap = dst;
143.11532 ++	tmp.dst.width  = dst->drawable.width;
143.11533 ++	tmp.dst.height = dst->drawable.height;
143.11534 ++	tmp.dst.format = sna_format_for_depth(dst->drawable.depth);
143.11535 ++	tmp.dst.bo = bo;
143.11536 ++	tmp.dst.x = tmp.dst.y = 0;
143.11537 ++
143.11538 ++	tmp.src.bo = sna_render_get_solid(sna, 0);
143.11539 ++	tmp.mask.bo = NULL;
143.11540 ++
143.11541 ++	tmp.floats_per_vertex = 2;
143.11542 ++	tmp.floats_per_rect = 6;
143.11543 ++	tmp.need_magic_ca_pass = false;
143.11544 ++
143.11545 ++	tmp.u.gen9.flags = FILL_FLAGS_NOBLEND;
143.11546 ++
143.11547 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, bo);
143.11548 ++	if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
143.11549 ++		kgem_submit(&sna->kgem);
143.11550 ++		if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
143.11551 ++			kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.11552 ++			return false;
143.11553 ++		}
143.11554 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.11555 ++	}
143.11556 ++
143.11557 ++	gen9_align_vertex(sna, &tmp);
143.11558 ++	gen9_emit_fill_state(sna, &tmp);
143.11559 ++
143.11560 ++	gen9_get_rectangles(sna, &tmp, 1, gen9_emit_fill_state);
143.11561 ++
143.11562 ++	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
143.11563 ++	sna->render.vertex_used += 6;
143.11564 ++	assert(sna->render.vertex_used <= sna->render.vertex_size);
143.11565 ++
143.11566 ++	v[0] = dst->drawable.width;
143.11567 ++	v[5] = v[1] = dst->drawable.height;
143.11568 ++	v[8] = v[4] = 0;
143.11569 ++	v[9] = 0;
143.11570 ++
143.11571 ++	v[7] = v[2]  = v[3]  = 1;
143.11572 ++	v[6] = v[10] = v[11] = 0;
143.11573 ++
143.11574 ++	gen8_vertex_flush(sna);
143.11575 ++	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
143.11576 ++
143.11577 ++	return true;
143.11578 ++}
143.11579 ++
143.11580 ++#if !NO_VIDEO
143.11581 ++static uint32_t gen9_bind_video_source(struct sna *sna,
143.11582 ++				       struct kgem_bo *bo,
143.11583 ++				       uint32_t delta,
143.11584 ++				       int width,
143.11585 ++				       int height,
143.11586 ++				       int pitch,
143.11587 ++				       uint32_t format)
143.11588 ++{
143.11589 ++	uint32_t *ss;
143.11590 ++	int offset;
143.11591 ++
143.11592 ++	offset = sna->kgem.surface -= SURFACE_DW;
143.11593 ++	ss = sna->kgem.batch + offset;
143.11594 ++	ss[0] = (SURFACE_2D << SURFACE_TYPE_SHIFT |
143.11595 ++		 gen9_tiling_bits(bo->tiling) |
143.11596 ++		 format << SURFACE_FORMAT_SHIFT |
143.11597 ++		 SURFACE_VALIGN_4 | SURFACE_HALIGN_4);
143.11598 ++	ss[1] = 0;
143.11599 ++	ss[2] = ((width - 1)  << SURFACE_WIDTH_SHIFT |
143.11600 ++		 (height - 1) << SURFACE_HEIGHT_SHIFT);
143.11601 ++	ss[3] = (pitch - 1) << SURFACE_PITCH_SHIFT;
143.11602 ++	ss[4] = 0;
143.11603 ++	ss[5] = 0;
143.11604 ++	ss[6] = 0;
143.11605 ++	ss[7] = SURFACE_SWIZZLE(RED, GREEN, BLUE, ALPHA);
143.11606 ++	*(uint64_t *)(ss+8) =
143.11607 ++		kgem_add_reloc64(&sna->kgem, offset + 8, bo,
143.11608 ++				 I915_GEM_DOMAIN_SAMPLER << 16,
143.11609 ++				 delta);
143.11610 ++	ss[10] = 0;
143.11611 ++	ss[11] = 0;
143.11612 ++	ss[12] = 0;
143.11613 ++	ss[13] = 0;
143.11614 ++	ss[14] = 0;
143.11615 ++	ss[15] = 0;
143.11616 ++
143.11617 ++	DBG(("[%x] bind bo(handle=%d, addr=%d), format=%d, width=%d, height=%d, pitch=%d, tiling=%d -> sampler\n",
143.11618 ++	     offset, bo->handle, ss[1],
143.11619 ++	     format, width, height, bo->pitch, bo->tiling));
143.11620 ++
143.11621 ++	return offset * sizeof(uint32_t);
143.11622 ++}
143.11623 ++
143.11624 ++static void gen9_emit_video_state(struct sna *sna,
143.11625 ++				  const struct sna_composite_op *op)
143.11626 ++{
143.11627 ++	struct sna_video_frame *frame = op->priv;
143.11628 ++	uint32_t src_surf_format;
143.11629 ++	uint32_t src_surf_base[6];
143.11630 ++	int src_width[6];
143.11631 ++	int src_height[6];
143.11632 ++	int src_pitch[6];
143.11633 ++	uint32_t *binding_table;
143.11634 ++	uint16_t offset;
143.11635 ++	int n_src, n;
143.11636 ++
143.11637 ++	/* XXX VeBox, bicubic */
143.11638 ++
143.11639 ++	gen9_get_batch(sna, op);
143.11640 ++
143.11641 ++	src_surf_base[0] = 0;
143.11642 ++	src_surf_base[1] = 0;
143.11643 ++	src_surf_base[2] = frame->VBufOffset;
143.11644 ++	src_surf_base[3] = frame->VBufOffset;
143.11645 ++	src_surf_base[4] = frame->UBufOffset;
143.11646 ++	src_surf_base[5] = frame->UBufOffset;
143.11647 ++
143.11648 ++	if (is_planar_fourcc(frame->id)) {
143.11649 ++		src_surf_format = SURFACEFORMAT_R8_UNORM;
143.11650 ++		src_width[1]  = src_width[0]  = frame->width;
143.11651 ++		src_height[1] = src_height[0] = frame->height;
143.11652 ++		src_pitch[1]  = src_pitch[0]  = frame->pitch[1];
143.11653 ++		src_width[4]  = src_width[5]  = src_width[2]  = src_width[3] =
143.11654 ++			frame->width / 2;
143.11655 ++		src_height[4] = src_height[5] = src_height[2] = src_height[3] =
143.11656 ++			frame->height / 2;
143.11657 ++		src_pitch[4]  = src_pitch[5]  = src_pitch[2]  = src_pitch[3] =
143.11658 ++			frame->pitch[0];
143.11659 ++		n_src = 6;
143.11660 ++	} else {
143.11661 ++		if (frame->id == FOURCC_RGB888)
143.11662 ++			src_surf_format = SURFACEFORMAT_B8G8R8X8_UNORM;
143.11663 ++		else if (frame->id == FOURCC_UYVY)
143.11664 ++			src_surf_format = SURFACEFORMAT_YCRCB_SWAPY;
143.11665 ++		else
143.11666 ++			src_surf_format = SURFACEFORMAT_YCRCB_NORMAL;
143.11667 ++
143.11668 ++		src_width[0]  = frame->width;
143.11669 ++		src_height[0] = frame->height;
143.11670 ++		src_pitch[0]  = frame->pitch[0];
143.11671 ++		n_src = 1;
143.11672 ++	}
143.11673 ++
143.11674 ++	binding_table = gen9_composite_get_binding_table(sna, &offset);
143.11675 ++
143.11676 ++	binding_table[0] =
143.11677 ++		gen9_bind_bo(sna,
143.11678 ++			     op->dst.bo, op->dst.width, op->dst.height,
143.11679 ++			     gen9_get_dest_format(op->dst.format),
143.11680 ++			     true);
143.11681 ++	for (n = 0; n < n_src; n++) {
143.11682 ++		binding_table[1+n] =
143.11683 ++			gen9_bind_video_source(sna,
143.11684 ++					       frame->bo,
143.11685 ++					       src_surf_base[n],
143.11686 ++					       src_width[n],
143.11687 ++					       src_height[n],
143.11688 ++					       src_pitch[n],
143.11689 ++					       src_surf_format);
143.11690 ++	}
143.11691 ++
143.11692 ++	gen9_emit_state(sna, op, offset);
143.11693 ++}
143.11694 ++
143.11695 ++static unsigned select_video_kernel(const struct sna_video_frame *frame)
143.11696 ++{
143.11697 ++	switch (frame->id) {
143.11698 ++	case FOURCC_YV12:
143.11699 ++	case FOURCC_I420:
143.11700 ++	case FOURCC_XVMC:
143.11701 ++		return GEN9_WM_KERNEL_VIDEO_PLANAR;
143.11702 ++
143.11703 ++	case FOURCC_RGB888:
143.11704 ++	case FOURCC_RGB565:
143.11705 ++		return GEN9_WM_KERNEL_VIDEO_RGB;
143.11706 ++
143.11707 ++	default:
143.11708 ++		return GEN9_WM_KERNEL_VIDEO_PACKED;
143.11709 ++	}
143.11710 ++}
143.11711 ++
143.11712 ++static bool
143.11713 ++gen9_render_video(struct sna *sna,
143.11714 ++		  struct sna_video *video,
143.11715 ++		  struct sna_video_frame *frame,
143.11716 ++		  RegionPtr dstRegion,
143.11717 ++		  PixmapPtr pixmap)
143.11718 ++{
143.11719 ++	struct sna_composite_op tmp;
143.11720 ++	struct sna_pixmap *priv = sna_pixmap(pixmap);
143.11721 ++	int dst_width = dstRegion->extents.x2 - dstRegion->extents.x1;
143.11722 ++	int dst_height = dstRegion->extents.y2 - dstRegion->extents.y1;
143.11723 ++	int src_width = frame->src.x2 - frame->src.x1;
143.11724 ++	int src_height = frame->src.y2 - frame->src.y1;
143.11725 ++	float src_offset_x, src_offset_y;
143.11726 ++	float src_scale_x, src_scale_y;
143.11727 ++	unsigned filter;
143.11728 ++	const BoxRec *box;
143.11729 ++	int nbox;
143.11730 ++
143.11731 ++	DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
143.11732 ++	     __FUNCTION__,
143.11733 ++	     src_width, src_height, dst_width, dst_height,
143.11734 ++	     region_num_rects(dstRegion),
143.11735 ++	     REGION_EXTENTS(NULL, dstRegion)->x1,
143.11736 ++	     REGION_EXTENTS(NULL, dstRegion)->y1,
143.11737 ++	     REGION_EXTENTS(NULL, dstRegion)->x2,
143.11738 ++	     REGION_EXTENTS(NULL, dstRegion)->y2));
143.11739 ++
143.11740 ++	assert(priv->gpu_bo);
143.11741 ++	assert(!too_large(pixmap->drawable.width, pixmap->drawable.height));
143.11742 ++	assert(!unaligned(priv->gpu_bo, pixmap->drawable.bitsPerPixel));
143.11743 ++
143.11744 ++	memset(&tmp, 0, sizeof(tmp));
143.11745 ++
143.11746 ++	tmp.dst.pixmap = pixmap;
143.11747 ++	tmp.dst.width  = pixmap->drawable.width;
143.11748 ++	tmp.dst.height = pixmap->drawable.height;
143.11749 ++	tmp.dst.format = sna_render_format_for_depth(pixmap->drawable.depth);
143.11750 ++	tmp.dst.bo = priv->gpu_bo;
143.11751 ++
143.11752 ++	tmp.src.bo = frame->bo;
143.11753 ++	tmp.mask.bo = NULL;
143.11754 ++
143.11755 ++	tmp.floats_per_vertex = 3;
143.11756 ++	tmp.floats_per_rect = 9;
143.11757 ++
143.11758 ++	DBG(("%s: scaling?=%d, planar?=%d [%x]\n",
143.11759 ++	     __FUNCTION__,
143.11760 ++	     src_width != dst_width || src_height != dst_height,
143.11761 ++	     is_planar_fourcc(frame->id), frame->id));
143.11762 ++
143.11763 ++	if (src_width == dst_width && src_height == dst_height)
143.11764 ++		filter = SAMPLER_FILTER_NEAREST;
143.11765 ++	else
143.11766 ++		filter = SAMPLER_FILTER_BILINEAR;
143.11767 ++
143.11768 ++	tmp.u.gen9.flags =
143.11769 ++		GEN9_SET_FLAGS(SAMPLER_OFFSET(filter, SAMPLER_EXTEND_PAD,
143.11770 ++					      SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE),
143.11771 ++			       NO_BLEND,
143.11772 ++			       select_video_kernel(frame),
143.11773 ++			       2);
143.11774 ++	tmp.priv = frame;
143.11775 ++
143.11776 ++	kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp.dst.bo);
143.11777 ++	if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL)) {
143.11778 ++		kgem_submit(&sna->kgem);
143.11779 ++		if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL))
143.11780 ++			return false;
143.11781 ++
143.11782 ++		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
143.11783 ++	}
143.11784 ++
143.11785 ++	gen9_align_vertex(sna, &tmp);
143.11786 ++	gen9_emit_video_state(sna, &tmp);
143.11787 ++
143.11788 ++	DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
143.11789 ++	     __FUNCTION__,
143.11790 ++	     frame->src.x1, frame->src.y1,
143.11791 ++	     src_width, src_height,
143.11792 ++	     dst_width, dst_height,
143.11793 ++	     frame->width, frame->height));
143.11794 ++
143.11795 ++	src_scale_x = (float)src_width / dst_width / frame->width;
143.11796 ++	src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
143.11797 ++
143.11798 ++	src_scale_y = (float)src_height / dst_height / frame->height;
143.11799 ++	src_offset_y = (float)frame->src.y1 / frame->height - dstRegion->extents.y1 * src_scale_y;
143.11800 ++
143.11801 ++	DBG(("%s: scale=(%f, %f), offset=(%f, %f)\n",
143.11802 ++	     __FUNCTION__,
143.11803 ++	     src_scale_x, src_scale_y,
143.11804 ++	     src_offset_x, src_offset_y));
143.11805 ++
143.11806 ++	box = region_rects(dstRegion);
143.11807 ++	nbox = region_num_rects(dstRegion);
143.11808 ++	while (nbox--) {
143.11809 ++		DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
143.11810 ++		     __FUNCTION__,
143.11811 ++		     box->x1, box->y1,
143.11812 ++		     box->x2, box->y2,
143.11813 ++		     box->x1 * src_scale_x + src_offset_x,
143.11814 ++		     box->y1 * src_scale_y + src_offset_y,
143.11815 ++		     box->x2 * src_scale_x + src_offset_x,
143.11816 ++		     box->y2 * src_scale_y + src_offset_y));
143.11817 ++
143.11818 ++		gen9_get_rectangles(sna, &tmp, 1, gen9_emit_video_state);
143.11819 ++
143.11820 ++		OUT_VERTEX(box->x2, box->y2);
143.11821 ++		OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
143.11822 ++		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.11823 ++
143.11824 ++		OUT_VERTEX(box->x1, box->y2);
143.11825 ++		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.11826 ++		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
143.11827 ++
143.11828 ++		OUT_VERTEX(box->x1, box->y1);
143.11829 ++		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
143.11830 ++		OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
143.11831 ++
143.11832 ++		box++;
143.11833 ++	}
143.11834 ++	gen8_vertex_flush(sna);
143.11835 ++
143.11836 ++	if (!DAMAGE_IS_ALL(priv->gpu_damage))
143.11837 ++		sna_damage_add(&priv->gpu_damage, dstRegion);
143.11838 ++
143.11839 ++	return true;
143.11840 ++}
143.11841 ++#endif
143.11842 ++
143.11843 ++static void gen9_render_flush(struct sna *sna)
143.11844 ++{
143.11845 ++	gen8_vertex_close(sna);
143.11846 ++
143.11847 ++	assert(sna->render.vb_id == 0);
143.11848 ++	assert(sna->render.vertex_offset == 0);
143.11849 ++}
143.11850 ++
143.11851 ++static void gen9_render_reset(struct sna *sna)
143.11852 ++{
143.11853 ++	sna->render_state.gen9.emit_flush = false;
143.11854 ++	sna->render_state.gen9.needs_invariant = true;
143.11855 ++	sna->render_state.gen9.ve_id = 3 << 2;
143.11856 ++	sna->render_state.gen9.ve_dirty = false;
143.11857 ++	sna->render_state.gen9.last_primitive = -1;
143.11858 ++
143.11859 ++	sna->render_state.gen9.num_sf_outputs = 0;
143.11860 ++	sna->render_state.gen9.samplers = -1;
143.11861 ++	sna->render_state.gen9.blend = -1;
143.11862 ++	sna->render_state.gen9.kernel = -1;
143.11863 ++	sna->render_state.gen9.drawrect_offset = -1;
143.11864 ++	sna->render_state.gen9.drawrect_limit = -1;
143.11865 ++	sna->render_state.gen9.surface_table = 0;
143.11866 ++
143.11867 ++	if (sna->render.vbo && !kgem_bo_can_map(&sna->kgem, sna->render.vbo)) {
143.11868 ++		DBG(("%s: discarding unmappable vbo\n", __FUNCTION__));
143.11869 ++		discard_vbo(sna);
143.11870 ++	}
143.11871 ++
143.11872 ++	sna->render.vertex_offset = 0;
143.11873 ++	sna->render.nvertex_reloc = 0;
143.11874 ++	sna->render.vb_id = 0;
143.11875 ++}
143.11876 ++
143.11877 ++static void gen9_render_fini(struct sna *sna)
143.11878 ++{
143.11879 ++	kgem_bo_destroy(&sna->kgem, sna->render_state.gen9.general_bo);
143.11880 ++}
143.11881 ++
143.11882 ++static bool gen9_render_setup(struct sna *sna)
143.11883 ++{
143.11884 ++	struct gen9_render_state *state = &sna->render_state.gen9;
143.11885 ++	struct sna_static_stream general;
143.11886 ++	struct gen9_sampler_state *ss;
143.11887 ++	int i, j, k, l, m;
143.11888 ++	uint32_t devid;
143.11889 ++
143.11890 ++	devid = intel_get_device_id(sna->dev);
143.11891 ++	if (devid & 0xf)
143.11892 ++		state->gt = GEN9_GT_BIAS + ((devid >> 4) & 0xf) + 1;
143.11893 ++	DBG(("%s: gt=%d\n", __FUNCTION__, state->gt));
143.11894 ++
143.11895 ++	state->info = &min_gt_info;
143.11896 ++	if (is_skl(sna))
143.11897 ++		state->info = &skl_gt_info;
143.11898 ++	if (is_bxt(sna))
143.11899 ++		state->info = &bxt_gt_info;
143.11900 ++	if (is_kbl(sna))
143.11901 ++		state->info = &kbl_gt_info;
143.11902 ++	if (is_glk(sna))
143.11903 ++		state->info = &glk_gt_info;
143.11904 ++
143.11905 ++	sna_static_stream_init(&general);
143.11906 ++
143.11907 ++	/* Zero pad the start. If you see an offset of 0x0 in the batchbuffer
143.11908 ++	 * dumps, you know it points to zero.
143.11909 ++	 */
143.11910 ++	null_create(&general);
143.11911 ++
143.11912 ++	for (m = 0; m < ARRAY_SIZE(wm_kernels); m++) {
143.11913 ++		if (wm_kernels[m].size) {
143.11914 ++			state->wm_kernel[m][1] =
143.11915 ++				sna_static_stream_add(&general,
143.11916 ++						      wm_kernels[m].data,
143.11917 ++						      wm_kernels[m].size,
143.11918 ++						      64);
143.11919 ++		} else {
143.11920 ++			if (USE_8_PIXEL_DISPATCH) {
143.11921 ++				state->wm_kernel[m][0] =
143.11922 ++					sna_static_stream_compile_wm(sna, &general,
143.11923 ++								     wm_kernels[m].data, 8);
143.11924 ++			}
143.11925 ++
143.11926 ++			if (USE_16_PIXEL_DISPATCH) {
143.11927 ++				state->wm_kernel[m][1] =
143.11928 ++					sna_static_stream_compile_wm(sna, &general,
143.11929 ++								     wm_kernels[m].data, 16);
143.11930 ++			}
143.11931 ++
143.11932 ++			if (USE_32_PIXEL_DISPATCH) {
143.11933 ++				state->wm_kernel[m][2] =
143.11934 ++					sna_static_stream_compile_wm(sna, &general,
143.11935 ++								     wm_kernels[m].data, 32);
143.11936 ++			}
143.11937 ++		}
143.11938 ++		assert(state->wm_kernel[m][0]|state->wm_kernel[m][1]|state->wm_kernel[m][2]);
143.11939 ++	}
143.11940 ++
143.11941 ++	COMPILE_TIME_ASSERT(SAMPLER_OFFSET(FILTER_COUNT, EXTEND_COUNT, FILTER_COUNT, EXTEND_COUNT) <= 0x7ff);
143.11942 ++	ss = sna_static_stream_map(&general,
143.11943 ++				   2 * sizeof(*ss) *
143.11944 ++				   (2 +
143.11945 ++				    FILTER_COUNT * EXTEND_COUNT *
143.11946 ++				    FILTER_COUNT * EXTEND_COUNT),
143.11947 ++				   32);
143.11948 ++	state->wm_state = sna_static_stream_offsetof(&general, ss);
143.11949 ++	sampler_copy_init(ss); ss += 2;
143.11950 ++	sampler_fill_init(ss); ss += 2;
143.11951 ++	for (i = 0; i < FILTER_COUNT; i++) {
143.11952 ++		for (j = 0; j < EXTEND_COUNT; j++) {
143.11953 ++			for (k = 0; k < FILTER_COUNT; k++) {
143.11954 ++				for (l = 0; l < EXTEND_COUNT; l++) {
143.11955 ++					sampler_state_init(ss++, i, j);
143.11956 ++					sampler_state_init(ss++, k, l);
143.11957 ++				}
143.11958 ++			}
143.11959 ++		}
143.11960 ++	}
143.11961 ++
143.11962 ++	state->cc_blend = gen9_create_blend_state(&general);
143.11963 ++
143.11964 ++	state->general_bo = sna_static_stream_fini(sna, &general);
143.11965 ++	return state->general_bo != NULL;
143.11966 ++}
143.11967 ++
143.11968 ++const char *gen9_render_init(struct sna *sna, const char *backend)
143.11969 ++{
143.11970 ++	if (!gen9_render_setup(sna))
143.11971 ++		return backend;
143.11972 ++
143.11973 ++	sna->kgem.context_switch = gen6_render_context_switch;
143.11974 ++	sna->kgem.retire = gen6_render_retire;
143.11975 ++	sna->kgem.expire = gen4_render_expire;
143.11976 ++
143.11977 ++#if !NO_COMPOSITE
143.11978 ++	sna->render.composite = gen9_render_composite;
143.11979 ++	sna->render.prefer_gpu |= PREFER_GPU_RENDER;
143.11980 ++#endif
143.11981 ++#if !NO_COMPOSITE_SPANS
143.11982 ++	sna->render.check_composite_spans = gen9_check_composite_spans;
143.11983 ++	sna->render.composite_spans = gen9_render_composite_spans;
143.11984 ++	sna->render.prefer_gpu |= PREFER_GPU_SPANS;
143.11985 ++#endif
143.11986 ++#if !NO_VIDEO
143.11987 ++	sna->render.video = gen9_render_video;
143.11988 ++#endif
143.11989 ++
143.11990 ++#if !NO_COPY_BOXES
143.11991 ++	sna->render.copy_boxes = gen9_render_copy_boxes;
143.11992 ++#endif
143.11993 ++#if !NO_COPY
143.11994 ++	sna->render.copy = gen9_render_copy;
143.11995 ++#endif
143.11996 ++
143.11997 ++#if !NO_FILL_BOXES
143.11998 ++	sna->render.fill_boxes = gen9_render_fill_boxes;
143.11999 ++#endif
143.12000 ++#if !NO_FILL
143.12001 ++	sna->render.fill = gen9_render_fill;
143.12002 ++#endif
143.12003 ++#if !NO_FILL_ONE
143.12004 ++	sna->render.fill_one = gen9_render_fill_one;
143.12005 ++#endif
143.12006 ++#if !NO_FILL_CLEAR
143.12007 ++	sna->render.clear = gen9_render_clear;
143.12008 ++#endif
143.12009 ++
143.12010 ++	sna->render.flush = gen9_render_flush;
143.12011 ++	sna->render.reset = gen9_render_reset;
143.12012 ++	sna->render.fini = gen9_render_fini;
143.12013 ++
143.12014 ++	sna->render.max_3d_size = GEN9_MAX_SIZE;
143.12015 ++	sna->render.max_3d_pitch = 1 << 18;
143.12016 ++	return sna->render_state.gen9.info->name;
143.12017 ++}
143.12018 +diff --git a/src/sna/gen9_render.h b/src/sna/gen9_render.h
143.12019 +new file mode 100644
143.12020 +index 00000000..e3cb3f93
143.12021 +--- /dev/null
143.12022 ++++ b/src/sna/gen9_render.h
143.12023 +@@ -0,0 +1,1130 @@
143.12024 ++#ifndef GEN9_RENDER_H
143.12025 ++#define GEN9_RENDER_H
143.12026 ++
143.12027 ++#define INTEL_MASK(high, low) (((1 << ((high) - (low) + 1)) - 1) << (low))
143.12028 ++
143.12029 ++#define GEN9_3D(pipeline,op,sub) \
143.12030 ++	((3 << 29) | ((pipeline) << 27) | ((op) << 24) | ((sub) << 16))
143.12031 ++
143.12032 ++#define GEN9_STATE_BASE_ADDRESS			GEN9_3D(0, 1, 1)
143.12033 ++# define BASE_ADDRESS_MODIFY			(1 << 0)
143.12034 ++
143.12035 ++#define GEN9_STATE_SIP				GEN9_3D(0, 1, 2)
143.12036 ++
143.12037 ++#define GEN9_3DSTATE_VF_STATISTICS		GEN9_3D(1, 0, 0xb)
143.12038 ++#define GEN9_PIPELINE_SELECT			GEN9_3D(1, 1, 4)
143.12039 ++# define PIPELINE_SELECT_3D		0
143.12040 ++# define PIPELINE_SELECT_MEDIA		1
143.12041 ++#define PIPELINE_SELECTION_MASK            (3 << 8)
143.12042 ++
143.12043 ++#define GEN9_MEDIA_STATE_POINTERS		GEN9_3D(2, 0, 0)
143.12044 ++#define GEN9_MEDIA_OBJECT			GEN9_3D(2, 1, 0)
143.12045 ++
143.12046 ++#define GEN9_3DSTATE_CLEAR_PARAMS               GEN9_3D(3, 0, 0x04)
143.12047 ++#define GEN9_3DSTATE_DEPTH_BUFFER               GEN9_3D(3, 0, 0x05)
143.12048 ++# define DEPTH_BUFFER_TYPE_SHIFT	29
143.12049 ++# define DEPTH_BUFFER_FORMAT_SHIFT	18
143.12050 ++
143.12051 ++#define GEN9_3DSTATE_STENCIL_BUFFER		GEN9_3D(3, 0, 0x06)
143.12052 ++#define GEN9_3DSTATE_HIER_DEPTH_BUFFER		GEN9_3D(3, 0, 0x07)
143.12053 ++#define GEN9_3DSTATE_VERTEX_BUFFERS		GEN9_3D(3, 0, 0x08)
143.12054 ++# define VB_INDEX_SHIFT			26
143.12055 ++# define VB_MODIFY_ENABLE		(1 << 14)
143.12056 ++#define GEN9_3DSTATE_VERTEX_ELEMENTS		GEN9_3D(3, 0, 0x09)
143.12057 ++# define VE_INDEX_SHIFT		26
143.12058 ++# define VE_VALID					(1 << 25)
143.12059 ++# define VE_FORMAT_SHIFT				16
143.12060 ++# define VE_OFFSET_SHIFT				0
143.12061 ++# define VE_COMPONENT_0_SHIFT			28
143.12062 ++# define VE_COMPONENT_1_SHIFT			24
143.12063 ++# define VE_COMPONENT_2_SHIFT			20
143.12064 ++# define VE_COMPONENT_3_SHIFT			16
143.12065 ++#define GEN9_3DSTATE_INDEX_BUFFER		GEN9_3D(3, 0, 0x0a)
143.12066 ++#define GEN9_3DSTATE_VF				GEN9_3D(3, 0, 0x0c)
143.12067 ++
143.12068 ++#define GEN9_3DSTATE_MULTISAMPLE		GEN9_3D(3, 0, 0x0d)
143.12069 ++/* DW1 */
143.12070 ++# define MULTISAMPLE_PIXEL_LOCATION_CENTER		(0 << 4)
143.12071 ++# define MULTISAMPLE_PIXEL_LOCATION_UPPER_LEFT	(1 << 4)
143.12072 ++# define MULTISAMPLE_NUMSAMPLES_1			(0 << 1)
143.12073 ++# define MULTISAMPLE_NUMSAMPLES_4			(2 << 1)
143.12074 ++# define MULTISAMPLE_NUMSAMPLES_8			(3 << 1)
143.12075 ++
143.12076 ++#define GEN9_3DSTATE_CC_STATE_POINTERS		GEN9_3D(3, 0, 0x0e)
143.12077 ++#define GEN9_3DSTATE_SCISSOR_STATE_POINTERS	GEN9_3D(3, 0, 0x0f)
143.12078 ++
143.12079 ++#define GEN9_3DSTATE_VS				GEN9_3D(3, 0, 0x10)
143.12080 ++#define GEN9_3DSTATE_GS				GEN9_3D(3, 0, 0x11)
143.12081 ++#define GEN9_3DSTATE_CLIP			GEN9_3D(3, 0, 0x12)
143.12082 ++#define GEN9_3DSTATE_SF				GEN9_3D(3, 0, 0x13)
143.12083 ++# define SF_TRI_PROVOKE_SHIFT		29
143.12084 ++# define SF_LINE_PROVOKE_SHIFT		27
143.12085 ++# define SF_FAN_PROVOKE_SHIFT		25
143.12086 ++
143.12087 ++#define GEN9_3DSTATE_WM				GEN9_3D(3, 0, 0x14)
143.12088 ++/* DW1 */
143.12089 ++# define WM_STATISTICS_ENABLE                              (1 << 31)
143.12090 ++# define WM_DEPTH_CLEAR                                    (1 << 30)
143.12091 ++# define WM_DEPTH_RESOLVE                                  (1 << 28)
143.12092 ++# define WM_HIERARCHICAL_DEPTH_RESOLVE                     (1 << 27)
143.12093 ++# define WM_KILL_ENABLE                                    (1 << 25)
143.12094 ++# define WM_POSITION_ZW_PIXEL                              (0 << 17)
143.12095 ++# define WM_POSITION_ZW_CENTROID                           (2 << 17)
143.12096 ++# define WM_POSITION_ZW_SAMPLE                             (3 << 17)
143.12097 ++# define WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC              (1 << 16)
143.12098 ++# define WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC            (1 << 15)
143.12099 ++# define WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC               (1 << 14)
143.12100 ++# define WM_PERSPECTIVE_SAMPLE_BARYCENTRIC                 (1 << 13)
143.12101 ++# define WM_PERSPECTIVE_CENTROID_BARYCENTRIC               (1 << 12)
143.12102 ++# define WM_PERSPECTIVE_PIXEL_BARYCENTRIC                  (1 << 11)
143.12103 ++# define WM_LINE_END_CAP_AA_WIDTH_0_5                      (0 << 8)
143.12104 ++# define WM_LINE_END_CAP_AA_WIDTH_1_0                      (1 << 8)
143.12105 ++# define WM_LINE_END_CAP_AA_WIDTH_2_0                      (2 << 8)
143.12106 ++# define WM_LINE_END_CAP_AA_WIDTH_4_0                      (3 << 8)
143.12107 ++# define WM_LINE_AA_WIDTH_0_5                              (0 << 6)
143.12108 ++# define WM_LINE_AA_WIDTH_1_0                              (1 << 6)
143.12109 ++# define WM_LINE_AA_WIDTH_2_0                              (2 << 6)
143.12110 ++# define WM_LINE_AA_WIDTH_4_0                              (3 << 6)
143.12111 ++# define WM_POLYGON_STIPPLE_ENABLE                         (1 << 4)
143.12112 ++# define WM_LINE_STIPPLE_ENABLE                            (1 << 3)
143.12113 ++# define WM_POINT_RASTRULE_UPPER_RIGHT                     (1 << 2)
143.12114 ++# define WM_MSRAST_OFF_PIXEL                               (0 << 0)
143.12115 ++# define WM_MSRAST_OFF_PATTERN                             (1 << 0)
143.12116 ++# define WM_MSRAST_ON_PIXEL                                (2 << 0)
143.12117 ++# define WM_MSRAST_ON_PATTERN                              (3 << 0)
143.12118 ++
143.12119 ++#define GEN9_3DSTATE_CONSTANT_VS		GEN9_3D(3, 0, 0x15)
143.12120 ++#define GEN9_3DSTATE_CONSTANT_GS		GEN9_3D(3, 0, 0x16)
143.12121 ++#define GEN9_3DSTATE_CONSTANT_PS		GEN9_3D(3, 0, 0x17)
143.12122 ++
143.12123 ++#define GEN9_3DSTATE_SAMPLE_MASK		GEN9_3D(3, 0, 0x18)
143.12124 ++
143.12125 ++#define GEN9_3DSTATE_CONSTANT_HS                GEN9_3D(3, 0, 0x19)
143.12126 ++#define GEN9_3DSTATE_CONSTANT_DS                GEN9_3D(3, 0, 0x1a)
143.12127 ++
143.12128 ++#define GEN9_3DSTATE_HS                         GEN9_3D(3, 0, 0x1b)
143.12129 ++#define GEN9_3DSTATE_TE                         GEN9_3D(3, 0, 0x1c)
143.12130 ++#define GEN9_3DSTATE_DS                         GEN9_3D(3, 0, 0x1d)
143.12131 ++#define GEN9_3DSTATE_STREAMOUT                  GEN9_3D(3, 0, 0x1e)
143.12132 ++
143.12133 ++#define GEN9_3DSTATE_SBE                        GEN9_3D(3, 0, 0x1f)
143.12134 ++/* DW1 */
143.12135 ++# define SBE_FORCE_VERTEX_URB_READ_LENGTH  (1<<29)
143.12136 ++# define SBE_FORCE_VERTEX_URB_READ_OFFSET  (1<<28)
143.12137 ++# define SBE_NUM_OUTPUTS_SHIFT             22
143.12138 ++# define SBE_SWIZZLE_ENABLE                (1 << 21)
143.12139 ++# define SBE_POINT_SPRITE_LOWERLEFT        (1 << 20)
143.12140 ++# define SBE_URB_ENTRY_READ_LENGTH_SHIFT   11
143.12141 ++# define SBE_URB_ENTRY_READ_OFFSET_SHIFT   5
143.12142 ++#define SBE_ACTIVE_COMPONENT_NONE          0
143.12143 ++#define SBE_ACTIVE_COMPONENT_XY            1 
143.12144 ++#define SBE_ACTIVE_COMPONENT_XYZ           2
143.12145 ++#define SBE_ACTIVE_COMPONENT_XYZW          3
143.12146 ++
143.12147 ++
143.12148 ++#define GEN9_3DSTATE_PS                                 GEN9_3D(3, 0, 0x20)
143.12149 ++/* DW1:DW2 kernel pointer */
143.12150 ++/* DW3 */
143.12151 ++# define PS_SPF_MODE                               (1 << 31)
143.12152 ++# define PS_VECTOR_MASK_ENABLE                     (1 << 30)
143.12153 ++# define PS_SAMPLER_COUNT_SHIFT                    27
143.12154 ++# define PS_BINDING_TABLE_ENTRY_COUNT_SHIFT        18
143.12155 ++# define PS_FLOATING_POINT_MODE_IEEE_754           (0 << 16)
143.12156 ++# define PS_FLOATING_POINT_MODE_ALT                (1 << 16)
143.12157 ++/* DW4:DW5: scratch space */
143.12158 ++/* DW6 */
143.12159 ++# define PS_MAX_THREADS_SHIFT                      23
143.12160 ++# define PS_MAX_THREADS                            (63 << PS_MAX_THREADS_SHIFT)
143.12161 ++# define PS_PUSH_CONSTANT_ENABLE                   (1 << 11)
143.12162 ++# define PS_RENDER_TARGET_CLEAR			   (1 << 8)
143.12163 ++# define PS_RENDER_TARGET_RESOLVE		   (1 << 6)
143.12164 ++# define PS_POSOFFSET_NONE                         (0 << 3)
143.12165 ++# define PS_POSOFFSET_CENTROID                     (2 << 3)
143.12166 ++# define PS_POSOFFSET_SAMPLE                       (3 << 3)
143.12167 ++# define PS_32_DISPATCH_ENABLE                     (1 << 2)
143.12168 ++# define PS_16_DISPATCH_ENABLE                     (1 << 1)
143.12169 ++# define PS_8_DISPATCH_ENABLE                      (1 << 0)
143.12170 ++/* DW7 */
143.12171 ++# define PS_DISPATCH_START_GRF_SHIFT_0             16
143.12172 ++# define PS_DISPATCH_START_GRF_SHIFT_1             8
143.12173 ++# define PS_DISPATCH_START_GRF_SHIFT_2             0
143.12174 ++/* DW8:D9: kernel 1 pointer */
143.12175 ++/* DW10:D11: kernel 2 pointer */
143.12176 ++
143.12177 ++#define GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP      GEN9_3D(3, 0, 0x21)
143.12178 ++#define GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_CC         GEN9_3D(3, 0, 0x23)
143.12179 ++
143.12180 ++#define GEN9_3DSTATE_BLEND_STATE_POINTERS               GEN9_3D(3, 0, 0x24)
143.12181 ++
143.12182 ++#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_VS          GEN9_3D(3, 0, 0x26)
143.12183 ++#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_HS          GEN9_3D(3, 0, 0x27)
143.12184 ++#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_DS          GEN9_3D(3, 0, 0x28)
143.12185 ++#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_GS          GEN9_3D(3, 0, 0x29)
143.12186 ++#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_PS          GEN9_3D(3, 0, 0x2a)
143.12187 ++
143.12188 ++#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_VS          GEN9_3D(3, 0, 0x2b)
143.12189 ++#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_HS          GEN9_3D(3, 0, 0x2c)
143.12190 ++#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_DS          GEN9_3D(3, 0, 0x2d)
143.12191 ++#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_GS          GEN9_3D(3, 0, 0x2e)
143.12192 ++#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_PS          GEN9_3D(3, 0, 0x2f)
143.12193 ++
143.12194 ++#define GEN9_3DSTATE_URB_VS                             GEN9_3D(3, 0, 0x30)
143.12195 ++#define GEN9_3DSTATE_URB_HS                             GEN9_3D(3, 0, 0x31)
143.12196 ++#define GEN9_3DSTATE_URB_DS                             GEN9_3D(3, 0, 0x32)
143.12197 ++#define GEN9_3DSTATE_URB_GS                             GEN9_3D(3, 0, 0x33)
143.12198 ++/* DW1 */
143.12199 ++# define URB_ENTRY_NUMBER_SHIFT            0
143.12200 ++# define URB_ENTRY_SIZE_SHIFT              16
143.12201 ++# define URB_STARTING_ADDRESS_SHIFT        25
143.12202 ++
143.12203 ++#define GEN9_3DSTATE_GATHER_CONSTANT_VS             GEN9_3D(3, 0, 0x34)
143.12204 ++#define GEN9_3DSTATE_GATHER_CONSTANT_GS             GEN9_3D(3, 0, 0x35)
143.12205 ++#define GEN9_3DSTATE_GATHER_CONSTANT_HS             GEN9_3D(3, 0, 0x36)
143.12206 ++#define GEN9_3DSTATE_GATHER_CONSTANT_DS             GEN9_3D(3, 0, 0x37)
143.12207 ++#define GEN9_3DSTATE_GATHER_CONSTANT_PS             GEN9_3D(3, 0, 0x38)
143.12208 ++
143.12209 ++#define GEN9_3DSTATE_DX9_CONSTANTF_VS             GEN9_3D(3, 0, 0x39)
143.12210 ++#define GEN9_3DSTATE_DX9_CONSTANTF_PS             GEN9_3D(3, 0, 0x3a)
143.12211 ++#define GEN9_3DSTATE_DX9_CONSTANTI_VS             GEN9_3D(3, 0, 0x3b)
143.12212 ++#define GEN9_3DSTATE_DX9_CONSTANTI_PS             GEN9_3D(3, 0, 0x3c)
143.12213 ++#define GEN9_3DSTATE_DX9_CONSTANTB_VS             GEN9_3D(3, 0, 0x3d)
143.12214 ++#define GEN9_3DSTATE_DX9_CONSTANTB_PS             GEN9_3D(3, 0, 0x3e)
143.12215 ++#define GEN9_3DSTATE_DX9_LOCAL_VALID_VS           GEN9_3D(3, 0, 0x3f)
143.12216 ++#define GEN9_3DSTATE_DX9_LOCAL_VALID_PS           GEN9_3D(3, 0, 0x40)
143.12217 ++#define GEN9_3DSTATE_DX9_GENERATE_ACTIVE_VS       GEN9_3D(3, 0, 0x41)
143.12218 ++#define GEN9_3DSTATE_DX9_GENERATE_ACTIVE_PS       GEN9_3D(3, 0, 0x42)
143.12219 ++
143.12220 ++#define GEN9_3DSTATE_BINDING_TABLE_EDIT_VS       GEN9_3D(3, 0, 0x43)
143.12221 ++#define GEN9_3DSTATE_BINDING_TABLE_EDIT_GS       GEN9_3D(3, 0, 0x44)
143.12222 ++#define GEN9_3DSTATE_BINDING_TABLE_EDIT_HS       GEN9_3D(3, 0, 0x45)
143.12223 ++#define GEN9_3DSTATE_BINDING_TABLE_EDIT_DS       GEN9_3D(3, 0, 0x46)
143.12224 ++#define GEN9_3DSTATE_BINDING_TABLE_EDIT_PS       GEN9_3D(3, 0, 0x47)
143.12225 ++
143.12226 ++#define GEN9_3DSTATE_VF_INSTANCING		GEN9_3D(3, 0, 0x49)
143.12227 ++#define GEN9_3DSTATE_VF_SGVS			GEN9_3D(3, 0, 0x4a)
143.12228 ++# define SGVS_ENABLE_INSTANCE_ID			(1 << 31)
143.12229 ++# define SGVS_INSTANCE_ID_COMPONENT_SHIFT		29
143.12230 ++# define SGVS_INSTANCE_ID_ELEMENT_OFFSET_SHIFT	16
143.12231 ++# define SGVS_ENABLE_VERTEX_ID			(1 << 15)
143.12232 ++# define SGVS_VERTEX_ID_COMPONENT_SHIFT            13
143.12233 ++# define SGVS_VERTEX_ID_ELEMENT_OFFSET_SHIFT	0
143.12234 ++#define GEN9_3DSTATE_VF_TOPOLOGY		GEN9_3D(3, 0, 0x4b)
143.12235 ++# define POINTLIST         0x01
143.12236 ++# define LINELIST          0x02
143.12237 ++# define LINESTRIP         0x03
143.12238 ++# define TRILIST           0x04
143.12239 ++# define TRISTRIP          0x05
143.12240 ++# define TRIFAN            0x06
143.12241 ++# define QUADLIST          0x07
143.12242 ++# define QUADSTRIP         0x08
143.12243 ++# define LINELIST_ADJ      0x09
143.12244 ++# define LINESTRIP_ADJ     0x0A
143.12245 ++# define TRILIST_ADJ       0x0B
143.12246 ++# define TRISTRIP_ADJ      0x0C
143.12247 ++# define TRISTRIP_REVERSE  0x0D
143.12248 ++# define POLYGON           0x0E
143.12249 ++# define RECTLIST          0x0F
143.12250 ++# define LINELOOP          0x10
143.12251 ++# define POINTLIST_BF      0x11
143.12252 ++# define LINESTRIP_CONT    0x12
143.12253 ++# define LINESTRIP_BF      0x13
143.12254 ++# define LINESTRIP_CONT_BF 0x14
143.12255 ++# define TRIFAN_NOSTIPPLE  0x15
143.12256 ++
143.12257 ++#define GEN9_3DSTATE_WM_CHROMAKEY		GEN9_3D(3, 0, 0x4c)
143.12258 ++
143.12259 ++#define GEN9_3DSTATE_PS_BLEND				GEN9_3D(3, 0, 0x4d)
143.12260 ++# define PS_BLEND_ALPHA_TO_COVERAGE_ENABLE		(1 << 31)
143.12261 ++# define PS_BLEND_HAS_WRITEABLE_RT			(1 << 30)
143.12262 ++# define PS_BLEND_COLOR_BLEND_ENABLE			(1 << 29)
143.12263 ++# define PS_BLEND_SRC_ALPHA_SHIFT			24
143.12264 ++# define PS_BLEND_DST_ALPHA_SHIFT			19
143.12265 ++# define PS_BLEND_SRC_SHIFT				14
143.12266 ++# define PS_BLEND_DST_SHIFT				9
143.12267 ++# define PS_BLEND_ALPHA_TEST_ENABLE			(1 << 8)
143.12268 ++# define PS_BLEND_INDEPENDENT_ALPHA_BLEND_ENABLE	(1 << 7)
143.12269 ++
143.12270 ++#define GEN9_3DSTATE_WM_DEPTH_STENCIL		GEN9_3D(3, 0, 0x4e)
143.12271 ++/* DW1 */
143.12272 ++# define WM_DS_STENCIL_TEST_MASK_MASK		INTEL_MASK(31, 24)
143.12273 ++# define WM_DS_STENCIL_TEST_MASK_SHIFT		24
143.12274 ++# define WM_DS_STENCIL_WRITE_MASK_MASK		INTEL_MASK(23, 16)
143.12275 ++# define WM_DS_STENCIL_WRITE_MASK_SHIFT		16
143.12276 ++# define WM_DS_BF_STENCIL_TEST_MASK_MASK		INTEL_MASK(15, 8)
143.12277 ++# define WM_DS_BF_STENCIL_TEST_MASK_SHIFT		8
143.12278 ++# define WM_DS_BF_STENCIL_WRITE_MASK_MASK		INTEL_MASK(7, 0)
143.12279 ++# define WM_DS_DEPTH_FUNC_SHIFT			5
143.12280 ++# define WM_DS_DOUBLE_SIDED_STENCIL_ENABLE		(1 << 4)
143.12281 ++# define WM_DS_STENCIL_TEST_ENABLE			(1 << 3)
143.12282 ++# define WM_DS_STENCIL_BUFFER_WRITE_ENABLE		(1 << 2)
143.12283 ++# define WM_DS_DEPTH_TEST_ENABLE			(1 << 1)
143.12284 ++# define WM_DS_DEPTH_BUFFER_WRITE_ENABLE		(1 << 0)
143.12285 ++/* DW2 */
143.12286 ++# define WM_DS_STENCIL_TEST_MASK_MASK		INTEL_MASK(31, 24)
143.12287 ++# define WM_DS_STENCIL_TEST_MASK_SHIFT		24
143.12288 ++# define WM_DS_STENCIL_WRITE_MASK_MASK		INTEL_MASK(23, 16)
143.12289 ++# define WM_DS_STENCIL_WRITE_MASK_SHIFT		16
143.12290 ++# define WM_DS_BF_STENCIL_TEST_MASK_MASK		INTEL_MASK(15, 8)
143.12291 ++# define WM_DS_BF_STENCIL_TEST_MASK_SHIFT		8
143.12292 ++# define WM_DS_BF_STENCIL_WRITE_MASK_MASK		INTEL_MASK(7, 0)
143.12293 ++# define WM_DS_BF_STENCIL_WRITE_MASK_SHIFT		0
143.12294 ++
143.12295 ++#define GEN9_3DSTATE_PS_EXTRA		GEN9_3D(3, 0, 0x4f)
143.12296 ++# define PSX_PIXEL_SHADER_VALID                    (1 << 31)
143.12297 ++# define PSX_PIXEL_SHADER_NO_RT_WRITE              (1 << 30)
143.12298 ++# define PSX_OMASK_TO_RENDER_TARGET                (1 << 29)
143.12299 ++# define PSX_KILL_ENABLE                           (1 << 28)
143.12300 ++# define PSX_PSCDEPTH_OFF                          (0 << 26)
143.12301 ++# define PSX_PSCDEPTH_ON                           (1 << 26)
143.12302 ++# define PSX_PSCDEPTH_ON_GE                        (2 << 26)
143.12303 ++# define PSX_PSCDEPTH_ON_LE                        (3 << 26)
143.12304 ++# define PSX_FORCE_COMPUTED_DEPTH                  (1 << 25)
143.12305 ++# define PSX_USES_SOURCE_DEPTH                     (1 << 24)
143.12306 ++# define PSX_USES_SOURCE_W                         (1 << 23)
143.12307 ++# define PSX_ATTRIBUTE_ENABLE                      (1 << 8)
143.12308 ++# define PSX_SHADER_DISABLES_ALPHA_TO_COVERAGE     (1 << 7)
143.12309 ++# define PSX_SHADER_IS_PER_SAMPLE                  (1 << 6)
143.12310 ++# define PSX_SHADER_HAS_UAV                        (1 << 2)
143.12311 ++# define PSX_SHADER_USES_INPUT_COVERAGE_MASK       (1 << 1)
143.12312 ++
143.12313 ++#define GEN9_3DSTATE_RASTER		GEN9_3D(3, 0, 0x50)
143.12314 ++/* DW1 */
143.12315 ++# define RASTER_FRONT_WINDING_CCW                  (1 << 21)
143.12316 ++# define RASTER_CULL_BOTH                          (0 << 16)
143.12317 ++# define RASTER_CULL_NONE                          (1 << 16)
143.12318 ++# define RASTER_CULL_FRONT                         (2 << 16)
143.12319 ++# define RASTER_CULL_BACK                          (3 << 16)
143.12320 ++# define RASTER_SMOOTH_POINT_ENABLE                (1 << 13)
143.12321 ++# define RASTER_LINE_AA_ENABLE                     (1 << 2)
143.12322 ++# define RASTER_VIEWPORT_Z_CLIP_TEST_ENABLE        (1 << 0)
143.12323 ++
143.12324 ++#define GEN9_3DSTATE_SBE_SWIZ		GEN9_3D(3, 0, 0x51)
143.12325 ++#define GEN9_3DSTATE_WM_HZ_OP		GEN9_3D(3, 0, 0x52)
143.12326 ++
143.12327 ++#define GEN9_3DSTATE_COMPONENT_PACKING          GEN6_3D(3, 0, 0x55)
143.12328 ++
143.12329 ++
143.12330 ++
143.12331 ++#define GEN9_3DSTATE_DRAWING_RECTANGLE		GEN9_3D(3, 1, 0x00)
143.12332 ++#define GEN9_3DSTATE_SAMPLER_PALETTE_LOAD	GEN9_3D(3, 1, 0x02)
143.12333 ++#define GEN9_3DSTATE_CHROMA_KEY			GEN9_3D(3, 1, 0x04)
143.12334 ++
143.12335 ++#define GEN9_3DSTATE_POLY_STIPPLE_OFFSET	GEN9_3D(3, 1, 0x06)
143.12336 ++#define GEN9_3DSTATE_POLY_STIPPLE_PATTERN	GEN9_3D(3, 1, 0x07)
143.12337 ++#define GEN9_3DSTATE_LINE_STIPPLE		GEN9_3D(3, 1, 0x08)
143.12338 ++#define GEN9_3DSTATE_AA_LINE_PARAMS		GEN9_3D(3, 1, 0x0a)
143.12339 ++#define GEN9_3DSTATE_SAMPLER_PALETTE_LOAD1	GEN9_3D(3, 1, 0x0c)
143.12340 ++#define GEN9_3DSTATE_MONOFILTER_SIZE		GEN9_3D(3, 1, 0x11)
143.12341 ++#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_VS	GEN9_3D(3, 1, 0x12)
143.12342 ++#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_HS	GEN9_3D(3, 1, 0x13)
143.12343 ++#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_DS	GEN9_3D(3, 1, 0x14)
143.12344 ++#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_GS	GEN9_3D(3, 1, 0x15)
143.12345 ++#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_PS	GEN9_3D(3, 1, 0x16)
143.12346 ++/* DW1 */
143.12347 ++# define PUSH_CONSTANT_BUFFER_OFFSET_SHIFT 16
143.12348 ++# define PUSH_CONSTANT_BUFFER_SIZE_SHIFT 0
143.12349 ++
143.12350 ++#define GEN9_3DSTATE_SO_DECL_LIST		GEN9_3D(3, 1, 0x17)
143.12351 ++#define GEN9_3DSTATE_SO_BUFFER			GEN9_3D(3, 1, 0x18)
143.12352 ++#define GEN9_3DSTATE_BINDING_TABLE_POOL_ALLOC	GEN9_3D(3, 1, 0x19)
143.12353 ++#define GEN9_3DSTATE_GATHER_BUFFER_POOL_ALLOC	GEN9_3D(3, 1, 0x1a)
143.12354 ++#define GEN9_3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC	GEN9_3D(3, 1, 0x1b)
143.12355 ++#define GEN9_3DSTATE_SAMPLE_PATTERN		GEN9_3D(3, 1, 0x1c)
143.12356 ++
143.12357 ++
143.12358 ++/* for GEN9_PIPE_CONTROL */
143.12359 ++#define GEN9_PIPE_CONTROL		GEN9_3D(3, 2, 0)
143.12360 ++#define PIPE_CONTROL_CS_STALL      (1 << 20)
143.12361 ++#define PIPE_CONTROL_NOWRITE       (0 << 14)
143.12362 ++#define PIPE_CONTROL_WRITE_QWORD   (1 << 14)
143.12363 ++#define PIPE_CONTROL_WRITE_DEPTH   (2 << 14)
143.12364 ++#define PIPE_CONTROL_WRITE_TIME    (3 << 14)
143.12365 ++#define PIPE_CONTROL_DEPTH_STALL   (1 << 13)
143.12366 ++#define PIPE_CONTROL_WC_FLUSH      (1 << 12)
143.12367 ++#define PIPE_CONTROL_IS_FLUSH      (1 << 11)
143.12368 ++#define PIPE_CONTROL_TC_FLUSH      (1 << 10)
143.12369 ++#define PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
143.12370 ++#define PIPE_CONTROL_FLUSH         (1 << 7)
143.12371 ++#define PIPE_CONTROL_GLOBAL_GTT    (1 << 2)
143.12372 ++#define PIPE_CONTROL_LOCAL_PGTT    (0 << 2)
143.12373 ++#define PIPE_CONTROL_STALL_AT_SCOREBOARD   (1 << 1)
143.12374 ++#define PIPE_CONTROL_DEPTH_CACHE_FLUSH	(1 << 0)
143.12375 ++
143.12376 ++
143.12377 ++#define GEN9_3DPRIMITIVE			GEN9_3D(3, 3, 0)
143.12378 ++
143.12379 ++/* 3DPRIMITIVE bits */
143.12380 ++#define VERTEX_SEQUENTIAL (0 << 15)
143.12381 ++#define VERTEX_RANDOM	  (1 << 15)
143.12382 ++
143.12383 ++#define ANISORATIO_2     0
143.12384 ++#define ANISORATIO_4     1
143.12385 ++#define ANISORATIO_6     2
143.12386 ++#define ANISORATIO_8     3
143.12387 ++#define ANISORATIO_10    4
143.12388 ++#define ANISORATIO_12    5
143.12389 ++#define ANISORATIO_14    6
143.12390 ++#define ANISORATIO_16    7
143.12391 ++
143.12392 ++#define BLENDFACTOR_ONE                 0x1
143.12393 ++#define BLENDFACTOR_SRC_COLOR           0x2
143.12394 ++#define BLENDFACTOR_SRC_ALPHA           0x3
143.12395 ++#define BLENDFACTOR_DST_ALPHA           0x4
143.12396 ++#define BLENDFACTOR_DST_COLOR           0x5
143.12397 ++#define BLENDFACTOR_SRC_ALPHA_SATURATE  0x6
143.12398 ++#define BLENDFACTOR_CONST_COLOR         0x7
143.12399 ++#define BLENDFACTOR_CONST_ALPHA         0x8
143.12400 ++#define BLENDFACTOR_SRC1_COLOR          0x9
143.12401 ++#define BLENDFACTOR_SRC1_ALPHA          0x0A
143.12402 ++#define BLENDFACTOR_ZERO                0x11
143.12403 ++#define BLENDFACTOR_INV_SRC_COLOR       0x12
143.12404 ++#define BLENDFACTOR_INV_SRC_ALPHA       0x13
143.12405 ++#define BLENDFACTOR_INV_DST_ALPHA       0x14
143.12406 ++#define BLENDFACTOR_INV_DST_COLOR       0x15
143.12407 ++#define BLENDFACTOR_INV_CONST_COLOR     0x17
143.12408 ++#define BLENDFACTOR_INV_CONST_ALPHA     0x18
143.12409 ++#define BLENDFACTOR_INV_SRC1_COLOR      0x19
143.12410 ++#define BLENDFACTOR_INV_SRC1_ALPHA      0x1A
143.12411 ++
143.12412 ++#define BLENDFUNCTION_ADD               0
143.12413 ++#define BLENDFUNCTION_SUBTRACT          1
143.12414 ++#define BLENDFUNCTION_REVERSE_SUBTRACT  2
143.12415 ++#define GEN9_BLENDFUNCTION_MIN               3
143.12416 ++#define BLENDFUNCTION_MAX               4
143.12417 ++
143.12418 ++#define ALPHATEST_FORMAT_UNORM8         0
143.12419 ++#define ALPHATEST_FORMAT_FLOAT32        1
143.12420 ++
143.12421 ++#define CHROMAKEY_KILL_ON_ANY_MATCH  0
143.12422 ++#define CHROMAKEY_REPLACE_BLACK      1
143.12423 ++
143.12424 ++#define CLIP_API_OGL     0
143.12425 ++#define CLIP_API_DX      1
143.12426 ++
143.12427 ++#define CLIPMODE_NORMAL              0
143.12428 ++#define CLIPMODE_CLIP_ALL            1
143.12429 ++#define CLIPMODE_CLIP_NON_REJECTED   2
143.12430 ++#define CLIPMODE_REJECT_ALL          3
143.12431 ++#define CLIPMODE_ACCEPT_ALL          4
143.12432 ++
143.12433 ++#define CLIP_NDCSPACE     0
143.12434 ++#define CLIP_SCREENSPACE  1
143.12435 ++
143.12436 ++#define COMPAREFUNCTION_ALWAYS       0
143.12437 ++#define COMPAREFUNCTION_NEVER        1
143.12438 ++#define COMPAREFUNCTION_LESS         2
143.12439 ++#define COMPAREFUNCTION_EQUAL        3
143.12440 ++#define COMPAREFUNCTION_LEQUAL       4
143.12441 ++#define COMPAREFUNCTION_GREATER      5
143.12442 ++#define COMPAREFUNCTION_NOTEQUAL     6
143.12443 ++#define COMPAREFUNCTION_GEQUAL       7
143.12444 ++
143.12445 ++#define COVERAGE_PIXELS_HALF     0
143.12446 ++#define COVERAGE_PIXELS_1        1
143.12447 ++#define COVERAGE_PIXELS_2        2
143.12448 ++#define COVERAGE_PIXELS_4        3
143.12449 ++
143.12450 ++#define DEPTHFORMAT_D32_FLOAT_S8X24_UINT     0
143.12451 ++#define DEPTHFORMAT_D32_FLOAT                1
143.12452 ++#define DEPTHFORMAT_D24_UNORM_S8_UINT        2
143.12453 ++#define DEPTHFORMAT_D16_UNORM                5
143.12454 ++
143.12455 ++#define FLOATING_POINT_IEEE_754        0
143.12456 ++#define FLOATING_POINT_NON_IEEE_754    1
143.12457 ++
143.12458 ++#define INDEX_BYTE     0
143.12459 ++#define INDEX_WORD     1
143.12460 ++#define INDEX_DWORD    2
143.12461 ++
143.12462 ++#define LOGICOPFUNCTION_CLEAR            0
143.12463 ++#define LOGICOPFUNCTION_NOR              1
143.12464 ++#define LOGICOPFUNCTION_AND_INVERTED     2
143.12465 ++#define LOGICOPFUNCTION_COPY_INVERTED    3
143.12466 ++#define LOGICOPFUNCTION_AND_REVERSE      4
143.12467 ++#define LOGICOPFUNCTION_INVERT           5
143.12468 ++#define LOGICOPFUNCTION_XOR              6
143.12469 ++#define LOGICOPFUNCTION_NAND             7
143.12470 ++#define LOGICOPFUNCTION_AND              8
143.12471 ++#define LOGICOPFUNCTION_EQUIV            9
143.12472 ++#define LOGICOPFUNCTION_NOOP             10
143.12473 ++#define LOGICOPFUNCTION_OR_INVERTED      11
143.12474 ++#define LOGICOPFUNCTION_COPY             12
143.12475 ++#define LOGICOPFUNCTION_OR_REVERSE       13
143.12476 ++#define LOGICOPFUNCTION_OR               14
143.12477 ++#define LOGICOPFUNCTION_SET              15
143.12478 ++
143.12479 ++#define MAPFILTER_NEAREST	0x0
143.12480 ++#define MAPFILTER_LINEAR	0x1
143.12481 ++#define MAPFILTER_ANISOTROPIC	0x2
143.12482 ++#define MAPFILTER_FLEXIBLE 	0x3
143.12483 ++#define MAPFILTER_MONO 		0x6
143.12484 ++
143.12485 ++#define MIPFILTER_NONE        0
143.12486 ++#define MIPFILTER_NEAREST     1
143.12487 ++#define MIPFILTER_LINEAR      3
143.12488 ++
143.12489 ++#define POLYGON_FRONT_FACING     0
143.12490 ++#define POLYGON_BACK_FACING      1
143.12491 ++
143.12492 ++#define PREFILTER_ALWAYS     0x0
143.12493 ++#define PREFILTER_NEVER      0x1
143.12494 ++#define PREFILTER_LESS       0x2
143.12495 ++#define PREFILTER_EQUAL      0x3
143.12496 ++#define PREFILTER_LEQUAL     0x4
143.12497 ++#define PREFILTER_GREATER    0x5
143.12498 ++#define PREFILTER_NOTEQUAL   0x6
143.12499 ++#define PREFILTER_GEQUAL     0x7
143.12500 ++
143.12501 ++#define RASTRULE_UPPER_LEFT  0
143.12502 ++#define RASTRULE_UPPER_RIGHT 1
143.12503 ++
143.12504 ++#define STENCILOP_KEEP               0
143.12505 ++#define STENCILOP_ZERO               1
143.12506 ++#define STENCILOP_REPLACE            2
143.12507 ++#define STENCILOP_INCRSAT            3
143.12508 ++#define STENCILOP_DECRSAT            4
143.12509 ++#define STENCILOP_INCR               5
143.12510 ++#define STENCILOP_DECR               6
143.12511 ++#define STENCILOP_INVERT             7
143.12512 ++
143.12513 ++#define SURFACE_MIPMAPLAYOUT_BELOW   0
143.12514 ++#define SURFACE_MIPMAPLAYOUT_RIGHT   1
143.12515 ++
143.12516 ++#define SURFACEFORMAT_R32G32B32A32_FLOAT             0x000
143.12517 ++#define SURFACEFORMAT_R32G32B32A32_SINT              0x001
143.12518 ++#define SURFACEFORMAT_R32G32B32A32_UINT              0x002
143.12519 ++#define SURFACEFORMAT_R32G32B32A32_UNORM             0x003
143.12520 ++#define SURFACEFORMAT_R32G32B32A32_SNORM             0x004
143.12521 ++#define SURFACEFORMAT_R64G64_FLOAT                   0x005
143.12522 ++#define SURFACEFORMAT_R32G32B32X32_FLOAT             0x006
143.12523 ++#define SURFACEFORMAT_R32G32B32A32_SSCALED           0x007
143.12524 ++#define SURFACEFORMAT_R32G32B32A32_USCALED           0x008
143.12525 ++#define SURFACEFORMAT_R32G32B32_FLOAT                0x040
143.12526 ++#define SURFACEFORMAT_R32G32B32_SINT                 0x041
143.12527 ++#define SURFACEFORMAT_R32G32B32_UINT                 0x042
143.12528 ++#define SURFACEFORMAT_R32G32B32_UNORM                0x043
143.12529 ++#define SURFACEFORMAT_R32G32B32_SNORM                0x044
143.12530 ++#define SURFACEFORMAT_R32G32B32_SSCALED              0x045
143.12531 ++#define SURFACEFORMAT_R32G32B32_USCALED              0x046
143.12532 ++#define SURFACEFORMAT_R16G16B16A16_UNORM             0x080
143.12533 ++#define SURFACEFORMAT_R16G16B16A16_SNORM             0x081
143.12534 ++#define SURFACEFORMAT_R16G16B16A16_SINT              0x082
143.12535 ++#define SURFACEFORMAT_R16G16B16A16_UINT              0x083
143.12536 ++#define SURFACEFORMAT_R16G16B16A16_FLOAT             0x084
143.12537 ++#define SURFACEFORMAT_R32G32_FLOAT                   0x085
143.12538 ++#define SURFACEFORMAT_R32G32_SINT                    0x086
143.12539 ++#define SURFACEFORMAT_R32G32_UINT                    0x087
143.12540 ++#define SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS       0x088
143.12541 ++#define SURFACEFORMAT_X32_TYPELESS_G8X24_UINT        0x089
143.12542 ++#define SURFACEFORMAT_L32A32_FLOAT                   0x08A
143.12543 ++#define SURFACEFORMAT_R32G32_UNORM                   0x08B
143.12544 ++#define SURFACEFORMAT_R32G32_SNORM                   0x08C
143.12545 ++#define SURFACEFORMAT_R64_FLOAT                      0x08D
143.12546 ++#define SURFACEFORMAT_R16G16B16X16_UNORM             0x08E
143.12547 ++#define SURFACEFORMAT_R16G16B16X16_FLOAT             0x08F
143.12548 ++#define SURFACEFORMAT_A32X32_FLOAT                   0x090
143.12549 ++#define SURFACEFORMAT_L32X32_FLOAT                   0x091
143.12550 ++#define SURFACEFORMAT_I32X32_FLOAT                   0x092
143.12551 ++#define SURFACEFORMAT_R16G16B16A16_SSCALED           0x093
143.12552 ++#define SURFACEFORMAT_R16G16B16A16_USCALED           0x094
143.12553 ++#define SURFACEFORMAT_R32G32_SSCALED                 0x095
143.12554 ++#define SURFACEFORMAT_R32G32_USCALED                 0x096
143.12555 ++#define SURFACEFORMAT_B8G8R8A8_UNORM                 0x0C0
143.12556 ++#define SURFACEFORMAT_B8G8R8A8_UNORM_SRGB            0x0C1
143.12557 ++#define SURFACEFORMAT_R10G10B10A2_UNORM              0x0C2
143.12558 ++#define SURFACEFORMAT_R10G10B10A2_UNORM_SRGB         0x0C3
143.12559 ++#define SURFACEFORMAT_R10G10B10A2_UINT               0x0C4
143.12560 ++#define SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM       0x0C5
143.12561 ++#define SURFACEFORMAT_R8G8B8A8_UNORM                 0x0C7
143.12562 ++#define SURFACEFORMAT_R8G8B8A8_UNORM_SRGB            0x0C8
143.12563 ++#define SURFACEFORMAT_R8G8B8A8_SNORM                 0x0C9
143.12564 ++#define SURFACEFORMAT_R8G8B8A8_SINT                  0x0CA
143.12565 ++#define SURFACEFORMAT_R8G8B8A8_UINT                  0x0CB
143.12566 ++#define SURFACEFORMAT_R16G16_UNORM                   0x0CC
143.12567 ++#define SURFACEFORMAT_R16G16_SNORM                   0x0CD
143.12568 ++#define SURFACEFORMAT_R16G16_SINT                    0x0CE
143.12569 ++#define SURFACEFORMAT_R16G16_UINT                    0x0CF
143.12570 ++#define SURFACEFORMAT_R16G16_FLOAT                   0x0D0
143.12571 ++#define SURFACEFORMAT_B10G10R10A2_UNORM              0x0D1
143.12572 ++#define SURFACEFORMAT_B10G10R10A2_UNORM_SRGB         0x0D2
143.12573 ++#define SURFACEFORMAT_R11G11B10_FLOAT                0x0D3
143.12574 ++#define SURFACEFORMAT_R32_SINT                       0x0D6
143.12575 ++#define SURFACEFORMAT_R32_UINT                       0x0D7
143.12576 ++#define SURFACEFORMAT_R32_FLOAT                      0x0D8
143.12577 ++#define SURFACEFORMAT_R24_UNORM_X8_TYPELESS          0x0D9
143.12578 ++#define SURFACEFORMAT_X24_TYPELESS_G8_UINT           0x0DA
143.12579 ++#define SURFACEFORMAT_L16A16_UNORM                   0x0DF
143.12580 ++#define SURFACEFORMAT_I24X8_UNORM                    0x0E0
143.12581 ++#define SURFACEFORMAT_L24X8_UNORM                    0x0E1
143.12582 ++#define SURFACEFORMAT_A24X8_UNORM                    0x0E2
143.12583 ++#define SURFACEFORMAT_I32_FLOAT                      0x0E3
143.12584 ++#define SURFACEFORMAT_L32_FLOAT                      0x0E4
143.12585 ++#define SURFACEFORMAT_A32_FLOAT                      0x0E5
143.12586 ++#define SURFACEFORMAT_B8G8R8X8_UNORM                 0x0E9
143.12587 ++#define SURFACEFORMAT_B8G8R8X8_UNORM_SRGB            0x0EA
143.12588 ++#define SURFACEFORMAT_R8G8B8X8_UNORM                 0x0EB
143.12589 ++#define SURFACEFORMAT_R8G8B8X8_UNORM_SRGB            0x0EC
143.12590 ++#define SURFACEFORMAT_R9G9B9E5_SHAREDEXP             0x0ED
143.12591 ++#define SURFACEFORMAT_B10G10R10X2_UNORM              0x0EE
143.12592 ++#define SURFACEFORMAT_L16A16_FLOAT                   0x0F0
143.12593 ++#define SURFACEFORMAT_R32_UNORM                      0x0F1
143.12594 ++#define SURFACEFORMAT_R32_SNORM                      0x0F2
143.12595 ++#define SURFACEFORMAT_R10G10B10X2_USCALED            0x0F3
143.12596 ++#define SURFACEFORMAT_R8G8B8A8_SSCALED               0x0F4
143.12597 ++#define SURFACEFORMAT_R8G8B8A8_USCALED               0x0F5
143.12598 ++#define SURFACEFORMAT_R16G16_SSCALED                 0x0F6
143.12599 ++#define SURFACEFORMAT_R16G16_USCALED                 0x0F7
143.12600 ++#define SURFACEFORMAT_R32_SSCALED                    0x0F8
143.12601 ++#define SURFACEFORMAT_R32_USCALED                    0x0F9
143.12602 ++#define SURFACEFORMAT_B5G6R5_UNORM                   0x100
143.12603 ++#define SURFACEFORMAT_B5G6R5_UNORM_SRGB              0x101
143.12604 ++#define SURFACEFORMAT_B5G5R5A1_UNORM                 0x102
143.12605 ++#define SURFACEFORMAT_B5G5R5A1_UNORM_SRGB            0x103
143.12606 ++#define SURFACEFORMAT_B4G4R4A4_UNORM                 0x104
143.12607 ++#define SURFACEFORMAT_B4G4R4A4_UNORM_SRGB            0x105
143.12608 ++#define SURFACEFORMAT_R8G8_UNORM                     0x106
143.12609 ++#define SURFACEFORMAT_R8G8_SNORM                     0x107
143.12610 ++#define SURFACEFORMAT_R8G8_SINT                      0x108
143.12611 ++#define SURFACEFORMAT_R8G8_UINT                      0x109
143.12612 ++#define SURFACEFORMAT_R16_UNORM                      0x10A
143.12613 ++#define SURFACEFORMAT_R16_SNORM                      0x10B
143.12614 ++#define SURFACEFORMAT_R16_SINT                       0x10C
143.12615 ++#define SURFACEFORMAT_R16_UINT                       0x10D
143.12616 ++#define SURFACEFORMAT_R16_FLOAT                      0x10E
143.12617 ++#define SURFACEFORMAT_I16_UNORM                      0x111
143.12618 ++#define SURFACEFORMAT_L16_UNORM                      0x112
143.12619 ++#define SURFACEFORMAT_A16_UNORM                      0x113
143.12620 ++#define SURFACEFORMAT_L8A8_UNORM                     0x114
143.12621 ++#define SURFACEFORMAT_I16_FLOAT                      0x115
143.12622 ++#define SURFACEFORMAT_L16_FLOAT                      0x116
143.12623 ++#define SURFACEFORMAT_A16_FLOAT                      0x117
143.12624 ++#define SURFACEFORMAT_R5G5_SNORM_B6_UNORM            0x119
143.12625 ++#define SURFACEFORMAT_B5G5R5X1_UNORM                 0x11A
143.12626 ++#define SURFACEFORMAT_B5G5R5X1_UNORM_SRGB            0x11B
143.12627 ++#define SURFACEFORMAT_R8G8_SSCALED                   0x11C
143.12628 ++#define SURFACEFORMAT_R8G8_USCALED                   0x11D
143.12629 ++#define SURFACEFORMAT_R16_SSCALED                    0x11E
143.12630 ++#define SURFACEFORMAT_R16_USCALED                    0x11F
143.12631 ++#define SURFACEFORMAT_R8_UNORM                       0x140
143.12632 ++#define SURFACEFORMAT_R8_SNORM                       0x141
143.12633 ++#define SURFACEFORMAT_R8_SINT                        0x142
143.12634 ++#define SURFACEFORMAT_R8_UINT                        0x143
143.12635 ++#define SURFACEFORMAT_A8_UNORM                       0x144
143.12636 ++#define SURFACEFORMAT_I8_UNORM                       0x145
143.12637 ++#define SURFACEFORMAT_L8_UNORM                       0x146
143.12638 ++#define SURFACEFORMAT_P4A4_UNORM                     0x147
143.12639 ++#define SURFACEFORMAT_A4P4_UNORM                     0x148
143.12640 ++#define SURFACEFORMAT_R8_SSCALED                     0x149
143.12641 ++#define SURFACEFORMAT_R8_USCALED                     0x14A
143.12642 ++#define SURFACEFORMAT_R1_UINT                        0x181
143.12643 ++#define SURFACEFORMAT_YCRCB_NORMAL                   0x182
143.12644 ++#define SURFACEFORMAT_YCRCB_SWAPUVY                  0x183
143.12645 ++#define SURFACEFORMAT_BC1_UNORM                      0x186
143.12646 ++#define SURFACEFORMAT_BC2_UNORM                      0x187
143.12647 ++#define SURFACEFORMAT_BC3_UNORM                      0x188
143.12648 ++#define SURFACEFORMAT_BC4_UNORM                      0x189
143.12649 ++#define SURFACEFORMAT_BC5_UNORM                      0x18A
143.12650 ++#define SURFACEFORMAT_BC1_UNORM_SRGB                 0x18B
143.12651 ++#define SURFACEFORMAT_BC2_UNORM_SRGB                 0x18C
143.12652 ++#define SURFACEFORMAT_BC3_UNORM_SRGB                 0x18D
143.12653 ++#define SURFACEFORMAT_MONO8                          0x18E
143.12654 ++#define SURFACEFORMAT_YCRCB_SWAPUV                   0x18F
143.12655 ++#define SURFACEFORMAT_YCRCB_SWAPY                    0x190
143.12656 ++#define SURFACEFORMAT_DXT1_RGB                       0x191
143.12657 ++#define SURFACEFORMAT_FXT1                           0x192
143.12658 ++#define SURFACEFORMAT_R8G8B8_UNORM                   0x193
143.12659 ++#define SURFACEFORMAT_R8G8B8_SNORM                   0x194
143.12660 ++#define SURFACEFORMAT_R8G8B8_SSCALED                 0x195
143.12661 ++#define SURFACEFORMAT_R8G8B8_USCALED                 0x196
143.12662 ++#define SURFACEFORMAT_R64G64B64A64_FLOAT             0x197
143.12663 ++#define SURFACEFORMAT_R64G64B64_FLOAT                0x198
143.12664 ++#define SURFACEFORMAT_BC4_SNORM                      0x199
143.12665 ++#define SURFACEFORMAT_BC5_SNORM                      0x19A
143.12666 ++#define SURFACEFORMAT_R16G16B16_UNORM                0x19C
143.12667 ++#define SURFACEFORMAT_R16G16B16_SNORM                0x19D
143.12668 ++#define SURFACEFORMAT_R16G16B16_SSCALED              0x19E
143.12669 ++#define SURFACEFORMAT_R16G16B16_USCALED              0x19F
143.12670 ++
143.12671 ++#define SURFACE_1D      0
143.12672 ++#define SURFACE_2D      1
143.12673 ++#define SURFACE_3D      2
143.12674 ++#define SURFACE_CUBE    3
143.12675 ++#define SURFACE_BUFFER  4
143.12676 ++#define SURFACE_NULL    7
143.12677 ++
143.12678 ++#define TEXCOORDMODE_WRAP            0
143.12679 ++#define TEXCOORDMODE_MIRROR          1
143.12680 ++#define TEXCOORDMODE_CLAMP           2
143.12681 ++#define TEXCOORDMODE_CUBE            3
143.12682 ++#define TEXCOORDMODE_CLAMP_BORDER    4
143.12683 ++#define TEXCOORDMODE_MIRROR_ONCE     5
143.12684 ++
143.12685 ++#define THREAD_PRIORITY_NORMAL   0
143.12686 ++#define THREAD_PRIORITY_HIGH     1
143.12687 ++
143.12688 ++#define VERTEX_SUBPIXEL_PRECISION_8BITS  0
143.12689 ++#define VERTEX_SUBPIXEL_PRECISION_4BITS  1
143.12690 ++
143.12691 ++#define COMPONENT_NOSTORE      0
143.12692 ++#define COMPONENT_STORE_SRC    1
143.12693 ++#define COMPONENT_STORE_0      2
143.12694 ++#define COMPONENT_STORE_1_FLT  3
143.12695 ++#define COMPONENT_STORE_1_INT  4
143.12696 ++#define COMPONENT_STORE_VID    5
143.12697 ++#define COMPONENT_STORE_IID    6
143.12698 ++#define COMPONENT_STORE_PID    7
143.12699 ++
143.12700 ++/* Execution Unit (EU) defines
143.12701 ++ */
143.12702 ++
143.12703 ++#define GEN9_ALIGN_1   0
143.12704 ++#define GEN9_ALIGN_16  1
143.12705 ++
143.12706 ++#define GEN9_ADDRESS_DIRECT                        0
143.12707 ++#define GEN9_ADDRESS_REGISTER_INDIRECT_REGISTER    1
143.12708 ++
143.12709 ++#define GEN9_CHANNEL_X     0
143.12710 ++#define GEN9_CHANNEL_Y     1
143.12711 ++#define GEN9_CHANNEL_Z     2
143.12712 ++#define GEN9_CHANNEL_W     3
143.12713 ++
143.12714 ++#define GEN9_COMPRESSION_NONE          0
143.12715 ++#define GEN9_COMPRESSION_2NDHALF       1
143.12716 ++#define GEN9_COMPRESSION_COMPRESSED    2
143.12717 ++
143.12718 ++#define GEN9_CONDITIONAL_NONE  0
143.12719 ++#define GEN9_CONDITIONAL_Z     1
143.12720 ++#define GEN9_CONDITIONAL_NZ    2
143.12721 ++#define GEN9_CONDITIONAL_EQ    1	/* Z */
143.12722 ++#define GEN9_CONDITIONAL_NEQ   2	/* NZ */
143.12723 ++#define GEN9_CONDITIONAL_G     3
143.12724 ++#define GEN9_CONDITIONAL_GE    4
143.12725 ++#define GEN9_CONDITIONAL_L     5
143.12726 ++#define GEN9_CONDITIONAL_LE    6
143.12727 ++#define GEN9_CONDITIONAL_C     7
143.12728 ++#define GEN9_CONDITIONAL_O     8
143.12729 ++
143.12730 ++#define GEN9_DEBUG_NONE        0
143.12731 ++#define GEN9_DEBUG_BREAKPOINT  1
143.12732 ++
143.12733 ++#define GEN9_DEPENDENCY_NORMAL         0
143.12734 ++#define GEN9_DEPENDENCY_NOTCLEARED     1
143.12735 ++#define GEN9_DEPENDENCY_NOTCHECKED     2
143.12736 ++#define GEN9_DEPENDENCY_DISABLE        3
143.12737 ++
143.12738 ++#define GEN9_EXECUTE_1     0
143.12739 ++#define GEN9_EXECUTE_2     1
143.12740 ++#define GEN9_EXECUTE_4     2
143.12741 ++#define GEN9_EXECUTE_8     3
143.12742 ++#define GEN9_EXECUTE_16    4
143.12743 ++#define GEN9_EXECUTE_32    5
143.12744 ++
143.12745 ++#define GEN9_HORIZONTAL_STRIDE_0   0
143.12746 ++#define GEN9_HORIZONTAL_STRIDE_1   1
143.12747 ++#define GEN9_HORIZONTAL_STRIDE_2   2
143.12748 ++#define GEN9_HORIZONTAL_STRIDE_4   3
143.12749 ++
143.12750 ++#define GEN9_INSTRUCTION_NORMAL    0
143.12751 ++#define GEN9_INSTRUCTION_SATURATE  1
143.12752 ++
143.12753 ++#define GEN9_OPCODE_MOV        1
143.12754 ++#define GEN9_OPCODE_SEL        2
143.12755 ++#define GEN9_OPCODE_NOT        4
143.12756 ++#define GEN9_OPCODE_AND        5
143.12757 ++#define GEN9_OPCODE_OR         6
143.12758 ++#define GEN9_OPCODE_XOR        7
143.12759 ++#define GEN9_OPCODE_SHR        8
143.12760 ++#define GEN9_OPCODE_SHL        9
143.12761 ++#define GEN9_OPCODE_RSR        10
143.12762 ++#define GEN9_OPCODE_RSL        11
143.12763 ++#define GEN9_OPCODE_ASR        12
143.12764 ++#define GEN9_OPCODE_CMP        16
143.12765 ++#define GEN9_OPCODE_JMPI       32
143.12766 ++#define GEN9_OPCODE_IF         34
143.12767 ++#define GEN9_OPCODE_IFF        35
143.12768 ++#define GEN9_OPCODE_ELSE       36
143.12769 ++#define GEN9_OPCODE_ENDIF      37
143.12770 ++#define GEN9_OPCODE_DO         38
143.12771 ++#define GEN9_OPCODE_WHILE      39
143.12772 ++#define GEN9_OPCODE_BREAK      40
143.12773 ++#define GEN9_OPCODE_CONTINUE   41
143.12774 ++#define GEN9_OPCODE_HALT       42
143.12775 ++#define GEN9_OPCODE_MSAVE      44
143.12776 ++#define GEN9_OPCODE_MRESTORE   45
143.12777 ++#define GEN9_OPCODE_PUSH       46
143.12778 ++#define GEN9_OPCODE_POP        47
143.12779 ++#define GEN9_OPCODE_WAIT       48
143.12780 ++#define GEN9_OPCODE_SEND       49
143.12781 ++#define GEN9_OPCODE_ADD        64
143.12782 ++#define GEN9_OPCODE_MUL        65
143.12783 ++#define GEN9_OPCODE_AVG        66
143.12784 ++#define GEN9_OPCODE_FRC        67
143.12785 ++#define GEN9_OPCODE_RNDU       68
143.12786 ++#define GEN9_OPCODE_RNDD       69
143.12787 ++#define GEN9_OPCODE_RNDE       70
143.12788 ++#define GEN9_OPCODE_RNDZ       71
143.12789 ++#define GEN9_OPCODE_MAC        72
143.12790 ++#define GEN9_OPCODE_MACH       73
143.12791 ++#define GEN9_OPCODE_LZD        74
143.12792 ++#define GEN9_OPCODE_SAD2       80
143.12793 ++#define GEN9_OPCODE_SADA2      81
143.12794 ++#define GEN9_OPCODE_DP4        84
143.12795 ++#define GEN9_OPCODE_DPH        85
143.12796 ++#define GEN9_OPCODE_DP3        86
143.12797 ++#define GEN9_OPCODE_DP2        87
143.12798 ++#define GEN9_OPCODE_DPA2       88
143.12799 ++#define GEN9_OPCODE_LINE       89
143.12800 ++#define GEN9_OPCODE_NOP        126
143.12801 ++
143.12802 ++#define GEN9_PREDICATE_NONE             0
143.12803 ++#define GEN9_PREDICATE_NORMAL           1
143.12804 ++#define GEN9_PREDICATE_ALIGN1_ANYV             2
143.12805 ++#define GEN9_PREDICATE_ALIGN1_ALLV             3
143.12806 ++#define GEN9_PREDICATE_ALIGN1_ANY2H            4
143.12807 ++#define GEN9_PREDICATE_ALIGN1_ALL2H            5
143.12808 ++#define GEN9_PREDICATE_ALIGN1_ANY4H            6
143.12809 ++#define GEN9_PREDICATE_ALIGN1_ALL4H            7
143.12810 ++#define GEN9_PREDICATE_ALIGN1_ANY8H            8
143.12811 ++#define GEN9_PREDICATE_ALIGN1_ALL8H            9
143.12812 ++#define GEN9_PREDICATE_ALIGN1_ANY16H           10
143.12813 ++#define GEN9_PREDICATE_ALIGN1_ALL16H           11
143.12814 ++#define GEN9_PREDICATE_ALIGN16_REPLICATE_X     2
143.12815 ++#define GEN9_PREDICATE_ALIGN16_REPLICATE_Y     3
143.12816 ++#define GEN9_PREDICATE_ALIGN16_REPLICATE_Z     4
143.12817 ++#define GEN9_PREDICATE_ALIGN16_REPLICATE_W     5
143.12818 ++#define GEN9_PREDICATE_ALIGN16_ANY4H           6
143.12819 ++#define GEN9_PREDICATE_ALIGN16_ALL4H           7
143.12820 ++
143.12821 ++#define GEN9_ARCHITECTURE_REGISTER_FILE    0
143.12822 ++#define GEN9_GENERAL_REGISTER_FILE         1
143.12823 ++#define GEN9_MESSAGE_REGISTER_FILE         2
143.12824 ++#define GEN9_IMMEDIATE_VALUE               3
143.12825 ++
143.12826 ++#define GEN9_REGISTER_TYPE_UD  0
143.12827 ++#define GEN9_REGISTER_TYPE_D   1
143.12828 ++#define GEN9_REGISTER_TYPE_UW  2
143.12829 ++#define GEN9_REGISTER_TYPE_W   3
143.12830 ++#define GEN9_REGISTER_TYPE_UB  4
143.12831 ++#define GEN9_REGISTER_TYPE_B   5
143.12832 ++#define GEN9_REGISTER_TYPE_VF  5	/* packed float vector, immediates only? */
143.12833 ++#define GEN9_REGISTER_TYPE_HF  6
143.12834 ++#define GEN9_REGISTER_TYPE_V   6	/* packed int vector, immediates only, uword dest only */
143.12835 ++#define GEN9_REGISTER_TYPE_F   7
143.12836 ++
143.12837 ++#define GEN9_ARF_NULL                  0x00
143.12838 ++#define GEN9_ARF_ADDRESS               0x10
143.12839 ++#define GEN9_ARF_ACCUMULATOR           0x20
143.12840 ++#define GEN9_ARF_FLAG                  0x30
143.12841 ++#define GEN9_ARF_MASK                  0x40
143.12842 ++#define GEN9_ARF_MASK_STACK            0x50
143.12843 ++#define GEN9_ARF_MASK_STACK_DEPTH      0x60
143.12844 ++#define GEN9_ARF_STATE                 0x70
143.12845 ++#define GEN9_ARF_CONTROL               0x80
143.12846 ++#define GEN9_ARF_NOTIFICATION_COUNT    0x90
143.12847 ++#define GEN9_ARF_IP                    0xA0
143.12848 ++
143.12849 ++#define GEN9_AMASK   0
143.12850 ++#define GEN9_IMASK   1
143.12851 ++#define GEN9_LMASK   2
143.12852 ++#define GEN9_CMASK   3
143.12853 ++
143.12854 ++#define GEN9_THREAD_NORMAL     0
143.12855 ++#define GEN9_THREAD_ATOMIC     1
143.12856 ++#define GEN9_THREAD_SWITCH     2
143.12857 ++
143.12858 ++#define GEN9_VERTICAL_STRIDE_0                 0
143.12859 ++#define GEN9_VERTICAL_STRIDE_1                 1
143.12860 ++#define GEN9_VERTICAL_STRIDE_2                 2
143.12861 ++#define GEN9_VERTICAL_STRIDE_4                 3
143.12862 ++#define GEN9_VERTICAL_STRIDE_8                 4
143.12863 ++#define GEN9_VERTICAL_STRIDE_16                5
143.12864 ++#define GEN9_VERTICAL_STRIDE_32                6
143.12865 ++#define GEN9_VERTICAL_STRIDE_64                7
143.12866 ++#define GEN9_VERTICAL_STRIDE_128               8
143.12867 ++#define GEN9_VERTICAL_STRIDE_256               9
143.12868 ++#define GEN9_VERTICAL_STRIDE_ONE_DIMENSIONAL   0xF
143.12869 ++
143.12870 ++#define GEN9_WIDTH_1       0
143.12871 ++#define GEN9_WIDTH_2       1
143.12872 ++#define GEN9_WIDTH_4       2
143.12873 ++#define GEN9_WIDTH_8       3
143.12874 ++#define GEN9_WIDTH_16      4
143.12875 ++
143.12876 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_1K      0
143.12877 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_2K      1
143.12878 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_4K      2
143.12879 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_8K      3
143.12880 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_16K     4
143.12881 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_32K     5
143.12882 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_64K     6
143.12883 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_128K    7
143.12884 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_256K    8
143.12885 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_512K    9
143.12886 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_1M      10
143.12887 ++#define GEN9_STATELESS_BUFFER_BOUNDARY_2M      11
143.12888 ++
143.12889 ++#define GEN9_POLYGON_FACING_FRONT      0
143.12890 ++#define GEN9_POLYGON_FACING_BACK       1
143.12891 ++
143.12892 ++#define GEN9_MESSAGE_TARGET_NULL               0
143.12893 ++#define GEN9_MESSAGE_TARGET_MATH               1
143.12894 ++#define GEN9_MESSAGE_TARGET_SAMPLER            2
143.12895 ++#define GEN9_MESSAGE_TARGET_GATEWAY            3
143.12896 ++#define GEN9_MESSAGE_TARGET_DATAPORT_READ      4
143.12897 ++#define GEN9_MESSAGE_TARGET_DATAPORT_WRITE     5
143.12898 ++#define GEN9_MESSAGE_TARGET_URB                6
143.12899 ++#define GEN9_MESSAGE_TARGET_THREAD_SPAWNER     7
143.12900 ++
143.12901 ++#define GEN9_SAMPLER_RETURN_FORMAT_FLOAT32     0
143.12902 ++#define GEN9_SAMPLER_RETURN_FORMAT_UINT32      2
143.12903 ++#define GEN9_SAMPLER_RETURN_FORMAT_SINT32      3
143.12904 ++
143.12905 ++#define GEN9_SAMPLER_MESSAGE_SIMD8_SAMPLE              0
143.12906 ++#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE             0
143.12907 ++#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS        0
143.12908 ++#define GEN9_SAMPLER_MESSAGE_SIMD8_KILLPIX             1
143.12909 ++#define GEN9_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_LOD        1
143.12910 ++#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE_LOD         1
143.12911 ++#define GEN9_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_GRADIENTS  2
143.12912 ++#define GEN9_SAMPLER_MESSAGE_SIMD8_SAMPLE_GRADIENTS    2
143.12913 ++#define GEN9_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_COMPARE    0
143.12914 ++#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE     2
143.12915 ++#define GEN9_SAMPLER_MESSAGE_SIMD4X2_RESINFO           2
143.12916 ++#define GEN9_SAMPLER_MESSAGE_SIMD8_RESINFO             2
143.12917 ++#define GEN9_SAMPLER_MESSAGE_SIMD16_RESINFO            2
143.12918 ++#define GEN9_SAMPLER_MESSAGE_SIMD4X2_LD                3
143.12919 ++#define GEN9_SAMPLER_MESSAGE_SIMD8_LD                  3
143.12920 ++#define GEN9_SAMPLER_MESSAGE_SIMD16_LD                 3
143.12921 ++
143.12922 ++#define GEN9_DATAPORT_OWORD_BLOCK_1_OWORDLOW   0
143.12923 ++#define GEN9_DATAPORT_OWORD_BLOCK_1_OWORDHIGH  1
143.12924 ++#define GEN9_DATAPORT_OWORD_BLOCK_2_OWORDS     2
143.12925 ++#define GEN9_DATAPORT_OWORD_BLOCK_4_OWORDS     3
143.12926 ++#define GEN9_DATAPORT_OWORD_BLOCK_8_OWORDS     4
143.12927 ++
143.12928 ++#define GEN9_DATAPORT_OWORD_DUAL_BLOCK_1OWORD     0
143.12929 ++#define GEN9_DATAPORT_OWORD_DUAL_BLOCK_4OWORDS    2
143.12930 ++
143.12931 ++#define GEN9_DATAPORT_DWORD_SCATTERED_BLOCK_8DWORDS   2
143.12932 ++#define GEN9_DATAPORT_DWORD_SCATTERED_BLOCK_16DWORDS  3
143.12933 ++
143.12934 ++#define GEN9_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ          0
143.12935 ++#define GEN9_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ     1
143.12936 ++#define GEN9_DATAPORT_READ_MESSAGE_DWORD_BLOCK_READ          2
143.12937 ++#define GEN9_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ      3
143.12938 ++
143.12939 ++#define GEN9_DATAPORT_READ_TARGET_DATA_CACHE      0
143.12940 ++#define GEN9_DATAPORT_READ_TARGET_RENDER_CACHE    1
143.12941 ++#define GEN9_DATAPORT_READ_TARGET_SAMPLER_CACHE   2
143.12942 ++
143.12943 ++#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE                0
143.12944 ++#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED     1
143.12945 ++#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN01         2
143.12946 ++#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN23         3
143.12947 ++#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01       4
143.12948 ++
143.12949 ++#define GEN9_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE                0
143.12950 ++#define GEN9_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE           1
143.12951 ++#define GEN9_DATAPORT_WRITE_MESSAGE_DWORD_BLOCK_WRITE                2
143.12952 ++#define GEN9_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE            3
143.12953 ++#define GEN9_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE              4
143.12954 ++#define GEN9_DATAPORT_WRITE_MESSAGE_STREAMED_VERTEX_BUFFER_WRITE     5
143.12955 ++#define GEN9_DATAPORT_WRITE_MESSAGE_FLUSH_RENDER_CACHE               7
143.12956 ++
143.12957 ++#define GEN9_MATH_FUNCTION_INV                              1
143.12958 ++#define GEN9_MATH_FUNCTION_LOG                              2
143.12959 ++#define GEN9_MATH_FUNCTION_EXP                              3
143.12960 ++#define GEN9_MATH_FUNCTION_SQRT                             4
143.12961 ++#define GEN9_MATH_FUNCTION_RSQ                              5
143.12962 ++#define GEN9_MATH_FUNCTION_SIN                              6 /* was 7 */
143.12963 ++#define GEN9_MATH_FUNCTION_COS                              7 /* was 8 */
143.12964 ++#define GEN9_MATH_FUNCTION_SINCOS                           8 /* was 6 */
143.12965 ++#define GEN9_MATH_FUNCTION_TAN                              9
143.12966 ++#define GEN9_MATH_FUNCTION_POW                              10
143.12967 ++#define GEN9_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER   11
143.12968 ++#define GEN9_MATH_FUNCTION_INT_DIV_QUOTIENT                 12
143.12969 ++#define GEN9_MATH_FUNCTION_INT_DIV_REMAINDER                13
143.12970 ++
143.12971 ++#define GEN9_MATH_INTEGER_UNSIGNED     0
143.12972 ++#define GEN9_MATH_INTEGER_SIGNED       1
143.12973 ++
143.12974 ++#define GEN9_MATH_PRECISION_FULL        0
143.12975 ++#define GEN9_MATH_PRECISION_PARTIAL     1
143.12976 ++
143.12977 ++#define GEN9_MATH_SATURATE_NONE         0
143.12978 ++#define GEN9_MATH_SATURATE_SATURATE     1
143.12979 ++
143.12980 ++#define GEN9_MATH_DATA_VECTOR  0
143.12981 ++#define GEN9_MATH_DATA_SCALAR  1
143.12982 ++
143.12983 ++#define GEN9_URB_OPCODE_WRITE  0
143.12984 ++
143.12985 ++#define GEN9_URB_SWIZZLE_NONE          0
143.12986 ++#define GEN9_URB_SWIZZLE_INTERLEAVE    1
143.12987 ++#define GEN9_URB_SWIZZLE_TRANSPOSE     2
143.12988 ++
143.12989 ++#define GEN9_SCRATCH_SPACE_SIZE_1K     0
143.12990 ++#define GEN9_SCRATCH_SPACE_SIZE_2K     1
143.12991 ++#define GEN9_SCRATCH_SPACE_SIZE_4K     2
143.12992 ++#define GEN9_SCRATCH_SPACE_SIZE_8K     3
143.12993 ++#define GEN9_SCRATCH_SPACE_SIZE_16K    4
143.12994 ++#define GEN9_SCRATCH_SPACE_SIZE_32K    5
143.12995 ++#define GEN9_SCRATCH_SPACE_SIZE_64K    6
143.12996 ++#define GEN9_SCRATCH_SPACE_SIZE_128K   7
143.12997 ++#define GEN9_SCRATCH_SPACE_SIZE_256K   8
143.12998 ++#define GEN9_SCRATCH_SPACE_SIZE_512K   9
143.12999 ++#define GEN9_SCRATCH_SPACE_SIZE_1M     10
143.13000 ++#define GEN9_SCRATCH_SPACE_SIZE_2M     11
143.13001 ++
143.13002 ++struct gen9_blend_state {
143.13003 ++	struct {
143.13004 ++		/* 00 */ uint32_t pad:19;
143.13005 ++		/* 19 */ uint32_t y_dither_offset:2;
143.13006 ++		/* 21 */ uint32_t x_dither_offset:2;
143.13007 ++		/* 23 */ uint32_t color_dither_enable:1;
143.13008 ++		/* 24 */ uint32_t alpha_test_function:3;
143.13009 ++		/* 27 */ uint32_t alpha_test:1;
143.13010 ++		/* 28 */ uint32_t alpha_to_coverage_dither:1;
143.13011 ++		/* 29 */ uint32_t alpha_to_one:1;
143.13012 ++		/* 30 */ uint32_t ia_blend:1;
143.13013 ++		/* 31 */ uint32_t alpha_to_coverage:1;
143.13014 ++	} common;
143.13015 ++
143.13016 ++	struct {
143.13017 ++		/* 00 */ uint32_t write_disable_blue:1;
143.13018 ++		/* 01 */ uint32_t write_disable_green:1;
143.13019 ++		/* 02 */ uint32_t write_disable_red:1;
143.13020 ++		/* 03 */ uint32_t write_disable_alpha:1;
143.13021 ++		/* 04 */ uint32_t pad0:1;
143.13022 ++		/* 05 */ uint32_t alpha_blend_function:3;
143.13023 ++		/* 08 */ uint32_t dest_alpha_blend_factor:5;
143.13024 ++		/* 13 */ uint32_t source_alpha_blend_factor:5;
143.13025 ++		/* 18 */ uint32_t color_blend_function:3;
143.13026 ++		/* 21 */ uint32_t dest_blend_factor:5;
143.13027 ++		/* 26 */ uint32_t source_blend_factor:5;
143.13028 ++		/* 31 */ uint32_t color_blend:1;
143.13029 ++		/* 32 */ uint32_t post_blend_clamp:1;
143.13030 ++		/* 33 */ uint32_t pre_blend_clamp:1;
143.13031 ++		/* 34 */ uint32_t color_clamp_range:2;
143.13032 ++		/* 36 */ uint32_t pre_blend_source_only_clamp:1;
143.13033 ++		/* 37 */ uint32_t pad1:22;
143.13034 ++		/* 59 */ uint32_t logic_op_function:4;
143.13035 ++		/* 63 */ uint32_t logic_op:1;
143.13036 ++	} rt;
143.13037 ++};
143.13038 ++
143.13039 ++struct gen9_color_calc_state {
143.13040 ++	struct {
143.13041 ++		/* 00 */ uint32_t alpha_test_format:1;
143.13042 ++		/* 01 */ uint32_t pad0:14;
143.13043 ++		/* 15 */ uint32_t round_disable:1;
143.13044 ++		/* 16 */ uint32_t bf_stencil_ref:8;
143.13045 ++		/* 24 */ uint32_t stencil_ref:8;
143.13046 ++	} cc0;
143.13047 ++
143.13048 ++	union {
143.13049 ++		float alpha_ref_f;
143.13050 ++		struct {
143.13051 ++			uint32_t ui:8;
143.13052 ++			uint32_t pad0:24;
143.13053 ++		} alpha_ref_fi;
143.13054 ++	} cc1;
143.13055 ++
143.13056 ++	float constant_r;
143.13057 ++	float constant_g;
143.13058 ++	float constant_b;
143.13059 ++	float constant_a;
143.13060 ++};
143.13061 ++
143.13062 ++struct gen9_sampler_state {
143.13063 ++	struct {
143.13064 ++		/* 00 */ unsigned int aniso_algorithm:1;
143.13065 ++		/* 01 */ unsigned int lod_bias:13;
143.13066 ++		/* 14 */ unsigned int min_filter:3;
143.13067 ++		/* 17 */ unsigned int mag_filter:3;
143.13068 ++		/* 20 */ unsigned int mip_filter:2;
143.13069 ++		/* 22 */ unsigned int base_level:5;
143.13070 ++		/* 27 */ unsigned int lod_preclamp:2;
143.13071 ++		/* 29 */ unsigned int default_color_mode:1;
143.13072 ++		/* 30 */ unsigned int flexible_filter_clamp:1;
143.13073 ++		/* 31 */ unsigned int disable:1;
143.13074 ++	} ss0;
143.13075 ++
143.13076 ++	struct {
143.13077 ++		/* 00 */ unsigned int cube_control_mode:1;
143.13078 ++		/* 01 */ unsigned int shadow_function:3;
143.13079 ++		/* 04 */ unsigned int chroma_key_mode:1;
143.13080 ++		/* 05 */ unsigned int chroma_key_index:2;
143.13081 ++		/* 07 */ unsigned int chroma_key_enable:1;
143.13082 ++		/* 08 */ unsigned int max_lod:12;
143.13083 ++		/* 20 */ unsigned int min_lod:12;
143.13084 ++	} ss1;
143.13085 ++
143.13086 ++	struct {
143.13087 ++		unsigned int pad:6;
143.13088 ++		unsigned int default_color_pointer:26;
143.13089 ++	} ss2;
143.13090 ++
143.13091 ++	struct {
143.13092 ++		/* 00 */ unsigned int r_wrap_mode:3;
143.13093 ++		/* 03 */ unsigned int t_wrap_mode:3;
143.13094 ++		/* 06 */ unsigned int s_wrap_mode:3;
143.13095 ++		/* 09 */ unsigned int pad:1;
143.13096 ++		/* 10 */ unsigned int non_normalized_coord:1;
143.13097 ++		/* 11 */ unsigned int trilinear_quality:2;
143.13098 ++		/* 13 */ unsigned int address_round:6;
143.13099 ++		/* 19 */ unsigned int max_aniso:3;
143.13100 ++		/* 22 */ unsigned int pad0:2;
143.13101 ++		/* 24 */ unsigned int non_separable_filter:8;
143.13102 ++	} ss3;
143.13103 ++};
143.13104 ++
143.13105 ++/* Surface state DW0 */
143.13106 ++#define SURFACE_RC_READ_WRITE	(1 << 8)
143.13107 ++#define SURFACE_TILED		(1 << 13)
143.13108 ++#define SURFACE_TILED_Y		(1 << 12)
143.13109 ++#define SURFACE_FORMAT_SHIFT	18
143.13110 ++#define SURFACE_VALIGN_1	(0 << 16) /* reserved! */
143.13111 ++#define SURFACE_VALIGN_4	(1 << 16)
143.13112 ++#define SURFACE_VALIGN_8	(2 << 16)
143.13113 ++#define SURFACE_VALIGN_16	(3 << 16)
143.13114 ++#define SURFACE_HALIGN_1	(0 << 14) /* reserved! */
143.13115 ++#define SURFACE_HALIGN_4	(1 << 14)
143.13116 ++#define SURFACE_HALIGN_8	(2 << 14)
143.13117 ++#define SURFACE_HALIGN_16	(3 << 14)
143.13118 ++#define SURFACE_TYPE_SHIFT		29
143.13119 ++
143.13120 ++/* Surface state DW2 */
143.13121 ++#define SURFACE_HEIGHT_SHIFT        16
143.13122 ++#define SURFACE_WIDTH_SHIFT         0
143.13123 ++
143.13124 ++/* Surface state DW3 */
143.13125 ++#define SURFACE_DEPTH_SHIFT         21
143.13126 ++#define SURFACE_PITCH_SHIFT         0
143.13127 ++
143.13128 ++#define SWIZZLE_ZERO		0
143.13129 ++#define SWIZZLE_ONE		1
143.13130 ++#define SWIZZLE_RED		4
143.13131 ++#define SWIZZLE_GREEN		5
143.13132 ++#define SWIZZLE_BLUE		6
143.13133 ++#define SWIZZLE_ALPHA		7
143.13134 ++#define __SURFACE_SWIZZLE(r,g,b,a) \
143.13135 ++	((a) << 16 | (b) << 19 | (g) << 22 | (r) << 25)
143.13136 ++#define SURFACE_SWIZZLE(r,g,b,a) \
143.13137 ++	__SURFACE_SWIZZLE(SWIZZLE_##r, SWIZZLE_##g, SWIZZLE_##b, SWIZZLE_##a)
143.13138 ++
143.13139 ++typedef enum {
143.13140 ++	SAMPLER_FILTER_NEAREST = 0,
143.13141 ++	SAMPLER_FILTER_BILINEAR,
143.13142 ++	FILTER_COUNT
143.13143 ++} sampler_filter_t;
143.13144 ++
143.13145 ++typedef enum {
143.13146 ++	SAMPLER_EXTEND_NONE = 0,
143.13147 ++	SAMPLER_EXTEND_REPEAT,
143.13148 ++	SAMPLER_EXTEND_PAD,
143.13149 ++	SAMPLER_EXTEND_REFLECT,
143.13150 ++	EXTEND_COUNT
143.13151 ++} sampler_extend_t;
143.13152 ++
143.13153 ++#endif
143.13154 +diff --git a/src/sna/kgem.c b/src/sna/kgem.c
143.13155 +index 78ed5407..f0d171ac 100644
143.13156 +--- a/src/sna/kgem.c
143.13157 ++++ b/src/sna/kgem.c
143.13158 +@@ -84,6 +84,10 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
143.13159 + #define DBG_NO_HANDLE_LUT 0
143.13160 + #define DBG_NO_WT 0
143.13161 + #define DBG_NO_WC_MMAP 0
143.13162 ++#define DBG_NO_BLT_Y 0
143.13163 ++#define DBG_NO_SCANOUT_Y 0
143.13164 ++#define DBG_NO_DIRTYFB 0
143.13165 ++#define DBG_NO_DETILING 0
143.13166 + #define DBG_DUMP 0
143.13167 + #define DBG_NO_MALLOC_CACHE 0
143.13168 + 
143.13169 +@@ -96,11 +100,6 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
143.13170 + #define SHOW_BATCH_BEFORE 0
143.13171 + #define SHOW_BATCH_AFTER 0
143.13172 + 
143.13173 +-#if !USE_WC_MMAP
143.13174 +-#undef DBG_NO_WC_MMAP
143.13175 +-#define DBG_NO_WC_MMAP 1
143.13176 +-#endif
143.13177 +-
143.13178 + #if 0
143.13179 + #define ASSERT_IDLE(kgem__, handle__) assert(!__kgem_busy(kgem__, handle__))
143.13180 + #define ASSERT_MAYBE_IDLE(kgem__, handle__, expect__) assert(!(expect__) || !__kgem_busy(kgem__, handle__))
143.13181 +@@ -187,6 +186,15 @@ struct local_i915_gem_caching {
143.13182 + #define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching)
143.13183 + #define LOCAL_IOCTL_I915_GEM_GET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_GET_CACHING, struct local_i915_gem_caching)
143.13184 + 
143.13185 ++struct local_i915_gem_mmap {
143.13186 ++	uint32_t handle;
143.13187 ++	uint32_t pad;
143.13188 ++	uint64_t offset;
143.13189 ++	uint64_t size;
143.13190 ++	uint64_t addr_ptr;
143.13191 ++};
143.13192 ++#define LOCAL_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct local_i915_gem_mmap)
143.13193 ++
143.13194 + struct local_i915_gem_mmap2 {
143.13195 + 	uint32_t handle;
143.13196 + 	uint32_t pad;
143.13197 +@@ -216,6 +224,12 @@ static struct kgem_bo *__kgem_freed_bo;
143.13198 + static struct kgem_request *__kgem_freed_request;
143.13199 + static struct drm_i915_gem_exec_object2 _kgem_dummy_exec;
143.13200 + 
143.13201 ++static inline struct sna *__to_sna(struct kgem *kgem)
143.13202 ++{
143.13203 ++	/* minor layering violations */
143.13204 ++	return container_of(kgem, struct sna, kgem);
143.13205 ++}
143.13206 ++
143.13207 + static inline int bytes(struct kgem_bo *bo)
143.13208 + {
143.13209 + 	return __kgem_bo_size(bo);
143.13210 +@@ -224,25 +238,31 @@ static inline int bytes(struct kgem_bo *bo)
143.13211 + #define bucket(B) (B)->size.pages.bucket
143.13212 + #define num_pages(B) (B)->size.pages.count
143.13213 + 
143.13214 +-static int do_ioctl(int fd, unsigned long req, void *arg)
143.13215 ++static int __do_ioctl(int fd, unsigned long req, void *arg)
143.13216 + {
143.13217 +-	int err;
143.13218 +-
143.13219 +-restart:
143.13220 +-	if (ioctl(fd, req, arg) == 0)
143.13221 +-		return 0;
143.13222 ++	do {
143.13223 ++		int err;
143.13224 + 
143.13225 +-	err = errno;
143.13226 ++		switch ((err = errno)) {
143.13227 ++		case EAGAIN:
143.13228 ++			sched_yield();
143.13229 ++		case EINTR:
143.13230 ++			break;
143.13231 ++		default:
143.13232 ++			return -err;
143.13233 ++		}
143.13234 + 
143.13235 +-	if (err == EINTR)
143.13236 +-		goto restart;
143.13237 ++		if (likely(ioctl(fd, req, arg) == 0))
143.13238 ++			return 0;
143.13239 ++	} while (1);
143.13240 ++}
143.13241 + 
143.13242 +-	if (err == EAGAIN) {
143.13243 +-		sched_yield();
143.13244 +-		goto restart;
143.13245 +-	}
143.13246 ++inline static int do_ioctl(int fd, unsigned long req, void *arg)
143.13247 ++{
143.13248 ++	if (likely(ioctl(fd, req, arg) == 0))
143.13249 ++		return 0;
143.13250 + 
143.13251 +-	return -err;
143.13252 ++	return __do_ioctl(fd, req, arg);
143.13253 + }
143.13254 + 
143.13255 + #ifdef DEBUG_MEMORY
143.13256 +@@ -266,6 +286,9 @@ static void assert_tiling(struct kgem *kgem, struct kgem_bo *bo)
143.13257 + 
143.13258 + 	assert(bo);
143.13259 + 
143.13260 ++	if (!kgem->can_fence && kgem->gen >= 040 && bo->tiling)
143.13261 ++		return; /* lies */
143.13262 ++
143.13263 + 	VG_CLEAR(tiling);
143.13264 + 	tiling.handle = bo->handle;
143.13265 + 	tiling.tiling_mode = bo->tiling;
143.13266 +@@ -273,7 +296,7 @@ static void assert_tiling(struct kgem *kgem, struct kgem_bo *bo)
143.13267 + 	assert(tiling.tiling_mode == bo->tiling);
143.13268 + }
143.13269 + 
143.13270 +-static void assert_cacheing(struct kgem *kgem, struct kgem_bo *bo)
143.13271 ++static void assert_caching(struct kgem *kgem, struct kgem_bo *bo)
143.13272 + {
143.13273 + 	struct local_i915_gem_caching arg;
143.13274 + 	int expect = kgem->has_llc ? SNOOPED : UNCACHED;
143.13275 +@@ -294,24 +317,117 @@ static void assert_bo_retired(struct kgem_bo *bo)
143.13276 + 	assert(bo->refcnt);
143.13277 + 	assert(bo->rq == NULL);
143.13278 + 	assert(bo->exec == NULL);
143.13279 ++	assert(!bo->needs_flush);
143.13280 + 	assert(list_is_empty(&bo->request));
143.13281 + }
143.13282 + #else
143.13283 + #define assert_tiling(kgem, bo)
143.13284 +-#define assert_cacheing(kgem, bo)
143.13285 ++#define assert_caching(kgem, bo)
143.13286 + #define assert_bo_retired(bo)
143.13287 + #endif
143.13288 + 
143.13289 ++static int __find_debugfs(struct kgem *kgem)
143.13290 ++{
143.13291 ++	int i;
143.13292 ++
143.13293 ++	for (i = 0; i < DRM_MAX_MINOR; i++) {
143.13294 ++		char path[80];
143.13295 ++
143.13296 ++		sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i);
143.13297 ++		if (access(path, R_OK) == 0)
143.13298 ++			return i;
143.13299 ++
143.13300 ++		sprintf(path, "/debug/dri/%d/i915_wedged", i);
143.13301 ++		if (access(path, R_OK) == 0)
143.13302 ++			return i;
143.13303 ++	}
143.13304 ++
143.13305 ++	return -1;
143.13306 ++}
143.13307 ++
143.13308 ++static int kgem_get_minor(struct kgem *kgem)
143.13309 ++{
143.13310 ++	struct stat st;
143.13311 ++
143.13312 ++	if (fstat(kgem->fd, &st))
143.13313 ++		return __find_debugfs(kgem);
143.13314 ++
143.13315 ++	if (!S_ISCHR(st.st_mode))
143.13316 ++		return __find_debugfs(kgem);
143.13317 ++
143.13318 ++	return st.st_rdev & 0x63;
143.13319 ++}
143.13320 ++
143.13321 ++static bool find_hang_state(struct kgem *kgem, char *path, int maxlen)
143.13322 ++{
143.13323 ++	int minor = kgem_get_minor(kgem);
143.13324 ++
143.13325 ++	/* Search for our hang state in a few canonical locations.
143.13326 ++	 * In the unlikely event of having multiple devices, we
143.13327 ++	 * will need to check which minor actually corresponds to ours.
143.13328 ++	 */
143.13329 ++
143.13330 ++	snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor);
143.13331 ++	if (access(path, R_OK) == 0)
143.13332 ++		return true;
143.13333 ++
143.13334 ++	snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor);
143.13335 ++	if (access(path, R_OK) == 0)
143.13336 ++		return true;
143.13337 ++
143.13338 ++	snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor);
143.13339 ++	if (access(path, R_OK) == 0)
143.13340 ++		return true;
143.13341 ++
143.13342 ++	path[0] = '\0';
143.13343 ++	return false;
143.13344 ++}
143.13345 ++
143.13346 ++static bool has_error_state(struct kgem *kgem, char *path)
143.13347 ++{
143.13348 ++   bool ret = false;
143.13349 ++   char no;
143.13350 ++   int fd;
143.13351 ++
143.13352 ++   fd = open(path, O_RDONLY);
143.13353 ++   if (fd >= 0) {
143.13354 ++      ret = read(fd, &no, 1) == 1 && no != 'N';
143.13355 ++      close(fd);
143.13356 ++   }
143.13357 ++
143.13358 ++   return ret;
143.13359 ++}
143.13360 ++
143.13361 ++static int kgem_get_screen_index(struct kgem *kgem)
143.13362 ++{
143.13363 ++	return __to_sna(kgem)->scrn->scrnIndex;
143.13364 ++}
143.13365 ++
143.13366 + static void
143.13367 + __kgem_set_wedged(struct kgem *kgem)
143.13368 + {
143.13369 ++	static int once;
143.13370 ++	char path[256];
143.13371 ++
143.13372 ++	if (kgem->wedged)
143.13373 ++		return;
143.13374 ++
143.13375 ++	if (!once &&
143.13376 ++	    find_hang_state(kgem, path, sizeof(path)) &&
143.13377 ++            has_error_state(kgem, path)) {
143.13378 ++		xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
143.13379 ++			   "When reporting this, please include %s and the full dmesg.\n",
143.13380 ++			   path);
143.13381 ++		once = 1;
143.13382 ++	}
143.13383 ++
143.13384 + 	kgem->wedged = true;
143.13385 +-	sna_render_mark_wedged(container_of(kgem, struct sna, kgem));
143.13386 ++	sna_render_mark_wedged(__to_sna(kgem));
143.13387 + }
143.13388 + 
143.13389 + static void kgem_sna_reset(struct kgem *kgem)
143.13390 + {
143.13391 +-	struct sna *sna = container_of(kgem, struct sna, kgem);
143.13392 ++	struct sna *sna = __to_sna(kgem);
143.13393 + 
143.13394 + 	sna->render.reset(sna);
143.13395 + 	sna->blt_state.fill_bo = 0;
143.13396 +@@ -319,7 +435,7 @@ static void kgem_sna_reset(struct kgem *kgem)
143.13397 + 
143.13398 + static void kgem_sna_flush(struct kgem *kgem)
143.13399 + {
143.13400 +-	struct sna *sna = container_of(kgem, struct sna, kgem);
143.13401 ++	struct sna *sna = __to_sna(kgem);
143.13402 + 
143.13403 + 	sna->render.flush(sna);
143.13404 + 
143.13405 +@@ -327,22 +443,53 @@ static void kgem_sna_flush(struct kgem *kgem)
143.13406 + 		sna_render_flush_solid(sna);
143.13407 + }
143.13408 + 
143.13409 +-static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
143.13410 ++static bool kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo)
143.13411 ++{
143.13412 ++	if (bo->scanout && bo->delta) {
143.13413 ++		DBG(("%s: releasing fb=%d for handle=%d\n",
143.13414 ++		     __FUNCTION__, bo->delta, bo->handle));
143.13415 ++		/* XXX will leak if we are not DRM_MASTER. *shrug* */
143.13416 ++		do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta);
143.13417 ++		bo->delta = 0;
143.13418 ++		return true;
143.13419 ++	} else
143.13420 ++		return false;
143.13421 ++}
143.13422 ++
143.13423 ++static bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo,
143.13424 ++			    int tiling, int stride)
143.13425 + {
143.13426 + 	struct drm_i915_gem_set_tiling set_tiling;
143.13427 + 	int err;
143.13428 + 
143.13429 ++	if (tiling == bo->tiling) {
143.13430 ++		if (tiling == I915_TILING_NONE) {
143.13431 ++			bo->pitch = stride;
143.13432 ++			return true;
143.13433 ++		}
143.13434 ++		if (stride == bo->pitch)
143.13435 ++			return true;
143.13436 ++	}
143.13437 ++
143.13438 + 	if (DBG_NO_TILING)
143.13439 + 		return false;
143.13440 + 
143.13441 + 	VG_CLEAR(set_tiling);
143.13442 + restart:
143.13443 +-	set_tiling.handle = handle;
143.13444 ++	set_tiling.handle = bo->handle;
143.13445 + 	set_tiling.tiling_mode = tiling;
143.13446 +-	set_tiling.stride = stride;
143.13447 ++	set_tiling.stride = tiling ? stride : 0;
143.13448 + 
143.13449 +-	if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
143.13450 +-		return true;
143.13451 ++	if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) {
143.13452 ++		bo->tiling = set_tiling.tiling_mode;
143.13453 ++		bo->pitch = set_tiling.tiling_mode ? set_tiling.stride : stride;
143.13454 ++		DBG(("%s: handle=%d, tiling=%d [%d], pitch=%d [%d]: %d\n",
143.13455 ++		     __FUNCTION__, bo->handle,
143.13456 ++		     bo->tiling, tiling,
143.13457 ++		     bo->pitch, stride,
143.13458 ++		     set_tiling.tiling_mode == tiling));
143.13459 ++		return set_tiling.tiling_mode == tiling;
143.13460 ++	}
143.13461 + 
143.13462 + 	err = errno;
143.13463 + 	if (err == EINTR)
143.13464 +@@ -353,6 +500,11 @@ restart:
143.13465 + 		goto restart;
143.13466 + 	}
143.13467 + 
143.13468 ++	if (err == EBUSY && kgem_bo_rmfb(kgem, bo))
143.13469 ++		goto restart;
143.13470 ++
143.13471 ++	ERR(("%s: failed to set-tiling(tiling=%d, pitch=%d) for handle=%d: %d\n",
143.13472 ++	     __FUNCTION__, tiling, stride, bo->handle, err));
143.13473 + 	return false;
143.13474 + }
143.13475 + 
143.13476 +@@ -437,10 +589,15 @@ static void *__kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo)
143.13477 + 	DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__,
143.13478 + 	     bo->handle, bytes(bo)));
143.13479 + 
143.13480 ++	if (bo->tiling && !kgem->can_fence)
143.13481 ++		return NULL;
143.13482 ++
143.13483 + 	VG_CLEAR(gtt);
143.13484 + retry_gtt:
143.13485 + 	gtt.handle = bo->handle;
143.13486 + 	if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &gtt))) {
143.13487 ++		DBG(("%s: failed %d, throttling/cleaning caches\n",
143.13488 ++		     __FUNCTION__, err));
143.13489 + 		assert(err != EINVAL);
143.13490 + 
143.13491 + 		(void)__kgem_throttle_retire(kgem, 0);
143.13492 +@@ -460,6 +617,8 @@ retry_mmap:
143.13493 + 		   kgem->fd, gtt.offset);
143.13494 + 	if (ptr == MAP_FAILED) {
143.13495 + 		err = errno;
143.13496 ++		DBG(("%s: failed %d, throttling/cleaning caches\n",
143.13497 ++		     __FUNCTION__, err));
143.13498 + 		assert(err != EINVAL);
143.13499 + 
143.13500 + 		if (__kgem_throttle_retire(kgem, 0))
143.13501 +@@ -498,6 +657,8 @@ retry_wc:
143.13502 + 	wc.size = bytes(bo);
143.13503 + 	wc.flags = I915_MMAP_WC;
143.13504 + 	if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP_v2, &wc))) {
143.13505 ++		DBG(("%s: failed %d, throttling/cleaning caches\n",
143.13506 ++		     __FUNCTION__, err));
143.13507 + 		assert(err != EINVAL);
143.13508 + 
143.13509 + 		if (__kgem_throttle_retire(kgem, 0))
143.13510 +@@ -519,16 +680,19 @@ retry_wc:
143.13511 + 
143.13512 + static void *__kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo)
143.13513 + {
143.13514 +-	struct drm_i915_gem_mmap mmap_arg;
143.13515 ++	struct local_i915_gem_mmap arg;
143.13516 + 	int err;
143.13517 + 
143.13518 ++	VG_CLEAR(arg);
143.13519 ++	arg.offset = 0;
143.13520 ++
143.13521 + retry:
143.13522 +-	VG_CLEAR(mmap_arg);
143.13523 +-	mmap_arg.handle = bo->handle;
143.13524 +-	mmap_arg.offset = 0;
143.13525 +-	mmap_arg.size = bytes(bo);
143.13526 +-	if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))) {
143.13527 +-		assert(err != EINVAL);
143.13528 ++	arg.handle = bo->handle;
143.13529 ++	arg.size = bytes(bo);
143.13530 ++	if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP, &arg))) {
143.13531 ++		DBG(("%s: failed %d, throttling/cleaning caches\n",
143.13532 ++		     __FUNCTION__, err));
143.13533 ++		assert(err != -EINVAL || bo->prime);
143.13534 + 
143.13535 + 		if (__kgem_throttle_retire(kgem, 0))
143.13536 + 			goto retry;
143.13537 +@@ -536,15 +700,16 @@ retry:
143.13538 + 		if (kgem_cleanup_cache(kgem))
143.13539 + 			goto retry;
143.13540 + 
143.13541 +-		ERR(("%s: failed to mmap handle=%d, %d bytes, into CPU domain: %d\n",
143.13542 +-		     __FUNCTION__, bo->handle, bytes(bo), -err));
143.13543 ++		ERR(("%s: failed to mmap handle=%d (prime? %d), %d bytes, into CPU domain: %d\n",
143.13544 ++		     __FUNCTION__, bo->handle, bo->prime, bytes(bo), -err));
143.13545 ++		bo->purged = 1;
143.13546 + 		return NULL;
143.13547 + 	}
143.13548 + 
143.13549 +-	VG(VALGRIND_MAKE_MEM_DEFINED(mmap_arg.addr_ptr, bytes(bo)));
143.13550 ++	VG(VALGRIND_MAKE_MEM_DEFINED(arg.addr_ptr, bytes(bo)));
143.13551 + 
143.13552 + 	DBG(("%s: caching CPU vma for %d\n", __FUNCTION__, bo->handle));
143.13553 +-	return bo->map__cpu = (void *)(uintptr_t)mmap_arg.addr_ptr;
143.13554 ++	return bo->map__cpu = (void *)(uintptr_t)arg.addr_ptr;
143.13555 + }
143.13556 + 
143.13557 + static int gem_write(int fd, uint32_t handle,
143.13558 +@@ -634,16 +799,10 @@ static void kgem_bo_retire(struct kgem *kgem, struct kgem_bo *bo)
143.13559 + 	assert(bo->exec == NULL);
143.13560 + 	assert(list_is_empty(&bo->vma));
143.13561 + 
143.13562 +-	if (bo->rq) {
143.13563 +-		__kgem_bo_clear_busy(bo);
143.13564 +-		kgem_retire(kgem);
143.13565 +-		assert_bo_retired(bo);
143.13566 +-	} else {
143.13567 +-		assert(bo->exec == NULL);
143.13568 +-		assert(list_is_empty(&bo->request));
143.13569 +-		assert(!bo->needs_flush);
143.13570 +-		ASSERT_IDLE(kgem, bo->handle);
143.13571 +-	}
143.13572 ++	if (bo->rq)
143.13573 ++		__kgem_retire_requests_upto(kgem, bo);
143.13574 ++	ASSERT_IDLE(kgem, bo->handle);
143.13575 ++	assert_bo_retired(bo);
143.13576 + }
143.13577 + 
143.13578 + static void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo)
143.13579 +@@ -655,10 +814,8 @@ static void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo)
143.13580 + 	assert(list_is_empty(&bo->vma));
143.13581 + 
143.13582 + 	if (bo->rq) {
143.13583 +-		if (!__kgem_busy(kgem, bo->handle)) {
143.13584 +-			__kgem_bo_clear_busy(bo);
143.13585 +-			kgem_retire(kgem);
143.13586 +-		}
143.13587 ++		if (!__kgem_busy(kgem, bo->handle))
143.13588 ++			__kgem_retire_requests_upto(kgem, bo);
143.13589 + 	} else {
143.13590 + 		assert(!bo->needs_flush);
143.13591 + 		ASSERT_IDLE(kgem, bo->handle);
143.13592 +@@ -694,6 +851,8 @@ retry:
143.13593 + 	}
143.13594 + 
143.13595 + 	if ((err = gem_write(kgem->fd, bo->handle, 0, length, data))) {
143.13596 ++		DBG(("%s: failed %d, throttling/cleaning caches\n",
143.13597 ++		     __FUNCTION__, err));
143.13598 + 		assert(err != EINVAL);
143.13599 + 
143.13600 + 		(void)__kgem_throttle_retire(kgem, 0);
143.13601 +@@ -728,27 +887,21 @@ static uint32_t gem_create(int fd, int num_pages)
143.13602 + 	return create.handle;
143.13603 + }
143.13604 + 
143.13605 +-static bool
143.13606 ++static void
143.13607 + kgem_bo_set_purgeable(struct kgem *kgem, struct kgem_bo *bo)
143.13608 + {
143.13609 +-#if DBG_NO_MADV
143.13610 +-	return true;
143.13611 +-#else
143.13612 ++#if !DBG_NO_MADV
143.13613 + 	struct drm_i915_gem_madvise madv;
143.13614 + 
143.13615 + 	assert(bo->exec == NULL);
143.13616 +-	assert(!bo->purged);
143.13617 + 
143.13618 + 	VG_CLEAR(madv);
143.13619 + 	madv.handle = bo->handle;
143.13620 + 	madv.madv = I915_MADV_DONTNEED;
143.13621 + 	if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) {
143.13622 +-		bo->purged = 1;
143.13623 +-		kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU;
143.13624 +-		return madv.retained;
143.13625 ++		bo->purged = true;
143.13626 ++		kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU;
143.13627 + 	}
143.13628 +-
143.13629 +-	return true;
143.13630 + #endif
143.13631 + }
143.13632 + 
143.13633 +@@ -788,7 +941,7 @@ kgem_bo_clear_purgeable(struct kgem *kgem, struct kgem_bo *bo)
143.13634 + 	madv.madv = I915_MADV_WILLNEED;
143.13635 + 	if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) {
143.13636 + 		bo->purged = !madv.retained;
143.13637 +-		kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU;
143.13638 ++		kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU;
143.13639 + 		return madv.retained;
143.13640 + 	}
143.13641 + 
143.13642 +@@ -869,13 +1022,17 @@ static struct kgem_request *__kgem_request_alloc(struct kgem *kgem)
143.13643 + {
143.13644 + 	struct kgem_request *rq;
143.13645 + 
143.13646 +-	rq = __kgem_freed_request;
143.13647 +-	if (rq) {
143.13648 +-		__kgem_freed_request = *(struct kgem_request **)rq;
143.13649 ++	if (unlikely(kgem->wedged)) {
143.13650 ++		rq = &kgem->static_request;
143.13651 + 	} else {
143.13652 +-		rq = malloc(sizeof(*rq));
143.13653 +-		if (rq == NULL)
143.13654 +-			rq = &kgem->static_request;
143.13655 ++		rq = __kgem_freed_request;
143.13656 ++		if (rq) {
143.13657 ++			__kgem_freed_request = *(struct kgem_request **)rq;
143.13658 ++		} else {
143.13659 ++			rq = malloc(sizeof(*rq));
143.13660 ++			if (rq == NULL)
143.13661 ++				rq = &kgem->static_request;
143.13662 ++		}
143.13663 + 	}
143.13664 + 
143.13665 + 	list_init(&rq->buffers);
143.13666 +@@ -925,11 +1082,11 @@ total_ram_size(void)
143.13667 + #ifdef HAVE_STRUCT_SYSINFO_TOTALRAM
143.13668 + 	struct sysinfo info;
143.13669 + 	if (sysinfo(&info) == 0)
143.13670 +-		return info.totalram * info.mem_unit;
143.13671 ++		return (size_t)info.totalram * info.mem_unit;
143.13672 + #endif
143.13673 + 
143.13674 + #ifdef _SC_PHYS_PAGES
143.13675 +-	 return sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
143.13676 ++	 return (size_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
143.13677 + #endif
143.13678 + 
143.13679 + 	return 0;
143.13680 +@@ -1150,6 +1307,10 @@ static bool test_has_wc_mmap(struct kgem *kgem)
143.13681 + 	if (DBG_NO_WC_MMAP)
143.13682 + 		return false;
143.13683 + 
143.13684 ++	/* XXX See https://bugs.freedesktop.org/show_bug.cgi?id=90841 */
143.13685 ++	if (kgem->gen < 033)
143.13686 ++		return false;
143.13687 ++
143.13688 + 	if (gem_param(kgem, LOCAL_I915_PARAM_MMAP_VERSION) < 1)
143.13689 + 		return false;
143.13690 + 
143.13691 +@@ -1187,7 +1348,7 @@ static bool test_has_caching(struct kgem *kgem)
143.13692 + 
143.13693 + static bool test_has_userptr(struct kgem *kgem)
143.13694 + {
143.13695 +-	uint32_t handle;
143.13696 ++	struct local_i915_gem_userptr arg;
143.13697 + 	void *ptr;
143.13698 + 
143.13699 + 	if (DBG_NO_USERPTR)
143.13700 +@@ -1200,11 +1361,23 @@ static bool test_has_userptr(struct kgem *kgem)
143.13701 + 	if (posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE))
143.13702 + 		return false;
143.13703 + 
143.13704 +-	handle = gem_userptr(kgem->fd, ptr, PAGE_SIZE, false);
143.13705 +-	gem_close(kgem->fd, handle);
143.13706 +-	free(ptr);
143.13707 ++	VG_CLEAR(arg);
143.13708 ++	arg.user_ptr = (uintptr_t)ptr;
143.13709 ++	arg.user_size = PAGE_SIZE;
143.13710 ++	arg.flags = I915_USERPTR_UNSYNCHRONIZED;
143.13711 + 
143.13712 +-	return handle != 0;
143.13713 ++	if (DBG_NO_UNSYNCHRONIZED_USERPTR ||
143.13714 ++	    do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) {
143.13715 ++		arg.flags &= ~I915_USERPTR_UNSYNCHRONIZED;
143.13716 ++		if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg))
143.13717 ++			arg.handle = 0;
143.13718 ++		/* Leak the userptr bo to keep the mmu_notifier alive */
143.13719 ++	} else {
143.13720 ++		gem_close(kgem->fd, arg.handle);
143.13721 ++		free(ptr);
143.13722 ++	}
143.13723 ++
143.13724 ++	return arg.handle != 0;
143.13725 + }
143.13726 + 
143.13727 + static bool test_has_create2(struct kgem *kgem)
143.13728 +@@ -1227,67 +1400,187 @@ static bool test_has_create2(struct kgem *kgem)
143.13729 + #endif
143.13730 + }
143.13731 + 
143.13732 +-static bool test_has_secure_batches(struct kgem *kgem)
143.13733 ++static bool test_can_blt_y(struct kgem *kgem)
143.13734 + {
143.13735 +-	if (DBG_NO_SECURE_BATCHES)
143.13736 ++	struct drm_i915_gem_exec_object2 object;
143.13737 ++	uint32_t batch[] = {
143.13738 ++#define MI_LOAD_REGISTER_IMM (0x22<<23 | (3-2))
143.13739 ++#define BCS_SWCTRL 0x22200
143.13740 ++#define BCS_SRC_Y (1 << 0)
143.13741 ++#define BCS_DST_Y (1 << 1)
143.13742 ++		MI_LOAD_REGISTER_IMM,
143.13743 ++		BCS_SWCTRL,
143.13744 ++		(BCS_SRC_Y | BCS_DST_Y) << 16 | (BCS_SRC_Y | BCS_DST_Y),
143.13745 ++
143.13746 ++		MI_LOAD_REGISTER_IMM,
143.13747 ++		BCS_SWCTRL,
143.13748 ++		(BCS_SRC_Y | BCS_DST_Y) << 16,
143.13749 ++
143.13750 ++		MI_BATCH_BUFFER_END,
143.13751 ++		0,
143.13752 ++	};
143.13753 ++	int ret;
143.13754 ++
143.13755 ++	if (DBG_NO_BLT_Y)
143.13756 + 		return false;
143.13757 + 
143.13758 +-	return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0;
143.13759 ++	if (kgem->gen < 060)
143.13760 ++		return false;
143.13761 ++
143.13762 ++	memset(&object, 0, sizeof(object));
143.13763 ++	object.handle = gem_create(kgem->fd, 1);
143.13764 ++
143.13765 ++	ret = gem_write(kgem->fd, object.handle, 0, sizeof(batch), batch);
143.13766 ++	if (ret == 0) {
143.13767 ++		struct drm_i915_gem_execbuffer2 execbuf;
143.13768 ++
143.13769 ++		memset(&execbuf, 0, sizeof(execbuf));
143.13770 ++		execbuf.buffers_ptr = (uintptr_t)&object;
143.13771 ++		execbuf.buffer_count = 1;
143.13772 ++		execbuf.flags = KGEM_BLT;
143.13773 ++
143.13774 ++		ret = do_ioctl(kgem->fd,
143.13775 ++			       DRM_IOCTL_I915_GEM_EXECBUFFER2,
143.13776 ++			       &execbuf);
143.13777 ++	}
143.13778 ++	gem_close(kgem->fd, object.handle);
143.13779 ++
143.13780 ++	return ret == 0;
143.13781 + }
143.13782 + 
143.13783 +-static bool test_has_pinned_batches(struct kgem *kgem)
143.13784 ++static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
143.13785 + {
143.13786 +-	if (DBG_NO_PINNED_BATCHES)
143.13787 ++	struct drm_i915_gem_set_tiling set_tiling;
143.13788 ++
143.13789 ++	if (DBG_NO_TILING)
143.13790 + 		return false;
143.13791 + 
143.13792 +-	return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0;
143.13793 ++	VG_CLEAR(set_tiling);
143.13794 ++	set_tiling.handle = handle;
143.13795 ++	set_tiling.tiling_mode = tiling;
143.13796 ++	set_tiling.stride = stride;
143.13797 ++
143.13798 ++	if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
143.13799 ++		return set_tiling.tiling_mode == tiling;
143.13800 ++
143.13801 ++	return false;
143.13802 + }
143.13803 + 
143.13804 +-static int kgem_get_screen_index(struct kgem *kgem)
143.13805 ++static bool test_can_scanout_y(struct kgem *kgem)
143.13806 + {
143.13807 +-	struct sna *sna = container_of(kgem, struct sna, kgem);
143.13808 +-	return sna->scrn->scrnIndex;
143.13809 ++	struct drm_mode_fb_cmd arg;
143.13810 ++	bool ret = false;
143.13811 ++
143.13812 ++	if (DBG_NO_SCANOUT_Y)
143.13813 ++		return false;
143.13814 ++
143.13815 ++	VG_CLEAR(arg);
143.13816 ++	arg.width = 32;
143.13817 ++	arg.height = 32;
143.13818 ++	arg.pitch = 4*32;
143.13819 ++	arg.bpp = 32;
143.13820 ++	arg.depth = 24;
143.13821 ++	arg.handle = gem_create(kgem->fd, 1);
143.13822 ++
143.13823 ++	if (gem_set_tiling(kgem->fd, arg.handle, I915_TILING_Y, arg.pitch))
143.13824 ++		ret = do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg) == 0;
143.13825 ++	if (!ret) {
143.13826 ++		struct local_mode_fb_cmd2 {
143.13827 ++			uint32_t fb_id;
143.13828 ++			uint32_t width, height;
143.13829 ++			uint32_t pixel_format;
143.13830 ++			uint32_t flags;
143.13831 ++
143.13832 ++			uint32_t handles[4];
143.13833 ++			uint32_t pitches[4];
143.13834 ++			uint32_t offsets[4];
143.13835 ++			uint64_t modifiers[4];
143.13836 ++		} f;
143.13837 ++#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
143.13838 ++		memset(&f, 0, sizeof(f));
143.13839 ++		f.width = arg.width;
143.13840 ++		f.height = arg.height;
143.13841 ++		f.handles[0] = arg.handle;
143.13842 ++		f.pitches[0] = arg.pitch;
143.13843 ++		f.modifiers[0] = (uint64_t)1 << 56 | 2; /* MOD_Y_TILED */
143.13844 ++		f.pixel_format = 'X' | 'R' << 8 | '2' << 16 | '4' << 24; /* XRGB8888 */
143.13845 ++		f.flags = 1 << 1; /* + modifier */
143.13846 ++		if (drmIoctl(kgem->fd, LOCAL_IOCTL_MODE_ADDFB2, &f) == 0) {
143.13847 ++			ret = true;
143.13848 ++			arg.fb_id = f.fb_id;
143.13849 ++		}
143.13850 ++	}
143.13851 ++	do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &arg.fb_id);
143.13852 ++	gem_close(kgem->fd, arg.handle);
143.13853 ++
143.13854 ++	return ret;
143.13855 + }
143.13856 + 
143.13857 +-static int __find_debugfs(struct kgem *kgem)
143.13858 ++static bool test_has_dirtyfb(struct kgem *kgem)
143.13859 + {
143.13860 +-	int i;
143.13861 ++	struct drm_mode_fb_cmd create;
143.13862 ++	bool ret = false;
143.13863 + 
143.13864 +-	for (i = 0; i < DRM_MAX_MINOR; i++) {
143.13865 +-		char path[80];
143.13866 ++	if (DBG_NO_DIRTYFB)
143.13867 ++		return false;
143.13868 + 
143.13869 +-		sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i);
143.13870 +-		if (access(path, R_OK) == 0)
143.13871 +-			return i;
143.13872 ++	VG_CLEAR(create);
143.13873 ++	create.width = 32;
143.13874 ++	create.height = 32;
143.13875 ++	create.pitch = 4*32;
143.13876 ++	create.bpp = 32;
143.13877 ++	create.depth = 32;
143.13878 ++	create.handle = gem_create(kgem->fd, 1);
143.13879 ++	if (create.handle == 0)
143.13880 ++		return false;
143.13881 + 
143.13882 +-		sprintf(path, "/debug/dri/%d/i915_wedged", i);
143.13883 +-		if (access(path, R_OK) == 0)
143.13884 +-			return i;
143.13885 ++	if (drmIoctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &create) == 0) {
143.13886 ++		struct drm_mode_fb_dirty_cmd dirty;
143.13887 ++
143.13888 ++		memset(&dirty, 0, sizeof(dirty));
143.13889 ++		dirty.fb_id = create.fb_id;
143.13890 ++		ret = drmIoctl(kgem->fd,
143.13891 ++			       DRM_IOCTL_MODE_DIRTYFB,
143.13892 ++			       &dirty) == 0;
143.13893 ++
143.13894 ++		/* XXX There may be multiple levels of DIRTYFB, depending on
143.13895 ++		 * whether the kernel thinks tracking dirty regions is
143.13896 ++		 * beneficial vs flagging the whole fb as dirty.
143.13897 ++		 */
143.13898 ++
143.13899 ++		drmIoctl(kgem->fd,
143.13900 ++			 DRM_IOCTL_MODE_RMFB,
143.13901 ++			 &create.fb_id);
143.13902 + 	}
143.13903 ++	gem_close(kgem->fd, create.handle);
143.13904 + 
143.13905 +-	return -1;
143.13906 ++	return ret;
143.13907 + }
143.13908 + 
143.13909 +-static int kgem_get_minor(struct kgem *kgem)
143.13910 ++static bool test_has_secure_batches(struct kgem *kgem)
143.13911 + {
143.13912 +-	struct stat st;
143.13913 ++	if (DBG_NO_SECURE_BATCHES)
143.13914 ++		return false;
143.13915 + 
143.13916 +-	if (fstat(kgem->fd, &st))
143.13917 +-		return __find_debugfs(kgem);
143.13918 ++	return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0;
143.13919 ++}
143.13920 + 
143.13921 +-	if (!S_ISCHR(st.st_mode))
143.13922 +-		return __find_debugfs(kgem);
143.13923 ++static bool test_has_pinned_batches(struct kgem *kgem)
143.13924 ++{
143.13925 ++	if (DBG_NO_PINNED_BATCHES)
143.13926 ++		return false;
143.13927 + 
143.13928 +-	return st.st_rdev & 0x63;
143.13929 ++	return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0;
143.13930 + }
143.13931 + 
143.13932 + static bool kgem_init_pinned_batches(struct kgem *kgem)
143.13933 + {
143.13934 + 	int count[2] = { 16, 4 };
143.13935 + 	int size[2] = { 1, 4 };
143.13936 ++	int ret = 0;
143.13937 + 	int n, i;
143.13938 + 
143.13939 +-	if (kgem->wedged)
143.13940 ++	if (unlikely(kgem->wedged))
143.13941 + 		return true;
143.13942 + 
143.13943 + 	for (n = 0; n < ARRAY_SIZE(count); n++) {
143.13944 +@@ -1311,7 +1604,8 @@ static bool kgem_init_pinned_batches(struct kgem *kgem)
143.13945 + 			}
143.13946 + 
143.13947 + 			pin.alignment = 0;
143.13948 +-			if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin)) {
143.13949 ++			ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin);
143.13950 ++			if (ret) {
143.13951 + 				gem_close(kgem->fd, pin.handle);
143.13952 + 				free(bo);
143.13953 + 				goto err;
143.13954 +@@ -1333,6 +1627,16 @@ err:
143.13955 + 		}
143.13956 + 	}
143.13957 + 
143.13958 ++	/* If we fail to pin some memory for 830gm/845g, we need to disable
143.13959 ++	 * acceleration as otherwise the machine will eventually fail. However,
143.13960 ++	 * the kernel started arbitrarily rejecting PIN, so hope for the best
143.13961 ++	 * if the ioctl no longer works.
143.13962 ++	 */
143.13963 ++	if (ret != -ENODEV && kgem->gen == 020)
143.13964 ++		return false;
143.13965 ++
143.13966 ++	kgem->has_pinned_batches = false;
143.13967 ++
143.13968 + 	/* For simplicity populate the lists with a single unpinned bo */
143.13969 + 	for (n = 0; n < ARRAY_SIZE(count); n++) {
143.13970 + 		struct kgem_bo *bo;
143.13971 +@@ -1340,18 +1644,18 @@ err:
143.13972 + 
143.13973 + 		handle = gem_create(kgem->fd, size[n]);
143.13974 + 		if (handle == 0)
143.13975 +-			break;
143.13976 ++			return false;
143.13977 + 
143.13978 + 		bo = __kgem_bo_alloc(handle, size[n]);
143.13979 + 		if (bo == NULL) {
143.13980 + 			gem_close(kgem->fd, handle);
143.13981 +-			break;
143.13982 ++			return false;
143.13983 + 		}
143.13984 + 
143.13985 + 		debug_alloc__bo(kgem, bo);
143.13986 + 		list_add(&bo->list, &kgem->pinned_batches[n]);
143.13987 + 	}
143.13988 +-	return false;
143.13989 ++	return true;
143.13990 + }
143.13991 + 
143.13992 + static void kgem_init_swizzling(struct kgem *kgem)
143.13993 +@@ -1364,7 +1668,7 @@ static void kgem_init_swizzling(struct kgem *kgem)
143.13994 + 	} tiling;
143.13995 + #define LOCAL_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct local_i915_gem_get_tiling_v2)
143.13996 + 
143.13997 +-	VG_CLEAR(tiling);
143.13998 ++	memset(&tiling, 0, sizeof(tiling));
143.13999 + 	tiling.handle = gem_create(kgem->fd, 1);
143.14000 + 	if (!tiling.handle)
143.14001 + 		return;
143.14002 +@@ -1375,12 +1679,23 @@ static void kgem_init_swizzling(struct kgem *kgem)
143.14003 + 	if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_TILING, &tiling))
143.14004 + 		goto out;
143.14005 + 
143.14006 +-	if (kgem->gen < 50 && tiling.phys_swizzle_mode != tiling.swizzle_mode)
143.14007 ++	DBG(("%s: swizzle_mode=%d, phys_swizzle_mode=%d\n",
143.14008 ++	     __FUNCTION__, tiling.swizzle_mode, tiling.phys_swizzle_mode));
143.14009 ++
143.14010 ++	kgem->can_fence =
143.14011 ++		!DBG_NO_TILING &&
143.14012 ++		tiling.swizzle_mode != I915_BIT_6_SWIZZLE_UNKNOWN;
143.14013 ++
143.14014 ++	if (kgem->gen < 050 && tiling.phys_swizzle_mode != tiling.swizzle_mode)
143.14015 + 		goto out;
143.14016 + 
143.14017 +-	choose_memcpy_tiled_x(kgem, tiling.swizzle_mode);
143.14018 ++	if (!DBG_NO_DETILING)
143.14019 ++		choose_memcpy_tiled_x(kgem,
143.14020 ++				      tiling.swizzle_mode,
143.14021 ++				      __to_sna(kgem)->cpu_features);
143.14022 + out:
143.14023 + 	gem_close(kgem->fd, tiling.handle);
143.14024 ++	DBG(("%s: can fence?=%d\n", __FUNCTION__, kgem->can_fence));
143.14025 + }
143.14026 + 
143.14027 + static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
143.14028 +@@ -1399,6 +1714,7 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
143.14029 + 	     bo->handle, (long long)bo->presumed_offset));
143.14030 + 	for (n = 0; n < kgem->nreloc__self; n++) {
143.14031 + 		int i = kgem->reloc__self[n];
143.14032 ++		uint64_t addr;
143.14033 + 
143.14034 + 		assert(kgem->reloc[i].target_handle == ~0U);
143.14035 + 		kgem->reloc[i].target_handle = bo->target_handle;
143.14036 +@@ -1412,13 +1728,17 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
143.14037 + 
143.14038 + 			kgem->reloc[i].delta -= shrink;
143.14039 + 		}
143.14040 +-		kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t)] =
143.14041 +-			kgem->reloc[i].delta + bo->presumed_offset;
143.14042 ++		addr = (int)kgem->reloc[i].delta + bo->presumed_offset;
143.14043 ++		kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t)] = addr;
143.14044 ++		if (kgem->gen >= 0100)
143.14045 ++			kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t) + 1] = addr >> 32;
143.14046 + 	}
143.14047 + 
143.14048 + 	if (n == 256) {
143.14049 + 		for (n = kgem->reloc__self[255]; n < kgem->nreloc; n++) {
143.14050 + 			if (kgem->reloc[n].target_handle == ~0U) {
143.14051 ++				uint64_t addr;
143.14052 ++
143.14053 + 				kgem->reloc[n].target_handle = bo->target_handle;
143.14054 + 				kgem->reloc[n].presumed_offset = bo->presumed_offset;
143.14055 + 
143.14056 +@@ -1429,8 +1749,11 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
143.14057 + 					     kgem->reloc[n].delta - shrink));
143.14058 + 					kgem->reloc[n].delta -= shrink;
143.14059 + 				}
143.14060 +-				kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t)] =
143.14061 +-					kgem->reloc[n].delta + bo->presumed_offset;
143.14062 ++
143.14063 ++				addr = (int)kgem->reloc[n].delta + bo->presumed_offset;
143.14064 ++				kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t)] = addr;
143.14065 ++				if (kgem->gen >= 0100)
143.14066 ++					kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t) + 1] = addr >> 32;
143.14067 + 			}
143.14068 + 		}
143.14069 + 	}
143.14070 +@@ -1444,6 +1767,44 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
143.14071 + 	}
143.14072 + }
143.14073 + 
143.14074 ++static int kgem_bo_wait(struct kgem *kgem, struct kgem_bo *bo)
143.14075 ++{
143.14076 ++	struct local_i915_gem_wait {
143.14077 ++		uint32_t handle;
143.14078 ++		uint32_t flags;
143.14079 ++		int64_t timeout;
143.14080 ++	} wait;
143.14081 ++#define LOCAL_I915_GEM_WAIT       0x2c
143.14082 ++#define LOCAL_IOCTL_I915_GEM_WAIT         DRM_IOWR(DRM_COMMAND_BASE + LOCAL_I915_GEM_WAIT, struct local_i915_gem_wait)
143.14083 ++	int ret;
143.14084 ++
143.14085 ++	DBG(("%s: waiting for handle=%d\n", __FUNCTION__, bo->handle));
143.14086 ++	if (bo->rq == NULL)
143.14087 ++		return 0;
143.14088 ++
143.14089 ++	VG_CLEAR(wait);
143.14090 ++	wait.handle = bo->handle;
143.14091 ++	wait.flags = 0;
143.14092 ++	wait.timeout = -1;
143.14093 ++	ret = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_WAIT, &wait);
143.14094 ++	if (ret) {
143.14095 ++		struct drm_i915_gem_set_domain set_domain;
143.14096 ++
143.14097 ++		VG_CLEAR(set_domain);
143.14098 ++		set_domain.handle = bo->handle;
143.14099 ++		set_domain.read_domains = I915_GEM_DOMAIN_GTT;
143.14100 ++		set_domain.write_domain = I915_GEM_DOMAIN_GTT;
143.14101 ++		ret = do_ioctl(kgem->fd,
143.14102 ++			       DRM_IOCTL_I915_GEM_SET_DOMAIN,
143.14103 ++			       &set_domain);
143.14104 ++	}
143.14105 ++
143.14106 ++	if (ret == 0)
143.14107 ++		__kgem_retire_requests_upto(kgem, bo);
143.14108 ++
143.14109 ++	return ret;
143.14110 ++}
143.14111 ++
143.14112 + static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
143.14113 + {
143.14114 + 	struct kgem_bo *last;
143.14115 +@@ -1464,20 +1825,41 @@ static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
143.14116 + 	if (!kgem->has_llc)
143.14117 + 		flags |= CREATE_UNCACHED;
143.14118 + 
143.14119 ++restart:
143.14120 + 	kgem->batch_bo = kgem_create_linear(kgem,
143.14121 + 					    sizeof(uint32_t)*kgem->batch_size,
143.14122 + 					    flags);
143.14123 + 	if (kgem->batch_bo)
143.14124 + 		kgem->batch = kgem_bo_map__cpu(kgem, kgem->batch_bo);
143.14125 + 	if (kgem->batch == NULL) {
143.14126 +-		DBG(("%s: unable to map batch bo, mallocing(size=%d)\n",
143.14127 +-		     __FUNCTION__,
143.14128 +-		     sizeof(uint32_t)*kgem->batch_size));
143.14129 ++		int ring = kgem->ring == KGEM_BLT;
143.14130 ++		assert(ring < ARRAY_SIZE(kgem->requests));
143.14131 ++
143.14132 + 		if (kgem->batch_bo) {
143.14133 + 			kgem_bo_destroy(kgem, kgem->batch_bo);
143.14134 + 			kgem->batch_bo = NULL;
143.14135 + 		}
143.14136 + 
143.14137 ++		if (!list_is_empty(&kgem->requests[ring])) {
143.14138 ++			struct kgem_request *rq;
143.14139 ++
143.14140 ++			rq = list_first_entry(&kgem->requests[ring],
143.14141 ++					      struct kgem_request, list);
143.14142 ++			assert(rq->ring == ring);
143.14143 ++			assert(rq->bo);
143.14144 ++			assert(RQ(rq->bo->rq) == rq);
143.14145 ++			if (kgem_bo_wait(kgem, rq->bo) == 0)
143.14146 ++				goto restart;
143.14147 ++		}
143.14148 ++
143.14149 ++		if (flags & CREATE_NO_THROTTLE) {
143.14150 ++			flags &= ~CREATE_NO_THROTTLE;
143.14151 ++			if (kgem_cleanup_cache(kgem))
143.14152 ++				goto restart;
143.14153 ++		}
143.14154 ++
143.14155 ++		DBG(("%s: unable to map batch bo, mallocing(size=%d)\n",
143.14156 ++		     __FUNCTION__, sizeof(uint32_t)*kgem->batch_size));
143.14157 + 		if (posix_memalign((void **)&kgem->batch, PAGE_SIZE,
143.14158 + 				   ALIGN(sizeof(uint32_t) * kgem->batch_size, PAGE_SIZE))) {
143.14159 + 			ERR(("%s: batch allocation failed, disabling acceleration\n", __FUNCTION__));
143.14160 +@@ -1495,18 +1877,79 @@ static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
143.14161 + 	return last;
143.14162 + }
143.14163 + 
143.14164 +-void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
143.14165 ++static void
143.14166 ++no_retire(struct kgem *kgem)
143.14167 ++{
143.14168 ++	(void)kgem;
143.14169 ++}
143.14170 ++
143.14171 ++static void
143.14172 ++no_expire(struct kgem *kgem)
143.14173 ++{
143.14174 ++	(void)kgem;
143.14175 ++}
143.14176 ++
143.14177 ++static void
143.14178 ++no_context_switch(struct kgem *kgem, int new_mode)
143.14179 ++{
143.14180 ++	(void)kgem;
143.14181 ++	(void)new_mode;
143.14182 ++}
143.14183 ++
143.14184 ++static uint64_t get_gtt_size(int fd)
143.14185 + {
143.14186 + 	struct drm_i915_gem_get_aperture aperture;
143.14187 ++	struct local_i915_gem_context_param {
143.14188 ++		uint32_t context;
143.14189 ++		uint32_t size;
143.14190 ++		uint64_t param;
143.14191 ++#define LOCAL_CONTEXT_PARAM_BAN_PERIOD	0x1
143.14192 ++#define LOCAL_CONTEXT_PARAM_NO_ZEROMAP	0x2
143.14193 ++#define LOCAL_CONTEXT_PARAM_GTT_SIZE	0x3
143.14194 ++		uint64_t value;
143.14195 ++	} p;
143.14196 ++#define LOCAL_I915_GEM_CONTEXT_GETPARAM       0x34
143.14197 ++#define LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_GETPARAM, struct local_i915_gem_context_param)
143.14198 ++
143.14199 ++	memset(&aperture, 0, sizeof(aperture));
143.14200 ++
143.14201 ++	memset(&p, 0, sizeof(p));
143.14202 ++	p.param = LOCAL_CONTEXT_PARAM_GTT_SIZE;
143.14203 ++	if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p) == 0)
143.14204 ++		aperture.aper_size = p.value;
143.14205 ++	if (aperture.aper_size == 0)
143.14206 ++		(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
143.14207 ++	if (aperture.aper_size == 0)
143.14208 ++		aperture.aper_size = 64*1024*1024;
143.14209 ++
143.14210 ++	DBG(("%s: aperture size %lld, available now %lld\n",
143.14211 ++	     __FUNCTION__,
143.14212 ++	     (long long)aperture.aper_size,
143.14213 ++	     (long long)aperture.aper_available_size));
143.14214 ++
143.14215 ++	/* clamp aperture to uint32_t for simplicity */
143.14216 ++	if (aperture.aper_size > 0xc0000000)
143.14217 ++		aperture.aper_size = 0xc0000000;
143.14218 ++
143.14219 ++	return aperture.aper_size;
143.14220 ++}
143.14221 ++
143.14222 ++void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
143.14223 ++{
143.14224 + 	size_t totalram;
143.14225 + 	unsigned half_gpu_max;
143.14226 + 	unsigned int i, j;
143.14227 ++	uint64_t gtt_size;
143.14228 + 
143.14229 + 	DBG(("%s: fd=%d, gen=%d\n", __FUNCTION__, fd, gen));
143.14230 + 
143.14231 + 	kgem->fd = fd;
143.14232 + 	kgem->gen = gen;
143.14233 + 
143.14234 ++	kgem->retire = no_retire;
143.14235 ++	kgem->expire = no_expire;
143.14236 ++	kgem->context_switch = no_context_switch;
143.14237 ++
143.14238 + 	list_init(&kgem->requests[0]);
143.14239 + 	list_init(&kgem->requests[1]);
143.14240 + 	list_init(&kgem->batch_buffers);
143.14241 +@@ -1586,10 +2029,21 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
143.14242 + 	DBG(("%s: can blt to cpu? %d\n", __FUNCTION__,
143.14243 + 	     kgem->can_blt_cpu));
143.14244 + 
143.14245 ++	kgem->can_blt_y = test_can_blt_y(kgem);
143.14246 ++	DBG(("%s: can blit to Y-tiled surfaces? %d\n", __FUNCTION__,
143.14247 ++	     kgem->can_blt_y));
143.14248 ++
143.14249 + 	kgem->can_render_y = gen != 021 && (gen >> 3) != 4;
143.14250 + 	DBG(("%s: can render to Y-tiled surfaces? %d\n", __FUNCTION__,
143.14251 + 	     kgem->can_render_y));
143.14252 + 
143.14253 ++	kgem->can_scanout_y = test_can_scanout_y(kgem);
143.14254 ++	DBG(("%s: can scanout Y-tiled surfaces? %d\n", __FUNCTION__,
143.14255 ++	     kgem->can_scanout_y));
143.14256 ++
143.14257 ++	kgem->has_dirtyfb = test_has_dirtyfb(kgem);
143.14258 ++	DBG(("%s: has dirty fb? %d\n", __FUNCTION__, kgem->has_dirtyfb));
143.14259 ++
143.14260 + 	kgem->has_secure_batches = test_has_secure_batches(kgem);
143.14261 + 	DBG(("%s: can use privileged batchbuffers? %d\n", __FUNCTION__,
143.14262 + 	     kgem->has_secure_batches));
143.14263 +@@ -1620,7 +2074,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
143.14264 + 	if (!kgem->has_relaxed_delta && kgem->batch_size > 4*1024)
143.14265 + 		kgem->batch_size = 4*1024;
143.14266 + 
143.14267 +-	if (!kgem_init_pinned_batches(kgem) && gen == 020) {
143.14268 ++	if (!kgem_init_pinned_batches(kgem)) {
143.14269 + 		xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
143.14270 + 			   "Unable to reserve memory for GPU, disabling acceleration.\n");
143.14271 + 		__kgem_set_wedged(kgem);
143.14272 +@@ -1640,35 +2094,24 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
143.14273 + 	     !DBG_NO_CPU && (kgem->has_llc | kgem->has_userptr | kgem->has_caching),
143.14274 + 	     kgem->has_llc, kgem->has_caching, kgem->has_userptr));
143.14275 + 
143.14276 +-	VG_CLEAR(aperture);
143.14277 +-	aperture.aper_size = 0;
143.14278 +-	(void)do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
143.14279 +-	if (aperture.aper_size == 0)
143.14280 +-		aperture.aper_size = 64*1024*1024;
143.14281 +-
143.14282 +-	DBG(("%s: aperture size %lld, available now %lld\n",
143.14283 +-	     __FUNCTION__,
143.14284 +-	     (long long)aperture.aper_size,
143.14285 +-	     (long long)aperture.aper_available_size));
143.14286 +-
143.14287 +-	kgem->aperture_total = aperture.aper_size;
143.14288 +-	kgem->aperture_high = aperture.aper_size * 3/4;
143.14289 +-	kgem->aperture_low = aperture.aper_size * 1/3;
143.14290 ++	gtt_size = get_gtt_size(fd);
143.14291 ++	kgem->aperture_total = gtt_size;
143.14292 ++	kgem->aperture_high = gtt_size * 3/4;
143.14293 ++	kgem->aperture_low = gtt_size * 1/3;
143.14294 + 	if (gen < 033) {
143.14295 + 		/* Severe alignment penalties */
143.14296 + 		kgem->aperture_high /= 2;
143.14297 + 		kgem->aperture_low /= 2;
143.14298 + 	}
143.14299 +-	DBG(("%s: aperture low=%d [%d], high=%d [%d]\n", __FUNCTION__,
143.14300 ++	DBG(("%s: aperture low=%u [%u], high=%u [%u]\n", __FUNCTION__,
143.14301 + 	     kgem->aperture_low, kgem->aperture_low / (1024*1024),
143.14302 + 	     kgem->aperture_high, kgem->aperture_high / (1024*1024)));
143.14303 + 
143.14304 + 	kgem->aperture_mappable = 256 * 1024 * 1024;
143.14305 + 	if (dev != NULL)
143.14306 + 		kgem->aperture_mappable = agp_aperture_size(dev, gen);
143.14307 +-	if (kgem->aperture_mappable == 0 ||
143.14308 +-	    kgem->aperture_mappable > aperture.aper_size)
143.14309 +-		kgem->aperture_mappable = aperture.aper_size;
143.14310 ++	if (kgem->aperture_mappable == 0 || kgem->aperture_mappable > gtt_size)
143.14311 ++		kgem->aperture_mappable = gtt_size;
143.14312 + 	DBG(("%s: aperture mappable=%d [%d MiB]\n", __FUNCTION__,
143.14313 + 	     kgem->aperture_mappable, kgem->aperture_mappable / (1024*1024)));
143.14314 + 
143.14315 +@@ -1697,7 +2140,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
143.14316 + 		     __FUNCTION__));
143.14317 + 		totalram = kgem->aperture_total;
143.14318 + 	}
143.14319 +-	DBG(("%s: total ram=%ld\n", __FUNCTION__, (long)totalram));
143.14320 ++	DBG(("%s: total ram=%lld\n", __FUNCTION__, (long long)totalram));
143.14321 + 	if (kgem->max_object_size > totalram / 2)
143.14322 + 		kgem->max_object_size = totalram / 2;
143.14323 + 	if (kgem->max_gpu_size > totalram / 4)
143.14324 +@@ -1749,11 +2192,11 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
143.14325 + 	if (DBG_NO_CPU)
143.14326 + 		kgem->max_cpu_size = 0;
143.14327 + 
143.14328 +-	DBG(("%s: maximum object size=%d\n",
143.14329 ++	DBG(("%s: maximum object size=%u\n",
143.14330 + 	     __FUNCTION__, kgem->max_object_size));
143.14331 +-	DBG(("%s: large object thresold=%d\n",
143.14332 ++	DBG(("%s: large object thresold=%u\n",
143.14333 + 	     __FUNCTION__, kgem->large_object_size));
143.14334 +-	DBG(("%s: max object sizes (gpu=%d, cpu=%d, tile upload=%d, copy=%d)\n",
143.14335 ++	DBG(("%s: max object sizes (gpu=%u, cpu=%u, tile upload=%u, copy=%u)\n",
143.14336 + 	     __FUNCTION__,
143.14337 + 	     kgem->max_gpu_size, kgem->max_cpu_size,
143.14338 + 	     kgem->max_upload_tile_size, kgem->max_copy_tile_size));
143.14339 +@@ -2043,8 +2486,34 @@ static void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo)
143.14340 + 	kgem->flush |= bo->flush;
143.14341 + }
143.14342 + 
143.14343 ++static void kgem_clear_swctrl(struct kgem *kgem)
143.14344 ++{
143.14345 ++	uint32_t *b;
143.14346 ++
143.14347 ++	if (kgem->bcs_state == 0)
143.14348 ++		return;
143.14349 ++
143.14350 ++	DBG(("%s: clearin SWCTRL LRI from %x\n",
143.14351 ++	     __FUNCTION__, kgem->bcs_state));
143.14352 ++
143.14353 ++	b = kgem->batch + kgem->nbatch;
143.14354 ++	kgem->nbatch += 7;
143.14355 ++
143.14356 ++	*b++ = MI_FLUSH_DW;
143.14357 ++	*b++ = 0;
143.14358 ++	*b++ = 0;
143.14359 ++	*b++ = 0;
143.14360 ++
143.14361 ++	*b++ = MI_LOAD_REGISTER_IMM;
143.14362 ++	*b++ = BCS_SWCTRL;
143.14363 ++	*b++ = (BCS_SRC_Y | BCS_DST_Y) << 16;
143.14364 ++
143.14365 ++	kgem->bcs_state = 0;
143.14366 ++}
143.14367 ++
143.14368 + static uint32_t kgem_end_batch(struct kgem *kgem)
143.14369 + {
143.14370 ++	kgem_clear_swctrl(kgem);
143.14371 + 	kgem->batch[kgem->nbatch++] = MI_BATCH_BUFFER_END;
143.14372 + 	if (kgem->nbatch & 1)
143.14373 + 		kgem->batch[kgem->nbatch++] = MI_NOOP;
143.14374 +@@ -2064,17 +2533,6 @@ static void kgem_bo_binding_free(struct kgem *kgem, struct kgem_bo *bo)
143.14375 + 	}
143.14376 + }
143.14377 + 
143.14378 +-static void kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo)
143.14379 +-{
143.14380 +-	if (bo->scanout && bo->delta) {
143.14381 +-		DBG(("%s: releasing fb=%d for handle=%d\n",
143.14382 +-		     __FUNCTION__, bo->delta, bo->handle));
143.14383 +-		/* XXX will leak if we are not DRM_MASTER. *shrug* */
143.14384 +-		do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta);
143.14385 +-		bo->delta = 0;
143.14386 +-	}
143.14387 +-}
143.14388 +-
143.14389 + static void kgem_bo_free(struct kgem *kgem, struct kgem_bo *bo)
143.14390 + {
143.14391 + 	DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo)));
143.14392 +@@ -2150,13 +2608,16 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
143.14393 + 	assert(!bo->snoop);
143.14394 + 	assert(!bo->flush);
143.14395 + 	assert(!bo->needs_flush);
143.14396 ++	assert(!bo->delta);
143.14397 + 	assert(list_is_empty(&bo->vma));
143.14398 + 	assert_tiling(kgem, bo);
143.14399 +-	assert_cacheing(kgem, bo);
143.14400 ++	assert_caching(kgem, bo);
143.14401 + 	ASSERT_IDLE(kgem, bo->handle);
143.14402 + 
143.14403 + 	if (bucket(bo) >= NUM_CACHE_BUCKETS) {
143.14404 + 		if (bo->map__gtt) {
143.14405 ++			DBG(("%s: relinquishing large GTT mapping for handle=%d\n",
143.14406 ++			     __FUNCTION__, bo->handle));
143.14407 + 			munmap(bo->map__gtt, bytes(bo));
143.14408 + 			bo->map__gtt = NULL;
143.14409 + 		}
143.14410 +@@ -2167,6 +2628,8 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
143.14411 + 		assert(list_is_empty(&bo->vma));
143.14412 + 		list_move(&bo->list, &kgem->inactive[bucket(bo)]);
143.14413 + 		if (bo->map__gtt && !kgem_bo_can_map(kgem, bo)) {
143.14414 ++			DBG(("%s: relinquishing old GTT mapping for handle=%d\n",
143.14415 ++			     __FUNCTION__, bo->handle));
143.14416 + 			munmap(bo->map__gtt, bytes(bo));
143.14417 + 			bo->map__gtt = NULL;
143.14418 + 		}
143.14419 +@@ -2191,6 +2654,10 @@ static struct kgem_bo *kgem_bo_replace_io(struct kgem_bo *bo)
143.14420 + 		return bo;
143.14421 + 
143.14422 + 	assert(!bo->snoop);
143.14423 ++	assert(!bo->purged);
143.14424 ++	assert(!bo->scanout);
143.14425 ++	assert(!bo->delta);
143.14426 ++
143.14427 + 	if (__kgem_freed_bo) {
143.14428 + 		base = __kgem_freed_bo;
143.14429 + 		__kgem_freed_bo = *(struct kgem_bo **)base;
143.14430 +@@ -2221,6 +2688,7 @@ inline static void kgem_bo_remove_from_inactive(struct kgem *kgem,
143.14431 + 	list_del(&bo->list);
143.14432 + 	assert(bo->rq == NULL);
143.14433 + 	assert(bo->exec == NULL);
143.14434 ++	assert(!bo->purged);
143.14435 + 	if (!list_is_empty(&bo->vma)) {
143.14436 + 		assert(bo->map__gtt || bo->map__wc || bo->map__cpu);
143.14437 + 		list_del(&bo->vma);
143.14438 +@@ -2305,7 +2773,6 @@ static void kgem_bo_move_to_scanout(struct kgem *kgem, struct kgem_bo *bo)
143.14439 + 		list_move(&bo->list, &kgem->scanout);
143.14440 + 
143.14441 + 	kgem->need_expire = true;
143.14442 +-
143.14443 + }
143.14444 + 
143.14445 + static void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo)
143.14446 +@@ -2316,6 +2783,8 @@ static void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo)
143.14447 + 	assert(!bo->needs_flush);
143.14448 + 	assert(bo->refcnt == 0);
143.14449 + 	assert(bo->exec == NULL);
143.14450 ++	assert(!bo->purged);
143.14451 ++	assert(!bo->delta);
143.14452 + 
143.14453 + 	if (DBG_NO_SNOOP_CACHE) {
143.14454 + 		kgem_bo_free(kgem, bo);
143.14455 +@@ -2351,8 +2820,7 @@ static bool kgem_bo_move_to_cache(struct kgem *kgem, struct kgem_bo *bo)
143.14456 + 		kgem_bo_move_to_snoop(kgem, bo);
143.14457 + 	} else if (bo->scanout) {
143.14458 + 		kgem_bo_move_to_scanout(kgem, bo);
143.14459 +-	} else if ((bo = kgem_bo_replace_io(bo))->reusable &&
143.14460 +-		   kgem_bo_set_purgeable(kgem, bo)) {
143.14461 ++	} else if ((bo = kgem_bo_replace_io(bo))->reusable) {
143.14462 + 		kgem_bo_move_to_inactive(kgem, bo);
143.14463 + 		retired = true;
143.14464 + 	} else
143.14465 +@@ -2429,7 +2897,7 @@ void kgem_bo_undo(struct kgem *kgem, struct kgem_bo *bo)
143.14466 + 	DBG(("%s: only handle in batch, discarding last operations for handle=%d\n",
143.14467 + 	     __FUNCTION__, bo->handle));
143.14468 + 
143.14469 +-	assert(bo->exec == &kgem->exec[0]);
143.14470 ++	assert(bo->exec == &_kgem_dummy_exec || bo->exec == &kgem->exec[0]);
143.14471 + 	assert(kgem->exec[0].handle == bo->handle);
143.14472 + 	assert(RQ(bo->rq) == kgem->next_request);
143.14473 + 
143.14474 +@@ -2457,16 +2925,23 @@ void kgem_bo_pair_undo(struct kgem *kgem, struct kgem_bo *a, struct kgem_bo *b)
143.14475 + 
143.14476 + 	if (a == NULL || b == NULL)
143.14477 + 		return;
143.14478 ++	assert(a != b);
143.14479 + 	if (a->exec == NULL || b->exec == NULL)
143.14480 + 		return;
143.14481 + 
143.14482 +-	DBG(("%s: only handles in batch, discarding last operations for handle=%d and handle=%d\n",
143.14483 +-	     __FUNCTION__, a->handle, b->handle));
143.14484 ++	DBG(("%s: only handles in batch, discarding last operations for handle=%d (index=%d) and handle=%d (index=%d)\n",
143.14485 ++	     __FUNCTION__,
143.14486 ++	     a->handle, a->proxy ? -1 : a->exec - kgem->exec,
143.14487 ++	     b->handle, b->proxy ? -1 : b->exec - kgem->exec));
143.14488 + 
143.14489 +-	assert(a->exec == &kgem->exec[0] || a->exec == &kgem->exec[1]);
143.14490 ++	assert(a->exec == &_kgem_dummy_exec ||
143.14491 ++	       a->exec == &kgem->exec[0] ||
143.14492 ++	       a->exec == &kgem->exec[1]);
143.14493 + 	assert(a->handle == kgem->exec[0].handle || a->handle == kgem->exec[1].handle);
143.14494 + 	assert(RQ(a->rq) == kgem->next_request);
143.14495 +-	assert(b->exec == &kgem->exec[0] || b->exec == &kgem->exec[1]);
143.14496 ++	assert(b->exec == &_kgem_dummy_exec ||
143.14497 ++	       b->exec == &kgem->exec[0] ||
143.14498 ++	       b->exec == &kgem->exec[1]);
143.14499 + 	assert(b->handle == kgem->exec[0].handle || b->handle == kgem->exec[1].handle);
143.14500 + 	assert(RQ(b->rq) == kgem->next_request);
143.14501 + 
143.14502 +@@ -2487,6 +2962,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
143.14503 + 	DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo)));
143.14504 + 
143.14505 + 	assert(list_is_empty(&bo->list));
143.14506 ++	assert(list_is_empty(&bo->vma));
143.14507 + 	assert(bo->refcnt == 0);
143.14508 + 	assert(bo->proxy == NULL);
143.14509 + 	assert(bo->active_scanout == 0);
143.14510 +@@ -2532,7 +3008,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
143.14511 + 	assert(bo->snoop == false);
143.14512 + 	assert(bo->io == false);
143.14513 + 	assert(bo->scanout == false);
143.14514 +-	assert_cacheing(kgem, bo);
143.14515 ++	assert_caching(kgem, bo);
143.14516 + 
143.14517 + 	kgem_bo_undo(kgem, bo);
143.14518 + 	assert(bo->refcnt == 0);
143.14519 +@@ -2556,9 +3032,6 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
143.14520 + 	assert(list_is_empty(&bo->request));
143.14521 + 
143.14522 + 	if (bo->map__cpu == NULL || bucket(bo) >= NUM_CACHE_BUCKETS) {
143.14523 +-		if (!kgem_bo_set_purgeable(kgem, bo))
143.14524 +-			goto destroy;
143.14525 +-
143.14526 + 		if (!kgem->has_llc && bo->domain == DOMAIN_CPU)
143.14527 + 			goto destroy;
143.14528 + 
143.14529 +@@ -2647,7 +3120,7 @@ static bool kgem_retire__flushing(struct kgem *kgem)
143.14530 + 		int count = 0;
143.14531 + 		list_for_each_entry(bo, &kgem->flushing, request)
143.14532 + 			count++;
143.14533 +-		DBG(("%s: %d bo on flushing list\n", __FUNCTION__, count));
143.14534 ++		DBG(("%s: %d bo on flushing list, retired? %d\n", __FUNCTION__, count, retired));
143.14535 + 	}
143.14536 + #endif
143.14537 + 
143.14538 +@@ -2656,6 +3129,34 @@ static bool kgem_retire__flushing(struct kgem *kgem)
143.14539 + 	return retired;
143.14540 + }
143.14541 + 
143.14542 ++static bool __kgem_bo_flush(struct kgem *kgem, struct kgem_bo *bo)
143.14543 ++{
143.14544 ++	struct drm_i915_gem_busy busy;
143.14545 ++
143.14546 ++	if (!bo->needs_flush)
143.14547 ++		return false;
143.14548 ++
143.14549 ++	bo->needs_flush = false;
143.14550 ++
143.14551 ++	VG_CLEAR(busy);
143.14552 ++	busy.handle = bo->handle;
143.14553 ++	busy.busy = !kgem->wedged;
143.14554 ++	(void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
143.14555 ++	DBG(("%s: handle=%d, busy=%d, wedged=%d\n",
143.14556 ++	     __FUNCTION__, bo->handle, busy.busy, kgem->wedged));
143.14557 ++
143.14558 ++	if (busy.busy == 0)
143.14559 ++		return false;
143.14560 ++
143.14561 ++	DBG(("%s: moving %d to flushing\n",
143.14562 ++	     __FUNCTION__, bo->handle));
143.14563 ++	list_add(&bo->request, &kgem->flushing);
143.14564 ++	bo->rq = MAKE_REQUEST(kgem, !!(busy.busy & ~0x1ffff));
143.14565 ++	bo->needs_flush = busy.busy & 0xffff;
143.14566 ++	kgem->need_retire = true;
143.14567 ++	return true;
143.14568 ++}
143.14569 ++
143.14570 + static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
143.14571 + {
143.14572 + 	bool retired = false;
143.14573 +@@ -2663,6 +3164,8 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
143.14574 + 	DBG(("%s: request %d complete\n",
143.14575 + 	     __FUNCTION__, rq->bo->handle));
143.14576 + 	assert(RQ(rq->bo->rq) == rq);
143.14577 ++	assert(rq != (struct kgem_request *)kgem);
143.14578 ++	assert(rq != &kgem->static_request);
143.14579 + 
143.14580 + 	if (rq == kgem->fence[rq->ring])
143.14581 + 		kgem->fence[rq->ring] = NULL;
143.14582 +@@ -2680,19 +3183,14 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
143.14583 + 
143.14584 + 		list_del(&bo->request);
143.14585 + 
143.14586 +-		if (bo->needs_flush)
143.14587 +-			bo->needs_flush = __kgem_busy(kgem, bo->handle);
143.14588 +-		if (bo->needs_flush) {
143.14589 +-			DBG(("%s: moving %d to flushing\n",
143.14590 ++		if (unlikely(__kgem_bo_flush(kgem, bo))) {
143.14591 ++			assert(bo != rq->bo);
143.14592 ++			DBG(("%s: movied %d to flushing\n",
143.14593 + 			     __FUNCTION__, bo->handle));
143.14594 +-			list_add(&bo->request, &kgem->flushing);
143.14595 +-			bo->rq = MAKE_REQUEST(kgem, RQ_RING(bo->rq));
143.14596 +-			kgem->need_retire = true;
143.14597 + 			continue;
143.14598 + 		}
143.14599 + 
143.14600 + 		bo->domain = DOMAIN_NONE;
143.14601 +-		bo->gtt_dirty = false;
143.14602 + 		bo->rq = NULL;
143.14603 + 		if (bo->refcnt)
143.14604 + 			continue;
143.14605 +@@ -2706,14 +3204,8 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
143.14606 + 	assert(rq->bo->refcnt > 0);
143.14607 + 
143.14608 + 	if (--rq->bo->refcnt == 0) {
143.14609 +-		if (kgem_bo_set_purgeable(kgem, rq->bo)) {
143.14610 +-			kgem_bo_move_to_inactive(kgem, rq->bo);
143.14611 +-			retired = true;
143.14612 +-		} else {
143.14613 +-			DBG(("%s: closing %d\n",
143.14614 +-			     __FUNCTION__, rq->bo->handle));
143.14615 +-			kgem_bo_free(kgem, rq->bo);
143.14616 +-		}
143.14617 ++		kgem_bo_move_to_inactive(kgem, rq->bo);
143.14618 ++		retired = true;
143.14619 + 	}
143.14620 + 
143.14621 + 	__kgem_request_free(rq);
143.14622 +@@ -2724,13 +3216,18 @@ static bool kgem_retire__requests_ring(struct kgem *kgem, int ring)
143.14623 + {
143.14624 + 	bool retired = false;
143.14625 + 
143.14626 ++	assert(ring < ARRAY_SIZE(kgem->requests));
143.14627 + 	while (!list_is_empty(&kgem->requests[ring])) {
143.14628 + 		struct kgem_request *rq;
143.14629 + 
143.14630 ++		DBG(("%s: retiring ring %d\n", __FUNCTION__, ring));
143.14631 ++
143.14632 + 		rq = list_first_entry(&kgem->requests[ring],
143.14633 + 				      struct kgem_request,
143.14634 + 				      list);
143.14635 + 		assert(rq->ring == ring);
143.14636 ++		assert(rq->bo);
143.14637 ++		assert(RQ(rq->bo->rq) == rq);
143.14638 + 		if (__kgem_busy(kgem, rq->bo->handle))
143.14639 + 			break;
143.14640 + 
143.14641 +@@ -2751,8 +3248,8 @@ static bool kgem_retire__requests_ring(struct kgem *kgem, int ring)
143.14642 + 					      struct kgem_request,
143.14643 + 					      list)->bo;
143.14644 + 
143.14645 +-		DBG(("%s: ring=%d, %d outstanding requests, oldest=%d\n",
143.14646 +-		     __FUNCTION__, ring, count, bo ? bo->handle : 0));
143.14647 ++		DBG(("%s: ring=%d, %d outstanding requests, oldest=%d, retired? %d\n",
143.14648 ++		     __FUNCTION__, ring, count, bo ? bo->handle : 0, retired));
143.14649 + 	}
143.14650 + #endif
143.14651 + 
143.14652 +@@ -2824,6 +3321,8 @@ bool __kgem_ring_is_idle(struct kgem *kgem, int ring)
143.14653 + 	rq = list_last_entry(&kgem->requests[ring],
143.14654 + 			     struct kgem_request, list);
143.14655 + 	assert(rq->ring == ring);
143.14656 ++	assert(rq->bo);
143.14657 ++	assert(RQ(rq->bo->rq) == rq);
143.14658 + 	if (__kgem_busy(kgem, rq->bo->handle)) {
143.14659 + 		DBG(("%s: last requests handle=%d still busy\n",
143.14660 + 		     __FUNCTION__, rq->bo->handle));
143.14661 +@@ -2845,23 +3344,30 @@ bool __kgem_ring_is_idle(struct kgem *kgem, int ring)
143.14662 + 	return true;
143.14663 + }
143.14664 + 
143.14665 +-void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo)
143.14666 ++bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo)
143.14667 + {
143.14668 +-	struct kgem_request *rq = bo->rq, *tmp;
143.14669 +-	struct list *requests = &kgem->requests[RQ_RING(rq) == I915_EXEC_BLT];
143.14670 ++	struct kgem_request * const rq = RQ(bo->rq), *tmp;
143.14671 ++	struct list *requests = &kgem->requests[rq->ring];
143.14672 ++
143.14673 ++	DBG(("%s(handle=%d, ring=%d)\n", __FUNCTION__, bo->handle, rq->ring));
143.14674 + 
143.14675 +-	rq = RQ(rq);
143.14676 + 	assert(rq != &kgem->static_request);
143.14677 + 	if (rq == (struct kgem_request *)kgem) {
143.14678 + 		__kgem_bo_clear_busy(bo);
143.14679 +-		return;
143.14680 ++		return false;
143.14681 + 	}
143.14682 + 
143.14683 ++	assert(rq->ring < ARRAY_SIZE(kgem->requests));
143.14684 + 	do {
143.14685 + 		tmp = list_first_entry(requests, struct kgem_request, list);
143.14686 + 		assert(tmp->ring == rq->ring);
143.14687 + 		__kgem_retire_rq(kgem, tmp);
143.14688 + 	} while (tmp != rq);
143.14689 ++
143.14690 ++	assert(bo->needs_flush || bo->rq == NULL);
143.14691 ++	assert(bo->needs_flush || list_is_empty(&bo->request));
143.14692 ++	assert(bo->needs_flush || bo->domain == DOMAIN_NONE);
143.14693 ++	return bo->rq;
143.14694 + }
143.14695 + 
143.14696 + #if 0
143.14697 +@@ -2932,6 +3438,7 @@ static void kgem_commit(struct kgem *kgem)
143.14698 + 		bo->binding.offset = 0;
143.14699 + 		bo->domain = DOMAIN_GPU;
143.14700 + 		bo->gpu_dirty = false;
143.14701 ++		bo->gtt_dirty = false;
143.14702 + 
143.14703 + 		if (bo->proxy) {
143.14704 + 			/* proxies are not used for domain tracking */
143.14705 +@@ -2955,6 +3462,23 @@ static void kgem_commit(struct kgem *kgem)
143.14706 + 			kgem_throttle(kgem);
143.14707 + 		}
143.14708 + 
143.14709 ++		while (!list_is_empty(&rq->buffers)) {
143.14710 ++			bo = list_first_entry(&rq->buffers,
143.14711 ++					      struct kgem_bo,
143.14712 ++					      request);
143.14713 ++
143.14714 ++			assert(RQ(bo->rq) == rq);
143.14715 ++			assert(bo->exec == NULL);
143.14716 ++			assert(bo->domain == DOMAIN_GPU);
143.14717 ++
143.14718 ++			list_del(&bo->request);
143.14719 ++			bo->domain = DOMAIN_NONE;
143.14720 ++			bo->rq = NULL;
143.14721 ++
143.14722 ++			if (bo->refcnt == 0)
143.14723 ++				_kgem_bo_destroy(kgem, bo);
143.14724 ++		}
143.14725 ++
143.14726 + 		kgem_retire(kgem);
143.14727 + 		assert(list_is_empty(&rq->buffers));
143.14728 + 
143.14729 +@@ -2964,7 +3488,9 @@ static void kgem_commit(struct kgem *kgem)
143.14730 + 		gem_close(kgem->fd, rq->bo->handle);
143.14731 + 		kgem_cleanup_cache(kgem);
143.14732 + 	} else {
143.14733 ++		assert(rq != (struct kgem_request *)kgem);
143.14734 + 		assert(rq->ring < ARRAY_SIZE(kgem->requests));
143.14735 ++		assert(rq->bo);
143.14736 + 		list_add_tail(&rq->list, &kgem->requests[rq->ring]);
143.14737 + 		kgem->need_throttle = kgem->need_retire = 1;
143.14738 + 
143.14739 +@@ -2988,8 +3514,10 @@ static void kgem_close_inactive(struct kgem *kgem)
143.14740 + {
143.14741 + 	unsigned int i;
143.14742 + 
143.14743 +-	for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++)
143.14744 ++	for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) {
143.14745 + 		kgem_close_list(kgem, &kgem->inactive[i]);
143.14746 ++		assert(list_is_empty(&kgem->inactive[i]));
143.14747 ++	}
143.14748 + }
143.14749 + 
143.14750 + static void kgem_finish_buffers(struct kgem *kgem)
143.14751 +@@ -3079,10 +3607,13 @@ static void kgem_finish_buffers(struct kgem *kgem)
143.14752 + 						kgem->has_handle_lut ? bo->base.target_handle : shrink->handle;
143.14753 + 					for (n = 0; n < kgem->nreloc; n++) {
143.14754 + 						if (kgem->reloc[n].target_handle == bo->base.target_handle) {
143.14755 ++							uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset;
143.14756 ++							kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr;
143.14757 ++							if (kgem->gen >= 0100)
143.14758 ++								kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32;
143.14759 ++
143.14760 + 							kgem->reloc[n].target_handle = shrink->target_handle;
143.14761 + 							kgem->reloc[n].presumed_offset = shrink->presumed_offset;
143.14762 +-							kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] =
143.14763 +-								kgem->reloc[n].delta + shrink->presumed_offset;
143.14764 + 						}
143.14765 + 					}
143.14766 + 
143.14767 +@@ -3124,10 +3655,13 @@ static void kgem_finish_buffers(struct kgem *kgem)
143.14768 + 						kgem->has_handle_lut ? bo->base.target_handle : shrink->handle;
143.14769 + 					for (n = 0; n < kgem->nreloc; n++) {
143.14770 + 						if (kgem->reloc[n].target_handle == bo->base.target_handle) {
143.14771 ++							uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset;
143.14772 ++							kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr;
143.14773 ++							if (kgem->gen >= 0100)
143.14774 ++								kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32;
143.14775 ++
143.14776 + 							kgem->reloc[n].target_handle = shrink->target_handle;
143.14777 + 							kgem->reloc[n].presumed_offset = shrink->presumed_offset;
143.14778 +-							kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] =
143.14779 +-								kgem->reloc[n].delta + shrink->presumed_offset;
143.14780 + 						}
143.14781 + 					}
143.14782 + 
143.14783 +@@ -3195,6 +3729,9 @@ static void kgem_cleanup(struct kgem *kgem)
143.14784 + 					kgem_bo_free(kgem, bo);
143.14785 + 			}
143.14786 + 
143.14787 ++			if (--rq->bo->refcnt == 0)
143.14788 ++				kgem_bo_free(kgem, rq->bo);
143.14789 ++
143.14790 + 			__kgem_request_free(rq);
143.14791 + 		}
143.14792 + 	}
143.14793 +@@ -3210,7 +3747,9 @@ kgem_batch_write(struct kgem *kgem,
143.14794 + 	char *ptr;
143.14795 + 	int ret;
143.14796 + 
143.14797 +-	ASSERT_IDLE(kgem, bo->handle);
143.14798 ++	assert(bo->exec == NULL);
143.14799 ++	assert(bo->rq == NULL);
143.14800 ++	assert(!__kgem_busy(kgem, bo->handle));
143.14801 + 
143.14802 + #if DBG_NO_EXEC
143.14803 + 	{
143.14804 +@@ -3371,55 +3910,54 @@ static int compact_batch_surface(struct kgem *kgem, int *shrink)
143.14805 + 	return size * sizeof(uint32_t);
143.14806 + }
143.14807 + 
143.14808 ++static struct kgem_bo *first_available(struct kgem *kgem, struct list *list)
143.14809 ++{
143.14810 ++	struct kgem_bo *bo;
143.14811 ++
143.14812 ++	list_for_each_entry(bo, list, list) {
143.14813 ++		assert(bo->refcnt > 0);
143.14814 ++
143.14815 ++		if (bo->rq) {
143.14816 ++			assert(RQ(bo->rq)->bo == bo);
143.14817 ++			if (__kgem_busy(kgem, bo->handle))
143.14818 ++				break;
143.14819 ++
143.14820 ++			__kgem_retire_rq(kgem, RQ(bo->rq));
143.14821 ++			assert(bo->rq == NULL);
143.14822 ++		}
143.14823 ++
143.14824 ++		if (bo->refcnt > 1)
143.14825 ++			continue;
143.14826 ++
143.14827 ++		list_move_tail(&bo->list, list);
143.14828 ++		return kgem_bo_reference(bo);
143.14829 ++	}
143.14830 ++
143.14831 ++	return NULL;
143.14832 ++}
143.14833 ++
143.14834 + static struct kgem_bo *
143.14835 + kgem_create_batch(struct kgem *kgem)
143.14836 + {
143.14837 +-#if !DBG_NO_SHRINK_BATCHES
143.14838 +-	struct drm_i915_gem_set_domain set_domain;
143.14839 + 	struct kgem_bo *bo;
143.14840 +-	int shrink = 0;
143.14841 +-	int size;
143.14842 ++	int size, shrink = 0;
143.14843 + 
143.14844 ++#if !DBG_NO_SHRINK_BATCHES
143.14845 + 	if (kgem->surface != kgem->batch_size)
143.14846 + 		size = compact_batch_surface(kgem, &shrink);
143.14847 + 	else
143.14848 + 		size = kgem->nbatch * sizeof(uint32_t);
143.14849 + 
143.14850 + 	if (size <= 4096) {
143.14851 +-		bo = list_first_entry(&kgem->pinned_batches[0],
143.14852 +-				      struct kgem_bo,
143.14853 +-				      list);
143.14854 +-		if (!bo->rq) {
143.14855 +-out_4096:
143.14856 +-			assert(bo->refcnt > 0);
143.14857 +-			list_move_tail(&bo->list, &kgem->pinned_batches[0]);
143.14858 +-			bo = kgem_bo_reference(bo);
143.14859 ++		bo = first_available(kgem, &kgem->pinned_batches[0]);
143.14860 ++		if (bo)
143.14861 + 			goto write;
143.14862 +-		}
143.14863 +-
143.14864 +-		if (!__kgem_busy(kgem, bo->handle)) {
143.14865 +-			assert(RQ(bo->rq)->bo == bo);
143.14866 +-			__kgem_retire_rq(kgem, RQ(bo->rq));
143.14867 +-			goto out_4096;
143.14868 +-		}
143.14869 + 	}
143.14870 + 
143.14871 +-	if (size <= 16384) {
143.14872 +-		bo = list_first_entry(&kgem->pinned_batches[1],
143.14873 +-				      struct kgem_bo,
143.14874 +-				      list);
143.14875 +-		if (!bo->rq) {
143.14876 +-out_16384:
143.14877 +-			assert(bo->refcnt > 0);
143.14878 +-			list_move_tail(&bo->list, &kgem->pinned_batches[1]);
143.14879 +-			bo = kgem_bo_reference(bo);
143.14880 +-			goto write;
143.14881 +-		}
143.14882 +-
143.14883 +-		if (!__kgem_busy(kgem, bo->handle)) {
143.14884 +-			__kgem_retire_rq(kgem, RQ(bo->rq));
143.14885 +-			goto out_16384;
143.14886 +-		}
143.14887 ++	if (size <= 16384) {
143.14888 ++		bo = first_available(kgem, &kgem->pinned_batches[1]);
143.14889 ++		if (bo)
143.14890 ++			goto write;
143.14891 + 	}
143.14892 + 
143.14893 + 	if (kgem->gen == 020) {
143.14894 +@@ -3443,16 +3981,8 @@ out_16384:
143.14895 + 			list_move_tail(&bo->list, &kgem->pinned_batches[size > 4096]);
143.14896 + 
143.14897 + 			DBG(("%s: syncing due to busy batches\n", __FUNCTION__));
143.14898 +-
143.14899 +-			VG_CLEAR(set_domain);
143.14900 +-			set_domain.handle = bo->handle;
143.14901 +-			set_domain.read_domains = I915_GEM_DOMAIN_GTT;
143.14902 +-			set_domain.write_domain = I915_GEM_DOMAIN_GTT;
143.14903 +-			if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
143.14904 +-				DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
143.14905 +-				kgem_throttle(kgem);
143.14906 ++			if (kgem_bo_wait(kgem, bo))
143.14907 + 				return NULL;
143.14908 +-			}
143.14909 + 
143.14910 + 			kgem_retire(kgem);
143.14911 + 			assert(bo->rq == NULL);
143.14912 +@@ -3460,9 +3990,14 @@ out_16384:
143.14913 + 			goto write;
143.14914 + 		}
143.14915 + 	}
143.14916 ++#else
143.14917 ++	if (kgem->surface != kgem->batch_size)
143.14918 ++		size = kgem->batch_size * sizeof(uint32_t);
143.14919 ++	else
143.14920 ++		size = kgem->nbatch * sizeof(uint32_t);
143.14921 ++#endif
143.14922 + 
143.14923 +-	bo = NULL;
143.14924 +-	if (!kgem->has_llc) {
143.14925 ++	if (!kgem->batch_bo || !kgem->has_llc) {
143.14926 + 		bo = kgem_create_linear(kgem, size, CREATE_NO_THROTTLE);
143.14927 + 		if (bo) {
143.14928 + write:
143.14929 +@@ -3471,14 +4006,11 @@ write:
143.14930 + 				kgem_bo_destroy(kgem, bo);
143.14931 + 				return NULL;
143.14932 + 			}
143.14933 ++			return bo;
143.14934 + 		}
143.14935 + 	}
143.14936 +-	if (bo == NULL)
143.14937 +-		bo = kgem_new_batch(kgem);
143.14938 +-	return bo;
143.14939 +-#else
143.14940 ++
143.14941 + 	return kgem_new_batch(kgem);
143.14942 +-#endif
143.14943 + }
143.14944 + 
143.14945 + #if !NDEBUG
143.14946 +@@ -3530,7 +4062,7 @@ static void dump_fence_regs(struct kgem *kgem)
143.14947 + 
143.14948 + static int do_execbuf(struct kgem *kgem, struct drm_i915_gem_execbuffer2 *execbuf)
143.14949 + {
143.14950 +-	int ret, err;
143.14951 ++	int ret;
143.14952 + 
143.14953 + retry:
143.14954 + 	ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
143.14955 +@@ -3547,26 +4079,25 @@ retry:
143.14956 + 
143.14957 + 	/* last gasp */
143.14958 + 	ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
143.14959 +-	if (ret == 0)
143.14960 +-		return 0;
143.14961 ++	if (ret != -ENOSPC)
143.14962 ++		return ret;
143.14963 ++
143.14964 ++	/* One final trick up our sleeve for when we run out of space.
143.14965 ++	 * We turn everything off to free up our pinned framebuffers,
143.14966 ++	 * sprites and cursors, and try just one more time.
143.14967 ++	 */
143.14968 + 
143.14969 + 	xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
143.14970 + 		   "Failed to submit rendering commands, trying again with outputs disabled.\n");
143.14971 + 
143.14972 +-	/* One last trick up our sleeve for when we run out of space.
143.14973 +-	 * We turn everything off to free up our pinned framebuffers,
143.14974 +-	 * sprites and cursors, and try one last time.
143.14975 +-	 */
143.14976 +-	err = errno;
143.14977 +-	if (sna_mode_disable(container_of(kgem, struct sna, kgem))) {
143.14978 ++	if (sna_mode_disable(__to_sna(kgem))) {
143.14979 + 		kgem_cleanup_cache(kgem);
143.14980 + 		ret = do_ioctl(kgem->fd,
143.14981 + 			       DRM_IOCTL_I915_GEM_EXECBUFFER2,
143.14982 + 			       execbuf);
143.14983 + 		DBG(("%s: last_gasp ret=%d\n", __FUNCTION__, ret));
143.14984 +-		sna_mode_enable(container_of(kgem, struct sna, kgem));
143.14985 ++		sna_mode_enable(__to_sna(kgem));
143.14986 + 	}
143.14987 +-	errno = err;
143.14988 + 
143.14989 + 	return ret;
143.14990 + }
143.14991 +@@ -3575,6 +4106,7 @@ void _kgem_submit(struct kgem *kgem)
143.14992 + {
143.14993 + 	struct kgem_request *rq;
143.14994 + 	uint32_t batch_end;
143.14995 ++	int i, ret;
143.14996 + 
143.14997 + 	assert(!DBG_NO_HW);
143.14998 + 	assert(!kgem->wedged);
143.14999 +@@ -3609,7 +4141,6 @@ void _kgem_submit(struct kgem *kgem)
143.15000 + 	rq->bo = kgem_create_batch(kgem);
143.15001 + 	if (rq->bo) {
143.15002 + 		struct drm_i915_gem_execbuffer2 execbuf;
143.15003 +-		int i, ret;
143.15004 + 
143.15005 + 		assert(!rq->bo->needs_flush);
143.15006 + 
143.15007 +@@ -3619,7 +4150,8 @@ void _kgem_submit(struct kgem *kgem)
143.15008 + 		kgem->exec[i].relocs_ptr = (uintptr_t)kgem->reloc;
143.15009 + 		kgem->exec[i].alignment = 0;
143.15010 + 		kgem->exec[i].offset = rq->bo->presumed_offset;
143.15011 +-		kgem->exec[i].flags = 0;
143.15012 ++		/* Make sure the kernel releases any fence, ignored if gen4+ */
143.15013 ++		kgem->exec[i].flags = EXEC_OBJECT_NEEDS_FENCE;
143.15014 + 		kgem->exec[i].rsvd1 = 0;
143.15015 + 		kgem->exec[i].rsvd2 = 0;
143.15016 + 
143.15017 +@@ -3631,7 +4163,8 @@ void _kgem_submit(struct kgem *kgem)
143.15018 + 		memset(&execbuf, 0, sizeof(execbuf));
143.15019 + 		execbuf.buffers_ptr = (uintptr_t)kgem->exec;
143.15020 + 		execbuf.buffer_count = kgem->nexec;
143.15021 +-		execbuf.batch_len = batch_end*sizeof(uint32_t);
143.15022 ++		if (kgem->gen < 030)
143.15023 ++			execbuf.batch_len = batch_end*sizeof(uint32_t);
143.15024 + 		execbuf.flags = kgem->ring | kgem->batch_flags;
143.15025 + 
143.15026 + 		if (DBG_DUMP) {
143.15027 +@@ -3645,91 +4178,98 @@ void _kgem_submit(struct kgem *kgem)
143.15028 + 		}
143.15029 + 
143.15030 + 		ret = do_execbuf(kgem, &execbuf);
143.15031 +-		if (DEBUG_SYNC && ret == 0) {
143.15032 +-			struct drm_i915_gem_set_domain set_domain;
143.15033 +-
143.15034 +-			VG_CLEAR(set_domain);
143.15035 +-			set_domain.handle = rq->bo->handle;
143.15036 +-			set_domain.read_domains = I915_GEM_DOMAIN_GTT;
143.15037 +-			set_domain.write_domain = I915_GEM_DOMAIN_GTT;
143.15038 ++	} else
143.15039 ++		ret = -ENOMEM;
143.15040 + 
143.15041 +-			ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
143.15042 ++	if (ret < 0) {
143.15043 ++		kgem_throttle(kgem);
143.15044 ++		if (!kgem->wedged) {
143.15045 ++			xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
143.15046 ++				   "Failed to submit rendering commands (%s), disabling acceleration.\n",
143.15047 ++				   strerror(-ret));
143.15048 ++			__kgem_set_wedged(kgem);
143.15049 + 		}
143.15050 +-		if (ret < 0) {
143.15051 +-			kgem_throttle(kgem);
143.15052 +-			if (!kgem->wedged) {
143.15053 +-				xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
143.15054 +-					   "Failed to submit rendering commands, disabling acceleration.\n");
143.15055 +-				__kgem_set_wedged(kgem);
143.15056 +-			}
143.15057 + 
143.15058 + #if !NDEBUG
143.15059 +-			ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n",
143.15060 +-			       kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface,
143.15061 +-			       kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret);
143.15062 ++		ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n",
143.15063 ++		       kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface,
143.15064 ++		       kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret);
143.15065 + 
143.15066 +-			for (i = 0; i < kgem->nexec; i++) {
143.15067 +-				struct kgem_bo *bo, *found = NULL;
143.15068 ++		for (i = 0; i < kgem->nexec; i++) {
143.15069 ++			struct kgem_bo *bo, *found = NULL;
143.15070 + 
143.15071 +-				list_for_each_entry(bo, &kgem->next_request->buffers, request) {
143.15072 +-					if (bo->handle == kgem->exec[i].handle) {
143.15073 +-						found = bo;
143.15074 +-						break;
143.15075 +-					}
143.15076 ++			list_for_each_entry(bo, &kgem->next_request->buffers, request) {
143.15077 ++				if (bo->handle == kgem->exec[i].handle) {
143.15078 ++					found = bo;
143.15079 ++					break;
143.15080 + 				}
143.15081 +-				ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n",
143.15082 +-				       i,
143.15083 +-				       kgem->exec[i].handle,
143.15084 +-				       (int)kgem->exec[i].offset,
143.15085 +-				       found ? kgem_bo_size(found) : -1,
143.15086 +-				       found ? found->tiling : -1,
143.15087 +-				       (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE),
143.15088 +-				       found ? found->snoop : -1,
143.15089 +-				       found ? found->purged : -1);
143.15090 + 			}
143.15091 +-			for (i = 0; i < kgem->nreloc; i++) {
143.15092 +-				ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n",
143.15093 +-				       i,
143.15094 +-				       (int)kgem->reloc[i].offset,
143.15095 +-				       kgem->reloc[i].target_handle,
143.15096 +-				       kgem->reloc[i].delta,
143.15097 +-				       kgem->reloc[i].read_domains,
143.15098 +-				       kgem->reloc[i].write_domain,
143.15099 +-				       (int)kgem->reloc[i].presumed_offset);
143.15100 ++			ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n",
143.15101 ++			       i,
143.15102 ++			       kgem->exec[i].handle,
143.15103 ++			       (int)kgem->exec[i].offset,
143.15104 ++			       found ? kgem_bo_size(found) : -1,
143.15105 ++			       found ? found->tiling : -1,
143.15106 ++			       (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE),
143.15107 ++			       found ? found->snoop : -1,
143.15108 ++			       found ? found->purged : -1);
143.15109 ++		}
143.15110 ++		for (i = 0; i < kgem->nreloc; i++) {
143.15111 ++			ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n",
143.15112 ++			       i,
143.15113 ++			       (int)kgem->reloc[i].offset,
143.15114 ++			       kgem->reloc[i].target_handle,
143.15115 ++			       kgem->reloc[i].delta,
143.15116 ++			       kgem->reloc[i].read_domains,
143.15117 ++			       kgem->reloc[i].write_domain,
143.15118 ++			       (int)kgem->reloc[i].presumed_offset);
143.15119 ++		}
143.15120 ++
143.15121 ++		{
143.15122 ++			struct drm_i915_gem_get_aperture aperture;
143.15123 ++			if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0)
143.15124 ++				ErrorF("Aperture size %lld, available %lld\n",
143.15125 ++				       (long long)aperture.aper_size,
143.15126 ++				       (long long)aperture.aper_available_size);
143.15127 ++		}
143.15128 ++
143.15129 ++		if (ret == -ENOSPC)
143.15130 ++			dump_gtt_info(kgem);
143.15131 ++		if (ret == -EDEADLK)
143.15132 ++			dump_fence_regs(kgem);
143.15133 ++
143.15134 ++		if (DEBUG_SYNC) {
143.15135 ++			int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666);
143.15136 ++			if (fd != -1) {
143.15137 ++				int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t));
143.15138 ++				assert(ignored == batch_end*sizeof(uint32_t));
143.15139 ++				close(fd);
143.15140 + 			}
143.15141 + 
143.15142 +-			{
143.15143 +-				struct drm_i915_gem_get_aperture aperture;
143.15144 +-				if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0)
143.15145 +-					ErrorF("Aperture size %lld, available %lld\n",
143.15146 +-					       (long long)aperture.aper_size,
143.15147 +-					       (long long)aperture.aper_available_size);
143.15148 +-			}
143.15149 ++			FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret);
143.15150 ++		}
143.15151 ++#endif
143.15152 ++	} else {
143.15153 ++		if (DEBUG_SYNC) {
143.15154 ++			struct drm_i915_gem_set_domain set_domain;
143.15155 + 
143.15156 +-			if (ret == -ENOSPC)
143.15157 +-				dump_gtt_info(kgem);
143.15158 +-			if (ret == -EDEADLK)
143.15159 +-				dump_fence_regs(kgem);
143.15160 +-
143.15161 +-			if (DEBUG_SYNC) {
143.15162 +-				int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666);
143.15163 +-				if (fd != -1) {
143.15164 +-					int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t));
143.15165 +-					assert(ignored == batch_end*sizeof(uint32_t));
143.15166 +-					close(fd);
143.15167 +-				}
143.15168 ++			VG_CLEAR(set_domain);
143.15169 ++			set_domain.handle = rq->bo->handle;
143.15170 ++			set_domain.read_domains = I915_GEM_DOMAIN_GTT;
143.15171 ++			set_domain.write_domain = I915_GEM_DOMAIN_GTT;
143.15172 + 
143.15173 +-				FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret);
143.15174 +-			}
143.15175 +-#endif
143.15176 ++			ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
143.15177 + 		}
143.15178 +-	}
143.15179 ++
143.15180 + #if SHOW_BATCH_AFTER
143.15181 +-	if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t)) == 0)
143.15182 +-		__kgem_batch_debug(kgem, batch_end);
143.15183 ++		if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t)) == 0)
143.15184 ++			__kgem_batch_debug(kgem, batch_end);
143.15185 + #endif
143.15186 +-	kgem_commit(kgem);
143.15187 +-	if (kgem->wedged)
143.15188 ++
143.15189 ++		kgem_commit(kgem);
143.15190 ++	}
143.15191 ++
143.15192 ++	if (unlikely(kgem->wedged))
143.15193 + 		kgem_cleanup(kgem);
143.15194 + 
143.15195 + 	kgem_reset(kgem);
143.15196 +@@ -3737,49 +4277,14 @@ void _kgem_submit(struct kgem *kgem)
143.15197 + 	assert(kgem->next_request != NULL);
143.15198 + }
143.15199 + 
143.15200 +-static bool find_hang_state(struct kgem *kgem, char *path, int maxlen)
143.15201 +-{
143.15202 +-	int minor = kgem_get_minor(kgem);
143.15203 +-
143.15204 +-	/* Search for our hang state in a few canonical locations.
143.15205 +-	 * In the unlikely event of having multiple devices, we
143.15206 +-	 * will need to check which minor actually corresponds to ours.
143.15207 +-	 */
143.15208 +-
143.15209 +-	snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor);
143.15210 +-	if (access(path, R_OK) == 0)
143.15211 +-		return true;
143.15212 +-
143.15213 +-	snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor);
143.15214 +-	if (access(path, R_OK) == 0)
143.15215 +-		return true;
143.15216 +-
143.15217 +-	snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor);
143.15218 +-	if (access(path, R_OK) == 0)
143.15219 +-		return true;
143.15220 +-
143.15221 +-	path[0] = '\0';
143.15222 +-	return false;
143.15223 +-}
143.15224 +-
143.15225 + void kgem_throttle(struct kgem *kgem)
143.15226 + {
143.15227 +-	if (kgem->wedged)
143.15228 ++	if (unlikely(kgem->wedged))
143.15229 + 		return;
143.15230 + 
143.15231 + 	if (__kgem_throttle(kgem, true)) {
143.15232 +-		static int once;
143.15233 +-		char path[128];
143.15234 +-
143.15235 + 		xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
143.15236 + 			   "Detected a hung GPU, disabling acceleration.\n");
143.15237 +-		if (!once && find_hang_state(kgem, path, sizeof(path))) {
143.15238 +-			xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
143.15239 +-				   "When reporting this, please include %s and the full dmesg.\n",
143.15240 +-				   path);
143.15241 +-			once = 1;
143.15242 +-		}
143.15243 +-
143.15244 + 		__kgem_set_wedged(kgem);
143.15245 + 		kgem->need_throttle = false;
143.15246 + 	}
143.15247 +@@ -3860,7 +4365,8 @@ bool kgem_expire_cache(struct kgem *kgem)
143.15248 + 	bool idle;
143.15249 + 	unsigned int i;
143.15250 + 
143.15251 +-	time(&now);
143.15252 ++	if (!time(&now))
143.15253 ++		return false;
143.15254 + 
143.15255 + 	while (__kgem_freed_bo) {
143.15256 + 		bo = __kgem_freed_bo;
143.15257 +@@ -3875,7 +4381,7 @@ bool kgem_expire_cache(struct kgem *kgem)
143.15258 + 	}
143.15259 + 
143.15260 + 	kgem_clean_large_cache(kgem);
143.15261 +-	if (container_of(kgem, struct sna, kgem)->scrn->vtSema)
143.15262 ++	if (__to_sna(kgem)->scrn->vtSema)
143.15263 + 		kgem_clean_scanout_cache(kgem);
143.15264 + 
143.15265 + 	expire = 0;
143.15266 +@@ -3885,6 +4391,7 @@ bool kgem_expire_cache(struct kgem *kgem)
143.15267 + 			break;
143.15268 + 		}
143.15269 + 
143.15270 ++		assert(now);
143.15271 + 		bo->delta = now;
143.15272 + 	}
143.15273 + 	if (expire) {
143.15274 +@@ -3909,7 +4416,7 @@ bool kgem_expire_cache(struct kgem *kgem)
143.15275 + #endif
143.15276 + 
143.15277 + 	kgem_retire(kgem);
143.15278 +-	if (kgem->wedged)
143.15279 ++	if (unlikely(kgem->wedged))
143.15280 + 		kgem_cleanup(kgem);
143.15281 + 
143.15282 + 	kgem->expire(kgem);
143.15283 +@@ -3930,6 +4437,8 @@ bool kgem_expire_cache(struct kgem *kgem)
143.15284 + 				break;
143.15285 + 			}
143.15286 + 
143.15287 ++			assert(now);
143.15288 ++			kgem_bo_set_purgeable(kgem, bo);
143.15289 + 			bo->delta = now;
143.15290 + 		}
143.15291 + 	}
143.15292 +@@ -3960,16 +4469,11 @@ bool kgem_expire_cache(struct kgem *kgem)
143.15293 + 				count++;
143.15294 + 				size += bytes(bo);
143.15295 + 				kgem_bo_free(kgem, bo);
143.15296 +-				DBG(("%s: expiring %d\n",
143.15297 ++				DBG(("%s: expiring handle=%d\n",
143.15298 + 				     __FUNCTION__, bo->handle));
143.15299 + 			}
143.15300 + 		}
143.15301 +-		if (!list_is_empty(&preserve)) {
143.15302 +-			preserve.prev->next = kgem->inactive[i].next;
143.15303 +-			kgem->inactive[i].next->prev = preserve.prev;
143.15304 +-			kgem->inactive[i].next = preserve.next;
143.15305 +-			preserve.next->prev = &kgem->inactive[i];
143.15306 +-		}
143.15307 ++		list_splice_tail(&preserve, &kgem->inactive[i]);
143.15308 + 	}
143.15309 + 
143.15310 + #ifdef DEBUG_MEMORY
143.15311 +@@ -3998,31 +4502,30 @@ bool kgem_cleanup_cache(struct kgem *kgem)
143.15312 + 	unsigned int i;
143.15313 + 	int n;
143.15314 + 
143.15315 ++	DBG(("%s\n", __FUNCTION__));
143.15316 ++
143.15317 + 	/* sync to the most recent request */
143.15318 + 	for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) {
143.15319 + 		if (!list_is_empty(&kgem->requests[n])) {
143.15320 + 			struct kgem_request *rq;
143.15321 +-			struct drm_i915_gem_set_domain set_domain;
143.15322 + 
143.15323 +-			rq = list_first_entry(&kgem->requests[n],
143.15324 +-					      struct kgem_request,
143.15325 +-					      list);
143.15326 ++			rq = list_last_entry(&kgem->requests[n],
143.15327 ++					     struct kgem_request,
143.15328 ++					     list);
143.15329 + 
143.15330 + 			DBG(("%s: sync on cleanup\n", __FUNCTION__));
143.15331 +-
143.15332 +-			VG_CLEAR(set_domain);
143.15333 +-			set_domain.handle = rq->bo->handle;
143.15334 +-			set_domain.read_domains = I915_GEM_DOMAIN_GTT;
143.15335 +-			set_domain.write_domain = I915_GEM_DOMAIN_GTT;
143.15336 +-			(void)do_ioctl(kgem->fd,
143.15337 +-				       DRM_IOCTL_I915_GEM_SET_DOMAIN,
143.15338 +-				       &set_domain);
143.15339 ++			assert(rq->ring == n);
143.15340 ++			assert(rq->bo);
143.15341 ++			assert(RQ(rq->bo->rq) == rq);
143.15342 ++			kgem_bo_wait(kgem, rq->bo);
143.15343 + 		}
143.15344 ++		assert(list_is_empty(&kgem->requests[n]));
143.15345 + 	}
143.15346 + 
143.15347 + 	kgem_retire(kgem);
143.15348 + 	kgem_cleanup(kgem);
143.15349 + 
143.15350 ++	DBG(("%s: need_expire?=%d\n", __FUNCTION__, kgem->need_expire));
143.15351 + 	if (!kgem->need_expire)
143.15352 + 		return false;
143.15353 + 
143.15354 +@@ -4049,6 +4552,8 @@ bool kgem_cleanup_cache(struct kgem *kgem)
143.15355 + 
143.15356 + 	kgem->need_purge = false;
143.15357 + 	kgem->need_expire = false;
143.15358 ++
143.15359 ++	DBG(("%s: complete\n", __FUNCTION__));
143.15360 + 	return true;
143.15361 + }
143.15362 + 
143.15363 +@@ -4079,16 +4584,15 @@ retry_large:
143.15364 + 				goto discard;
143.15365 + 
143.15366 + 			if (bo->tiling != I915_TILING_NONE) {
143.15367 +-				if (use_active)
143.15368 ++				if (use_active && kgem->gen < 040)
143.15369 + 					goto discard;
143.15370 + 
143.15371 +-				if (!gem_set_tiling(kgem->fd, bo->handle,
143.15372 ++				if (!kgem_set_tiling(kgem, bo,
143.15373 + 						    I915_TILING_NONE, 0))
143.15374 + 					goto discard;
143.15375 +-
143.15376 +-				bo->tiling = I915_TILING_NONE;
143.15377 +-				bo->pitch = 0;
143.15378 + 			}
143.15379 ++			assert(bo->tiling == I915_TILING_NONE);
143.15380 ++			bo->pitch = 0;
143.15381 + 
143.15382 + 			if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo))
143.15383 + 				goto discard;
143.15384 +@@ -4169,17 +4673,17 @@ discard:
143.15385 + 				break;
143.15386 + 			}
143.15387 + 
143.15388 +-			if (I915_TILING_NONE != bo->tiling &&
143.15389 +-			    !gem_set_tiling(kgem->fd, bo->handle,
143.15390 +-					    I915_TILING_NONE, 0))
143.15391 +-				continue;
143.15392 ++			if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) {
143.15393 ++				kgem_bo_free(kgem, bo);
143.15394 ++				break;
143.15395 ++			}
143.15396 + 
143.15397 + 			kgem_bo_remove_from_inactive(kgem, bo);
143.15398 + 			assert(list_is_empty(&bo->vma));
143.15399 + 			assert(list_is_empty(&bo->list));
143.15400 + 
143.15401 +-			bo->tiling = I915_TILING_NONE;
143.15402 +-			bo->pitch = 0;
143.15403 ++			assert(bo->tiling == I915_TILING_NONE);
143.15404 ++			assert(bo->pitch == 0);
143.15405 + 			bo->delta = 0;
143.15406 + 			DBG(("  %s: found handle=%d (num_pages=%d) in linear vma cache\n",
143.15407 + 			     __FUNCTION__, bo->handle, num_pages(bo)));
143.15408 +@@ -4225,13 +4729,13 @@ discard:
143.15409 + 			if (first)
143.15410 + 				continue;
143.15411 + 
143.15412 +-			if (!gem_set_tiling(kgem->fd, bo->handle,
143.15413 +-					    I915_TILING_NONE, 0))
143.15414 +-				continue;
143.15415 +-
143.15416 +-			bo->tiling = I915_TILING_NONE;
143.15417 +-			bo->pitch = 0;
143.15418 ++			if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) {
143.15419 ++				kgem_bo_free(kgem, bo);
143.15420 ++				break;
143.15421 ++			}
143.15422 + 		}
143.15423 ++		assert(bo->tiling == I915_TILING_NONE);
143.15424 ++		bo->pitch = 0;
143.15425 + 
143.15426 + 		if (bo->map__gtt || bo->map__wc || bo->map__cpu) {
143.15427 + 			if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) {
143.15428 +@@ -4269,7 +4773,7 @@ discard:
143.15429 + 			kgem_bo_remove_from_inactive(kgem, bo);
143.15430 + 
143.15431 + 		assert(bo->tiling == I915_TILING_NONE);
143.15432 +-		bo->pitch = 0;
143.15433 ++		assert(bo->pitch == 0);
143.15434 + 		bo->delta = 0;
143.15435 + 		DBG(("  %s: found handle=%d (num_pages=%d) in linear %s cache\n",
143.15436 + 		     __FUNCTION__, bo->handle, num_pages(bo),
143.15437 +@@ -4340,9 +4844,9 @@ struct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name)
143.15438 + 
143.15439 + 	bo->unique_id = kgem_get_unique_id(kgem);
143.15440 + 	bo->tiling = tiling.tiling_mode;
143.15441 +-	bo->reusable = false;
143.15442 + 	bo->prime = true;
143.15443 +-	bo->purged = true; /* no coherency guarantees */
143.15444 ++	bo->reusable = false;
143.15445 ++	kgem_bo_unclean(kgem, bo);
143.15446 + 
143.15447 + 	debug_alloc__bo(kgem, bo);
143.15448 + 	return bo;
143.15449 +@@ -4448,6 +4952,8 @@ int kgem_bo_export_to_prime(struct kgem *kgem, struct kgem_bo *bo)
143.15450 + #if defined(DRM_IOCTL_PRIME_HANDLE_TO_FD) && defined(O_CLOEXEC)
143.15451 + 	struct drm_prime_handle args;
143.15452 + 
143.15453 ++	assert(kgem_bo_is_fenced(kgem, bo));
143.15454 ++
143.15455 + 	VG_CLEAR(args);
143.15456 + 	args.handle = bo->handle;
143.15457 + 	args.flags = O_CLOEXEC;
143.15458 +@@ -4479,6 +4985,8 @@ struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags)
143.15459 + 	if ((flags & CREATE_UNCACHED) == 0) {
143.15460 + 		bo = search_linear_cache(kgem, size, CREATE_INACTIVE | flags);
143.15461 + 		if (bo) {
143.15462 ++			assert(!bo->purged);
143.15463 ++			assert(!bo->delta);
143.15464 + 			assert(bo->domain != DOMAIN_GPU);
143.15465 + 			ASSERT_IDLE(kgem, bo->handle);
143.15466 + 			bo->refcnt = 1;
143.15467 +@@ -4760,8 +5268,7 @@ static void __kgem_bo_make_scanout(struct kgem *kgem,
143.15468 + 				   struct kgem_bo *bo,
143.15469 + 				   int width, int height)
143.15470 + {
143.15471 +-	ScrnInfoPtr scrn =
143.15472 +-		container_of(kgem, struct sna, kgem)->scrn;
143.15473 ++	ScrnInfoPtr scrn = __to_sna(kgem)->scrn;
143.15474 + 	struct drm_mode_fb_cmd arg;
143.15475 + 
143.15476 + 	assert(bo->proxy == NULL);
143.15477 +@@ -4809,6 +5316,48 @@ static void __kgem_bo_make_scanout(struct kgem *kgem,
143.15478 + 	}
143.15479 + }
143.15480 + 
143.15481 ++static bool tiling_changed(struct kgem_bo *bo, int tiling, int pitch)
143.15482 ++{
143.15483 ++	if (tiling != bo->tiling)
143.15484 ++		return true;
143.15485 ++
143.15486 ++	return tiling != I915_TILING_NONE && pitch != bo->pitch;
143.15487 ++}
143.15488 ++
143.15489 ++static void set_gpu_tiling(struct kgem *kgem,
143.15490 ++			   struct kgem_bo *bo,
143.15491 ++			   int tiling, int pitch)
143.15492 ++{
143.15493 ++	DBG(("%s: handle=%d, tiling=%d, pitch=%d\n",
143.15494 ++	     __FUNCTION__, bo->handle, tiling, pitch));
143.15495 ++
143.15496 ++	if (tiling_changed(bo, tiling, pitch) && bo->map__gtt) {
143.15497 ++		if (!list_is_empty(&bo->vma)) {
143.15498 ++			list_del(&bo->vma);
143.15499 ++			kgem->vma[0].count--;
143.15500 ++		}
143.15501 ++		munmap(bo->map__gtt, bytes(bo));
143.15502 ++		bo->map__gtt = NULL;
143.15503 ++	}
143.15504 ++
143.15505 ++	bo->tiling = tiling;
143.15506 ++	bo->pitch = pitch;
143.15507 ++}
143.15508 ++
143.15509 ++bool kgem_bo_is_fenced(struct kgem *kgem, struct kgem_bo *bo)
143.15510 ++{
143.15511 ++	struct drm_i915_gem_get_tiling tiling;
143.15512 ++
143.15513 ++	assert(kgem);
143.15514 ++	assert(bo);
143.15515 ++
143.15516 ++	VG_CLEAR(tiling);
143.15517 ++	tiling.handle = bo->handle;
143.15518 ++	tiling.tiling_mode = bo->tiling;
143.15519 ++	(void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling);
143.15520 ++	return tiling.tiling_mode == bo->tiling; /* assume pitch is fine! */
143.15521 ++}
143.15522 ++
143.15523 + struct kgem_bo *kgem_create_2d(struct kgem *kgem,
143.15524 + 			       int width,
143.15525 + 			       int height,
143.15526 +@@ -4892,8 +5441,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
143.15527 + 			return last;
143.15528 + 		}
143.15529 + 
143.15530 +-		if (container_of(kgem, struct sna, kgem)->scrn->vtSema) {
143.15531 +-			ScrnInfoPtr scrn = container_of(kgem, struct sna, kgem)->scrn;
143.15532 ++		if (__to_sna(kgem)->scrn->vtSema) {
143.15533 ++			ScrnInfoPtr scrn = __to_sna(kgem)->scrn;
143.15534 + 
143.15535 + 			list_for_each_entry_reverse(bo, &kgem->scanout, list) {
143.15536 + 				struct drm_mode_fb_cmd arg;
143.15537 +@@ -4915,11 +5464,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
143.15538 + 						bo->delta = 0;
143.15539 + 					}
143.15540 + 
143.15541 +-					if (gem_set_tiling(kgem->fd, bo->handle,
143.15542 +-							   tiling, pitch)) {
143.15543 +-						bo->tiling = tiling;
143.15544 +-						bo->pitch = pitch;
143.15545 +-					} else {
143.15546 ++					if (!kgem_set_tiling(kgem, bo,
143.15547 ++							     tiling, pitch)) {
143.15548 + 						kgem_bo_free(kgem, bo);
143.15549 + 						break;
143.15550 + 					}
143.15551 +@@ -4950,6 +5496,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
143.15552 + 			}
143.15553 + 		}
143.15554 + 
143.15555 ++		if (flags & CREATE_CACHED)
143.15556 ++			return NULL;
143.15557 ++
143.15558 + 		bo = __kgem_bo_create_as_display(kgem, size, tiling, pitch);
143.15559 + 		if (bo)
143.15560 + 			return bo;
143.15561 +@@ -4987,14 +5536,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
143.15562 + 				if (num_pages(bo) < size)
143.15563 + 					continue;
143.15564 + 
143.15565 +-				if (bo->pitch != pitch || bo->tiling != tiling) {
143.15566 +-					if (!gem_set_tiling(kgem->fd, bo->handle,
143.15567 +-							    tiling, pitch))
143.15568 +-						continue;
143.15569 +-
143.15570 +-					bo->pitch = pitch;
143.15571 +-					bo->tiling = tiling;
143.15572 +-				}
143.15573 ++				if (!kgem_set_tiling(kgem, bo, tiling, pitch) &&
143.15574 ++				    !exact)
143.15575 ++					set_gpu_tiling(kgem, bo, tiling, pitch);
143.15576 + 			}
143.15577 + 
143.15578 + 			kgem_bo_remove_from_active(kgem, bo);
143.15579 +@@ -5020,14 +5564,11 @@ large_inactive:
143.15580 + 			if (size > num_pages(bo))
143.15581 + 				continue;
143.15582 + 
143.15583 +-			if (bo->tiling != tiling ||
143.15584 +-			    (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
143.15585 +-				if (!gem_set_tiling(kgem->fd, bo->handle,
143.15586 +-						    tiling, pitch))
143.15587 ++			if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
143.15588 ++				if (kgem->gen >= 040 && !exact)
143.15589 ++					set_gpu_tiling(kgem, bo, tiling, pitch);
143.15590 ++				else
143.15591 + 					continue;
143.15592 +-
143.15593 +-				bo->tiling = tiling;
143.15594 +-				bo->pitch = pitch;
143.15595 + 			}
143.15596 + 
143.15597 + 			if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
143.15598 +@@ -5039,7 +5580,6 @@ large_inactive:
143.15599 + 
143.15600 + 			assert(bo->domain != DOMAIN_GPU);
143.15601 + 			bo->unique_id = kgem_get_unique_id(kgem);
143.15602 +-			bo->pitch = pitch;
143.15603 + 			bo->delta = 0;
143.15604 + 			DBG(("  1:from large inactive: pitch=%d, tiling=%d, handle=%d, id=%d\n",
143.15605 + 			     bo->pitch, bo->tiling, bo->handle, bo->unique_id));
143.15606 +@@ -5088,14 +5628,13 @@ large_inactive:
143.15607 + 				if (bo->tiling != tiling ||
143.15608 + 				    (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
143.15609 + 					if (bo->map__gtt ||
143.15610 +-					    !gem_set_tiling(kgem->fd, bo->handle,
143.15611 +-							    tiling, pitch)) {
143.15612 ++					    !kgem_set_tiling(kgem, bo,
143.15613 ++							     tiling, pitch)) {
143.15614 + 						DBG(("inactive GTT vma with wrong tiling: %d < %d\n",
143.15615 + 						     bo->tiling, tiling));
143.15616 +-						continue;
143.15617 ++						kgem_bo_free(kgem, bo);
143.15618 ++						break;
143.15619 + 					}
143.15620 +-					bo->tiling = tiling;
143.15621 +-					bo->pitch = pitch;
143.15622 + 				}
143.15623 + 
143.15624 + 				if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
143.15625 +@@ -5103,8 +5642,11 @@ large_inactive:
143.15626 + 					break;
143.15627 + 				}
143.15628 + 
143.15629 ++				if (tiling == I915_TILING_NONE)
143.15630 ++					bo->pitch = pitch;
143.15631 ++
143.15632 + 				assert(bo->tiling == tiling);
143.15633 +-				bo->pitch = pitch;
143.15634 ++				assert(bo->pitch >= pitch);
143.15635 + 				bo->delta = 0;
143.15636 + 				bo->unique_id = kgem_get_unique_id(kgem);
143.15637 + 
143.15638 +@@ -5170,15 +5712,12 @@ search_active:
143.15639 + 				if (num_pages(bo) < size)
143.15640 + 					continue;
143.15641 + 
143.15642 +-				if (bo->pitch != pitch) {
143.15643 +-					if (!gem_set_tiling(kgem->fd,
143.15644 +-							    bo->handle,
143.15645 +-							    tiling, pitch))
143.15646 +-						continue;
143.15647 +-
143.15648 +-					bo->pitch = pitch;
143.15649 +-				}
143.15650 ++				if (!kgem_set_tiling(kgem, bo, tiling, pitch) &&
143.15651 ++				    !exact)
143.15652 ++					set_gpu_tiling(kgem, bo, tiling, pitch);
143.15653 + 			}
143.15654 ++			assert(bo->tiling == tiling);
143.15655 ++			assert(bo->pitch >= pitch);
143.15656 + 
143.15657 + 			kgem_bo_remove_from_active(kgem, bo);
143.15658 + 
143.15659 +@@ -5233,19 +5772,21 @@ search_active:
143.15660 + 				if (num_pages(bo) < size)
143.15661 + 					continue;
143.15662 + 
143.15663 +-				if (bo->tiling != tiling ||
143.15664 +-				    (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
143.15665 +-					if (!gem_set_tiling(kgem->fd,
143.15666 +-							    bo->handle,
143.15667 +-							    tiling, pitch))
143.15668 +-						continue;
143.15669 ++				if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
143.15670 ++					if (kgem->gen >= 040 && !exact) {
143.15671 ++						set_gpu_tiling(kgem, bo,
143.15672 ++							       tiling, pitch);
143.15673 ++					} else {
143.15674 ++						kgem_bo_free(kgem, bo);
143.15675 ++						break;
143.15676 ++					}
143.15677 + 				}
143.15678 ++				assert(bo->tiling == tiling);
143.15679 ++				assert(bo->pitch >= pitch);
143.15680 + 
143.15681 + 				kgem_bo_remove_from_active(kgem, bo);
143.15682 + 
143.15683 + 				bo->unique_id = kgem_get_unique_id(kgem);
143.15684 +-				bo->pitch = pitch;
143.15685 +-				bo->tiling = tiling;
143.15686 + 				bo->delta = 0;
143.15687 + 				DBG(("  1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n",
143.15688 + 				     bo->pitch, bo->tiling, bo->handle, bo->unique_id));
143.15689 +@@ -5323,11 +5864,13 @@ search_inactive:
143.15690 + 			continue;
143.15691 + 		}
143.15692 + 
143.15693 +-		if (bo->tiling != tiling ||
143.15694 +-		    (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
143.15695 +-			if (!gem_set_tiling(kgem->fd, bo->handle,
143.15696 +-					    tiling, pitch))
143.15697 +-				continue;
143.15698 ++		if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
143.15699 ++			if (kgem->gen >= 040 && !exact) {
143.15700 ++				set_gpu_tiling(kgem, bo, tiling, pitch);
143.15701 ++			} else {
143.15702 ++				kgem_bo_free(kgem, bo);
143.15703 ++				break;
143.15704 ++			}
143.15705 + 		}
143.15706 + 
143.15707 + 		if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
143.15708 +@@ -5338,9 +5881,8 @@ search_inactive:
143.15709 + 		kgem_bo_remove_from_inactive(kgem, bo);
143.15710 + 		assert(list_is_empty(&bo->list));
143.15711 + 		assert(list_is_empty(&bo->vma));
143.15712 +-
143.15713 +-		bo->pitch = pitch;
143.15714 +-		bo->tiling = tiling;
143.15715 ++		assert(bo->tiling == tiling);
143.15716 ++		assert(bo->pitch >= pitch);
143.15717 + 
143.15718 + 		bo->delta = 0;
143.15719 + 		bo->unique_id = kgem_get_unique_id(kgem);
143.15720 +@@ -5388,14 +5930,17 @@ search_inactive:
143.15721 + 			kgem_bo_remove_from_active(kgem, bo);
143.15722 + 			__kgem_bo_clear_busy(bo);
143.15723 + 
143.15724 +-			if (tiling != I915_TILING_NONE && bo->pitch != pitch) {
143.15725 +-				if (!gem_set_tiling(kgem->fd, bo->handle, tiling, pitch)) {
143.15726 ++			if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
143.15727 ++				if (kgem->gen >= 040 && !exact) {
143.15728 ++					set_gpu_tiling(kgem, bo, tiling, pitch);
143.15729 ++				} else {
143.15730 + 					kgem_bo_free(kgem, bo);
143.15731 + 					goto no_retire;
143.15732 + 				}
143.15733 + 			}
143.15734 ++			assert(bo->tiling == tiling);
143.15735 ++			assert(bo->pitch >= pitch);
143.15736 + 
143.15737 +-			bo->pitch = pitch;
143.15738 + 			bo->unique_id = kgem_get_unique_id(kgem);
143.15739 + 			bo->delta = 0;
143.15740 + 			DBG(("  2:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n",
143.15741 +@@ -5440,18 +5985,21 @@ create:
143.15742 + 	}
143.15743 + 
143.15744 + 	bo->unique_id = kgem_get_unique_id(kgem);
143.15745 +-	if (tiling == I915_TILING_NONE ||
143.15746 +-	    gem_set_tiling(kgem->fd, handle, tiling, pitch)) {
143.15747 +-		bo->tiling = tiling;
143.15748 +-		bo->pitch = pitch;
143.15749 ++	if (kgem_set_tiling(kgem, bo, tiling, pitch)) {
143.15750 + 		if (flags & CREATE_SCANOUT)
143.15751 + 			__kgem_bo_make_scanout(kgem, bo, width, height);
143.15752 + 	} else {
143.15753 +-		if (flags & CREATE_EXACT) {
143.15754 +-			DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__));
143.15755 +-			gem_close(kgem->fd, handle);
143.15756 +-			free(bo);
143.15757 +-			return NULL;
143.15758 ++		if (kgem->gen >= 040) {
143.15759 ++			assert(!kgem->can_fence);
143.15760 ++			bo->tiling = tiling;
143.15761 ++			bo->pitch = pitch;
143.15762 ++		} else {
143.15763 ++			if (flags & CREATE_EXACT) {
143.15764 ++				DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__));
143.15765 ++				gem_close(kgem->fd, handle);
143.15766 ++				free(bo);
143.15767 ++				return NULL;
143.15768 ++			}
143.15769 + 		}
143.15770 + 	}
143.15771 + 
143.15772 +@@ -5608,7 +6156,7 @@ static void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo)
143.15773 + 
143.15774 + void kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo)
143.15775 + {
143.15776 +-	if (!bo->needs_flush)
143.15777 ++	if (!bo->needs_flush && !bo->gtt_dirty)
143.15778 + 		return;
143.15779 + 
143.15780 + 	kgem_bo_submit(kgem, bo);
143.15781 +@@ -5621,18 +6169,24 @@ void kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo)
143.15782 + 	if (bo->rq)
143.15783 + 		__kgem_flush(kgem, bo);
143.15784 + 
143.15785 ++	if (bo->scanout && kgem->needs_dirtyfb) {
143.15786 ++		struct drm_mode_fb_dirty_cmd cmd;
143.15787 ++		memset(&cmd, 0, sizeof(cmd));
143.15788 ++		cmd.fb_id = bo->delta;
143.15789 ++		(void)drmIoctl(kgem->fd, DRM_IOCTL_MODE_DIRTYFB, &cmd);
143.15790 ++	}
143.15791 ++
143.15792 + 	/* Whatever actually happens, we can regard the GTT write domain
143.15793 + 	 * as being flushed.
143.15794 + 	 */
143.15795 +-	bo->gtt_dirty = false;
143.15796 +-	bo->needs_flush = false;
143.15797 +-	bo->domain = DOMAIN_NONE;
143.15798 ++	__kgem_bo_clear_dirty(bo);
143.15799 + }
143.15800 + 
143.15801 + inline static bool nearly_idle(struct kgem *kgem)
143.15802 + {
143.15803 + 	int ring = kgem->ring == KGEM_BLT;
143.15804 + 
143.15805 ++	assert(ring < ARRAY_SIZE(kgem->requests));
143.15806 + 	if (list_is_singular(&kgem->requests[ring]))
143.15807 + 		return true;
143.15808 + 
143.15809 +@@ -5720,7 +6274,7 @@ static inline bool kgem_flush(struct kgem *kgem, bool flush)
143.15810 + 	if (kgem->nreloc == 0)
143.15811 + 		return true;
143.15812 + 
143.15813 +-	if (container_of(kgem, struct sna, kgem)->flags & SNA_POWERSAVE)
143.15814 ++	if (__to_sna(kgem)->flags & SNA_POWERSAVE)
143.15815 + 		return true;
143.15816 + 
143.15817 + 	if (kgem->flush == flush && kgem->aperture < kgem->aperture_low)
143.15818 +@@ -5982,6 +6536,55 @@ bool kgem_check_many_bo_fenced(struct kgem *kgem, ...)
143.15819 + 	return kgem_flush(kgem, flush);
143.15820 + }
143.15821 + 
143.15822 ++void __kgem_bcs_set_tiling(struct kgem *kgem,
143.15823 ++			   struct kgem_bo *src,
143.15824 ++			   struct kgem_bo *dst)
143.15825 ++{
143.15826 ++	uint32_t state, *b;
143.15827 ++
143.15828 ++	DBG(("%s: src handle=%d:tiling=%d, dst handle=%d:tiling=%d\n",
143.15829 ++	     __FUNCTION__,
143.15830 ++	     src ? src->handle : 0, src ? src->tiling : 0,
143.15831 ++	     dst ? dst->handle : 0, dst ? dst->tiling : 0));
143.15832 ++	assert(kgem->mode == KGEM_BLT);
143.15833 ++	assert(dst == NULL || kgem_bo_can_blt(kgem, dst));
143.15834 ++	assert(src == NULL || kgem_bo_can_blt(kgem, src));
143.15835 ++
143.15836 ++	state = 0;
143.15837 ++	if (dst && dst->tiling == I915_TILING_Y)
143.15838 ++		state |= BCS_DST_Y;
143.15839 ++	if (src && src->tiling == I915_TILING_Y)
143.15840 ++		state |= BCS_SRC_Y;
143.15841 ++
143.15842 ++	if (kgem->bcs_state == state)
143.15843 ++		return;
143.15844 ++
143.15845 ++	DBG(("%s: updating SWCTRL %x -> %x\n", __FUNCTION__,
143.15846 ++	     kgem->bcs_state, state));
143.15847 ++
143.15848 ++	/* Over-estimate space in case we need to re-emit the cmd packet */
143.15849 ++	if (!kgem_check_batch(kgem, 24)) {
143.15850 ++		_kgem_submit(kgem);
143.15851 ++		_kgem_set_mode(kgem, KGEM_BLT);
143.15852 ++		if (state == 0)
143.15853 ++			return;
143.15854 ++	}
143.15855 ++
143.15856 ++	b = kgem->batch + kgem->nbatch;
143.15857 ++	if (kgem->nbatch) {
143.15858 ++		*b++ = MI_FLUSH_DW;
143.15859 ++		*b++ = 0;
143.15860 ++		*b++ = 0;
143.15861 ++		*b++ = 0;
143.15862 ++	}
143.15863 ++	*b++ = MI_LOAD_REGISTER_IMM;
143.15864 ++	*b++ = BCS_SWCTRL;
143.15865 ++	*b++ = (BCS_SRC_Y | BCS_DST_Y) << 16 | state;
143.15866 ++	kgem->nbatch = b - kgem->batch;
143.15867 ++
143.15868 ++	kgem->bcs_state = state;
143.15869 ++}
143.15870 ++
143.15871 + uint32_t kgem_add_reloc(struct kgem *kgem,
143.15872 + 			uint32_t pos,
143.15873 + 			struct kgem_bo *bo,
143.15874 +@@ -6195,12 +6798,6 @@ static void kgem_trim_vma_cache(struct kgem *kgem, int type, int bucket)
143.15875 + 
143.15876 + 		list_del(&bo->vma);
143.15877 + 		kgem->vma[type].count--;
143.15878 +-
143.15879 +-		if (!bo->purged && !kgem_bo_set_purgeable(kgem, bo)) {
143.15880 +-			DBG(("%s: freeing unpurgeable old mapping\n",
143.15881 +-			     __FUNCTION__));
143.15882 +-			kgem_bo_free(kgem, bo);
143.15883 +-		}
143.15884 + 	}
143.15885 + }
143.15886 + 
143.15887 +@@ -6216,8 +6813,8 @@ static void *__kgem_bo_map__gtt_or_wc(struct kgem *kgem, struct kgem_bo *bo)
143.15888 + 	kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo));
143.15889 + 
143.15890 + 	if (bo->tiling || !kgem->has_wc_mmap) {
143.15891 +-		assert(num_pages(bo) <= kgem->aperture_mappable / 2);
143.15892 + 		assert(kgem->gen != 021 || bo->tiling != I915_TILING_Y);
143.15893 ++		warn_unless(num_pages(bo) <= kgem->aperture_mappable / 2);
143.15894 + 
143.15895 + 		ptr = bo->map__gtt;
143.15896 + 		if (ptr == NULL)
143.15897 +@@ -6291,6 +6888,7 @@ void *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo)
143.15898 + 			DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
143.15899 + 			kgem_throttle(kgem);
143.15900 + 		}
143.15901 ++		bo->needs_flush = false;
143.15902 + 		kgem_bo_retire(kgem, bo);
143.15903 + 		bo->domain = DOMAIN_GTT;
143.15904 + 		bo->gtt_dirty = true;
143.15905 +@@ -6319,14 +6917,16 @@ void *kgem_bo_map__wc(struct kgem *kgem, struct kgem_bo *bo)
143.15906 + 	     bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain));
143.15907 + 
143.15908 + 	assert(bo->proxy == NULL);
143.15909 +-	assert(bo->exec == NULL);
143.15910 + 	assert(list_is_empty(&bo->list));
143.15911 + 	assert_tiling(kgem, bo);
143.15912 + 	assert(!bo->purged || bo->reusable);
143.15913 + 
143.15914 + 	if (bo->map__wc)
143.15915 + 		return bo->map__wc;
143.15916 ++	if (!kgem->has_wc_mmap)
143.15917 ++		return NULL;
143.15918 + 
143.15919 ++	kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo));
143.15920 + 	return __kgem_bo_map__wc(kgem, bo);
143.15921 + }
143.15922 + 
143.15923 +@@ -6373,6 +6973,8 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
143.15924 + {
143.15925 + 	struct drm_gem_flink flink;
143.15926 + 
143.15927 ++	assert(kgem_bo_is_fenced(kgem, bo));
143.15928 ++
143.15929 + 	VG_CLEAR(flink);
143.15930 + 	flink.handle = bo->handle;
143.15931 + 	if (do_ioctl(kgem->fd, DRM_IOCTL_GEM_FLINK, &flink))
143.15932 +@@ -6387,7 +6989,6 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
143.15933 + 	 * party, we track the lifetime accurately.
143.15934 + 	 */
143.15935 + 	bo->reusable = false;
143.15936 +-
143.15937 + 	kgem_bo_unclean(kgem, bo);
143.15938 + 
143.15939 + 	return flink.name;
143.15940 +@@ -6411,16 +7012,34 @@ struct kgem_bo *kgem_create_map(struct kgem *kgem,
143.15941 + 	first_page = (uintptr_t)ptr;
143.15942 + 	last_page = first_page + size + PAGE_SIZE - 1;
143.15943 + 
143.15944 +-	first_page &= ~(PAGE_SIZE-1);
143.15945 +-	last_page &= ~(PAGE_SIZE-1);
143.15946 ++	first_page &= ~(uintptr_t)(PAGE_SIZE-1);
143.15947 ++	last_page &= ~(uintptr_t)(PAGE_SIZE-1);
143.15948 + 	assert(last_page > first_page);
143.15949 + 
143.15950 + 	handle = gem_userptr(kgem->fd,
143.15951 + 			     (void *)first_page, last_page-first_page,
143.15952 + 			     read_only);
143.15953 + 	if (handle == 0) {
143.15954 +-		DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno));
143.15955 +-		return NULL;
143.15956 ++		if (read_only && kgem->has_wc_mmap) {
143.15957 ++			struct drm_i915_gem_set_domain set_domain;
143.15958 ++
143.15959 ++			handle = gem_userptr(kgem->fd,
143.15960 ++					     (void *)first_page, last_page-first_page,
143.15961 ++					     false);
143.15962 ++
143.15963 ++			VG_CLEAR(set_domain);
143.15964 ++			set_domain.handle = handle;
143.15965 ++			set_domain.read_domains = I915_GEM_DOMAIN_GTT;
143.15966 ++			set_domain.write_domain = 0;
143.15967 ++			if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
143.15968 ++				gem_close(kgem->fd, handle);
143.15969 ++				handle = 0;
143.15970 ++			}
143.15971 ++		}
143.15972 ++		if (handle == 0) {
143.15973 ++			DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno));
143.15974 ++			return NULL;
143.15975 ++		}
143.15976 + 	}
143.15977 + 
143.15978 + 	bo = __kgem_bo_alloc(handle, (last_page - first_page) / PAGE_SIZE);
143.15979 +@@ -6483,8 +7102,10 @@ void kgem_bo_sync__cpu(struct kgem *kgem, struct kgem_bo *bo)
143.15980 + 			DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
143.15981 + 			kgem_throttle(kgem);
143.15982 + 		}
143.15983 ++		bo->needs_flush = false;
143.15984 + 		kgem_bo_retire(kgem, bo);
143.15985 + 		bo->domain = DOMAIN_CPU;
143.15986 ++		bo->gtt_dirty = true;
143.15987 + 	}
143.15988 + }
143.15989 + 
143.15990 +@@ -6505,6 +7126,9 @@ void kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write)
143.15991 + 	assert(bo->refcnt);
143.15992 + 	assert(!bo->purged);
143.15993 + 
143.15994 ++	if (bo->rq == NULL && (kgem->has_llc || bo->snoop) && !write)
143.15995 ++		return;
143.15996 ++
143.15997 + 	if (bo->domain != DOMAIN_CPU || FORCE_MMAP_SYNC & (1 << DOMAIN_CPU)) {
143.15998 + 		struct drm_i915_gem_set_domain set_domain;
143.15999 + 
143.16000 +@@ -6522,9 +7146,11 @@ void kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write)
143.16001 + 			DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
143.16002 + 			kgem_throttle(kgem);
143.16003 + 		}
143.16004 ++		bo->needs_flush = false;
143.16005 + 		if (write) {
143.16006 + 			kgem_bo_retire(kgem, bo);
143.16007 + 			bo->domain = DOMAIN_CPU;
143.16008 ++			bo->gtt_dirty = true;
143.16009 + 		} else {
143.16010 + 			if (bo->exec == NULL)
143.16011 + 				kgem_bo_maybe_retire(kgem, bo);
143.16012 +@@ -6539,6 +7165,7 @@ void kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo)
143.16013 + 	assert(bo->refcnt);
143.16014 + 	assert(bo->proxy == NULL);
143.16015 + 	assert_tiling(kgem, bo);
143.16016 ++	assert(!bo->snoop);
143.16017 + 
143.16018 + 	kgem_bo_submit(kgem, bo);
143.16019 + 
143.16020 +@@ -6559,6 +7186,7 @@ void kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo)
143.16021 + 			DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
143.16022 + 			kgem_throttle(kgem);
143.16023 + 		}
143.16024 ++		bo->needs_flush = false;
143.16025 + 		kgem_bo_retire(kgem, bo);
143.16026 + 		bo->domain = DOMAIN_GTT;
143.16027 + 		bo->gtt_dirty = true;
143.16028 +@@ -7485,6 +8113,7 @@ kgem_replace_bo(struct kgem *kgem,
143.16029 + 		}
143.16030 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.16031 + 	}
143.16032 ++	kgem_bcs_set_tiling(kgem, src, dst);
143.16033 + 
143.16034 + 	br00 = XY_SRC_COPY_BLT_CMD;
143.16035 + 	br13 = pitch;
143.16036 +@@ -7553,6 +8182,9 @@ bool kgem_bo_convert_to_gpu(struct kgem *kgem,
143.16037 + 	     __FUNCTION__, bo->handle, flags, __kgem_bo_is_busy(kgem, bo)));
143.16038 + 	assert(bo->tiling == I915_TILING_NONE);
143.16039 + 
143.16040 ++	if (flags & (__MOVE_PRIME | __MOVE_SCANOUT))
143.16041 ++		return false;
143.16042 ++
143.16043 + 	if (kgem->has_llc)
143.16044 + 		return true;
143.16045 + 
143.16046 +diff --git a/src/sna/kgem.h b/src/sna/kgem.h
143.16047 +index 2267bacf..08b4eb20 100644
143.16048 +--- a/src/sna/kgem.h
143.16049 ++++ b/src/sna/kgem.h
143.16050 +@@ -42,6 +42,7 @@ struct kgem_bo {
143.16051 + #define RQ(rq) ((struct kgem_request *)((uintptr_t)(rq) & ~3))
143.16052 + #define RQ_RING(rq) ((uintptr_t)(rq) & 3)
143.16053 + #define RQ_IS_BLT(rq) (RQ_RING(rq) == KGEM_BLT)
143.16054 ++#define RQ_IS_RENDER(rq) (RQ_RING(rq) == KGEM_RENDER)
143.16055 + #define MAKE_REQUEST(rq, ring) ((struct kgem_request *)((uintptr_t)(rq) | (ring)))
143.16056 + 
143.16057 + 	struct drm_i915_gem_exec_object2 *exec;
143.16058 +@@ -103,7 +104,7 @@ struct kgem_request {
143.16059 + 	struct list list;
143.16060 + 	struct kgem_bo *bo;
143.16061 + 	struct list buffers;
143.16062 +-	int ring;
143.16063 ++	unsigned ring;
143.16064 + };
143.16065 + 
143.16066 + enum {
143.16067 +@@ -112,6 +113,12 @@ enum {
143.16068 + 	NUM_MAP_TYPES,
143.16069 + };
143.16070 + 
143.16071 ++typedef void (*memcpy_box_func)(const void *src, void *dst, int bpp,
143.16072 ++				int32_t src_stride, int32_t dst_stride,
143.16073 ++				int16_t src_x, int16_t src_y,
143.16074 ++				int16_t dst_x, int16_t dst_y,
143.16075 ++				uint16_t width, uint16_t height);
143.16076 ++
143.16077 + struct kgem {
143.16078 + 	unsigned wedged;
143.16079 + 	int fd;
143.16080 +@@ -157,6 +164,8 @@ struct kgem {
143.16081 + 		int16_t count;
143.16082 + 	} vma[NUM_MAP_TYPES];
143.16083 + 
143.16084 ++	uint32_t bcs_state;
143.16085 ++
143.16086 + 	uint32_t batch_flags;
143.16087 + 	uint32_t batch_flags_base;
143.16088 + #define I915_EXEC_SECURE (1<<9)
143.16089 +@@ -186,9 +195,15 @@ struct kgem {
143.16090 + 	uint32_t has_no_reloc :1;
143.16091 + 	uint32_t has_handle_lut :1;
143.16092 + 	uint32_t has_wc_mmap :1;
143.16093 ++	uint32_t has_dirtyfb :1;
143.16094 + 
143.16095 ++	uint32_t can_fence :1;
143.16096 + 	uint32_t can_blt_cpu :1;
143.16097 ++	uint32_t can_blt_y :1;
143.16098 + 	uint32_t can_render_y :1;
143.16099 ++	uint32_t can_scanout_y :1;
143.16100 ++
143.16101 ++	uint32_t needs_dirtyfb :1;
143.16102 + 
143.16103 + 	uint16_t fence_max;
143.16104 + 	uint16_t half_cpu_cache_pages;
143.16105 +@@ -203,16 +218,9 @@ struct kgem {
143.16106 + 	void (*retire)(struct kgem *kgem);
143.16107 + 	void (*expire)(struct kgem *kgem);
143.16108 + 
143.16109 +-	void (*memcpy_to_tiled_x)(const void *src, void *dst, int bpp,
143.16110 +-				  int32_t src_stride, int32_t dst_stride,
143.16111 +-				  int16_t src_x, int16_t src_y,
143.16112 +-				  int16_t dst_x, int16_t dst_y,
143.16113 +-				  uint16_t width, uint16_t height);
143.16114 +-	void (*memcpy_from_tiled_x)(const void *src, void *dst, int bpp,
143.16115 +-				    int32_t src_stride, int32_t dst_stride,
143.16116 +-				    int16_t src_x, int16_t src_y,
143.16117 +-				    int16_t dst_x, int16_t dst_y,
143.16118 +-				    uint16_t width, uint16_t height);
143.16119 ++	memcpy_box_func memcpy_to_tiled_x;
143.16120 ++	memcpy_box_func memcpy_from_tiled_x;
143.16121 ++	memcpy_box_func memcpy_between_tiled_x;
143.16122 + 
143.16123 + 	struct kgem_bo *batch_bo;
143.16124 + 
143.16125 +@@ -230,7 +238,7 @@ struct kgem {
143.16126 + 
143.16127 + #define KGEM_MAX_DEFERRED_VBO 16
143.16128 + 
143.16129 +-#define KGEM_BATCH_RESERVED 1
143.16130 ++#define KGEM_BATCH_RESERVED 8 /* LRI(SWCTRL) + END */
143.16131 + #define KGEM_RELOC_RESERVED (KGEM_MAX_DEFERRED_VBO)
143.16132 + #define KGEM_EXEC_RESERVED (1+KGEM_MAX_DEFERRED_VBO)
143.16133 + 
143.16134 +@@ -317,6 +325,7 @@ bool kgem_bo_convert_to_gpu(struct kgem *kgem,
143.16135 + 			    struct kgem_bo *bo,
143.16136 + 			    unsigned flags);
143.16137 + 
143.16138 ++bool kgem_bo_is_fenced(struct kgem *kgem, struct kgem_bo *bo);
143.16139 + uint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format);
143.16140 + void kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset);
143.16141 + 
143.16142 +@@ -342,6 +351,11 @@ static inline bool kgem_ring_is_idle(struct kgem *kgem, int ring)
143.16143 + {
143.16144 + 	ring = ring == KGEM_BLT;
143.16145 + 
143.16146 ++	if (kgem->needs_semaphore &&
143.16147 ++	    !list_is_empty(&kgem->requests[!ring]) &&
143.16148 ++	    !__kgem_ring_is_idle(kgem, !ring))
143.16149 ++		return false;
143.16150 ++
143.16151 + 	if (list_is_empty(&kgem->requests[ring]))
143.16152 + 		return true;
143.16153 + 
143.16154 +@@ -390,6 +404,7 @@ void _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo);
143.16155 + static inline void kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
143.16156 + {
143.16157 + 	assert(bo->refcnt);
143.16158 ++	assert(bo->refcnt > bo->active_scanout);
143.16159 + 	if (--bo->refcnt == 0)
143.16160 + 		_kgem_bo_destroy(kgem, bo);
143.16161 + }
143.16162 +@@ -400,13 +415,13 @@ static inline void kgem_set_mode(struct kgem *kgem,
143.16163 + 				 enum kgem_mode mode,
143.16164 + 				 struct kgem_bo *bo)
143.16165 + {
143.16166 +-	assert(!kgem->wedged);
143.16167 ++	warn_unless(!kgem->wedged);
143.16168 + 
143.16169 + #if DEBUG_FLUSH_BATCH
143.16170 + 	kgem_submit(kgem);
143.16171 + #endif
143.16172 + 
143.16173 +-	if (kgem->nreloc && bo->exec == NULL && kgem_ring_is_idle(kgem, kgem->ring)) {
143.16174 ++	if (kgem->nreloc && bo->rq == NULL && kgem_ring_is_idle(kgem, kgem->ring)) {
143.16175 + 		DBG(("%s: flushing before new bo\n", __FUNCTION__));
143.16176 + 		_kgem_submit(kgem);
143.16177 + 	}
143.16178 +@@ -422,7 +437,7 @@ static inline void _kgem_set_mode(struct kgem *kgem, enum kgem_mode mode)
143.16179 + {
143.16180 + 	assert(kgem->mode == KGEM_NONE);
143.16181 + 	assert(kgem->nbatch == 0);
143.16182 +-	assert(!kgem->wedged);
143.16183 ++	warn_unless(!kgem->wedged);
143.16184 + 	kgem->context_switch(kgem, mode);
143.16185 + 	kgem->mode = mode;
143.16186 + }
143.16187 +@@ -566,7 +581,7 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem,
143.16188 + {
143.16189 + 	assert(bo->refcnt);
143.16190 + 
143.16191 +-	if (bo->tiling == I915_TILING_Y) {
143.16192 ++	if (bo->tiling == I915_TILING_Y && !kgem->can_blt_y) {
143.16193 + 		DBG(("%s: can not blt to handle=%d, tiling=Y\n",
143.16194 + 		     __FUNCTION__, bo->handle));
143.16195 + 		return false;
143.16196 +@@ -581,6 +596,22 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem,
143.16197 + 	return kgem_bo_blt_pitch_is_ok(kgem, bo);
143.16198 + }
143.16199 + 
143.16200 ++void __kgem_bcs_set_tiling(struct kgem *kgem,
143.16201 ++			   struct kgem_bo *src,
143.16202 ++			   struct kgem_bo *dst);
143.16203 ++
143.16204 ++inline static void kgem_bcs_set_tiling(struct kgem *kgem,
143.16205 ++				       struct kgem_bo *src,
143.16206 ++				       struct kgem_bo *dst)
143.16207 ++{
143.16208 ++	assert(kgem->mode == KGEM_BLT);
143.16209 ++
143.16210 ++	if (!kgem->can_blt_y)
143.16211 ++		return;
143.16212 ++
143.16213 ++	__kgem_bcs_set_tiling(kgem, src, dst);
143.16214 ++}
143.16215 ++
143.16216 + static inline bool kgem_bo_is_snoop(struct kgem_bo *bo)
143.16217 + {
143.16218 + 	assert(bo->refcnt);
143.16219 +@@ -607,17 +638,24 @@ static inline void kgem_bo_mark_busy(struct kgem *kgem, struct kgem_bo *bo, int
143.16220 + 	}
143.16221 + }
143.16222 + 
143.16223 +-inline static void __kgem_bo_clear_busy(struct kgem_bo *bo)
143.16224 ++static inline void __kgem_bo_clear_dirty(struct kgem_bo *bo)
143.16225 + {
143.16226 + 	DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle));
143.16227 +-	bo->rq = NULL;
143.16228 +-	list_del(&bo->request);
143.16229 + 
143.16230 + 	bo->domain = DOMAIN_NONE;
143.16231 + 	bo->needs_flush = false;
143.16232 + 	bo->gtt_dirty = false;
143.16233 + }
143.16234 + 
143.16235 ++inline static void __kgem_bo_clear_busy(struct kgem_bo *bo)
143.16236 ++{
143.16237 ++	DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle));
143.16238 ++	bo->rq = NULL;
143.16239 ++	list_del(&bo->request);
143.16240 ++
143.16241 ++	__kgem_bo_clear_dirty(bo);
143.16242 ++}
143.16243 ++
143.16244 + static inline bool kgem_bo_is_busy(struct kgem_bo *bo)
143.16245 + {
143.16246 + 	DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
143.16247 +@@ -626,7 +664,7 @@ static inline bool kgem_bo_is_busy(struct kgem_bo *bo)
143.16248 + 	return bo->rq;
143.16249 + }
143.16250 + 
143.16251 +-void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo);
143.16252 ++bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo);
143.16253 + static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo)
143.16254 + {
143.16255 + 	DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
143.16256 +@@ -636,14 +674,13 @@ static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo)
143.16257 + 	if (bo->exec)
143.16258 + 		return true;
143.16259 + 
143.16260 +-	if (bo->rq && !__kgem_busy(kgem, bo->handle)) {
143.16261 +-		__kgem_retire_requests_upto(kgem, bo);
143.16262 +-		assert(list_is_empty(&bo->request));
143.16263 +-		assert(bo->rq == NULL);
143.16264 +-		assert(bo->domain == DOMAIN_NONE);
143.16265 +-	}
143.16266 ++	if (bo->rq == NULL)
143.16267 ++		return false;
143.16268 ++
143.16269 ++	if (__kgem_busy(kgem, bo->handle))
143.16270 ++		return true;
143.16271 + 
143.16272 +-	return kgem_bo_is_busy(bo);
143.16273 ++	return __kgem_retire_requests_upto(kgem, bo);
143.16274 + }
143.16275 + 
143.16276 + static inline bool kgem_bo_is_render(struct kgem_bo *bo)
143.16277 +@@ -651,7 +688,15 @@ static inline bool kgem_bo_is_render(struct kgem_bo *bo)
143.16278 + 	DBG(("%s: handle=%d, rq? %d [%d]\n", __FUNCTION__,
143.16279 + 	     bo->handle, bo->rq != NULL, (int)RQ_RING(bo->rq)));
143.16280 + 	assert(bo->refcnt);
143.16281 +-	return bo->rq && RQ_RING(bo->rq) == I915_EXEC_RENDER;
143.16282 ++	return bo->rq && RQ_RING(bo->rq) != KGEM_BLT;
143.16283 ++}
143.16284 ++
143.16285 ++static inline bool kgem_bo_is_blt(struct kgem_bo *bo)
143.16286 ++{
143.16287 ++	DBG(("%s: handle=%d, rq? %d\n", __FUNCTION__,
143.16288 ++	     bo->handle, bo->rq != NULL, (int)RQ_RING(bo->rq)));
143.16289 ++	assert(bo->refcnt);
143.16290 ++	return RQ_RING(bo->rq) == KGEM_BLT;
143.16291 + }
143.16292 + 
143.16293 + static inline void kgem_bo_mark_unreusable(struct kgem_bo *bo)
143.16294 +@@ -852,6 +897,6 @@ memcpy_from_tiled_x(struct kgem *kgem,
143.16295 + 					 width, height);
143.16296 + }
143.16297 + 
143.16298 +-void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling);
143.16299 ++void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling, unsigned cpu);
143.16300 + 
143.16301 + #endif /* KGEM_H */
143.16302 +diff --git a/src/sna/kgem_debug_gen4.c b/src/sna/kgem_debug_gen4.c
143.16303 +index 9b80dc88..8e6e47b6 100644
143.16304 +--- a/src/sna/kgem_debug_gen4.c
143.16305 ++++ b/src/sna/kgem_debug_gen4.c
143.16306 +@@ -598,7 +598,7 @@ int kgem_gen4_decode_3d(struct kgem *kgem, uint32_t offset)
143.16307 + 		assert(len == 7);
143.16308 + 		kgem_debug_print(data, offset, 0,
143.16309 + 			  "3DSTATE_DEPTH_BUFFER\n");
143.16310 +-		kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
143.16311 ++		kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
143.16312 + 			  get_965_surfacetype(data[1] >> 29),
143.16313 + 			  get_965_depthformat((data[1] >> 18) & 0x7),
143.16314 + 			  (data[1] & 0x0001ffff) + 1,
143.16315 +diff --git a/src/sna/kgem_debug_gen5.c b/src/sna/kgem_debug_gen5.c
143.16316 +index 8b55dd91..f1b1275f 100644
143.16317 +--- a/src/sna/kgem_debug_gen5.c
143.16318 ++++ b/src/sna/kgem_debug_gen5.c
143.16319 +@@ -573,7 +573,7 @@ int kgem_gen5_decode_3d(struct kgem *kgem, uint32_t offset)
143.16320 + 		assert(len == 7);
143.16321 + 		kgem_debug_print(data, offset, 0,
143.16322 + 			  "3DSTATE_DEPTH_BUFFER\n");
143.16323 +-		kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
143.16324 ++		kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
143.16325 + 			  get_965_surfacetype(data[1] >> 29),
143.16326 + 			  get_965_depthformat((data[1] >> 18) & 0x7),
143.16327 + 			  (data[1] & 0x0001ffff) + 1,
143.16328 +diff --git a/src/sna/kgem_debug_gen6.c b/src/sna/kgem_debug_gen6.c
143.16329 +index 7ef55d38..579c5d54 100644
143.16330 +--- a/src/sna/kgem_debug_gen6.c
143.16331 ++++ b/src/sna/kgem_debug_gen6.c
143.16332 +@@ -985,7 +985,7 @@ int kgem_gen6_decode_3d(struct kgem *kgem, uint32_t offset)
143.16333 + 		assert(len == 7);
143.16334 + 		kgem_debug_print(data, offset, 0,
143.16335 + 			  "3DSTATE_DEPTH_BUFFER\n");
143.16336 +-		kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
143.16337 ++		kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
143.16338 + 			  get_965_surfacetype(data[1] >> 29),
143.16339 + 			  get_965_depthformat((data[1] >> 18) & 0x7),
143.16340 + 			  (data[1] & 0x0001ffff) + 1,
143.16341 +diff --git a/src/sna/sna.h b/src/sna/sna.h
143.16342 +index 18425e30..7861110a 100644
143.16343 +--- a/src/sna/sna.h
143.16344 ++++ b/src/sna/sna.h
143.16345 +@@ -154,6 +154,8 @@ struct sna_pixmap {
143.16346 + #define MAPPED_GTT 1
143.16347 + #define MAPPED_CPU 2
143.16348 + 	uint8_t flush :2;
143.16349 ++#define FLUSH_READ 1
143.16350 ++#define FLUSH_WRITE 2
143.16351 + 	uint8_t shm :1;
143.16352 + 	uint8_t clear :1;
143.16353 + 	uint8_t header :1;
143.16354 +@@ -179,18 +181,31 @@ static inline WindowPtr get_root_window(ScreenPtr screen)
143.16355 + #endif
143.16356 + }
143.16357 + 
143.16358 ++#if !NDEBUG
143.16359 ++static PixmapPtr check_pixmap(PixmapPtr pixmap)
143.16360 ++{
143.16361 ++	if (pixmap != NULL) {
143.16362 ++		assert(pixmap->refcnt >= 1);
143.16363 ++		assert(pixmap->devKind != 0xdeadbeef);
143.16364 ++	}
143.16365 ++	return pixmap;
143.16366 ++}
143.16367 ++#else
143.16368 ++#define check_pixmap(p) p
143.16369 ++#endif
143.16370 ++
143.16371 + static inline PixmapPtr get_window_pixmap(WindowPtr window)
143.16372 + {
143.16373 + 	assert(window);
143.16374 + 	assert(window->drawable.type != DRAWABLE_PIXMAP);
143.16375 +-	return fbGetWindowPixmap(window);
143.16376 ++	return check_pixmap(fbGetWindowPixmap(window));
143.16377 + }
143.16378 + 
143.16379 + static inline PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
143.16380 + {
143.16381 + 	assert(drawable);
143.16382 + 	if (drawable->type == DRAWABLE_PIXMAP)
143.16383 +-		return (PixmapPtr)drawable;
143.16384 ++		return check_pixmap((PixmapPtr)drawable);
143.16385 + 	else
143.16386 + 		return get_window_pixmap((WindowPtr)drawable);
143.16387 + }
143.16388 +@@ -244,11 +259,12 @@ struct sna {
143.16389 + #define SNA_NO_VSYNC		0x40
143.16390 + #define SNA_TRIPLE_BUFFER	0x80
143.16391 + #define SNA_TEAR_FREE		0x100
143.16392 +-#define SNA_FORCE_SHADOW	0x200
143.16393 +-#define SNA_FLUSH_GTT		0x400
143.16394 ++#define SNA_WANT_TEAR_FREE	0x200
143.16395 ++#define SNA_FORCE_SHADOW	0x400
143.16396 ++#define SNA_FLUSH_GTT		0x800
143.16397 + #define SNA_PERFORMANCE		0x1000
143.16398 + #define SNA_POWERSAVE		0x2000
143.16399 +-#define SNA_REMOVE_OUTPUTS	0x4000
143.16400 ++#define SNA_NO_DPMS		0x4000
143.16401 + #define SNA_HAS_FLIP		0x10000
143.16402 + #define SNA_HAS_ASYNC_FLIP	0x20000
143.16403 + #define SNA_LINEAR_FB		0x40000
143.16404 +@@ -265,7 +281,13 @@ struct sna {
143.16405 + #define AVX 0x80
143.16406 + #define AVX2 0x100
143.16407 + 
143.16408 +-	unsigned watch_flush;
143.16409 ++	bool ignore_copy_area : 1;
143.16410 ++
143.16411 ++	unsigned watch_shm_flush;
143.16412 ++	unsigned watch_dri_flush;
143.16413 ++	unsigned damage_event;
143.16414 ++	bool needs_shm_flush;
143.16415 ++	bool needs_dri_flush;
143.16416 + 
143.16417 + 	struct timeval timer_tv;
143.16418 + 	uint32_t timer_expire[NUM_TIMERS];
143.16419 +@@ -284,9 +306,17 @@ struct sna {
143.16420 + 		struct kgem_bo *shadow;
143.16421 + 		unsigned front_active;
143.16422 + 		unsigned shadow_active;
143.16423 ++		unsigned rr_active;
143.16424 + 		unsigned flip_active;
143.16425 ++		unsigned hidden;
143.16426 ++		bool shadow_enabled;
143.16427 ++		bool shadow_wait;
143.16428 + 		bool dirty;
143.16429 + 
143.16430 ++		struct drm_event_vblank *shadow_events;
143.16431 ++		int shadow_nevent;
143.16432 ++		int shadow_size;
143.16433 ++
143.16434 + 		int max_crtc_width, max_crtc_height;
143.16435 + 		RegionRec shadow_region;
143.16436 + 		RegionRec shadow_cancel;
143.16437 +@@ -318,7 +348,8 @@ struct sna {
143.16438 + 		uint32_t fg, bg;
143.16439 + 		int size;
143.16440 + 
143.16441 +-		int active;
143.16442 ++		bool disable;
143.16443 ++		bool active;
143.16444 + 		int last_x;
143.16445 + 		int last_y;
143.16446 + 
143.16447 +@@ -331,8 +362,9 @@ struct sna {
143.16448 + 	} cursor;
143.16449 + 
143.16450 + 	struct sna_dri2 {
143.16451 +-		bool available;
143.16452 +-		bool open;
143.16453 ++		bool available : 1;
143.16454 ++		bool enable : 1;
143.16455 ++		bool open : 1;
143.16456 + 
143.16457 + #if HAVE_DRI2
143.16458 + 		void *flip_pending;
143.16459 +@@ -341,8 +373,11 @@ struct sna {
143.16460 + 	} dri2;
143.16461 + 
143.16462 + 	struct sna_dri3 {
143.16463 +-		bool available;
143.16464 +-		bool open;
143.16465 ++		bool available :1;
143.16466 ++		bool override : 1;
143.16467 ++		bool enable : 1;
143.16468 ++		bool open :1;
143.16469 ++
143.16470 + #if HAVE_DRI3
143.16471 + 		SyncScreenCreateFenceFunc create_fence;
143.16472 + 		struct list pixmaps;
143.16473 +@@ -353,6 +388,9 @@ struct sna {
143.16474 + 		bool available;
143.16475 + 		bool open;
143.16476 + #if HAVE_PRESENT
143.16477 ++		struct list vblank_queue;
143.16478 ++		uint64_t unflip;
143.16479 ++		void *freed_info;
143.16480 + #endif
143.16481 + 	} present;
143.16482 + 
143.16483 +@@ -364,8 +402,10 @@ struct sna {
143.16484 + 	EntityInfoPtr pEnt;
143.16485 + 	const struct intel_device_info *info;
143.16486 + 
143.16487 ++#if !HAVE_NOTIFY_FD
143.16488 + 	ScreenBlockHandlerProcPtr BlockHandler;
143.16489 + 	ScreenWakeupHandlerProcPtr WakeupHandler;
143.16490 ++#endif
143.16491 + 	CloseScreenProcPtr CloseScreen;
143.16492 + 
143.16493 + 	PicturePtr clear;
143.16494 +@@ -383,6 +423,7 @@ struct sna {
143.16495 + 		struct gen6_render_state gen6;
143.16496 + 		struct gen7_render_state gen7;
143.16497 + 		struct gen8_render_state gen8;
143.16498 ++		struct gen9_render_state gen9;
143.16499 + 	} render_state;
143.16500 + 
143.16501 + 	/* Broken-out options. */
143.16502 +@@ -420,7 +461,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
143.16503 + bool sna_mode_fake_init(struct sna *sna, int num_fake);
143.16504 + bool sna_mode_wants_tear_free(struct sna *sna);
143.16505 + void sna_mode_adjust_frame(struct sna *sna, int x, int y);
143.16506 +-extern void sna_mode_discover(struct sna *sna);
143.16507 ++extern void sna_mode_discover(struct sna *sna, bool tell);
143.16508 + extern void sna_mode_check(struct sna *sna);
143.16509 + extern bool sna_mode_disable(struct sna *sna);
143.16510 + extern void sna_mode_enable(struct sna *sna);
143.16511 +@@ -434,6 +475,7 @@ extern void sna_shadow_unset_crtc(struct sna *sna, xf86CrtcPtr crtc);
143.16512 + extern bool sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv,
143.16513 + 					     const RegionRec *region);
143.16514 + extern void sna_mode_set_primary(struct sna *sna);
143.16515 ++extern bool sna_mode_find_hotplug_connector(struct sna *sna, unsigned id);
143.16516 + extern void sna_mode_close(struct sna *sna);
143.16517 + extern void sna_mode_fini(struct sna *sna);
143.16518 + 
143.16519 +@@ -444,6 +486,7 @@ extern bool sna_cursors_init(ScreenPtr screen, struct sna *sna);
143.16520 + typedef void (*sna_flip_handler_t)(struct drm_event_vblank *e,
143.16521 + 				   void *data);
143.16522 + 
143.16523 ++extern bool sna_needs_page_flip(struct sna *sna, struct kgem_bo *bo);
143.16524 + extern int sna_page_flip(struct sna *sna,
143.16525 + 			 struct kgem_bo *bo,
143.16526 + 			 sna_flip_handler_t handler,
143.16527 +@@ -461,6 +504,11 @@ to_sna_from_screen(ScreenPtr screen)
143.16528 + 	return to_sna(xf86ScreenToScrn(screen));
143.16529 + }
143.16530 + 
143.16531 ++pure static inline ScreenPtr to_screen_from_sna(struct sna *sna)
143.16532 ++{
143.16533 ++	return xf86ScrnToScreen(sna->scrn);
143.16534 ++}
143.16535 ++
143.16536 + pure static inline struct sna *
143.16537 + to_sna_from_pixmap(PixmapPtr pixmap)
143.16538 + {
143.16539 +@@ -498,12 +546,11 @@ to_sna_from_kgem(struct kgem *kgem)
143.16540 + extern xf86CrtcPtr sna_covering_crtc(struct sna *sna,
143.16541 + 				     const BoxRec *box,
143.16542 + 				     xf86CrtcPtr desired);
143.16543 ++extern xf86CrtcPtr sna_primary_crtc(struct sna *sna);
143.16544 + 
143.16545 + extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
143.16546 + 				  xf86CrtcPtr crtc, const BoxRec *clip);
143.16547 + 
143.16548 +-xf86CrtcPtr sna_mode_first_crtc(struct sna *sna);
143.16549 +-
143.16550 + const struct ust_msc {
143.16551 + 	uint64_t msc;
143.16552 + 	int tv_sec;
143.16553 +@@ -536,6 +583,11 @@ static inline uint64_t ust64(int tv_sec, int tv_usec)
143.16554 + 	return (uint64_t)tv_sec * 1000000 + tv_usec;
143.16555 + }
143.16556 + 
143.16557 ++static inline uint64_t swap_ust(const struct ust_msc *swap)
143.16558 ++{
143.16559 ++	return ust64(swap->tv_sec, swap->tv_usec);
143.16560 ++}
143.16561 ++
143.16562 + #if HAVE_DRI2
143.16563 + bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen);
143.16564 + void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event);
143.16565 +@@ -567,20 +619,59 @@ bool sna_present_open(struct sna *sna, ScreenPtr pScreen);
143.16566 + void sna_present_update(struct sna *sna);
143.16567 + void sna_present_close(struct sna *sna, ScreenPtr pScreen);
143.16568 + void sna_present_vblank_handler(struct drm_event_vblank *event);
143.16569 ++void sna_present_cancel_flip(struct sna *sna);
143.16570 + #else
143.16571 + static inline bool sna_present_open(struct sna *sna, ScreenPtr pScreen) { return false; }
143.16572 + static inline void sna_present_update(struct sna *sna) { }
143.16573 + static inline void sna_present_close(struct sna *sna, ScreenPtr pScreen) { }
143.16574 + static inline void sna_present_vblank_handler(struct drm_event_vblank *event) { }
143.16575 ++static inline void sna_present_cancel_flip(struct sna *sna) { }
143.16576 + #endif
143.16577 + 
143.16578 +-extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation);
143.16579 +-extern int sna_crtc_to_pipe(xf86CrtcPtr crtc);
143.16580 +-extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc);
143.16581 +-extern uint32_t sna_crtc_id(xf86CrtcPtr crtc);
143.16582 +-extern bool sna_crtc_is_on(xf86CrtcPtr crtc);
143.16583 ++extern unsigned sna_crtc_count_sprites(xf86CrtcPtr crtc);
143.16584 ++extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, unsigned idx, uint32_t rotation);
143.16585 ++extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc, unsigned idx);
143.16586 + extern bool sna_crtc_is_transformed(xf86CrtcPtr crtc);
143.16587 + 
143.16588 ++#define CRTC_VBLANK 0x3
143.16589 ++#define CRTC_ON 0x80000000
143.16590 ++
143.16591 ++uint32_t sna_crtc_id(xf86CrtcPtr crtc);
143.16592 ++
143.16593 ++static inline unsigned long *sna_crtc_flags(xf86CrtcPtr crtc)
143.16594 ++{
143.16595 ++	unsigned long *flags = crtc->driver_private;
143.16596 ++	assert(flags);
143.16597 ++	return flags;
143.16598 ++}
143.16599 ++
143.16600 ++static inline unsigned sna_crtc_pipe(xf86CrtcPtr crtc)
143.16601 ++{
143.16602 ++	return *sna_crtc_flags(crtc) >> 8 & 0xff;
143.16603 ++}
143.16604 ++
143.16605 ++static inline bool sna_crtc_is_on(xf86CrtcPtr crtc)
143.16606 ++{
143.16607 ++	return *sna_crtc_flags(crtc) & CRTC_ON;
143.16608 ++}
143.16609 ++
143.16610 ++static inline void sna_crtc_set_vblank(xf86CrtcPtr crtc)
143.16611 ++{
143.16612 ++	assert((*sna_crtc_flags(crtc) & CRTC_VBLANK) < 3);
143.16613 ++	++*sna_crtc_flags(crtc);
143.16614 ++}
143.16615 ++
143.16616 ++static inline void sna_crtc_clear_vblank(xf86CrtcPtr crtc)
143.16617 ++{
143.16618 ++	assert(*sna_crtc_flags(crtc) & CRTC_VBLANK);
143.16619 ++	--*sna_crtc_flags(crtc);
143.16620 ++}
143.16621 ++
143.16622 ++static inline bool sna_crtc_has_vblank(xf86CrtcPtr crtc)
143.16623 ++{
143.16624 ++	return *sna_crtc_flags(crtc) & CRTC_VBLANK;
143.16625 ++}
143.16626 ++
143.16627 + CARD32 sna_format_for_depth(int depth);
143.16628 + CARD32 sna_render_format_for_depth(int depth);
143.16629 + 
143.16630 +@@ -998,15 +1089,14 @@ static inline uint32_t pixmap_size(PixmapPtr pixmap)
143.16631 + 
143.16632 + bool sna_accel_init(ScreenPtr sreen, struct sna *sna);
143.16633 + void sna_accel_create(struct sna *sna);
143.16634 +-void sna_accel_block_handler(struct sna *sna, struct timeval **tv);
143.16635 +-void sna_accel_wakeup_handler(struct sna *sna);
143.16636 +-void sna_accel_watch_flush(struct sna *sna, int enable);
143.16637 ++void sna_accel_block(struct sna *sna, struct timeval **tv);
143.16638 + void sna_accel_flush(struct sna *sna);
143.16639 + void sna_accel_enter(struct sna *sna);
143.16640 + void sna_accel_leave(struct sna *sna);
143.16641 + void sna_accel_close(struct sna *sna);
143.16642 + void sna_accel_free(struct sna *sna);
143.16643 + 
143.16644 ++void sna_watch_flush(struct sna *sna, int enable);
143.16645 + void sna_copy_fbcon(struct sna *sna);
143.16646 + 
143.16647 + bool sna_composite_create(struct sna *sna);
143.16648 +@@ -1127,6 +1217,16 @@ memcpy_blt(const void *src, void *dst, int bpp,
143.16649 + 	   uint16_t width, uint16_t height);
143.16650 + 
143.16651 + void
143.16652 ++affine_blt(const void *src, void *dst, int bpp,
143.16653 ++	   int16_t src_x, int16_t src_y,
143.16654 ++	   int16_t src_width, int16_t src_height,
143.16655 ++	   int32_t src_stride,
143.16656 ++	   int16_t dst_x, int16_t dst_y,
143.16657 ++	   uint16_t dst_width, uint16_t dst_height,
143.16658 ++	   int32_t dst_stride,
143.16659 ++	   const struct pixman_f_transform *t);
143.16660 ++
143.16661 ++void
143.16662 + memmove_box(const void *src, void *dst,
143.16663 + 	    int bpp, int32_t stride,
143.16664 + 	    const BoxRec *box,
143.16665 +@@ -1182,6 +1282,31 @@ box_intersect(BoxPtr a, const BoxRec *b)
143.16666 + 	return true;
143.16667 + }
143.16668 + 
143.16669 ++const BoxRec *
143.16670 ++__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y);
143.16671 ++inline static const BoxRec *
143.16672 ++find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
143.16673 ++{
143.16674 ++	/* Special case for incremental trapezoid clipping */
143.16675 ++	if (begin == end)
143.16676 ++		return end;
143.16677 ++
143.16678 ++	/* Quick test if scanline is within range of clip boxes */
143.16679 ++	if (begin->y2 > y) {
143.16680 ++		assert(end == begin + 1 ||
143.16681 ++		       __find_clip_box_for_y(begin, end, y) == begin);
143.16682 ++		return begin;
143.16683 ++	}
143.16684 ++	if (y >= end[-1].y2) {
143.16685 ++		assert(end == begin + 1 ||
143.16686 ++		       __find_clip_box_for_y(begin, end, y) == end);
143.16687 ++		return end;
143.16688 ++	}
143.16689 ++
143.16690 ++	/* Otherwise bisect to find the first box crossing y */
143.16691 ++	return __find_clip_box_for_y(begin, end, y);
143.16692 ++}
143.16693 ++
143.16694 + unsigned sna_cpu_detect(void);
143.16695 + char *sna_cpu_features_to_string(unsigned features, char *line);
143.16696 + 
143.16697 +@@ -1237,4 +1362,17 @@ static inline void sigtrap_put(void)
143.16698 + extern int getline(char **line, size_t *len, FILE *file);
143.16699 + #endif
143.16700 + 
143.16701 ++static inline void add_shm_flush(struct sna *sna, struct sna_pixmap *priv)
143.16702 ++{
143.16703 ++	if (!priv->shm)
143.16704 ++		return;
143.16705 ++
143.16706 ++	DBG(("%s: marking handle=%d for SHM flush\n",
143.16707 ++	     __FUNCTION__, priv->cpu_bo->handle));
143.16708 ++
143.16709 ++	assert(!priv->flush);
143.16710 ++	sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.16711 ++	sna->needs_shm_flush = true;
143.16712 ++}
143.16713 ++
143.16714 + #endif /* _SNA_H */
143.16715 +diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
143.16716 +index baf5f609..25a075cf 100644
143.16717 +--- a/src/sna/sna_accel.c
143.16718 ++++ b/src/sna/sna_accel.c
143.16719 +@@ -50,8 +50,11 @@
143.16720 + #endif
143.16721 + #include <shmint.h>
143.16722 + 
143.16723 ++#include <X11/extensions/damageproto.h>
143.16724 ++
143.16725 + #include <sys/time.h>
143.16726 + #include <sys/mman.h>
143.16727 ++#include <sys/ioctl.h>
143.16728 + #include <unistd.h>
143.16729 + 
143.16730 + #ifdef HAVE_VALGRIND
143.16731 +@@ -66,7 +69,8 @@
143.16732 + #define FORCE_FLUSH 0
143.16733 + #define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
143.16734 + 
143.16735 +-#define DEFAULT_TILING I915_TILING_X
143.16736 ++#define DEFAULT_PIXMAP_TILING I915_TILING_X
143.16737 ++#define DEFAULT_SCANOUT_TILING I915_TILING_X
143.16738 + 
143.16739 + #define USE_INPLACE 1
143.16740 + #define USE_SPANS 0 /* -1 force CPU, 1 force GPU */
143.16741 +@@ -115,6 +119,11 @@
143.16742 + #define RECTILINEAR	0x4
143.16743 + #define OVERWRITES	0x8
143.16744 + 
143.16745 ++#if XFONT2_CLIENT_FUNCS_VERSION >= 1
143.16746 ++#define AllocateFontPrivateIndex() xfont2_allocate_font_private_index()
143.16747 ++#define FontSetPrivate(font, idx, data) xfont2_font_set_private(font, idx, data)
143.16748 ++#endif
143.16749 ++
143.16750 + #if 0
143.16751 + static void __sna_fallback_flush(DrawablePtr d)
143.16752 + {
143.16753 +@@ -213,6 +222,7 @@ static GCOps sna_gc_ops__tmp;
143.16754 + static const GCFuncs sna_gc_funcs;
143.16755 + static const GCFuncs sna_gc_funcs__cpu;
143.16756 + 
143.16757 ++static void sna_shm_watch_flush(struct sna *sna, int enable);
143.16758 + static void
143.16759 + sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);
143.16760 + 
143.16761 +@@ -527,10 +537,10 @@ sna_pixmap_alloc_cpu(struct sna *sna,
143.16762 + 		DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
143.16763 + 		     pixmap->drawable.width, pixmap->drawable.height));
143.16764 + 
143.16765 +-		hint = 0;
143.16766 +-		if ((flags & MOVE_ASYNC_HINT) == 0 &&
143.16767 +-		    ((flags & MOVE_READ) == 0 || (priv->gpu_damage && !priv->clear && !sna->kgem.has_llc)))
143.16768 +-			hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
143.16769 ++		hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
143.16770 ++		if ((flags & MOVE_ASYNC_HINT) ||
143.16771 ++		    (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu))
143.16772 ++			hint = 0;
143.16773 + 
143.16774 + 		priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
143.16775 + 						  pixmap->drawable.width,
143.16776 +@@ -580,7 +590,7 @@ static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
143.16777 + 		if (priv->cpu_bo->flush) {
143.16778 + 			assert(!priv->cpu_bo->reusable);
143.16779 + 			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
143.16780 +-			sna_accel_watch_flush(sna, -1);
143.16781 ++			sna_shm_watch_flush(sna, -1);
143.16782 + 		}
143.16783 + 		kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
143.16784 + 	} else if (!IS_STATIC_PTR(priv->ptr))
143.16785 +@@ -612,9 +622,9 @@ static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool a
143.16786 + 
143.16787 + static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
143.16788 + {
143.16789 +-#if DEFAULT_TILING == I915_TILING_NONE
143.16790 ++#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE
143.16791 + 	return I915_TILING_NONE;
143.16792 +-#elif DEFAULT_TILING == I915_TILING_X
143.16793 ++#elif DEFAULT_PIXMAP_TILING == I915_TILING_X
143.16794 + 	return I915_TILING_X;
143.16795 + #else
143.16796 + 	/* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
143.16797 +@@ -630,15 +640,6 @@ static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
143.16798 + 	     pixmap->drawable.height > sna->render.max_3d_size))
143.16799 + 		return I915_TILING_X;
143.16800 + 
143.16801 +-	if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage,
143.16802 +-			      pixmap->drawable.width,
143.16803 +-			      pixmap->drawable.height)) {
143.16804 +-		DBG(("%s: entire source is damaged, using Y-tiling\n",
143.16805 +-		     __FUNCTION__));
143.16806 +-		sna_damage_destroy(&sna_pixmap(priv)->gpu_damage);
143.16807 +-		return I915_TILING_Y;
143.16808 +-	}
143.16809 +-
143.16810 + 	return I915_TILING_Y;
143.16811 + #endif
143.16812 + }
143.16813 +@@ -666,6 +667,7 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
143.16814 + 	     __FUNCTION__, priv->gpu_bo->tiling, tiling,
143.16815 + 	     pixmap->drawable.width, pixmap->drawable.height));
143.16816 + 	assert(priv->gpu_damage == NULL || priv->gpu_bo);
143.16817 ++	assert(priv->gpu_bo->tiling != tiling);
143.16818 + 
143.16819 + 	if (priv->pinned) {
143.16820 + 		DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
143.16821 +@@ -690,6 +692,12 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
143.16822 + 		return NULL;
143.16823 + 	}
143.16824 + 
143.16825 ++	if (bo->tiling == priv->gpu_bo->tiling) {
143.16826 ++		DBG(("%s: tiling request failed\n", __FUNCTION__));
143.16827 ++		kgem_bo_destroy(&sna->kgem, bo);
143.16828 ++		return NULL;
143.16829 ++	}
143.16830 ++
143.16831 + 	box.x1 = box.y1 = 0;
143.16832 + 	box.x2 = pixmap->drawable.width;
143.16833 + 	box.y2 = pixmap->drawable.height;
143.16834 +@@ -824,8 +832,8 @@ create_pixmap(struct sna *sna, ScreenPtr screen,
143.16835 + 		datasize += adjust;
143.16836 + 	}
143.16837 + 
143.16838 +-	DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n",
143.16839 +-	     __FUNCTION__, width, height, depth, (long)datasize));
143.16840 ++	DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n",
143.16841 ++	     __FUNCTION__, width, height, depth, bpp, (long)datasize));
143.16842 + 	pixmap = AllocatePixmap(screen, datasize);
143.16843 + 	if (!pixmap)
143.16844 + 		return NullPixmap;
143.16845 +@@ -878,7 +886,11 @@ __pop_freed_pixmap(struct sna *sna)
143.16846 + 	pixmap = sna->freed_pixmap;
143.16847 + 	sna->freed_pixmap = pixmap->devPrivate.ptr;
143.16848 + 
143.16849 ++	DBG(("%s: reusing freed pixmap=%ld header\n",
143.16850 ++	     __FUNCTION__, pixmap->drawable.serialNumber));
143.16851 ++
143.16852 + 	assert(pixmap->refcnt == 0);
143.16853 ++	assert(pixmap->devKind = 0xdeadbeef);
143.16854 + 	assert(sna_pixmap(pixmap));
143.16855 + 	assert(sna_pixmap(pixmap)->header);
143.16856 + 
143.16857 +@@ -990,7 +1002,7 @@ fallback:
143.16858 + 	}
143.16859 + 	priv->cpu_bo->pitch = pitch;
143.16860 + 	kgem_bo_mark_unreusable(priv->cpu_bo);
143.16861 +-	sna_accel_watch_flush(sna, 1);
143.16862 ++	sna_shm_watch_flush(sna, 1);
143.16863 + #ifdef DEBUG_MEMORY
143.16864 + 	sna->debug_memory.cpu_bo_allocs++;
143.16865 + 	sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
143.16866 +@@ -1081,6 +1093,18 @@ sna_pixmap_create_scratch(ScreenPtr screen,
143.16867 + 	return pixmap;
143.16868 + }
143.16869 + 
143.16870 ++static unsigned small_copy(const RegionRec *region)
143.16871 ++{
143.16872 ++	if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) {
143.16873 ++		DBG(("%s: region:%dx%d\n", __FUNCTION__,
143.16874 ++		     (region->extents.x2 - region->extents.x1),
143.16875 ++		     (region->extents.y2 - region->extents.y1)));
143.16876 ++		return COPY_SMALL;
143.16877 ++	}
143.16878 ++
143.16879 ++	return 0;
143.16880 ++}
143.16881 ++
143.16882 + #ifdef CREATE_PIXMAP_USAGE_SHARED
143.16883 + static Bool
143.16884 + sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
143.16885 +@@ -1124,7 +1148,7 @@ sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
143.16886 + 				    pixmap->drawable.height,
143.16887 + 				    pixmap->drawable.bitsPerPixel,
143.16888 + 				    I915_TILING_NONE,
143.16889 +-				    CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
143.16890 ++				    CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
143.16891 + 		if (bo == NULL) {
143.16892 + 			DBG(("%s: allocation failed\n", __FUNCTION__));
143.16893 + 			return FALSE;
143.16894 +@@ -1243,7 +1267,7 @@ sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
143.16895 + 					      width, height,
143.16896 + 					      pixmap->drawable.bitsPerPixel,
143.16897 + 					      I915_TILING_NONE,
143.16898 +-					      CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
143.16899 ++					      CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
143.16900 + 		if (priv->gpu_bo == NULL) {
143.16901 + 			free(priv);
143.16902 + 			FreePixmap(pixmap);
143.16903 +@@ -1311,7 +1335,7 @@ static PixmapPtr sna_create_pixmap(ScreenPtr screen,
143.16904 + 
143.16905 + 	if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
143.16906 + 		flags &= ~KGEM_CAN_CREATE_GPU;
143.16907 +-	if (wedged(sna))
143.16908 ++	if (wedged(sna) && usage != SNA_CREATE_FB)
143.16909 + 		flags &= ~KGEM_CAN_CREATE_GTT;
143.16910 + 
143.16911 + 	DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags));
143.16912 +@@ -1417,10 +1441,13 @@ static void __sna_free_pixmap(struct sna *sna,
143.16913 + 	__sna_pixmap_free_cpu(sna, priv);
143.16914 + 
143.16915 + 	if (priv->flush)
143.16916 +-		sna_accel_watch_flush(sna, -1);
143.16917 ++		sna_watch_flush(sna, -1);
143.16918 + 
143.16919 ++#if !NDEBUG
143.16920 ++	pixmap->devKind = 0xdeadbeef;
143.16921 ++#endif
143.16922 + 	if (priv->header) {
143.16923 +-		assert(pixmap->drawable.pScreen == sna->scrn->pScreen);
143.16924 ++		assert(pixmap->drawable.pScreen == to_screen_from_sna(sna));
143.16925 + 		assert(!priv->shm);
143.16926 + 		pixmap->devPrivate.ptr = sna->freed_pixmap;
143.16927 + 		sna->freed_pixmap = pixmap;
143.16928 +@@ -1485,7 +1512,7 @@ static Bool sna_destroy_pixmap(PixmapPtr pixmap)
143.16929 + 	if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
143.16930 + 		DBG(("%s: deferring release of active SHM pixmap=%ld\n",
143.16931 + 		     __FUNCTION__, pixmap->drawable.serialNumber));
143.16932 +-		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.16933 ++		add_shm_flush(sna, priv);
143.16934 + 		kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */
143.16935 + 	} else
143.16936 + 		__sna_free_pixmap(sna, pixmap, priv);
143.16937 +@@ -1529,7 +1556,7 @@ static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, un
143.16938 + 		if (!priv->cpu_bo)
143.16939 + 			return true;
143.16940 + 
143.16941 +-		assert(!priv->cpu_bo->needs_flush);
143.16942 ++		assert(!priv->cpu_bo->needs_flush || (flags & MOVE_WRITE) == 0);
143.16943 + 		assert(priv->pixmap->devKind == priv->cpu_bo->pitch);
143.16944 + 		return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu);
143.16945 + 	}
143.16946 +@@ -1557,6 +1584,11 @@ static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, un
143.16947 + 		return true;
143.16948 + 	}
143.16949 + 
143.16950 ++	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__wc)) {
143.16951 ++		assert(priv->mapped == MAPPED_GTT);
143.16952 ++		return true;
143.16953 ++	}
143.16954 ++
143.16955 + 	return false;
143.16956 + }
143.16957 + 
143.16958 +@@ -1577,6 +1609,16 @@ static inline bool pixmap_inplace(struct sna *sna,
143.16959 + 		return false;
143.16960 + 
143.16961 + 	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
143.16962 ++		if (priv->clear) {
143.16963 ++			DBG(("%s: no, clear GPU bo is busy\n", __FUNCTION__));
143.16964 ++			return false;
143.16965 ++		}
143.16966 ++
143.16967 ++		if (flags & MOVE_ASYNC_HINT) {
143.16968 ++			DBG(("%s: no, async hint and GPU bo is busy\n", __FUNCTION__));
143.16969 ++			return false;
143.16970 ++		}
143.16971 ++
143.16972 + 		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
143.16973 + 			DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
143.16974 + 			return false;
143.16975 +@@ -1624,7 +1666,7 @@ static bool sna_pixmap_alloc_gpu(struct sna *sna,
143.16976 + 	if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) {
143.16977 + 		flags |= CREATE_SCANOUT;
143.16978 + 		tiling = kgem_choose_tiling(&sna->kgem,
143.16979 +-					    -I915_TILING_X,
143.16980 ++					    -DEFAULT_SCANOUT_TILING,
143.16981 + 					    pixmap->drawable.width,
143.16982 + 					    pixmap->drawable.height,
143.16983 + 					    pixmap->drawable.bitsPerPixel);
143.16984 +@@ -1861,7 +1903,9 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
143.16985 + 	assert(priv->gpu_bo == cow->bo);
143.16986 + 	assert(cow->refcnt);
143.16987 + 
143.16988 +-	if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow))
143.16989 ++	if (flags && /* flags == 0 => force decouple */
143.16990 ++	    (flags & MOVE_WRITE) == 0 &&
143.16991 ++	    (((flags & __MOVE_FORCE) == 0) || IS_COW_OWNER(priv->cow)))
143.16992 + 		return true;
143.16993 + 
143.16994 + 	if (!IS_COW_OWNER(priv->cow))
143.16995 +@@ -1933,7 +1977,7 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
143.16996 + 			box.y2 = pixmap->drawable.height;
143.16997 + 
143.16998 + 			if (flags & __MOVE_PRIME) {
143.16999 +-				create = CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
143.17000 ++				create = CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
143.17001 + 				tiling = I915_TILING_NONE;
143.17002 + 			} else {
143.17003 + 				create = 0;
143.17004 +@@ -2021,6 +2065,10 @@ sna_pixmap_make_cow(struct sna *sna,
143.17005 + 		     cow->bo->handle));
143.17006 + 
143.17007 + 		src_priv->cow = MAKE_COW_OWNER(cow);
143.17008 ++		if (src_priv->flush & FLUSH_WRITE) {
143.17009 ++			assert(!src_priv->shm);
143.17010 ++			sna_add_flush_pixmap(sna, src_priv, src_priv->gpu_bo);
143.17011 ++		}
143.17012 + 	}
143.17013 + 
143.17014 + 	if (cow == COW(dst_priv->cow)) {
143.17015 +@@ -2267,6 +2315,7 @@ skip_inplace_map:
143.17016 + 	    (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL &&
143.17017 + 	    priv->gpu_bo->tiling == I915_TILING_NONE &&
143.17018 + 	    (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
143.17019 ++	    (!priv->clear || !kgem_bo_is_busy(priv->gpu_bo)) &&
143.17020 + 	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
143.17021 + 	     (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) {
143.17022 + 		void *ptr;
143.17023 +@@ -2330,7 +2379,9 @@ skip_inplace_map:
143.17024 + 			     pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
143.17025 + 
143.17026 + 			if (priv->cpu_bo) {
143.17027 ++				kgem_bo_undo(&sna->kgem, priv->cpu_bo);
143.17028 + 				if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
143.17029 ++				    sna->kgem.can_blt_cpu &&
143.17030 + 				    sna->render.fill_one(sna,
143.17031 + 							  pixmap, priv->cpu_bo, priv->clear_color,
143.17032 + 							  0, 0,
143.17033 +@@ -2344,21 +2395,26 @@ skip_inplace_map:
143.17034 + 				assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
143.17035 + 			}
143.17036 + 
143.17037 +-			assert(pixmap->devKind);
143.17038 +-			if (priv->clear_color == 0 ||
143.17039 +-			    pixmap->drawable.bitsPerPixel == 8 ||
143.17040 +-			    priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
143.17041 +-				memset(pixmap->devPrivate.ptr, priv->clear_color,
143.17042 +-				       (size_t)pixmap->devKind * pixmap->drawable.height);
143.17043 +-			} else {
143.17044 +-				pixman_fill(pixmap->devPrivate.ptr,
143.17045 +-					    pixmap->devKind/sizeof(uint32_t),
143.17046 +-					    pixmap->drawable.bitsPerPixel,
143.17047 +-					    0, 0,
143.17048 +-					    pixmap->drawable.width,
143.17049 +-					    pixmap->drawable.height,
143.17050 +-					    priv->clear_color);
143.17051 +-			}
143.17052 ++			if (sigtrap_get() == 0) {
143.17053 ++				assert(pixmap->devKind);
143.17054 ++				sigtrap_assert_active();
143.17055 ++				if (priv->clear_color == 0 ||
143.17056 ++				    pixmap->drawable.bitsPerPixel == 8 ||
143.17057 ++				    priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
143.17058 ++					memset(pixmap->devPrivate.ptr, priv->clear_color,
143.17059 ++					       (size_t)pixmap->devKind * pixmap->drawable.height);
143.17060 ++				} else {
143.17061 ++					pixman_fill(pixmap->devPrivate.ptr,
143.17062 ++						    pixmap->devKind/sizeof(uint32_t),
143.17063 ++						    pixmap->drawable.bitsPerPixel,
143.17064 ++						    0, 0,
143.17065 ++						    pixmap->drawable.width,
143.17066 ++						    pixmap->drawable.height,
143.17067 ++						    priv->clear_color);
143.17068 ++				}
143.17069 ++				sigtrap_put();
143.17070 ++			} else
143.17071 ++				return false;
143.17072 + 
143.17073 + clear_done:
143.17074 + 			sna_damage_all(&priv->cpu_damage, pixmap);
143.17075 +@@ -2414,6 +2470,10 @@ done:
143.17076 + 			DBG(("%s: discarding idle GPU bo\n", __FUNCTION__));
143.17077 + 			sna_pixmap_free_gpu(sna, priv);
143.17078 + 		}
143.17079 ++		if (priv->flush) {
143.17080 ++			assert(!priv->shm);
143.17081 ++			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
143.17082 ++		}
143.17083 + 		priv->source_count = SOURCE_BIAS;
143.17084 + 	}
143.17085 + 
143.17086 +@@ -2531,6 +2591,9 @@ static bool cpu_clear_boxes(struct sna *sna,
143.17087 + {
143.17088 + 	struct sna_fill_op fill;
143.17089 + 
143.17090 ++	if (!sna->kgem.can_blt_cpu)
143.17091 ++		return false;
143.17092 ++
143.17093 + 	if (!sna_fill_init_blt(&fill, sna,
143.17094 + 			       pixmap, priv->cpu_bo,
143.17095 + 			       GXcopy, priv->clear_color,
143.17096 +@@ -2659,6 +2722,10 @@ sna_drawable_move_region_to_cpu(DrawablePtr drawable,
143.17097 + 					}
143.17098 + 				}
143.17099 + 				sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
143.17100 ++				if (priv->flush) {
143.17101 ++					assert(!priv->shm);
143.17102 ++					sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
143.17103 ++				}
143.17104 + 
143.17105 + 				if (dx | dy)
143.17106 + 					RegionTranslate(region, -dx, -dy);
143.17107 +@@ -2904,17 +2971,22 @@ move_to_cpu:
143.17108 + 			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
143.17109 + 		}
143.17110 + 
143.17111 +-		assert(pixmap->devKind);
143.17112 +-		do {
143.17113 +-			pixman_fill(pixmap->devPrivate.ptr,
143.17114 +-				    pixmap->devKind/sizeof(uint32_t),
143.17115 +-				    pixmap->drawable.bitsPerPixel,
143.17116 +-				    box->x1, box->y1,
143.17117 +-				    box->x2 - box->x1,
143.17118 +-				    box->y2 - box->y1,
143.17119 +-				    priv->clear_color);
143.17120 +-			box++;
143.17121 +-		} while (--n);
143.17122 ++		if (sigtrap_get() == 0) {
143.17123 ++			assert(pixmap->devKind);
143.17124 ++			sigtrap_assert_active();
143.17125 ++			do {
143.17126 ++				pixman_fill(pixmap->devPrivate.ptr,
143.17127 ++					    pixmap->devKind/sizeof(uint32_t),
143.17128 ++					    pixmap->drawable.bitsPerPixel,
143.17129 ++					    box->x1, box->y1,
143.17130 ++					    box->x2 - box->x1,
143.17131 ++					    box->y2 - box->y1,
143.17132 ++					    priv->clear_color);
143.17133 ++				box++;
143.17134 ++			} while (--n);
143.17135 ++			sigtrap_put();
143.17136 ++		} else
143.17137 ++			return false;
143.17138 + 
143.17139 + clear_done:
143.17140 + 		if (flags & MOVE_WRITE ||
143.17141 +@@ -3209,13 +3281,14 @@ __sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
143.17142 + {
143.17143 + 	struct sna_pixmap *priv;
143.17144 + 
143.17145 ++	assert(flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE));
143.17146 + 	if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
143.17147 + 		return NULL;
143.17148 + 
143.17149 + 	priv = sna_pixmap(pixmap);
143.17150 + 	if (priv == NULL) {
143.17151 + 		DBG(("%s: not attached\n", __FUNCTION__));
143.17152 +-		if ((flags & __MOVE_DRI) == 0)
143.17153 ++		if ((flags & (__MOVE_DRI | __MOVE_SCANOUT)) == 0)
143.17154 + 			return NULL;
143.17155 + 
143.17156 + 		if (pixmap->usage_hint == -1) {
143.17157 +@@ -3238,6 +3311,44 @@ __sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
143.17158 + 	return priv;
143.17159 + }
143.17160 + 
143.17161 ++inline static void sna_pixmap_unclean(struct sna *sna,
143.17162 ++				      struct sna_pixmap *priv,
143.17163 ++				      unsigned flags)
143.17164 ++{
143.17165 ++	struct drm_i915_gem_busy busy;
143.17166 ++
143.17167 ++	assert(DAMAGE_IS_ALL(priv->gpu_damage));
143.17168 ++	assert(priv->gpu_bo);
143.17169 ++	assert(priv->gpu_bo->proxy == NULL);
143.17170 ++	assert_pixmap_map(priv->pixmap, priv);
143.17171 ++
143.17172 ++	sna_damage_destroy(&priv->cpu_damage);
143.17173 ++	list_del(&priv->flush_list);
143.17174 ++
143.17175 ++	if (flags & (__MOVE_DRI | __MOVE_SCANOUT))
143.17176 ++		return;
143.17177 ++
143.17178 ++	if (!priv->flush || priv->gpu_bo->exec)
143.17179 ++		return;
143.17180 ++
143.17181 ++	busy.handle = priv->gpu_bo->handle;
143.17182 ++	busy.busy = 0;
143.17183 ++	ioctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
143.17184 ++
143.17185 ++	DBG(("%s(pixmap=%ld): cleaning foreign bo handle=%u, busy=%x [ring=%d]\n",
143.17186 ++	     __FUNCTION__,
143.17187 ++	     priv->pixmap->drawable.serialNumber,
143.17188 ++	     busy.handle, busy.busy, !!(busy.busy & (0xfffe << 16))));
143.17189 ++
143.17190 ++	if (busy.busy) {
143.17191 ++		unsigned mode = KGEM_RENDER;
143.17192 ++		if (busy.busy & (0xfffe << 16))
143.17193 ++			mode = KGEM_BLT;
143.17194 ++		kgem_bo_mark_busy(&sna->kgem, priv->gpu_bo, mode);
143.17195 ++	} else
143.17196 ++		__kgem_bo_clear_busy(priv->gpu_bo);
143.17197 ++}
143.17198 ++
143.17199 + struct sna_pixmap *
143.17200 + sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
143.17201 + {
143.17202 +@@ -3287,12 +3398,14 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
143.17203 + 	if (priv->cow) {
143.17204 + 		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
143.17205 + 
143.17206 ++		assert(cow);
143.17207 ++
143.17208 + 		if ((flags & MOVE_READ) == 0) {
143.17209 + 			if (priv->gpu_damage) {
143.17210 + 				r.extents = *box;
143.17211 + 				r.data = NULL;
143.17212 + 				if (!region_subsumes_damage(&r, priv->gpu_damage))
143.17213 +-					cow |= MOVE_READ;
143.17214 ++					cow |= MOVE_READ | __MOVE_FORCE;
143.17215 + 			}
143.17216 + 		} else {
143.17217 + 			if (priv->cpu_damage) {
143.17218 +@@ -3303,22 +3416,18 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
143.17219 + 			}
143.17220 + 		}
143.17221 + 
143.17222 +-		if (cow) {
143.17223 +-			if (!sna_pixmap_undo_cow(sna, priv, cow))
143.17224 +-				return NULL;
143.17225 ++		if (!sna_pixmap_undo_cow(sna, priv, cow))
143.17226 ++			return NULL;
143.17227 + 
143.17228 +-			if (priv->gpu_bo == NULL)
143.17229 +-				sna_damage_destroy(&priv->gpu_damage);
143.17230 +-		}
143.17231 ++		if (priv->gpu_bo == NULL)
143.17232 ++			sna_damage_destroy(&priv->gpu_damage);
143.17233 + 	}
143.17234 + 
143.17235 + 	if (sna_damage_is_all(&priv->gpu_damage,
143.17236 + 			      pixmap->drawable.width,
143.17237 + 			      pixmap->drawable.height)) {
143.17238 +-		assert(priv->gpu_bo);
143.17239 +-		assert(priv->gpu_bo->proxy == NULL);
143.17240 +-		sna_damage_destroy(&priv->cpu_damage);
143.17241 +-		list_del(&priv->flush_list);
143.17242 ++		DBG(("%s: already all-damaged\n", __FUNCTION__));
143.17243 ++		sna_pixmap_unclean(sna, priv, flags);
143.17244 + 		goto done;
143.17245 + 	}
143.17246 + 
143.17247 +@@ -3360,10 +3469,7 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
143.17248 + 		return priv;
143.17249 + 	}
143.17250 + 
143.17251 +-	if (priv->shm) {
143.17252 +-		assert(!priv->flush);
143.17253 +-		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.17254 +-	}
143.17255 ++	add_shm_flush(sna, priv);
143.17256 + 
143.17257 + 	assert(priv->cpu_damage);
143.17258 + 	region_set(&r, box);
143.17259 +@@ -3527,7 +3633,8 @@ sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
143.17260 + 	}
143.17261 + 
143.17262 + 	if (priv->cow) {
143.17263 +-		unsigned cow = MOVE_WRITE | MOVE_READ;
143.17264 ++		unsigned cow = MOVE_WRITE | MOVE_READ | __MOVE_FORCE;
143.17265 ++		assert(cow);
143.17266 + 
143.17267 + 		if (flags & IGNORE_DAMAGE) {
143.17268 + 			if (priv->gpu_damage) {
143.17269 +@@ -3717,8 +3824,11 @@ create_gpu_bo:
143.17270 + 				else
143.17271 + 					move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
143.17272 + 
143.17273 +-				if (sna_pixmap_move_to_gpu(pixmap, move))
143.17274 ++				if (sna_pixmap_move_to_gpu(pixmap, move)) {
143.17275 ++					sna_damage_all(&priv->gpu_damage,
143.17276 ++						       pixmap);
143.17277 + 					goto use_gpu_bo;
143.17278 ++				}
143.17279 + 			}
143.17280 + 
143.17281 + 			if (DAMAGE_IS_ALL(priv->gpu_damage) ||
143.17282 +@@ -3934,26 +4044,28 @@ prefer_gpu_bo:
143.17283 + 			goto move_to_gpu;
143.17284 + 		}
143.17285 + 
143.17286 +-		if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
143.17287 +-			if (priv->gpu_bo && priv->gpu_bo->tiling) {
143.17288 +-				DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
143.17289 +-				goto prefer_gpu_bo;
143.17290 ++		if (!priv->shm) {
143.17291 ++			if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
143.17292 ++				if (priv->gpu_bo && priv->gpu_bo->tiling) {
143.17293 ++					DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
143.17294 ++					goto prefer_gpu_bo;
143.17295 ++				}
143.17296 ++
143.17297 ++				if (priv->cpu_bo->pitch >= 4096) {
143.17298 ++					DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
143.17299 ++					goto prefer_gpu_bo;
143.17300 ++				}
143.17301 + 			}
143.17302 + 
143.17303 +-			if (priv->cpu_bo->pitch >= 4096) {
143.17304 +-				DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
143.17305 ++			if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
143.17306 ++				DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
143.17307 + 				goto prefer_gpu_bo;
143.17308 + 			}
143.17309 +-		}
143.17310 +-
143.17311 +-		if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
143.17312 +-			DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
143.17313 +-			goto prefer_gpu_bo;
143.17314 +-		}
143.17315 + 
143.17316 +-		if (!sna->kgem.can_blt_cpu) {
143.17317 +-			DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
143.17318 +-			goto prefer_gpu_bo;
143.17319 ++			if (!sna->kgem.can_blt_cpu) {
143.17320 ++				DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
143.17321 ++				goto prefer_gpu_bo;
143.17322 ++			}
143.17323 + 		}
143.17324 + 	}
143.17325 + 
143.17326 +@@ -3967,9 +4079,7 @@ prefer_gpu_bo:
143.17327 + 	}
143.17328 + 
143.17329 + 	if (priv->shm) {
143.17330 +-		assert(!priv->flush);
143.17331 +-		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.17332 +-
143.17333 ++		add_shm_flush(sna, priv);
143.17334 + 		/* As we may have flushed and retired,, recheck for busy bo */
143.17335 + 		if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo))
143.17336 + 			return NULL;
143.17337 +@@ -4019,7 +4129,7 @@ sna_pixmap_create_upload(ScreenPtr screen,
143.17338 + 	assert(width);
143.17339 + 	assert(height);
143.17340 + 
143.17341 +-	if (depth == 1)
143.17342 ++	if (depth < 8)
143.17343 + 		return create_pixmap(sna, screen, width, height, depth,
143.17344 + 				     CREATE_PIXMAP_USAGE_SCRATCH);
143.17345 + 
143.17346 +@@ -4121,27 +4231,21 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
143.17347 + 
143.17348 + 	if (priv->cow) {
143.17349 + 		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
143.17350 ++		assert(cow);
143.17351 + 		if (flags & MOVE_READ && priv->cpu_damage)
143.17352 + 			cow |= MOVE_WRITE;
143.17353 +-		if (cow) {
143.17354 +-			if (!sna_pixmap_undo_cow(sna, priv, cow))
143.17355 +-				return NULL;
143.17356 ++		if (!sna_pixmap_undo_cow(sna, priv, cow))
143.17357 ++			return NULL;
143.17358 + 
143.17359 +-			if (priv->gpu_bo == NULL)
143.17360 +-				sna_damage_destroy(&priv->gpu_damage);
143.17361 +-		}
143.17362 ++		if (priv->gpu_bo == NULL)
143.17363 ++			sna_damage_destroy(&priv->gpu_damage);
143.17364 + 	}
143.17365 + 
143.17366 + 	if (sna_damage_is_all(&priv->gpu_damage,
143.17367 + 			      pixmap->drawable.width,
143.17368 + 			      pixmap->drawable.height)) {
143.17369 + 		DBG(("%s: already all-damaged\n", __FUNCTION__));
143.17370 +-		assert(DAMAGE_IS_ALL(priv->gpu_damage));
143.17371 +-		assert(priv->gpu_bo);
143.17372 +-		assert(priv->gpu_bo->proxy == NULL);
143.17373 +-		assert_pixmap_map(pixmap, priv);
143.17374 +-		sna_damage_destroy(&priv->cpu_damage);
143.17375 +-		list_del(&priv->flush_list);
143.17376 ++		sna_pixmap_unclean(sna, priv, flags);
143.17377 + 		goto active;
143.17378 + 	}
143.17379 + 
143.17380 +@@ -4206,7 +4310,7 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
143.17381 + 				if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
143.17382 + 					create = CREATE_GTT_MAP | CREATE_INACTIVE;
143.17383 + 				if (flags & __MOVE_PRIME)
143.17384 +-					create |= CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
143.17385 ++					create |= CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
143.17386 + 
143.17387 + 				sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
143.17388 + 			}
143.17389 +@@ -4282,10 +4386,7 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
143.17390 + 		goto done;
143.17391 + 	}
143.17392 + 
143.17393 +-	if (priv->shm) {
143.17394 +-		assert(!priv->flush);
143.17395 +-		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.17396 +-	}
143.17397 ++	add_shm_flush(sna, priv);
143.17398 + 
143.17399 + 	n = sna_damage_get_boxes(priv->cpu_damage, &box);
143.17400 + 	assert(n);
143.17401 +@@ -4534,7 +4635,7 @@ static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr
143.17402 + 	return box32_clip(box, gc);
143.17403 + }
143.17404 + 
143.17405 +-static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
143.17406 ++static inline void box_add_xy(BoxPtr box, int16_t x, int16_t y)
143.17407 + {
143.17408 + 	if (box->x1 > x)
143.17409 + 		box->x1 = x;
143.17410 +@@ -4547,6 +4648,11 @@ static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
143.17411 + 		box->y2 = y;
143.17412 + }
143.17413 + 
143.17414 ++static inline void box_add_pt(BoxPtr box, const DDXPointRec *pt)
143.17415 ++{
143.17416 ++	box_add_xy(box, pt->x, pt->y);
143.17417 ++}
143.17418 ++
143.17419 + static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
143.17420 + {
143.17421 + 	b16->x1 = b32->x1;
143.17422 +@@ -4864,6 +4970,7 @@ try_upload__inplace(PixmapPtr pixmap, RegionRec *region,
143.17423 + 	pixmap->devPrivate.ptr = dst;
143.17424 + 	pixmap->devKind = priv->gpu_bo->pitch;
143.17425 + 	priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
143.17426 ++	priv->cpu &= priv->mapped == MAPPED_CPU;
143.17427 + 	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
143.17428 + 
143.17429 + 	box = region_rects(region);
143.17430 +@@ -4923,8 +5030,7 @@ done:
143.17431 + 			sna_damage_all(&priv->gpu_damage, pixmap);
143.17432 + 		}
143.17433 + 
143.17434 +-		if (priv->shm)
143.17435 +-			sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.17436 ++		add_shm_flush(sna, priv);
143.17437 + 	}
143.17438 + 
143.17439 + 	assert(!priv->clear);
143.17440 +@@ -5172,6 +5278,16 @@ static inline uint8_t blt_depth(int depth)
143.17441 + 	}
143.17442 + }
143.17443 + 
143.17444 ++inline static void blt_done(struct sna *sna)
143.17445 ++{
143.17446 ++	sna->blt_state.fill_bo = 0;
143.17447 ++	if (sna->kgem.nbatch && __kgem_ring_empty(&sna->kgem)) {
143.17448 ++		DBG(("%s: flushing BLT operation on empty ring\n",
143.17449 ++		     __FUNCTION__));
143.17450 ++		_kgem_submit(&sna->kgem);
143.17451 ++	}
143.17452 ++}
143.17453 ++
143.17454 + static bool
143.17455 + sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
143.17456 + 		     int x, int y, int w, int  h, char *bits)
143.17457 +@@ -5217,6 +5333,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
143.17458 + 
143.17459 + 	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
143.17460 + 	assert(kgem_bo_can_blt(&sna->kgem, bo));
143.17461 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.17462 + 
143.17463 + 	/* Region is pre-clipped and translated into pixmap space */
143.17464 + 	box = region_rects(region);
143.17465 +@@ -5238,6 +5355,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
143.17466 + 				return false;
143.17467 + 			_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.17468 + 		}
143.17469 ++		kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.17470 + 
143.17471 + 		upload = kgem_create_buffer(&sna->kgem,
143.17472 + 					    bstride*bh,
143.17473 +@@ -5331,7 +5449,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
143.17474 + 		box++;
143.17475 + 	} while (--n);
143.17476 + 
143.17477 +-	sna->blt_state.fill_bo = 0;
143.17478 ++	blt_done(sna);
143.17479 + 	return true;
143.17480 + }
143.17481 + 
143.17482 +@@ -5381,6 +5499,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
143.17483 + 
143.17484 + 	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
143.17485 + 	assert(kgem_bo_can_blt(&sna->kgem, bo));
143.17486 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.17487 + 
143.17488 + 	skip = h * BitmapBytePad(w + left);
143.17489 + 	for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
143.17490 +@@ -5408,6 +5527,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
143.17491 + 					return false;
143.17492 + 				_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.17493 + 			}
143.17494 ++			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.17495 + 
143.17496 + 			upload = kgem_create_buffer(&sna->kgem,
143.17497 + 						    bstride*bh,
143.17498 +@@ -5509,7 +5629,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
143.17499 + 		} while (--n);
143.17500 + 	}
143.17501 + 
143.17502 +-	sna->blt_state.fill_bo = 0;
143.17503 ++	blt_done(sna);
143.17504 + 	return true;
143.17505 + }
143.17506 + 
143.17507 +@@ -5837,7 +5957,7 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
143.17508 + 		if (!sna->render.copy_boxes(sna, alu,
143.17509 + 					    &pixmap->drawable, priv->gpu_bo, sx, sy,
143.17510 + 					    &pixmap->drawable, priv->gpu_bo, tx, ty,
143.17511 +-					    box, n, 0)) {
143.17512 ++					    box, n, small_copy(region))) {
143.17513 + 			DBG(("%s: fallback - accelerated copy boxes failed\n",
143.17514 + 			     __FUNCTION__));
143.17515 + 			goto fallback;
143.17516 +@@ -6098,6 +6218,9 @@ sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
143.17517 + 
143.17518 + 	kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
143.17519 + 
143.17520 ++	if (sigtrap_get())
143.17521 ++		return false;
143.17522 ++
143.17523 + 	box = region_rects(region);
143.17524 + 	n = region_num_rects(region);
143.17525 + 	if (src_priv->gpu_bo->tiling) {
143.17526 +@@ -6137,6 +6260,8 @@ sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
143.17527 + 		}
143.17528 + 	}
143.17529 + 
143.17530 ++	sigtrap_put();
143.17531 ++
143.17532 + 	return true;
143.17533 + 
143.17534 + upload_inplace:
143.17535 +@@ -6234,6 +6359,9 @@ upload_inplace:
143.17536 + 
143.17537 + 	assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
143.17538 + 
143.17539 ++	if (sigtrap_get())
143.17540 ++		return false;
143.17541 ++
143.17542 + 	box = region_rects(region);
143.17543 + 	n = region_num_rects(region);
143.17544 + 	if (dst_priv->gpu_bo->tiling) {
143.17545 +@@ -6265,15 +6393,19 @@ upload_inplace:
143.17546 + 		} while (--n);
143.17547 + 
143.17548 + 		if (!dst_priv->shm) {
143.17549 +-			assert(ptr == MAP(dst_priv->gpu_bo->map__cpu));
143.17550 + 			dst_pixmap->devPrivate.ptr = ptr;
143.17551 + 			dst_pixmap->devKind = dst_priv->gpu_bo->pitch;
143.17552 +-			dst_priv->mapped = MAPPED_CPU;
143.17553 ++			if (ptr == MAP(dst_priv->gpu_bo->map__cpu)) {
143.17554 ++				dst_priv->mapped = MAPPED_CPU;
143.17555 ++				dst_priv->cpu = true;
143.17556 ++			} else
143.17557 ++				dst_priv->mapped = MAPPED_GTT;
143.17558 + 			assert_pixmap_map(dst_pixmap, dst_priv);
143.17559 +-			dst_priv->cpu = true;
143.17560 + 		}
143.17561 + 	}
143.17562 + 
143.17563 ++	sigtrap_put();
143.17564 ++
143.17565 + 	return true;
143.17566 + }
143.17567 + 
143.17568 +@@ -6326,6 +6458,16 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
143.17569 + 
143.17570 + 	assert(region_num_rects(region));
143.17571 + 
143.17572 ++	if (src_priv &&
143.17573 ++	    src_priv->gpu_bo == NULL &&
143.17574 ++	    src_priv->cpu_bo == NULL &&
143.17575 ++	    src_priv->ptr == NULL) {
143.17576 ++		/* Rare but still happens, nothing to copy */
143.17577 ++		DBG(("%s: src pixmap=%ld is empty\n",
143.17578 ++		     __FUNCTION__, src_pixmap->drawable.serialNumber));
143.17579 ++		return;
143.17580 ++	}
143.17581 ++
143.17582 + 	if (src_pixmap == dst_pixmap)
143.17583 + 		return sna_self_copy_boxes(src, dst, gc,
143.17584 + 					   region, dx, dy,
143.17585 +@@ -6491,15 +6633,14 @@ discard_cow:
143.17586 + 					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
143.17587 + 					sna_damage_destroy(&dst_priv->cpu_damage);
143.17588 + 					list_del(&dst_priv->flush_list);
143.17589 +-					if (dst_priv->shm)
143.17590 +-						sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo);
143.17591 ++					add_shm_flush(sna, dst_priv);
143.17592 + 					return;
143.17593 + 				}
143.17594 + 			}
143.17595 + 			if (!sna->render.copy_boxes(sna, alu,
143.17596 + 						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
143.17597 + 						    &dst_pixmap->drawable, bo, 0, 0,
143.17598 +-						    box, n, 0)) {
143.17599 ++						    box, n, small_copy(region))) {
143.17600 + 				DBG(("%s: fallback - accelerated copy boxes failed\n",
143.17601 + 				     __FUNCTION__));
143.17602 + 				goto fallback;
143.17603 +@@ -6536,7 +6677,7 @@ discard_cow:
143.17604 + 			if (!sna->render.copy_boxes(sna, alu,
143.17605 + 						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
143.17606 + 						    &dst_pixmap->drawable, bo, 0, 0,
143.17607 +-						    box, n, 0)) {
143.17608 ++						    box, n, small_copy(region))) {
143.17609 + 				DBG(("%s: fallback - accelerated copy boxes failed\n",
143.17610 + 				     __FUNCTION__));
143.17611 + 				goto fallback;
143.17612 +@@ -6571,15 +6712,12 @@ discard_cow:
143.17613 + 			if (replaces && UNDO)
143.17614 + 				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
143.17615 + 
143.17616 +-			if (src_priv->shm) {
143.17617 +-				assert(!src_priv->flush);
143.17618 +-				sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo);
143.17619 +-			}
143.17620 ++			add_shm_flush(sna, src_priv);
143.17621 + 
143.17622 + 			if (!sna->render.copy_boxes(sna, alu,
143.17623 + 						    &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy,
143.17624 + 						    &dst_pixmap->drawable, bo, 0, 0,
143.17625 +-						    box, n, src_priv->shm ? COPY_LAST : 0)) {
143.17626 ++						    box, n, small_copy(region) | (src_priv->shm ? COPY_LAST : 0))) {
143.17627 + 				DBG(("%s: fallback - accelerated copy boxes failed\n",
143.17628 + 				     __FUNCTION__));
143.17629 + 				goto fallback;
143.17630 +@@ -6631,8 +6769,7 @@ discard_cow:
143.17631 + 				ok = sna->render.copy_boxes(sna, alu,
143.17632 + 							    &src_pixmap->drawable, src_bo, src_dx, src_dy,
143.17633 + 							    &dst_pixmap->drawable, bo, 0, 0,
143.17634 +-							    box, n, COPY_LAST);
143.17635 +-
143.17636 ++							    box, n, small_copy(region) |  COPY_LAST);
143.17637 + 				kgem_bo_sync__cpu(&sna->kgem, src_bo);
143.17638 + 				assert(src_bo->rq == NULL);
143.17639 + 				kgem_bo_destroy(&sna->kgem, src_bo);
143.17640 +@@ -6780,18 +6917,22 @@ fallback:
143.17641 + 				return;
143.17642 + 		}
143.17643 + 
143.17644 +-		assert(dst_pixmap->devPrivate.ptr);
143.17645 +-		assert(dst_pixmap->devKind);
143.17646 +-		do {
143.17647 +-			pixman_fill(dst_pixmap->devPrivate.ptr,
143.17648 +-				    dst_pixmap->devKind/sizeof(uint32_t),
143.17649 +-				    dst_pixmap->drawable.bitsPerPixel,
143.17650 +-				    box->x1, box->y1,
143.17651 +-				    box->x2 - box->x1,
143.17652 +-				    box->y2 - box->y1,
143.17653 +-				    src_priv->clear_color);
143.17654 +-			box++;
143.17655 +-		} while (--n);
143.17656 ++		if (sigtrap_get() == 0) {
143.17657 ++			assert(dst_pixmap->devPrivate.ptr);
143.17658 ++			assert(dst_pixmap->devKind);
143.17659 ++			sigtrap_assert_active();
143.17660 ++			do {
143.17661 ++				pixman_fill(dst_pixmap->devPrivate.ptr,
143.17662 ++					    dst_pixmap->devKind/sizeof(uint32_t),
143.17663 ++					    dst_pixmap->drawable.bitsPerPixel,
143.17664 ++					    box->x1, box->y1,
143.17665 ++					    box->x2 - box->x1,
143.17666 ++					    box->y2 - box->y1,
143.17667 ++					    src_priv->clear_color);
143.17668 ++				box++;
143.17669 ++			} while (--n);
143.17670 ++			sigtrap_put();
143.17671 ++		}
143.17672 + 	} else if (!sna_copy_boxes__inplace(sna, region, alu,
143.17673 + 					    src_pixmap, src_priv,
143.17674 + 					    src_dx, src_dy,
143.17675 +@@ -6848,36 +6989,39 @@ fallback:
143.17676 + 				((char *)src_pixmap->devPrivate.ptr +
143.17677 + 				 src_dy * src_stride + src_dx * bpp / 8);
143.17678 + 
143.17679 +-			do {
143.17680 +-				DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
143.17681 +-				     __FUNCTION__,
143.17682 +-				     box->x1, box->y1,
143.17683 +-				     box->x2 - box->x1,
143.17684 +-				     box->y2 - box->y1,
143.17685 +-				     src_dx, src_dy,
143.17686 +-				     src_stride, dst_stride));
143.17687 +-
143.17688 +-				assert(box->x1 >= 0);
143.17689 +-				assert(box->y1 >= 0);
143.17690 +-				assert(box->x2 <= dst_pixmap->drawable.width);
143.17691 +-				assert(box->y2 <= dst_pixmap->drawable.height);
143.17692 +-
143.17693 +-				assert(box->x1 + src_dx >= 0);
143.17694 +-				assert(box->y1 + src_dy >= 0);
143.17695 +-				assert(box->x2 + src_dx <= src_pixmap->drawable.width);
143.17696 +-				assert(box->y2 + src_dy <= src_pixmap->drawable.height);
143.17697 +-				assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
143.17698 +-				assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
143.17699 +-				assert(src_stride);
143.17700 +-				assert(dst_stride);
143.17701 +-				memcpy_blt(src_bits, dst_bits, bpp,
143.17702 +-					   src_stride, dst_stride,
143.17703 +-					   box->x1, box->y1,
143.17704 +-					   box->x1, box->y1,
143.17705 +-					   box->x2 - box->x1,
143.17706 +-					   box->y2 - box->y1);
143.17707 +-				box++;
143.17708 +-			} while (--n);
143.17709 ++			if (sigtrap_get() == 0) {
143.17710 ++				do {
143.17711 ++					DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
143.17712 ++					     __FUNCTION__,
143.17713 ++					     box->x1, box->y1,
143.17714 ++					     box->x2 - box->x1,
143.17715 ++					     box->y2 - box->y1,
143.17716 ++					     src_dx, src_dy,
143.17717 ++					     src_stride, dst_stride));
143.17718 ++
143.17719 ++					assert(box->x1 >= 0);
143.17720 ++					assert(box->y1 >= 0);
143.17721 ++					assert(box->x2 <= dst_pixmap->drawable.width);
143.17722 ++					assert(box->y2 <= dst_pixmap->drawable.height);
143.17723 ++
143.17724 ++					assert(box->x1 + src_dx >= 0);
143.17725 ++					assert(box->y1 + src_dy >= 0);
143.17726 ++					assert(box->x2 + src_dx <= src_pixmap->drawable.width);
143.17727 ++					assert(box->y2 + src_dy <= src_pixmap->drawable.height);
143.17728 ++					assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
143.17729 ++					assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
143.17730 ++					assert(src_stride);
143.17731 ++					assert(dst_stride);
143.17732 ++					memcpy_blt(src_bits, dst_bits, bpp,
143.17733 ++						   src_stride, dst_stride,
143.17734 ++						   box->x1, box->y1,
143.17735 ++						   box->x1, box->y1,
143.17736 ++						   box->x2 - box->x1,
143.17737 ++						   box->y2 - box->y1);
143.17738 ++					box++;
143.17739 ++				} while (--n);
143.17740 ++				sigtrap_put();
143.17741 ++			}
143.17742 + 		} else {
143.17743 + 			DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
143.17744 + 
143.17745 +@@ -6931,7 +7075,8 @@ sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
143.17746 + 
143.17747 + 	/* Short cut for unmapped windows */
143.17748 + 	if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
143.17749 +-		DBG(("%s: unmapped\n", __FUNCTION__));
143.17750 ++		DBG(("%s: unmapped/unrealized dst (pixmap=%ld)\n",
143.17751 ++		     __FUNCTION__, get_window_pixmap((WindowPtr)dst)));
143.17752 + 		return NULL;
143.17753 + 	}
143.17754 + 
143.17755 +@@ -7115,19 +7260,28 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
143.17756 + 	if (gc->planemask == 0)
143.17757 + 		return NULL;
143.17758 + 
143.17759 +-	DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
143.17760 ++	if (sna->ignore_copy_area)
143.17761 ++		return NULL;
143.17762 ++
143.17763 ++	DBG(("%s: src=pixmap=%ld:(%d, %d)x(%d, %d)+(%d, %d) -> dst=pixmap=%ld:(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
143.17764 + 	     __FUNCTION__,
143.17765 ++	     get_drawable_pixmap(src)->drawable.serialNumber,
143.17766 + 	     src_x, src_y, width, height, src->x, src->y,
143.17767 ++	     get_drawable_pixmap(dst)->drawable.serialNumber,
143.17768 + 	     dst_x, dst_y, dst->x, dst->y,
143.17769 + 	     gc->alu, gc->planemask, gc->depth));
143.17770 + 
143.17771 + 	if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
143.17772 +-	    !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8)
143.17773 ++	    !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) {
143.17774 ++		DBG(("%s: fallback copy\n", __FUNCTION__));
143.17775 + 		copy = sna_fallback_copy_boxes;
143.17776 +-	else if (src == dst)
143.17777 ++	} else if (src == dst) {
143.17778 ++		DBG(("%s: self copy\n", __FUNCTION__));
143.17779 + 		copy = sna_self_copy_boxes;
143.17780 +-	else
143.17781 ++	} else {
143.17782 ++		DBG(("%s: normal copy\n", __FUNCTION__));
143.17783 + 		copy = sna_copy_boxes;
143.17784 ++	}
143.17785 + 
143.17786 + 	return sna_do_copy(src, dst, gc,
143.17787 + 			   src_x, src_y,
143.17788 +@@ -7136,30 +7290,21 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
143.17789 + 			   copy, 0, NULL);
143.17790 + }
143.17791 + 
143.17792 +-static const BoxRec *
143.17793 +-find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
143.17794 ++const BoxRec *
143.17795 ++__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
143.17796 + {
143.17797 +-    const BoxRec *mid;
143.17798 +-
143.17799 +-    if (end == begin)
143.17800 +-	return end;
143.17801 +-
143.17802 +-    if (end - begin == 1) {
143.17803 ++	assert(end - begin > 1);
143.17804 ++	do {
143.17805 ++		const BoxRec *mid = begin + (end - begin) / 2;
143.17806 ++		if (mid->y2 > y)
143.17807 ++			end = mid;
143.17808 ++		else
143.17809 ++			begin = mid;
143.17810 ++	} while (end > begin + 1);
143.17811 + 	if (begin->y2 > y)
143.17812 +-	    return begin;
143.17813 ++		return begin;
143.17814 + 	else
143.17815 +-	    return end;
143.17816 +-    }
143.17817 +-
143.17818 +-    mid = begin + (end - begin) / 2;
143.17819 +-    if (mid->y2 > y)
143.17820 +-	/* If no box is found in [begin, mid], the function
143.17821 +-	 * will return @mid, which is then known to be the
143.17822 +-	 * correct answer.
143.17823 +-	 */
143.17824 +-	return find_clip_box_for_y(begin, mid, y);
143.17825 +-    else
143.17826 +-	return find_clip_box_for_y(mid, end, y);
143.17827 ++		return end;
143.17828 + }
143.17829 + 
143.17830 + struct sna_fill_spans {
143.17831 +@@ -8223,6 +8368,8 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
143.17832 + 	}
143.17833 + 	br13 |= blt_depth(drawable->depth) << 24;
143.17834 + 	br13 |= copy_ROP[gc->alu] << 16;
143.17835 ++	DBG(("%s: target-depth=%d, alu=%d, bg=%08x, fg=%08x\n",
143.17836 ++	     __FUNCTION__, drawable->depth, gc->alu, gc->bgPixel, gc->fgPixel));
143.17837 + 
143.17838 + 	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
143.17839 + 	assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
143.17840 +@@ -8255,6 +8402,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
143.17841 + 					return; /* XXX fallback? */
143.17842 + 				_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.17843 + 			}
143.17844 ++			kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
143.17845 + 
143.17846 + 			assert(sna->kgem.mode == KGEM_BLT);
143.17847 + 			if (sna->kgem.gen >= 0100) {
143.17848 +@@ -8270,8 +8418,8 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
143.17849 + 							 I915_GEM_DOMAIN_RENDER |
143.17850 + 							 KGEM_RELOC_FENCED,
143.17851 + 							 0);
143.17852 +-				b[5] = gc->bgPixel;
143.17853 +-				b[6] = gc->fgPixel;
143.17854 ++				b[6] = gc->bgPixel;
143.17855 ++				b[7] = gc->fgPixel;
143.17856 + 
143.17857 + 				dst = (uint8_t *)&b[8];
143.17858 + 				sna->kgem.nbatch += 8 + src_stride;
143.17859 +@@ -8322,6 +8470,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
143.17860 + 					return; /* XXX fallback? */
143.17861 + 				_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.17862 + 			}
143.17863 ++			kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
143.17864 + 
143.17865 + 			upload = kgem_create_buffer(&sna->kgem,
143.17866 + 						    bstride*bh,
143.17867 +@@ -8408,7 +8557,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
143.17868 + 		sna_damage_add_to_pixmap(arg->damage, region, pixmap);
143.17869 + 	}
143.17870 + 	assert_pixmap_damage(pixmap);
143.17871 +-	sna->blt_state.fill_bo = 0;
143.17872 ++	blt_done(sna);
143.17873 + }
143.17874 + 
143.17875 + static void
143.17876 +@@ -8472,6 +8621,7 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
143.17877 + 				return; /* XXX fallback? */
143.17878 + 			_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.17879 + 		}
143.17880 ++		kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
143.17881 + 
143.17882 + 		upload = kgem_create_buffer(&sna->kgem,
143.17883 + 					    bstride*bh,
143.17884 +@@ -8588,6 +8738,8 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
143.17885 + 				}
143.17886 + 			}
143.17887 + 
143.17888 ++			kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo);
143.17889 ++
143.17890 + 			assert(sna->kgem.mode == KGEM_BLT);
143.17891 + 			b = sna->kgem.batch + sna->kgem.nbatch;
143.17892 + 			if (sna->kgem.gen >= 0100) {
143.17893 +@@ -8641,7 +8793,7 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
143.17894 + 		sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap);
143.17895 + 	}
143.17896 + 	assert_pixmap_damage(dst_pixmap);
143.17897 +-	sna->blt_state.fill_bo = 0;
143.17898 ++	blt_done(sna);
143.17899 + }
143.17900 + 
143.17901 + static RegionPtr
143.17902 +@@ -8895,36 +9047,11 @@ sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
143.17903 + 			last.x += pt->x;
143.17904 + 			last.y += pt->y;
143.17905 + 			pt++;
143.17906 +-			box_add_pt(&box, last.x, last.y);
143.17907 ++			box_add_xy(&box, last.x, last.y);
143.17908 + 		}
143.17909 + 	} else {
143.17910 +-		--n; ++pt;
143.17911 +-		while (n >= 8) {
143.17912 +-			box_add_pt(&box, pt[0].x, pt[0].y);
143.17913 +-			box_add_pt(&box, pt[1].x, pt[1].y);
143.17914 +-			box_add_pt(&box, pt[2].x, pt[2].y);
143.17915 +-			box_add_pt(&box, pt[3].x, pt[3].y);
143.17916 +-			box_add_pt(&box, pt[4].x, pt[4].y);
143.17917 +-			box_add_pt(&box, pt[5].x, pt[5].y);
143.17918 +-			box_add_pt(&box, pt[6].x, pt[6].y);
143.17919 +-			box_add_pt(&box, pt[7].x, pt[7].y);
143.17920 +-			pt += 8;
143.17921 +-			n -= 8;
143.17922 +-		}
143.17923 +-		if (n & 4) {
143.17924 +-			box_add_pt(&box, pt[0].x, pt[0].y);
143.17925 +-			box_add_pt(&box, pt[1].x, pt[1].y);
143.17926 +-			box_add_pt(&box, pt[2].x, pt[2].y);
143.17927 +-			box_add_pt(&box, pt[3].x, pt[3].y);
143.17928 +-			pt += 4;
143.17929 +-		}
143.17930 +-		if (n & 2) {
143.17931 +-			box_add_pt(&box, pt[0].x, pt[0].y);
143.17932 +-			box_add_pt(&box, pt[1].x, pt[1].y);
143.17933 +-			pt += 2;
143.17934 +-		}
143.17935 +-		if (n & 1)
143.17936 +-			box_add_pt(&box, pt[0].x, pt[0].y);
143.17937 ++		while (--n)
143.17938 ++			box_add_pt(&box, ++pt);
143.17939 + 	}
143.17940 + 	box.x2++;
143.17941 + 	box.y2++;
143.17942 +@@ -9636,7 +9763,7 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
143.17943 + 			y += pt->y;
143.17944 + 			if (blt)
143.17945 + 				blt &= pt->x == 0 || pt->y == 0;
143.17946 +-			box_add_pt(&box, x, y);
143.17947 ++			box_add_xy(&box, x, y);
143.17948 + 		}
143.17949 + 	} else {
143.17950 + 		int x = box.x1;
143.17951 +@@ -9648,7 +9775,7 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
143.17952 + 				x = pt->x;
143.17953 + 				y = pt->y;
143.17954 + 			}
143.17955 +-			box_add_pt(&box, pt->x, pt->y);
143.17956 ++			box_add_pt(&box, pt);
143.17957 + 		}
143.17958 + 	}
143.17959 + 	box.x2++;
143.17960 +@@ -10037,7 +10164,7 @@ out:
143.17961 + 	RegionUninit(&data.region);
143.17962 + }
143.17963 + 
143.17964 +-static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
143.17965 ++static inline bool box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
143.17966 + {
143.17967 + 	if (seg->x1 == seg->x2) {
143.17968 + 		if (seg->y1 > seg->y2) {
143.17969 +@@ -10051,6 +10178,9 @@ static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
143.17970 + 			if (gc->capStyle != CapNotLast)
143.17971 + 				b->y2++;
143.17972 + 		}
143.17973 ++		if (b->y1 >= b->y2)
143.17974 ++			return false;
143.17975 ++
143.17976 + 		b->x1 = seg->x1;
143.17977 + 		b->x2 = seg->x1 + 1;
143.17978 + 	} else {
143.17979 +@@ -10065,6 +10195,9 @@ static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
143.17980 + 			if (gc->capStyle != CapNotLast)
143.17981 + 				b->x2++;
143.17982 + 		}
143.17983 ++		if (b->x1 >= b->x2)
143.17984 ++			return false;
143.17985 ++
143.17986 + 		b->y1 = seg->y1;
143.17987 + 		b->y2 = seg->y1 + 1;
143.17988 + 	}
143.17989 +@@ -10073,6 +10206,7 @@ static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
143.17990 + 	     __FUNCTION__,
143.17991 + 	     seg->x1, seg->y1, seg->x2, seg->y2,
143.17992 + 	     b->x1, b->y1, b->x2, b->y2));
143.17993 ++	return true;
143.17994 + }
143.17995 + 
143.17996 + static bool
143.17997 +@@ -10107,12 +10241,13 @@ sna_poly_segment_blt(DrawablePtr drawable,
143.17998 + 					nbox = ARRAY_SIZE(boxes);
143.17999 + 				n -= nbox;
143.18000 + 				do {
143.18001 +-					box_from_seg(b, seg++, gc);
143.18002 +-					if (b->y2 > b->y1 && b->x2 > b->x1) {
143.18003 ++					if (box_from_seg(b, seg++, gc)) {
143.18004 ++						assert(!box_empty(b));
143.18005 + 						b->x1 += dx;
143.18006 + 						b->x2 += dx;
143.18007 + 						b->y1 += dy;
143.18008 + 						b->y2 += dy;
143.18009 ++						assert(!box_empty(b));
143.18010 + 						b++;
143.18011 + 					}
143.18012 + 				} while (--nbox);
143.18013 +@@ -10131,7 +10266,10 @@ sna_poly_segment_blt(DrawablePtr drawable,
143.18014 + 					nbox = ARRAY_SIZE(boxes);
143.18015 + 				n -= nbox;
143.18016 + 				do {
143.18017 +-					box_from_seg(b++, seg++, gc);
143.18018 ++					if (box_from_seg(b, seg++, gc)) {
143.18019 ++						assert(!box_empty(b));
143.18020 ++						b++;
143.18021 ++					}
143.18022 + 				} while (--nbox);
143.18023 + 
143.18024 + 				if (b != boxes) {
143.18025 +@@ -10156,7 +10294,10 @@ sna_poly_segment_blt(DrawablePtr drawable,
143.18026 + 			do {
143.18027 + 				BoxRec box;
143.18028 + 
143.18029 +-				box_from_seg(&box, seg++, gc);
143.18030 ++				if (!box_from_seg(&box, seg++, gc))
143.18031 ++					continue;
143.18032 ++
143.18033 ++				assert(!box_empty(&box));
143.18034 + 				box.x1 += drawable->x;
143.18035 + 				box.x2 += drawable->x;
143.18036 + 				box.y1 += drawable->y;
143.18037 +@@ -10174,6 +10315,7 @@ sna_poly_segment_blt(DrawablePtr drawable,
143.18038 + 						b->x2 += dx;
143.18039 + 						b->y1 += dy;
143.18040 + 						b->y2 += dy;
143.18041 ++						assert(!box_empty(b));
143.18042 + 						if (++b == last_box) {
143.18043 + 							fill.boxes(sna, &fill, boxes, last_box-boxes);
143.18044 + 							if (damage)
143.18045 +@@ -10185,7 +10327,10 @@ sna_poly_segment_blt(DrawablePtr drawable,
143.18046 + 			} while (--n);
143.18047 + 		} else {
143.18048 + 			do {
143.18049 +-				box_from_seg(b, seg++, gc);
143.18050 ++				if (!box_from_seg(b, seg++, gc))
143.18051 ++					continue;
143.18052 ++
143.18053 ++				assert(!box_empty(b));
143.18054 + 				b->x1 += drawable->x;
143.18055 + 				b->x2 += drawable->x;
143.18056 + 				b->y1 += drawable->y;
143.18057 +@@ -10195,6 +10340,7 @@ sna_poly_segment_blt(DrawablePtr drawable,
143.18058 + 					b->x2 += dx;
143.18059 + 					b->y1 += dy;
143.18060 + 					b->y2 += dy;
143.18061 ++					assert(!box_empty(b));
143.18062 + 					if (++b == last_box) {
143.18063 + 						fill.boxes(sna, &fill, boxes, last_box-boxes);
143.18064 + 						if (damage)
143.18065 +@@ -10319,8 +10465,11 @@ sna_poly_zero_segment_blt(DrawablePtr drawable,
143.18066 + 				}
143.18067 + 				b->x2++;
143.18068 + 				b->y2++;
143.18069 +-				if (oc1 | oc2)
143.18070 +-					box_intersect(b, extents);
143.18071 ++
143.18072 ++				if ((oc1 | oc2) && !box_intersect(b, extents))
143.18073 ++					continue;
143.18074 ++
143.18075 ++				assert(!box_empty(b));
143.18076 + 				if (++b == last_box) {
143.18077 + 					ret = &&rectangle_continue;
143.18078 + 					goto *jump;
143.18079 +@@ -10383,6 +10532,7 @@ rectangle_continue:
143.18080 + 						     __FUNCTION__, x1, y1,
143.18081 + 						     b->x1, b->y1, b->x2, b->y2));
143.18082 + 
143.18083 ++						assert(!box_empty(b));
143.18084 + 						if (++b == last_box) {
143.18085 + 							ret = &&X_continue;
143.18086 + 							goto *jump;
143.18087 +@@ -10407,6 +10557,7 @@ X_continue:
143.18088 + 						b->x2 = x1 + 1;
143.18089 + 					b->y2 = b->y1 + 1;
143.18090 + 
143.18091 ++					assert(!box_empty(b));
143.18092 + 					if (++b == last_box) {
143.18093 + 						ret = &&X2_continue;
143.18094 + 						goto *jump;
143.18095 +@@ -10468,6 +10619,7 @@ X2_continue:
143.18096 + 							b->y2 = y1 + 1;
143.18097 + 						b->x2 = x1 + 1;
143.18098 + 
143.18099 ++						assert(!box_empty(b));
143.18100 + 						if (++b == last_box) {
143.18101 + 							ret = &&Y_continue;
143.18102 + 							goto *jump;
143.18103 +@@ -10491,6 +10643,7 @@ Y_continue:
143.18104 + 						b->y2 = y1 + 1;
143.18105 + 					b->x2 = x1 + 1;
143.18106 + 
143.18107 ++					assert(!box_empty(b));
143.18108 + 					if (++b == last_box) {
143.18109 + 						ret = &&Y2_continue;
143.18110 + 						goto *jump;
143.18111 +@@ -11785,14 +11938,29 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
143.18112 + 				if (nbox > ARRAY_SIZE(boxes))
143.18113 + 					nbox = ARRAY_SIZE(boxes);
143.18114 + 				n -= nbox;
143.18115 +-				do {
143.18116 ++				while (nbox >= 2) {
143.18117 ++					b[0].x1 = rect[0].x + dx;
143.18118 ++					b[0].y1 = rect[0].y + dy;
143.18119 ++					b[0].x2 = b[0].x1 + rect[0].width;
143.18120 ++					b[0].y2 = b[0].y1 + rect[0].height;
143.18121 ++
143.18122 ++					b[1].x1 = rect[1].x + dx;
143.18123 ++					b[1].y1 = rect[1].y + dy;
143.18124 ++					b[1].x2 = b[1].x1 + rect[1].width;
143.18125 ++					b[1].y2 = b[1].y1 + rect[1].height;
143.18126 ++
143.18127 ++					b += 2;
143.18128 ++					rect += 2;
143.18129 ++					nbox -= 2;
143.18130 ++				}
143.18131 ++				if (nbox) {
143.18132 + 					b->x1 = rect->x + dx;
143.18133 + 					b->y1 = rect->y + dy;
143.18134 + 					b->x2 = b->x1 + rect->width;
143.18135 + 					b->y2 = b->y1 + rect->height;
143.18136 + 					b++;
143.18137 + 					rect++;
143.18138 +-				} while (--nbox);
143.18139 ++				}
143.18140 + 				fill.boxes(sna, &fill, boxes, b-boxes);
143.18141 + 				b = boxes;
143.18142 + 			} while (n);
143.18143 +@@ -11802,14 +11970,29 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
143.18144 + 				if (nbox > ARRAY_SIZE(boxes))
143.18145 + 					nbox = ARRAY_SIZE(boxes);
143.18146 + 				n -= nbox;
143.18147 +-				do {
143.18148 ++				while (nbox >= 2) {
143.18149 ++					b[0].x1 = rect[0].x;
143.18150 ++					b[0].y1 = rect[0].y;
143.18151 ++					b[0].x2 = b[0].x1 + rect[0].width;
143.18152 ++					b[0].y2 = b[0].y1 + rect[0].height;
143.18153 ++
143.18154 ++					b[1].x1 = rect[1].x;
143.18155 ++					b[1].y1 = rect[1].y;
143.18156 ++					b[1].x2 = b[1].x1 + rect[1].width;
143.18157 ++					b[1].y2 = b[1].y1 + rect[1].height;
143.18158 ++
143.18159 ++					b += 2;
143.18160 ++					rect += 2;
143.18161 ++					nbox -= 2;
143.18162 ++				}
143.18163 ++				if (nbox) {
143.18164 + 					b->x1 = rect->x;
143.18165 + 					b->y1 = rect->y;
143.18166 + 					b->x2 = b->x1 + rect->width;
143.18167 + 					b->y2 = b->y1 + rect->height;
143.18168 + 					b++;
143.18169 + 					rect++;
143.18170 +-				} while (--nbox);
143.18171 ++				}
143.18172 + 				fill.boxes(sna, &fill, boxes, b-boxes);
143.18173 + 				b = boxes;
143.18174 + 			} while (n);
143.18175 +@@ -12192,6 +12375,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
143.18176 + 			return false;
143.18177 + 		_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18178 + 	}
143.18179 ++	kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
143.18180 + 
143.18181 + 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
143.18182 + 	assert(extents->x1 + dx >= 0);
143.18183 +@@ -12335,6 +12519,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
143.18184 + 
143.18185 + 			_kgem_submit(&sna->kgem);
143.18186 + 			_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18187 ++			kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
143.18188 + 		} while (1);
143.18189 + 	} else {
143.18190 + 		RegionRec clip;
143.18191 +@@ -12403,6 +12588,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
143.18192 + 					if (!kgem_check_batch(&sna->kgem, 3)) {
143.18193 + 						_kgem_submit(&sna->kgem);
143.18194 + 						_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18195 ++						kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
143.18196 + 
143.18197 + 						unwind_batch = sna->kgem.nbatch;
143.18198 + 						unwind_reloc = sna->kgem.nreloc;
143.18199 +@@ -12499,6 +12685,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
143.18200 + 							DBG(("%s: emitting split batch\n", __FUNCTION__));
143.18201 + 							_kgem_submit(&sna->kgem);
143.18202 + 							_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18203 ++							kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
143.18204 + 
143.18205 + 							unwind_batch = sna->kgem.nbatch;
143.18206 + 							unwind_reloc = sna->kgem.nreloc;
143.18207 +@@ -12572,7 +12759,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
143.18208 + 	}
143.18209 + done:
143.18210 + 	assert_pixmap_damage(pixmap);
143.18211 +-	sna->blt_state.fill_bo = 0;
143.18212 ++	blt_done(sna);
143.18213 + 	return true;
143.18214 + }
143.18215 + 
143.18216 +@@ -13128,6 +13315,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
143.18217 + 			return false;
143.18218 + 		_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18219 + 	}
143.18220 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18221 + 
143.18222 + 	if (!clipped) {
143.18223 + 		dx += drawable->x;
143.18224 +@@ -13240,6 +13428,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
143.18225 + 
143.18226 + 			_kgem_submit(&sna->kgem);
143.18227 + 			_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18228 ++			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18229 + 		} while (1);
143.18230 + 	} else {
143.18231 + 		RegionRec clip;
143.18232 +@@ -13297,6 +13486,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
143.18233 + 					if (!kgem_check_batch(&sna->kgem, 3)) {
143.18234 + 						_kgem_submit(&sna->kgem);
143.18235 + 						_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18236 ++						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18237 + 
143.18238 + 						assert(sna->kgem.mode == KGEM_BLT);
143.18239 + 						b = sna->kgem.batch + sna->kgem.nbatch;
143.18240 +@@ -13369,6 +13559,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
143.18241 + 						if (!kgem_check_batch(&sna->kgem, 3)) {
143.18242 + 							_kgem_submit(&sna->kgem);
143.18243 + 							_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18244 ++							kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18245 + 
143.18246 + 							assert(sna->kgem.mode == KGEM_BLT);
143.18247 + 							b = sna->kgem.batch + sna->kgem.nbatch;
143.18248 +@@ -13419,7 +13610,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
143.18249 + 	}
143.18250 + 
143.18251 + 	assert_pixmap_damage(pixmap);
143.18252 +-	sna->blt_state.fill_bo = 0;
143.18253 ++	blt_done(sna);
143.18254 + 	return true;
143.18255 + }
143.18256 + 
143.18257 +@@ -13499,6 +13690,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18258 + 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
143.18259 + 	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
143.18260 + 	assert(kgem_bo_can_blt(&sna->kgem, bo));
143.18261 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18262 + 
143.18263 + 	br00 = 3 << 20;
143.18264 + 	br13 = bo->pitch;
143.18265 +@@ -13543,6 +13735,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18266 + 						return false;
143.18267 + 					_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18268 + 				}
143.18269 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18270 + 
143.18271 + 				assert(sna->kgem.mode == KGEM_BLT);
143.18272 + 				b = sna->kgem.batch + sna->kgem.nbatch;
143.18273 +@@ -13606,6 +13799,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18274 + 						return false;
143.18275 + 					_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18276 + 				}
143.18277 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18278 + 
143.18279 + 				upload = kgem_create_buffer(&sna->kgem,
143.18280 + 							    bstride*bh,
143.18281 +@@ -13736,6 +13930,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18282 + 							return false;
143.18283 + 						_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18284 + 					}
143.18285 ++					kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18286 + 
143.18287 + 					assert(sna->kgem.mode == KGEM_BLT);
143.18288 + 					b = sna->kgem.batch + sna->kgem.nbatch;
143.18289 +@@ -13797,6 +13992,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18290 + 							return false;
143.18291 + 						_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18292 + 					}
143.18293 ++					kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18294 + 
143.18295 + 					upload = kgem_create_buffer(&sna->kgem,
143.18296 + 								    bstride*bh,
143.18297 +@@ -13927,6 +14123,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18298 + 								return false;
143.18299 + 							_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18300 + 						}
143.18301 ++						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18302 + 
143.18303 + 						assert(sna->kgem.mode == KGEM_BLT);
143.18304 + 						b = sna->kgem.batch + sna->kgem.nbatch;
143.18305 +@@ -13987,6 +14184,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18306 + 								return false;
143.18307 + 							_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18308 + 						}
143.18309 ++						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18310 + 
143.18311 + 						upload = kgem_create_buffer(&sna->kgem,
143.18312 + 									    bstride*bh,
143.18313 +@@ -14064,7 +14262,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
143.18314 + 		}
143.18315 + 	}
143.18316 + 
143.18317 +-	sna->blt_state.fill_bo = 0;
143.18318 ++	blt_done(sna);
143.18319 + 	return true;
143.18320 + }
143.18321 + 
143.18322 +@@ -14126,6 +14324,7 @@ sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
143.18323 + 					return; /* XXX fallback? */
143.18324 + 				_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18325 + 			}
143.18326 ++			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18327 + 
143.18328 + 			assert(sna->kgem.mode == KGEM_BLT);
143.18329 + 			b = sna->kgem.batch + sna->kgem.nbatch;
143.18330 +@@ -14251,6 +14450,7 @@ sna_poly_fill_rect_stippled_n_box(struct sna *sna,
143.18331 + 					return; /* XXX fallback? */
143.18332 + 				_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18333 + 			}
143.18334 ++			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18335 + 
143.18336 + 			assert(sna->kgem.mode == KGEM_BLT);
143.18337 + 			b = sna->kgem.batch + sna->kgem.nbatch;
143.18338 +@@ -14414,6 +14614,7 @@ sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
143.18339 + 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
143.18340 + 	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
143.18341 + 	assert(kgem_bo_can_blt(&sna->kgem, bo));
143.18342 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18343 + 
143.18344 + 	br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
143.18345 + 	br13 = bo->pitch;
143.18346 +@@ -14526,7 +14727,7 @@ sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
143.18347 + 	}
143.18348 + 
143.18349 + 	assert_pixmap_damage(pixmap);
143.18350 +-	sna->blt_state.fill_bo = 0;
143.18351 ++	blt_done(sna);
143.18352 + 	return true;
143.18353 + }
143.18354 + 
143.18355 +@@ -14559,6 +14760,7 @@ sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
143.18356 + 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
143.18357 + 	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
143.18358 + 	assert(kgem_bo_can_blt(&sna->kgem, bo));
143.18359 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18360 + 
143.18361 + 	br00 = XY_MONO_SRC_COPY | 3 << 20;
143.18362 + 	br13 = bo->pitch;
143.18363 +@@ -14673,7 +14875,7 @@ sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
143.18364 + 	assert_pixmap_damage(pixmap);
143.18365 + 	if (tile)
143.18366 + 		kgem_bo_destroy(&sna->kgem, tile);
143.18367 +-	sna->blt_state.fill_bo = 0;
143.18368 ++	blt_done(sna);
143.18369 + 	return true;
143.18370 + }
143.18371 + 
143.18372 +@@ -15281,6 +15483,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
143.18373 + 		}
143.18374 + 		_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18375 + 	}
143.18376 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18377 + 
143.18378 + 	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
143.18379 + 	     __FUNCTION__,
143.18380 +@@ -15368,6 +15571,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
143.18381 + 			if (!kgem_check_batch(&sna->kgem, 3+len)) {
143.18382 + 				_kgem_submit(&sna->kgem);
143.18383 + 				_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18384 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18385 + 
143.18386 + 				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
143.18387 + 				     __FUNCTION__,
143.18388 +@@ -15479,7 +15683,7 @@ skip:
143.18389 + 	}
143.18390 + 
143.18391 + 	assert_pixmap_damage(pixmap);
143.18392 +-	sna->blt_state.fill_bo = 0;
143.18393 ++	blt_done(sna);
143.18394 + 	return true;
143.18395 + }
143.18396 + 
143.18397 +@@ -16002,6 +16206,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
143.18398 + 		}
143.18399 + 		_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18400 + 	}
143.18401 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18402 + 
143.18403 + 	unwind_batch = sna->kgem.nbatch;
143.18404 + 	unwind_reloc = sna->kgem.nreloc;
143.18405 +@@ -16111,6 +16316,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
143.18406 + 			if (!kgem_check_batch(&sna->kgem, 3+len)) {
143.18407 + 				_kgem_submit(&sna->kgem);
143.18408 + 				_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18409 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18410 + 
143.18411 + 				unwind_batch = sna->kgem.nbatch;
143.18412 + 				unwind_reloc = sna->kgem.nreloc;
143.18413 +@@ -16229,7 +16435,7 @@ skip:
143.18414 + 	}
143.18415 + 
143.18416 + 	assert_pixmap_damage(pixmap);
143.18417 +-	sna->blt_state.fill_bo = 0;
143.18418 ++	blt_done(sna);
143.18419 + 	return true;
143.18420 + }
143.18421 + 
143.18422 +@@ -16450,6 +16656,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
143.18423 + 
143.18424 + 	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
143.18425 + 	assert(kgem_bo_can_blt(&sna->kgem, bo));
143.18426 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18427 + 
143.18428 + 	/* Region is pre-clipped and translated into pixmap space */
143.18429 + 	box = region_rects(region);
143.18430 +@@ -16471,6 +16678,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
143.18431 + 				return false;
143.18432 + 			_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.18433 + 		}
143.18434 ++		kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.18435 + 
143.18436 + 		upload = kgem_create_buffer(&sna->kgem,
143.18437 + 					    bstride*bh,
143.18438 +@@ -16564,7 +16772,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
143.18439 + 		box++;
143.18440 + 	} while (--n);
143.18441 + 
143.18442 +-	sna->blt_state.fill_bo = 0;
143.18443 ++	blt_done(sna);
143.18444 + 	return true;
143.18445 + }
143.18446 + 
143.18447 +@@ -16754,7 +16962,9 @@ static int sna_create_gc(GCPtr gc)
143.18448 + 
143.18449 + 	gc->freeCompClip = 0;
143.18450 + 	gc->pCompositeClip = 0;
143.18451 ++#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0)
143.18452 + 	gc->pRotatedPixmap = 0;
143.18453 ++#endif
143.18454 + 
143.18455 + 	fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
143.18456 + 
143.18457 +@@ -16789,7 +16999,8 @@ sna_get_image__inplace(PixmapPtr pixmap,
143.18458 + 		break;
143.18459 + 	}
143.18460 + 
143.18461 +-	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
143.18462 ++	if ((flags & MOVE_INPLACE_HINT) == 0 &&
143.18463 ++	    !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
143.18464 + 		return false;
143.18465 + 
143.18466 + 	if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
143.18467 +@@ -16801,11 +17012,19 @@ sna_get_image__inplace(PixmapPtr pixmap,
143.18468 + 	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
143.18469 + 	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
143.18470 + 
143.18471 +-	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
143.18472 +-	if (src == NULL)
143.18473 +-		return false;
143.18474 ++	if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) {
143.18475 ++		src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
143.18476 ++		if (src == NULL)
143.18477 ++			return false;
143.18478 + 
143.18479 +-	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
143.18480 ++		kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
143.18481 ++	} else {
143.18482 ++		src = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
143.18483 ++		if (src == NULL)
143.18484 ++			return false;
143.18485 ++
143.18486 ++		kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
143.18487 ++	}
143.18488 + 
143.18489 + 	if (sigtrap_get())
143.18490 + 		return false;
143.18491 +@@ -16833,12 +17052,11 @@ sna_get_image__inplace(PixmapPtr pixmap,
143.18492 + 			   region->extents.x2 - region->extents.x1,
143.18493 + 			   region->extents.y2 - region->extents.y1);
143.18494 + 		if (!priv->shm) {
143.18495 +-			assert(src == MAP(priv->gpu_bo->map__cpu));
143.18496 + 			pixmap->devPrivate.ptr = src;
143.18497 + 			pixmap->devKind = priv->gpu_bo->pitch;
143.18498 +-			priv->mapped = MAPPED_CPU;
143.18499 ++			priv->mapped = src == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
143.18500 + 			assert_pixmap_map(pixmap, priv);
143.18501 +-			priv->cpu = true;
143.18502 ++			priv->cpu &= priv->mapped == MAPPED_CPU;
143.18503 + 		}
143.18504 + 	}
143.18505 + 
143.18506 +@@ -16930,7 +17148,7 @@ sna_get_image__fast(PixmapPtr pixmap,
143.18507 + 	if (priv == NULL || priv->gpu_damage == NULL)
143.18508 + 		return false;
143.18509 + 
143.18510 +-	if (priv->clear) {
143.18511 ++	if (priv->clear && sigtrap_get() == 0) {
143.18512 + 		int w = region->extents.x2 - region->extents.x1;
143.18513 + 		int h = region->extents.y2 - region->extents.y1;
143.18514 + 		int pitch = PixmapBytePad(w, pixmap->drawable.depth);
143.18515 +@@ -16939,6 +17157,7 @@ sna_get_image__fast(PixmapPtr pixmap,
143.18516 + 		     __FUNCTION__, priv->clear_color));
143.18517 + 		assert(DAMAGE_IS_ALL(priv->gpu_damage));
143.18518 + 		assert(priv->cpu_damage == NULL);
143.18519 ++		sigtrap_assert_active();
143.18520 + 
143.18521 + 		if (priv->clear_color == 0 ||
143.18522 + 		    pixmap->drawable.bitsPerPixel == 8 ||
143.18523 +@@ -16955,6 +17174,7 @@ sna_get_image__fast(PixmapPtr pixmap,
143.18524 + 				    priv->clear_color);
143.18525 + 		}
143.18526 + 
143.18527 ++		sigtrap_put();
143.18528 + 		return true;
143.18529 + 	}
143.18530 + 
143.18531 +@@ -17001,8 +17221,7 @@ sna_get_image(DrawablePtr drawable,
143.18532 + 	if (ACCEL_GET_IMAGE &&
143.18533 + 	    !FORCE_FALLBACK &&
143.18534 + 	    format == ZPixmap &&
143.18535 +-	    drawable->bitsPerPixel >= 8 &&
143.18536 +-	    PM_IS_SOLID(drawable, mask)) {
143.18537 ++	    drawable->bitsPerPixel >= 8) {
143.18538 + 		PixmapPtr pixmap = get_drawable_pixmap(drawable);
143.18539 + 		int16_t dx, dy;
143.18540 + 
143.18541 +@@ -17014,7 +17233,7 @@ sna_get_image(DrawablePtr drawable,
143.18542 + 		region.data = NULL;
143.18543 + 
143.18544 + 		if (sna_get_image__fast(pixmap, &region, dst, flags))
143.18545 +-			return;
143.18546 ++			goto apply_planemask;
143.18547 + 
143.18548 + 		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
143.18549 + 						     &region, flags))
143.18550 +@@ -17032,6 +17251,16 @@ sna_get_image(DrawablePtr drawable,
143.18551 + 				   region.extents.x1, region.extents.y1, 0, 0, w, h);
143.18552 + 			sigtrap_put();
143.18553 + 		}
143.18554 ++
143.18555 ++apply_planemask:
143.18556 ++		if (!PM_IS_SOLID(drawable, mask)) {
143.18557 ++			FbStip pm = fbReplicatePixel(mask, drawable->bitsPerPixel);
143.18558 ++			FbStip *d = (FbStip *)dst;
143.18559 ++			int i, n = PixmapBytePad(w, drawable->depth) / sizeof(FbStip) * h;
143.18560 ++
143.18561 ++			for (i = 0; i < n; i++)
143.18562 ++				d[i] &= pm;
143.18563 ++		}
143.18564 + 	} else {
143.18565 + 		region.extents.x1 = x + drawable->x;
143.18566 + 		region.extents.y1 = y + drawable->y;
143.18567 +@@ -17162,17 +17391,19 @@ void sna_accel_flush(struct sna *sna)
143.18568 + 				__sna_free_pixmap(sna, priv->pixmap, priv);
143.18569 + 			}
143.18570 + 		} else {
143.18571 ++			unsigned hints;
143.18572 + 			DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
143.18573 + 			     priv->pixmap->drawable.serialNumber));
143.18574 + 			assert(priv->flush);
143.18575 +-			if (sna_pixmap_move_to_gpu(priv->pixmap,
143.18576 +-						   MOVE_READ | __MOVE_FORCE)) {
143.18577 +-				if (priv->flush & IS_CLIPPED) {
143.18578 ++			hints = MOVE_READ | __MOVE_FORCE;
143.18579 ++			if (priv->flush & FLUSH_WRITE)
143.18580 ++				hints |= MOVE_WRITE;
143.18581 ++			if (sna_pixmap_move_to_gpu(priv->pixmap, hints)) {
143.18582 ++				if (priv->flush & FLUSH_WRITE) {
143.18583 + 					kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
143.18584 + 					sna_damage_all(&priv->gpu_damage, priv->pixmap);
143.18585 + 					assert(priv->cpu_damage == NULL);
143.18586 +-					priv->clear = false;
143.18587 +-					priv->cpu = false;
143.18588 ++					assert(priv->clear == false);
143.18589 + 				}
143.18590 + 			}
143.18591 + 		}
143.18592 +@@ -17184,10 +17415,46 @@ void sna_accel_flush(struct sna *sna)
143.18593 + }
143.18594 + 
143.18595 + static void
143.18596 +-sna_accel_flush_callback(CallbackListPtr *list,
143.18597 +-			 pointer user_data, pointer call_data)
143.18598 ++sna_shm_flush_callback(CallbackListPtr *list,
143.18599 ++		       pointer user_data, pointer call_data)
143.18600 + {
143.18601 +-	sna_accel_flush(user_data);
143.18602 ++	struct sna *sna = user_data;
143.18603 ++
143.18604 ++	if (!sna->needs_shm_flush)
143.18605 ++		return;
143.18606 ++
143.18607 ++	sna_accel_flush(sna);
143.18608 ++	sna->needs_shm_flush = false;
143.18609 ++}
143.18610 ++
143.18611 ++static void
143.18612 ++sna_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
143.18613 ++{
143.18614 ++	struct sna *sna = user_data;
143.18615 ++
143.18616 ++	if (!sna->needs_dri_flush)
143.18617 ++		return;
143.18618 ++
143.18619 ++	sna_accel_flush(sna);
143.18620 ++	sna->needs_dri_flush = false;
143.18621 ++}
143.18622 ++
143.18623 ++static void
143.18624 ++sna_event_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
143.18625 ++{
143.18626 ++	EventInfoRec *eventinfo = call_data;
143.18627 ++	struct sna *sna = user_data;
143.18628 ++	int i;
143.18629 ++
143.18630 ++	if (sna->needs_dri_flush)
143.18631 ++		return;
143.18632 ++
143.18633 ++	for (i = 0; i < eventinfo->count; i++) {
143.18634 ++		if (eventinfo->events[i].u.u.type == sna->damage_event) {
143.18635 ++			sna->needs_dri_flush = true;
143.18636 ++			return;
143.18637 ++		}
143.18638 ++	}
143.18639 + }
143.18640 + 
143.18641 + static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
143.18642 +@@ -17199,6 +17466,7 @@ static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
143.18643 + 
143.18644 + 	assert(sna->vblank_interval);
143.18645 + 	assert(sna->front);
143.18646 ++	assert(!sna->mode.hidden);
143.18647 + 
143.18648 + 	priv = sna_pixmap(sna->front);
143.18649 + 	if (priv->gpu_bo == NULL)
143.18650 +@@ -17217,7 +17485,7 @@ static void sna_accel_disarm_timer(struct sna *sna, int id)
143.18651 + static bool has_offload_slaves(struct sna *sna)
143.18652 + {
143.18653 + #if HAS_PIXMAP_SHARING
143.18654 +-	ScreenPtr screen = sna->scrn->pScreen;
143.18655 ++	ScreenPtr screen = to_screen_from_sna(sna);
143.18656 + 	PixmapDirtyUpdatePtr dirty;
143.18657 + 
143.18658 + 	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
143.18659 +@@ -17231,11 +17499,14 @@ static bool has_offload_slaves(struct sna *sna)
143.18660 + 
143.18661 + static bool has_shadow(struct sna *sna)
143.18662 + {
143.18663 +-	DamagePtr damage = sna->mode.shadow_damage;
143.18664 ++	DamagePtr damage;
143.18665 + 
143.18666 +-	if (damage == NULL)
143.18667 ++	if (!sna->mode.shadow_enabled)
143.18668 + 		return false;
143.18669 + 
143.18670 ++	damage = sna->mode.shadow_damage;
143.18671 ++	assert(damage);
143.18672 ++
143.18673 + 	DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
143.18674 + 	     __FUNCTION__,
143.18675 + 	     RegionNotEmpty(DamageRegion(damage)),
143.18676 +@@ -17365,9 +17636,8 @@ static bool sna_accel_do_expire(struct sna *sna)
143.18677 + static void sna_accel_post_damage(struct sna *sna)
143.18678 + {
143.18679 + #if HAS_PIXMAP_SHARING
143.18680 +-	ScreenPtr screen = sna->scrn->pScreen;
143.18681 ++	ScreenPtr screen = to_screen_from_sna(sna);
143.18682 + 	PixmapDirtyUpdatePtr dirty;
143.18683 +-	bool flush = false;
143.18684 + 
143.18685 + 	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
143.18686 + 		RegionRec region, *damage;
143.18687 +@@ -17376,8 +17646,6 @@ static void sna_accel_post_damage(struct sna *sna)
143.18688 + 		int16_t dx, dy;
143.18689 + 		int n;
143.18690 + 
143.18691 +-		assert(dirty->src == sna->front);
143.18692 +-
143.18693 + 		damage = DamageRegion(dirty->damage);
143.18694 + 		if (RegionNil(damage))
143.18695 + 			continue;
143.18696 +@@ -17477,7 +17745,14 @@ fallback:
143.18697 + 						    box, n, COPY_LAST))
143.18698 + 				goto fallback;
143.18699 + 
143.18700 +-			flush = true;
143.18701 ++			/* Before signalling the slave via ProcessPending,
143.18702 ++			 * ensure not only the batch is submitted as the
143.18703 ++			 * slave may be using the Damage callback to perform
143.18704 ++			 * its copy, but also that the memory must be coherent
143.18705 ++			 * - we need to treat it as uncached for the PCI slave
143.18706 ++			 * will bypass LLC.
143.18707 ++			 */
143.18708 ++			kgem_bo_sync__gtt(&sna->kgem, __sna_pixmap_get_bo(dst));
143.18709 + 		}
143.18710 + 
143.18711 + 		DamageRegionProcessPending(&dirty->slave_dst->drawable);
143.18712 +@@ -17485,8 +17760,6 @@ skip:
143.18713 + 		RegionUninit(&region);
143.18714 + 		DamageEmpty(dirty->damage);
143.18715 + 	}
143.18716 +-	if (flush)
143.18717 +-		kgem_submit(&sna->kgem);
143.18718 + #endif
143.18719 + }
143.18720 + 
143.18721 +@@ -17689,6 +17962,7 @@ sna_set_screen_pixmap(PixmapPtr pixmap)
143.18722 + static Bool
143.18723 + sna_create_window(WindowPtr win)
143.18724 + {
143.18725 ++	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
143.18726 + 	sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
143.18727 + 	return TRUE;
143.18728 + }
143.18729 +@@ -17714,6 +17988,7 @@ sna_unmap_window(WindowPtr win)
143.18730 + static Bool
143.18731 + sna_destroy_window(WindowPtr win)
143.18732 + {
143.18733 ++	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
143.18734 + 	sna_video_destroy_window(win);
143.18735 + 	sna_dri2_destroy_window(win);
143.18736 + 	return TRUE;
143.18737 +@@ -17790,20 +18065,34 @@ static bool sna_option_accel_none(struct sna *sna)
143.18738 + 	if (wedged(sna))
143.18739 + 		return true;
143.18740 + 
143.18741 +-	if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE))
143.18742 ++	if (!xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_ENABLE, TRUE))
143.18743 + 		return true;
143.18744 + 
143.18745 ++	if (sna->kgem.gen >= 0120)
143.18746 ++		return true;
143.18747 ++
143.18748 ++	if (!intel_option_cast_to_bool(sna->Options,
143.18749 ++				       OPTION_ACCEL_METHOD,
143.18750 ++				       !IS_DEFAULT_ACCEL_METHOD(NOACCEL)))
143.18751 ++		return false;
143.18752 ++
143.18753 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
143.18754 + 	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
143.18755 + 	if (s == NULL)
143.18756 + 		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
143.18757 + 
143.18758 + 	return strcasecmp(s, "none") == 0;
143.18759 ++#else
143.18760 ++	return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
143.18761 ++#endif
143.18762 + }
143.18763 + 
143.18764 + static bool sna_option_accel_blt(struct sna *sna)
143.18765 + {
143.18766 + 	const char *s;
143.18767 + 
143.18768 ++	assert(sna->kgem.gen < 0120);
143.18769 ++
143.18770 + 	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
143.18771 + 	if (s == NULL)
143.18772 + 		return false;
143.18773 +@@ -17811,6 +18100,13 @@ static bool sna_option_accel_blt(struct sna *sna)
143.18774 + 	return strcasecmp(s, "blt") == 0;
143.18775 + }
143.18776 + 
143.18777 ++#if HAVE_NOTIFY_FD
143.18778 ++static void sna_accel_notify(int fd, int ready, void *data)
143.18779 ++{
143.18780 ++	sna_mode_wakeup(data);
143.18781 ++}
143.18782 ++#endif
143.18783 ++
143.18784 + bool sna_accel_init(ScreenPtr screen, struct sna *sna)
143.18785 + {
143.18786 + 	const char *backend;
143.18787 +@@ -17822,7 +18118,7 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
143.18788 + 	list_init(&sna->flush_pixmaps);
143.18789 + 	list_init(&sna->active_pixmaps);
143.18790 + 
143.18791 +-	AddGeneralSocket(sna->kgem.fd);
143.18792 ++	SetNotifyFd(sna->kgem.fd, sna_accel_notify, X_NOTIFY_READ, sna);
143.18793 + 
143.18794 + #ifdef DEBUG_MEMORY
143.18795 + 	sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
143.18796 +@@ -17892,21 +18188,23 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
143.18797 + 		backend = "disabled";
143.18798 + 		sna->kgem.wedged = true;
143.18799 + 		sna_render_mark_wedged(sna);
143.18800 +-	} else if (sna_option_accel_blt(sna) || sna->info->gen >= 0110)
143.18801 ++	} else if (sna_option_accel_blt(sna))
143.18802 + 		(void)backend;
143.18803 +-	else if (sna->info->gen >= 0100)
143.18804 ++	else if (sna->kgem.gen >= 0110)
143.18805 ++		backend = gen9_render_init(sna, backend);
143.18806 ++	else if (sna->kgem.gen >= 0100)
143.18807 + 		backend = gen8_render_init(sna, backend);
143.18808 +-	else if (sna->info->gen >= 070)
143.18809 ++	else if (sna->kgem.gen >= 070)
143.18810 + 		backend = gen7_render_init(sna, backend);
143.18811 +-	else if (sna->info->gen >= 060)
143.18812 ++	else if (sna->kgem.gen >= 060)
143.18813 + 		backend = gen6_render_init(sna, backend);
143.18814 +-	else if (sna->info->gen >= 050)
143.18815 ++	else if (sna->kgem.gen >= 050)
143.18816 + 		backend = gen5_render_init(sna, backend);
143.18817 +-	else if (sna->info->gen >= 040)
143.18818 ++	else if (sna->kgem.gen >= 040)
143.18819 + 		backend = gen4_render_init(sna, backend);
143.18820 +-	else if (sna->info->gen >= 030)
143.18821 ++	else if (sna->kgem.gen >= 030)
143.18822 + 		backend = gen3_render_init(sna, backend);
143.18823 +-	else if (sna->info->gen >= 020)
143.18824 ++	else if (sna->kgem.gen >= 020)
143.18825 + 		backend = gen2_render_init(sna, backend);
143.18826 + 
143.18827 + 	DBG(("%s(backend=%s, prefer_gpu=%x)\n",
143.18828 +@@ -17924,8 +18222,14 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
143.18829 + 
143.18830 + void sna_accel_create(struct sna *sna)
143.18831 + {
143.18832 ++	ExtensionEntry *damage;
143.18833 ++
143.18834 + 	DBG(("%s\n", __FUNCTION__));
143.18835 + 
143.18836 ++	damage = CheckExtension("DAMAGE");
143.18837 ++	if (damage)
143.18838 ++		sna->damage_event = damage->eventBase + XDamageNotify;
143.18839 ++
143.18840 + 	if (!sna_glyphs_create(sna))
143.18841 + 		goto fail;
143.18842 + 
143.18843 +@@ -17943,27 +18247,59 @@ fail:
143.18844 + 	no_render_init(sna);
143.18845 + }
143.18846 + 
143.18847 +-void sna_accel_watch_flush(struct sna *sna, int enable)
143.18848 ++static void sna_shm_watch_flush(struct sna *sna, int enable)
143.18849 + {
143.18850 + 	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
143.18851 + 	assert(enable);
143.18852 + 
143.18853 +-	if (sna->watch_flush == 0) {
143.18854 ++	if (sna->watch_shm_flush == 0) {
143.18855 ++		DBG(("%s: installing shm watchers\n", __FUNCTION__));
143.18856 ++		assert(enable > 0);
143.18857 ++
143.18858 ++		if (!AddCallback(&FlushCallback, sna_shm_flush_callback, sna))
143.18859 ++			return;
143.18860 ++
143.18861 ++		sna->watch_shm_flush++;
143.18862 ++	}
143.18863 ++
143.18864 ++	sna->watch_shm_flush += enable;
143.18865 ++}
143.18866 ++
143.18867 ++void sna_watch_flush(struct sna *sna, int enable)
143.18868 ++{
143.18869 ++	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
143.18870 ++	assert(enable);
143.18871 ++
143.18872 ++	if (sna->watch_dri_flush == 0) {
143.18873 ++		int err = 0;
143.18874 ++
143.18875 + 		DBG(("%s: installing watchers\n", __FUNCTION__));
143.18876 + 		assert(enable > 0);
143.18877 +-		if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) {
143.18878 ++
143.18879 ++		if (!sna->damage_event)
143.18880 ++			return;
143.18881 ++
143.18882 ++		if (!AddCallback(&EventCallback, sna_event_callback, sna))
143.18883 ++			err = 1;
143.18884 ++
143.18885 ++		if (!AddCallback(&FlushCallback, sna_flush_callback, sna))
143.18886 ++			err = 1;
143.18887 ++
143.18888 ++		if (err) {
143.18889 + 			xf86DrvMsg(sna->scrn->scrnIndex, X_Error,
143.18890 + 				   "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n");
143.18891 + 		}
143.18892 +-		sna->watch_flush++;
143.18893 ++
143.18894 ++		sna->watch_dri_flush++;
143.18895 + 	}
143.18896 + 
143.18897 +-	sna->watch_flush += enable;
143.18898 ++	sna->watch_dri_flush += enable;
143.18899 + }
143.18900 + 
143.18901 + void sna_accel_leave(struct sna *sna)
143.18902 + {
143.18903 + 	DBG(("%s\n", __FUNCTION__));
143.18904 ++	sna_scanout_flush(sna);
143.18905 + 
143.18906 + 	/* as root we always have permission to render */
143.18907 + 	if (geteuid() == 0)
143.18908 +@@ -17997,13 +18333,15 @@ void sna_accel_close(struct sna *sna)
143.18909 + 
143.18910 + 	sna_pixmap_expire(sna);
143.18911 + 
143.18912 +-	DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
143.18913 +-	RemoveGeneralSocket(sna->kgem.fd);
143.18914 ++	DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
143.18915 ++	DeleteCallback(&FlushCallback, sna_flush_callback, sna);
143.18916 ++	DeleteCallback(&EventCallback, sna_event_callback, sna);
143.18917 ++	RemoveNotifyFd(sna->kgem.fd);
143.18918 + 
143.18919 + 	kgem_cleanup_cache(&sna->kgem);
143.18920 + }
143.18921 + 
143.18922 +-void sna_accel_block_handler(struct sna *sna, struct timeval **tv)
143.18923 ++void sna_accel_block(struct sna *sna, struct timeval **tv)
143.18924 + {
143.18925 + 	sigtrap_assert_inactive();
143.18926 + 
143.18927 +@@ -18044,10 +18382,17 @@ restart:
143.18928 + 	if (sna_accel_do_debug_memory(sna))
143.18929 + 		sna_accel_debug_memory(sna);
143.18930 + 
143.18931 +-	if (sna->watch_flush == 1) {
143.18932 +-		DBG(("%s: removing watchers\n", __FUNCTION__));
143.18933 +-		DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
143.18934 +-		sna->watch_flush = 0;
143.18935 ++	if (sna->watch_shm_flush == 1) {
143.18936 ++		DBG(("%s: removing shm watchers\n", __FUNCTION__));
143.18937 ++		DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
143.18938 ++		sna->watch_shm_flush = 0;
143.18939 ++	}
143.18940 ++
143.18941 ++	if (sna->watch_dri_flush == 1) {
143.18942 ++		DBG(("%s: removing dri watchers\n", __FUNCTION__));
143.18943 ++		DeleteCallback(&FlushCallback, sna_flush_callback, sna);
143.18944 ++		DeleteCallback(&EventCallback, sna_event_callback, sna);
143.18945 ++		sna->watch_dri_flush = 0;
143.18946 + 	}
143.18947 + 
143.18948 + 	if (sna->timer_active & 1) {
143.18949 +@@ -18083,22 +18428,6 @@ set_tv:
143.18950 + 	}
143.18951 + }
143.18952 + 
143.18953 +-void sna_accel_wakeup_handler(struct sna *sna)
143.18954 +-{
143.18955 +-	DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__,
143.18956 +-	     sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge));
143.18957 +-
143.18958 +-	if (!sna->kgem.nbatch)
143.18959 +-		return;
143.18960 +-
143.18961 +-	if (kgem_is_idle(&sna->kgem)) {
143.18962 +-		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
143.18963 +-		_kgem_submit(&sna->kgem);
143.18964 +-	}
143.18965 +-
143.18966 +-	sigtrap_assert_inactive();
143.18967 +-}
143.18968 +-
143.18969 + void sna_accel_free(struct sna *sna)
143.18970 + {
143.18971 + 	DBG(("%s\n", __FUNCTION__));
143.18972 +diff --git a/src/sna/sna_acpi.c b/src/sna/sna_acpi.c
143.18973 +index dcc0287b..643d04af 100644
143.18974 +--- a/src/sna/sna_acpi.c
143.18975 ++++ b/src/sna/sna_acpi.c
143.18976 +@@ -92,7 +92,7 @@ void _sna_acpi_wakeup(struct sna *sna)
143.18977 + 		DBG(("%s: error [%d], detaching from acpid\n", __FUNCTION__, n));
143.18978 + 
143.18979 + 		/* XXX reattach later? */
143.18980 +-		RemoveGeneralSocket(sna->acpi.fd);
143.18981 ++		RemoveNotifyFd(sna->acpi.fd);
143.18982 + 		sna_acpi_fini(sna);
143.18983 + 		return;
143.18984 + 	}
143.18985 +@@ -136,6 +136,13 @@ void _sna_acpi_wakeup(struct sna *sna)
143.18986 + 	} while (n);
143.18987 + }
143.18988 + 
143.18989 ++#if HAVE_NOTIFY_FD
143.18990 ++static void sna_acpi_notify(int fd, int read, void *data)
143.18991 ++{
143.18992 ++	_sna_acpi_wakeup(data);
143.18993 ++}
143.18994 ++#endif
143.18995 ++
143.18996 + static int read_power_state(const char *path)
143.18997 + {
143.18998 + 	DIR *dir;
143.18999 +@@ -200,7 +207,7 @@ void sna_acpi_init(struct sna *sna)
143.19000 + 
143.19001 + 	DBG(("%s: attaching to acpid\n", __FUNCTION__));
143.19002 + 
143.19003 +-	AddGeneralSocket(sna->acpi.fd);
143.19004 ++	SetNotifyFd(sna->acpi.fd, sna_acpi_notify, X_NOTIFY_READ, sna);
143.19005 + 	sna->acpi.remain = sizeof(sna->acpi.event) - 1;
143.19006 + 	sna->acpi.offset = 0;
143.19007 + 
143.19008 +diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
143.19009 +index de8f6ec3..ddd2586d 100644
143.19010 +--- a/src/sna/sna_blt.c
143.19011 ++++ b/src/sna/sna_blt.c
143.19012 +@@ -86,6 +86,11 @@ static const uint8_t fill_ROP[] = {
143.19013 + 	ROP_1
143.19014 + };
143.19015 + 
143.19016 ++static void sig_done(struct sna *sna, const struct sna_composite_op *op)
143.19017 ++{
143.19018 ++	sigtrap_put();
143.19019 ++}
143.19020 ++
143.19021 + static void nop_done(struct sna *sna, const struct sna_composite_op *op)
143.19022 + {
143.19023 + 	assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
143.19024 +@@ -129,7 +134,6 @@ static bool sna_blt_fill_init(struct sna *sna,
143.19025 + 	struct kgem *kgem = &sna->kgem;
143.19026 + 
143.19027 + 	assert(kgem_bo_can_blt (kgem, bo));
143.19028 +-	assert(bo->tiling != I915_TILING_Y);
143.19029 + 	blt->bo[0] = bo;
143.19030 + 
143.19031 + 	blt->br13 = bo->pitch;
143.19032 +@@ -183,6 +187,7 @@ static bool sna_blt_fill_init(struct sna *sna,
143.19033 + 				return false;
143.19034 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19035 + 		}
143.19036 ++		kgem_bcs_set_tiling(kgem, NULL, bo);
143.19037 + 
143.19038 + 		assert(sna->kgem.mode == KGEM_BLT);
143.19039 + 		b = kgem->batch + kgem->nbatch;
143.19040 +@@ -237,17 +242,13 @@ static bool sna_blt_fill_init(struct sna *sna,
143.19041 + 	return true;
143.19042 + }
143.19043 + 
143.19044 +-noinline static void sna_blt_fill_begin(struct sna *sna,
143.19045 +-					const struct sna_blt_state *blt)
143.19046 ++noinline static void __sna_blt_fill_begin(struct sna *sna,
143.19047 ++					  const struct sna_blt_state *blt)
143.19048 + {
143.19049 + 	struct kgem *kgem = &sna->kgem;
143.19050 + 	uint32_t *b;
143.19051 + 
143.19052 +-	if (kgem->nreloc) {
143.19053 +-		_kgem_submit(kgem);
143.19054 +-		_kgem_set_mode(kgem, KGEM_BLT);
143.19055 +-		assert(kgem->nbatch == 0);
143.19056 +-	}
143.19057 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, blt->bo[0]);
143.19058 + 
143.19059 + 	assert(kgem->mode == KGEM_BLT);
143.19060 + 	b = kgem->batch + kgem->nbatch;
143.19061 +@@ -293,6 +294,21 @@ noinline static void sna_blt_fill_begin(struct sna *sna,
143.19062 + 	}
143.19063 + }
143.19064 + 
143.19065 ++inline static void sna_blt_fill_begin(struct sna *sna,
143.19066 ++				      const struct sna_blt_state *blt)
143.19067 ++{
143.19068 ++	struct kgem *kgem = &sna->kgem;
143.19069 ++
143.19070 ++	if (kgem->nreloc) {
143.19071 ++		_kgem_submit(kgem);
143.19072 ++		_kgem_set_mode(kgem, KGEM_BLT);
143.19073 ++		kgem_bcs_set_tiling(kgem, NULL, blt->bo[0]);
143.19074 ++		assert(kgem->nbatch == 0);
143.19075 ++	}
143.19076 ++
143.19077 ++	__sna_blt_fill_begin(sna, blt);
143.19078 ++}
143.19079 ++
143.19080 + inline static void sna_blt_fill_one(struct sna *sna,
143.19081 + 				    const struct sna_blt_state *blt,
143.19082 + 				    int16_t x, int16_t y,
143.19083 +@@ -330,8 +346,8 @@ static bool sna_blt_copy_init(struct sna *sna,
143.19084 + {
143.19085 + 	struct kgem *kgem = &sna->kgem;
143.19086 + 
143.19087 +-	assert(kgem_bo_can_blt (kgem, src));
143.19088 +-	assert(kgem_bo_can_blt (kgem, dst));
143.19089 ++	assert(kgem_bo_can_blt(kgem, src));
143.19090 ++	assert(kgem_bo_can_blt(kgem, dst));
143.19091 + 
143.19092 + 	blt->bo[0] = src;
143.19093 + 	blt->bo[1] = dst;
143.19094 +@@ -370,6 +386,7 @@ static bool sna_blt_copy_init(struct sna *sna,
143.19095 + 			return false;
143.19096 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.19097 + 	}
143.19098 ++	kgem_bcs_set_tiling(&sna->kgem, src, dst);
143.19099 + 
143.19100 + 	sna->blt_state.fill_bo = 0;
143.19101 + 	return true;
143.19102 +@@ -424,6 +441,7 @@ static bool sna_blt_alpha_fixup_init(struct sna *sna,
143.19103 + 			return false;
143.19104 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.19105 + 	}
143.19106 ++	kgem_bcs_set_tiling(&sna->kgem, src, dst);
143.19107 + 
143.19108 + 	sna->blt_state.fill_bo = 0;
143.19109 + 	return true;
143.19110 +@@ -454,6 +472,7 @@ static void sna_blt_alpha_fixup_one(struct sna *sna,
143.19111 + 	    !kgem_check_reloc(kgem, 2)) {
143.19112 + 		_kgem_submit(kgem);
143.19113 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.19114 ++		kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]);
143.19115 + 	}
143.19116 + 
143.19117 + 	assert(sna->kgem.mode == KGEM_BLT);
143.19118 +@@ -582,6 +601,7 @@ static void sna_blt_copy_one(struct sna *sna,
143.19119 + 	    !kgem_check_reloc(kgem, 2)) {
143.19120 + 		_kgem_submit(kgem);
143.19121 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.19122 ++		kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]);
143.19123 + 	}
143.19124 + 
143.19125 + 	assert(sna->kgem.mode == KGEM_BLT);
143.19126 +@@ -912,8 +932,27 @@ sna_composite_mask_is_opaque(PicturePtr mask)
143.19127 + 		return is_solid(mask) && is_white(mask);
143.19128 + 	else if (!PICT_FORMAT_A(mask->format))
143.19129 + 		return true;
143.19130 +-	else
143.19131 +-		return is_solid(mask) && is_opaque_solid(mask);
143.19132 ++	else if (mask->pSourcePict) {
143.19133 ++		PictSolidFill *fill = (PictSolidFill *) mask->pSourcePict;
143.19134 ++		return (fill->color >> 24) == 0xff;
143.19135 ++	} else {
143.19136 ++		struct sna_pixmap *priv;
143.19137 ++		assert(mask->pDrawable);
143.19138 ++
143.19139 ++		if (mask->pDrawable->width  == 1 &&
143.19140 ++		    mask->pDrawable->height == 1 &&
143.19141 ++		    mask->repeat)
143.19142 ++			return pixel_is_opaque(get_pixel(mask), mask->format);
143.19143 ++
143.19144 ++		if (mask->transform)
143.19145 ++			return false;
143.19146 ++
143.19147 ++		priv = sna_pixmap_from_drawable(mask->pDrawable);
143.19148 ++		if (priv == NULL || !priv->clear)
143.19149 ++			return false;
143.19150 ++
143.19151 ++		return pixel_is_opaque(priv->clear_color, mask->format);
143.19152 ++	}
143.19153 + }
143.19154 + 
143.19155 + fastcall
143.19156 +@@ -971,6 +1010,7 @@ static void blt_composite_fill__cpu(struct sna *sna,
143.19157 + 
143.19158 + 	assert(op->dst.pixmap->devPrivate.ptr);
143.19159 + 	assert(op->dst.pixmap->devKind);
143.19160 ++	sigtrap_assert_active();
143.19161 + 	pixman_fill(op->dst.pixmap->devPrivate.ptr,
143.19162 + 		    op->dst.pixmap->devKind / sizeof(uint32_t),
143.19163 + 		    op->dst.pixmap->drawable.bitsPerPixel,
143.19164 +@@ -990,6 +1030,7 @@ blt_composite_fill_box_no_offset__cpu(struct sna *sna,
143.19165 + 
143.19166 + 	assert(op->dst.pixmap->devPrivate.ptr);
143.19167 + 	assert(op->dst.pixmap->devKind);
143.19168 ++	sigtrap_assert_active();
143.19169 + 	pixman_fill(op->dst.pixmap->devPrivate.ptr,
143.19170 + 		    op->dst.pixmap->devKind / sizeof(uint32_t),
143.19171 + 		    op->dst.pixmap->drawable.bitsPerPixel,
143.19172 +@@ -1010,6 +1051,7 @@ blt_composite_fill_boxes_no_offset__cpu(struct sna *sna,
143.19173 + 
143.19174 + 		assert(op->dst.pixmap->devPrivate.ptr);
143.19175 + 		assert(op->dst.pixmap->devKind);
143.19176 ++		sigtrap_assert_active();
143.19177 + 		pixman_fill(op->dst.pixmap->devPrivate.ptr,
143.19178 + 			    op->dst.pixmap->devKind / sizeof(uint32_t),
143.19179 + 			    op->dst.pixmap->drawable.bitsPerPixel,
143.19180 +@@ -1031,6 +1073,7 @@ blt_composite_fill_box__cpu(struct sna *sna,
143.19181 + 
143.19182 + 	assert(op->dst.pixmap->devPrivate.ptr);
143.19183 + 	assert(op->dst.pixmap->devKind);
143.19184 ++	sigtrap_assert_active();
143.19185 + 	pixman_fill(op->dst.pixmap->devPrivate.ptr,
143.19186 + 		    op->dst.pixmap->devKind / sizeof(uint32_t),
143.19187 + 		    op->dst.pixmap->drawable.bitsPerPixel,
143.19188 +@@ -1052,6 +1095,7 @@ blt_composite_fill_boxes__cpu(struct sna *sna,
143.19189 + 
143.19190 + 		assert(op->dst.pixmap->devPrivate.ptr);
143.19191 + 		assert(op->dst.pixmap->devKind);
143.19192 ++		sigtrap_assert_active();
143.19193 + 		pixman_fill(op->dst.pixmap->devPrivate.ptr,
143.19194 + 			    op->dst.pixmap->devKind / sizeof(uint32_t),
143.19195 + 			    op->dst.pixmap->drawable.bitsPerPixel,
143.19196 +@@ -1159,12 +1203,15 @@ static inline void _sna_blt_maybe_clear(const struct sna_composite_op *op, const
143.19197 + 	    box->y2 - box->y1 >= op->dst.height) {
143.19198 + 		struct sna_pixmap *priv = sna_pixmap(op->dst.pixmap);
143.19199 + 		if (op->dst.bo == priv->gpu_bo) {
143.19200 ++			sna_damage_all(&priv->gpu_damage, op->dst.pixmap);
143.19201 ++			sna_damage_destroy(&priv->cpu_damage);
143.19202 + 			priv->clear = true;
143.19203 + 			priv->clear_color = op->u.blt.pixel;
143.19204 + 			DBG(("%s: pixmap=%ld marking clear [%08x]\n",
143.19205 + 			     __FUNCTION__,
143.19206 + 			     op->dst.pixmap->drawable.serialNumber,
143.19207 + 			     op->u.blt.pixel));
143.19208 ++			((struct sna_composite_op *)op)->damage = NULL;
143.19209 + 		}
143.19210 + 	}
143.19211 + }
143.19212 +@@ -1404,6 +1451,7 @@ begin_blt(struct sna *sna,
143.19213 + 			return false;
143.19214 + 
143.19215 + 		_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.19216 ++		kgem_bcs_set_tiling(&sna->kgem, NULL, op->dst.bo);
143.19217 + 	}
143.19218 + 
143.19219 + 	return true;
143.19220 +@@ -1429,6 +1477,7 @@ prepare_blt_clear(struct sna *sna,
143.19221 + 	DBG(("%s\n", __FUNCTION__));
143.19222 + 
143.19223 + 	if (op->dst.bo == NULL) {
143.19224 ++		op->u.blt.pixel = 0;
143.19225 + 		op->blt   = blt_composite_fill__cpu;
143.19226 + 		if (op->dst.x|op->dst.y) {
143.19227 + 			op->box   = blt_composite_fill_box__cpu;
143.19228 +@@ -1439,9 +1488,8 @@ prepare_blt_clear(struct sna *sna,
143.19229 + 			op->boxes = blt_composite_fill_boxes_no_offset__cpu;
143.19230 + 			op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu;
143.19231 + 		}
143.19232 +-		op->done  = nop_done;
143.19233 +-		op->u.blt.pixel = 0;
143.19234 +-		return true;
143.19235 ++		op->done = sig_done;
143.19236 ++		return sigtrap_get() == 0;
143.19237 + 	}
143.19238 + 
143.19239 + 	op->blt = blt_composite_fill;
143.19240 +@@ -1484,8 +1532,8 @@ prepare_blt_fill(struct sna *sna,
143.19241 + 			op->boxes = blt_composite_fill_boxes_no_offset__cpu;
143.19242 + 			op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu;
143.19243 + 		}
143.19244 +-		op->done = nop_done;
143.19245 +-		return true;
143.19246 ++		op->done = sig_done;
143.19247 ++		return sigtrap_get() == 0;
143.19248 + 	}
143.19249 + 
143.19250 + 	op->blt = blt_composite_fill;
143.19251 +@@ -1668,6 +1716,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna,
143.19252 + 
143.19253 + 			_kgem_submit(kgem);
143.19254 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19255 ++			kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19256 + 		} while (1);
143.19257 + 	} else {
143.19258 + 		do {
143.19259 +@@ -1724,6 +1773,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna,
143.19260 + 
143.19261 + 			_kgem_submit(kgem);
143.19262 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19263 ++			kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19264 + 		} while (1);
143.19265 + 	}
143.19266 + 	sna_vertex_unlock(&sna->render);
143.19267 +@@ -1806,6 +1856,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna,
143.19268 + 
143.19269 + 			_kgem_submit(kgem);
143.19270 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19271 ++			kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19272 + 		} while (1);
143.19273 + 	} else {
143.19274 + 		do {
143.19275 +@@ -1864,6 +1915,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna,
143.19276 + 
143.19277 + 			_kgem_submit(kgem);
143.19278 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19279 ++			kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19280 + 		} while (1);
143.19281 + 	}
143.19282 + 	sna_vertex_unlock(&sna->render);
143.19283 +@@ -1973,6 +2025,7 @@ prepare_blt_copy(struct sna *sna,
143.19284 + 		}
143.19285 + 		_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.19286 + 	}
143.19287 ++	kgem_bcs_set_tiling(&sna->kgem, bo, op->dst.bo);
143.19288 + 
143.19289 + 	DBG(("%s\n", __FUNCTION__));
143.19290 + 
143.19291 +@@ -2396,6 +2449,9 @@ prepare_blt_put(struct sna *sna,
143.19292 + 			op->box   = blt_put_composite_box;
143.19293 + 			op->boxes = blt_put_composite_boxes;
143.19294 + 		}
143.19295 ++
143.19296 ++		op->done = nop_done;
143.19297 ++		return true;
143.19298 + 	} else {
143.19299 + 		if (alpha_fixup) {
143.19300 + 			op->u.blt.pixel = alpha_fixup;
143.19301 +@@ -2407,10 +2463,10 @@ prepare_blt_put(struct sna *sna,
143.19302 + 			op->box   = blt_put_composite_box__cpu;
143.19303 + 			op->boxes = blt_put_composite_boxes__cpu;
143.19304 + 		}
143.19305 +-	}
143.19306 +-	op->done = nop_done;
143.19307 + 
143.19308 +-	return true;
143.19309 ++		op->done = sig_done;
143.19310 ++		return sigtrap_get() == 0;
143.19311 ++	}
143.19312 + }
143.19313 + 
143.19314 + static bool
143.19315 +@@ -2544,6 +2600,7 @@ sna_blt_composite(struct sna *sna,
143.19316 + clear:
143.19317 + 		if (was_clear && sna_pixmap(tmp->dst.pixmap)->clear_color == 0) {
143.19318 + 			sna_pixmap(tmp->dst.pixmap)->clear = true;
143.19319 ++nop:
143.19320 + 			return prepare_blt_nop(sna, tmp);
143.19321 + 		}
143.19322 + 
143.19323 +@@ -2559,6 +2616,7 @@ clear:
143.19324 + 		}
143.19325 + 		tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
143.19326 + 						  &dst_box, &tmp->damage);
143.19327 ++		assert(!tmp->damage || !DAMAGE_IS_ALL(*tmp->damage));
143.19328 + 		if (tmp->dst.bo) {
143.19329 + 			if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) {
143.19330 + 				DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n",
143.19331 +@@ -2567,6 +2625,8 @@ clear:
143.19332 + 			}
143.19333 + 			if (hint & REPLACES)
143.19334 + 				kgem_bo_undo(&sna->kgem, tmp->dst.bo);
143.19335 ++			if (flags & COMPOSITE_UPLOAD)
143.19336 ++				return false;
143.19337 + 		} else {
143.19338 + 			RegionRec region;
143.19339 + 
143.19340 +@@ -2590,32 +2650,40 @@ clear:
143.19341 + 		}
143.19342 + 		if (op == PictOpOver && is_opaque_solid(src))
143.19343 + 			op = PictOpSrc;
143.19344 +-		if (op == PictOpAdd && is_white(src))
143.19345 ++		if (op == PictOpAdd &&
143.19346 ++		    PICT_FORMAT_RGB(src->format) == PICT_FORMAT_RGB(dst->format) &&
143.19347 ++		    is_white(src))
143.19348 + 			op = PictOpSrc;
143.19349 + 		if (was_clear && (op == PictOpAdd || op == PictOpOver)) {
143.19350 + 			if (sna_pixmap(tmp->dst.pixmap)->clear_color == 0)
143.19351 + 				op = PictOpSrc;
143.19352 + 			if (op == PictOpOver) {
143.19353 ++				unsigned dst_color = solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color);
143.19354 + 				color = over(get_solid_color(src, PICT_a8r8g8b8),
143.19355 +-					     color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
143.19356 +-							   dst->format, PICT_a8r8g8b8));
143.19357 ++					     dst_color);
143.19358 + 				op = PictOpSrc;
143.19359 + 				DBG(("%s: precomputing solid OVER (%08x, %08x) -> %08x\n",
143.19360 + 				     __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8),
143.19361 +-				     color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
143.19362 +-						   dst->format, PICT_a8r8g8b8),
143.19363 ++				     solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color),
143.19364 + 				     color));
143.19365 ++				if (color == dst_color)
143.19366 ++					goto nop;
143.19367 ++				else
143.19368 ++					goto fill;
143.19369 + 			}
143.19370 + 			if (op == PictOpAdd) {
143.19371 ++				unsigned dst_color = solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color);
143.19372 + 				color = add(get_solid_color(src, PICT_a8r8g8b8),
143.19373 +-					    color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
143.19374 +-							  dst->format, PICT_a8r8g8b8));
143.19375 ++					    dst_color);
143.19376 + 				op = PictOpSrc;
143.19377 + 				DBG(("%s: precomputing solid ADD (%08x, %08x) -> %08x\n",
143.19378 + 				     __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8),
143.19379 +-				     color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
143.19380 +-						   dst->format, PICT_a8r8g8b8),
143.19381 ++				     solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color),
143.19382 + 				     color));
143.19383 ++				if (color == dst_color)
143.19384 ++					goto nop;
143.19385 ++				else
143.19386 ++					goto fill;
143.19387 + 			}
143.19388 + 		}
143.19389 + 		if (op == PictOpOutReverse && is_opaque_solid(src))
143.19390 +@@ -2649,6 +2717,7 @@ fill:
143.19391 + 		}
143.19392 + 		tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
143.19393 + 						  &dst_box, &tmp->damage);
143.19394 ++		assert(!tmp->damage || !DAMAGE_IS_ALL(*tmp->damage));
143.19395 + 		if (tmp->dst.bo) {
143.19396 + 			if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) {
143.19397 + 				DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n",
143.19398 +@@ -2657,6 +2726,8 @@ fill:
143.19399 + 			}
143.19400 + 			if (hint & REPLACES)
143.19401 + 				kgem_bo_undo(&sna->kgem, tmp->dst.bo);
143.19402 ++			if (flags & COMPOSITE_UPLOAD)
143.19403 ++				return false;
143.19404 + 		} else {
143.19405 + 			RegionRec region;
143.19406 + 
143.19407 +@@ -2720,8 +2791,8 @@ fill:
143.19408 + 	if (is_clear(src_pixmap)) {
143.19409 + 		if (src->repeat ||
143.19410 + 		    (x >= 0 && y >= 0 &&
143.19411 +-		     x + width  < src_pixmap->drawable.width &&
143.19412 +-		     y + height < src_pixmap->drawable.height)) {
143.19413 ++		     x + width  <= src_pixmap->drawable.width &&
143.19414 ++		     y + height <= src_pixmap->drawable.height)) {
143.19415 + 			color = color_convert(sna_pixmap(src_pixmap)->clear_color,
143.19416 + 					      src->format, tmp->dst.format);
143.19417 + 			goto fill;
143.19418 +@@ -2795,7 +2866,7 @@ fill:
143.19419 + 		if (src_pixmap->drawable.width  <= sna->render.max_3d_size &&
143.19420 + 		    src_pixmap->drawable.height <= sna->render.max_3d_size &&
143.19421 + 		    bo->pitch <= sna->render.max_3d_pitch &&
143.19422 +-		    (flags & COMPOSITE_FALLBACK) == 0)
143.19423 ++		    (flags & (COMPOSITE_UPLOAD | COMPOSITE_FALLBACK)) == 0)
143.19424 + 		{
143.19425 + 			return false;
143.19426 + 		}
143.19427 +@@ -2817,6 +2888,7 @@ fill:
143.19428 + 	}
143.19429 + 	tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
143.19430 + 					  &dst_box, &tmp->damage);
143.19431 ++	assert(!tmp->damage || !DAMAGE_IS_ALL(*tmp->damage));
143.19432 + 
143.19433 + 	if (tmp->dst.bo && hint & REPLACES) {
143.19434 + 		struct sna_pixmap *priv = sna_pixmap(tmp->dst.pixmap);
143.19435 +@@ -2846,7 +2918,7 @@ fallback:
143.19436 + 			DBG(("%s: fallback -- unaccelerated upload\n",
143.19437 + 			     __FUNCTION__));
143.19438 + 			goto fallback;
143.19439 +-		} else {
143.19440 ++		} else if ((flags & COMPOSITE_UPLOAD) == 0) {
143.19441 + 			ret = prepare_blt_copy(sna, tmp, bo, alpha_fixup);
143.19442 + 			if (!ret)
143.19443 + 				goto fallback;
143.19444 +@@ -3023,6 +3095,7 @@ sna_blt_composite__convert(struct sna *sna,
143.19445 + 		}
143.19446 + 		_kgem_set_mode(&sna->kgem, KGEM_BLT);
143.19447 + 	}
143.19448 ++	kgem_bcs_set_tiling(&sna->kgem, tmp->src.bo, tmp->dst.bo);
143.19449 + 
143.19450 + 	if (alpha_fixup) {
143.19451 + 		tmp->blt   = blt_composite_copy_with_alpha;
143.19452 +@@ -3062,7 +3135,7 @@ static void sna_blt_fill_op_blt(struct sna *sna,
143.19453 + 	if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
143.19454 + 		const struct sna_blt_state *blt = &op->base.u.blt;
143.19455 + 
143.19456 +-		sna_blt_fill_begin(sna, blt);
143.19457 ++		__sna_blt_fill_begin(sna, blt);
143.19458 + 
143.19459 + 		sna->blt_state.fill_bo = blt->bo[0]->unique_id;
143.19460 + 		sna->blt_state.fill_pixel = blt->pixel;
143.19461 +@@ -3079,7 +3152,7 @@ fastcall static void sna_blt_fill_op_box(struct sna *sna,
143.19462 + 	if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
143.19463 + 		const struct sna_blt_state *blt = &op->base.u.blt;
143.19464 + 
143.19465 +-		sna_blt_fill_begin(sna, blt);
143.19466 ++		__sna_blt_fill_begin(sna, blt);
143.19467 + 
143.19468 + 		sna->blt_state.fill_bo = blt->bo[0]->unique_id;
143.19469 + 		sna->blt_state.fill_pixel = blt->pixel;
143.19470 +@@ -3097,7 +3170,7 @@ fastcall static void sna_blt_fill_op_boxes(struct sna *sna,
143.19471 + 	if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
143.19472 + 		const struct sna_blt_state *blt = &op->base.u.blt;
143.19473 + 
143.19474 +-		sna_blt_fill_begin(sna, blt);
143.19475 ++		__sna_blt_fill_begin(sna, blt);
143.19476 + 
143.19477 + 		sna->blt_state.fill_bo = blt->bo[0]->unique_id;
143.19478 + 		sna->blt_state.fill_pixel = blt->pixel;
143.19479 +@@ -3132,7 +3205,7 @@ fastcall static void sna_blt_fill_op_points(struct sna *sna,
143.19480 + 	DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, n));
143.19481 + 
143.19482 + 	if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
143.19483 +-		sna_blt_fill_begin(sna, blt);
143.19484 ++		__sna_blt_fill_begin(sna, blt);
143.19485 + 
143.19486 + 		sna->blt_state.fill_bo = blt->bo[0]->unique_id;
143.19487 + 		sna->blt_state.fill_pixel = blt->pixel;
143.19488 +@@ -3162,65 +3235,15 @@ fastcall static void sna_blt_fill_op_points(struct sna *sna,
143.19489 + 		assert(kgem->nbatch < kgem->surface);
143.19490 + 
143.19491 + 		if ((dx|dy) == 0) {
143.19492 +-			while (n_this_time >= 8) {
143.19493 +-				*((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
143.19494 +-				*((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
143.19495 +-				*((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0);
143.19496 +-				*((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0);
143.19497 +-				*((uint64_t *)b + 4) = pt_add(cmd, p+4, 0, 0);
143.19498 +-				*((uint64_t *)b + 5) = pt_add(cmd, p+5, 0, 0);
143.19499 +-				*((uint64_t *)b + 6) = pt_add(cmd, p+6, 0, 0);
143.19500 +-				*((uint64_t *)b + 7) = pt_add(cmd, p+7, 0, 0);
143.19501 +-				b += 16;
143.19502 +-				n_this_time -= 8;
143.19503 +-				p += 8;
143.19504 +-			}
143.19505 +-			if (n_this_time & 4) {
143.19506 +-				*((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
143.19507 +-				*((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
143.19508 +-				*((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0);
143.19509 +-				*((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0);
143.19510 +-				b += 8;
143.19511 +-				p += 4;
143.19512 +-			}
143.19513 +-			if (n_this_time & 2) {
143.19514 +-				*((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
143.19515 +-				*((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
143.19516 +-				b += 4;
143.19517 +-				p += 2;
143.19518 +-			}
143.19519 +-			if (n_this_time & 1)
143.19520 +-				*((uint64_t *)b + 0) = pt_add(cmd, p++, 0, 0);
143.19521 ++			do {
143.19522 ++				*(uint64_t *)b = pt_add(cmd, p++, 0, 0);
143.19523 ++				b += 2;
143.19524 ++			} while (--n_this_time);
143.19525 + 		} else {
143.19526 +-			while (n_this_time >= 8) {
143.19527 +-				*((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
143.19528 +-				*((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
143.19529 +-				*((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy);
143.19530 +-				*((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy);
143.19531 +-				*((uint64_t *)b + 4) = pt_add(cmd, p+4, dx, dy);
143.19532 +-				*((uint64_t *)b + 5) = pt_add(cmd, p+5, dx, dy);
143.19533 +-				*((uint64_t *)b + 6) = pt_add(cmd, p+6, dx, dy);
143.19534 +-				*((uint64_t *)b + 7) = pt_add(cmd, p+7, dx, dy);
143.19535 +-				b += 16;
143.19536 +-				n_this_time -= 8;
143.19537 +-				p += 8;
143.19538 +-			}
143.19539 +-			if (n_this_time & 4) {
143.19540 +-				*((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
143.19541 +-				*((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
143.19542 +-				*((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy);
143.19543 +-				*((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy);
143.19544 +-				b += 8;
143.19545 +-				p += 8;
143.19546 +-			}
143.19547 +-			if (n_this_time & 2) {
143.19548 +-				*((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
143.19549 +-				*((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
143.19550 +-				b += 4;
143.19551 +-				p += 2;
143.19552 +-			}
143.19553 +-			if (n_this_time & 1)
143.19554 +-				*((uint64_t *)b + 0) = pt_add(cmd, p++, dx, dy);
143.19555 ++			do {
143.19556 ++				*(uint64_t *)b = pt_add(cmd, p++, dx, dy);
143.19557 ++				b += 2;
143.19558 ++			} while (--n_this_time);
143.19559 + 		}
143.19560 + 
143.19561 + 		if (!n)
143.19562 +@@ -3414,6 +3437,7 @@ static bool sna_blt_fill_box(struct sna *sna, uint8_t alu,
143.19563 + 
143.19564 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.19565 + 	}
143.19566 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.19567 + 
143.19568 + 	assert(kgem_check_batch(kgem, 6));
143.19569 + 	assert(kgem_check_reloc(kgem, 1));
143.19570 +@@ -3520,6 +3544,8 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu,
143.19571 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19572 + 		}
143.19573 + 
143.19574 ++		kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.19575 ++
143.19576 + 		assert(sna->kgem.mode == KGEM_BLT);
143.19577 + 		b = kgem->batch + kgem->nbatch;
143.19578 + 		if (kgem->gen >= 0100) {
143.19579 +@@ -3608,6 +3634,7 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu,
143.19580 + 
143.19581 + 			_kgem_submit(kgem);
143.19582 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19583 ++			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
143.19584 + 
143.19585 + 			assert(sna->kgem.mode == KGEM_BLT);
143.19586 + 			b = kgem->batch + kgem->nbatch;
143.19587 +@@ -3754,6 +3781,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
143.19588 + 		}
143.19589 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.19590 + 	}
143.19591 ++	kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19592 + 
143.19593 + 	if ((dst_dx | dst_dy) == 0) {
143.19594 + 		if (kgem->gen >= 0100) {
143.19595 +@@ -3814,6 +3842,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
143.19596 + 
143.19597 + 				_kgem_submit(kgem);
143.19598 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.19599 ++				kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19600 + 			} while (1);
143.19601 + 		} else {
143.19602 + 			uint64_t hdr = (uint64_t)br13 << 32 | cmd | 6;
143.19603 +@@ -3871,6 +3900,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
143.19604 + 
143.19605 + 				_kgem_submit(kgem);
143.19606 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.19607 ++				kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19608 + 			} while (1);
143.19609 + 		}
143.19610 + 	} else {
143.19611 +@@ -3932,6 +3962,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
143.19612 + 
143.19613 + 				_kgem_submit(kgem);
143.19614 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.19615 ++				kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19616 + 			} while (1);
143.19617 + 		} else {
143.19618 + 			cmd |= 6;
143.19619 +@@ -3989,6 +4020,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
143.19620 + 
143.19621 + 				_kgem_submit(kgem);
143.19622 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.19623 ++				kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19624 + 			} while (1);
143.19625 + 		}
143.19626 + 	}
143.19627 +@@ -4095,6 +4127,7 @@ bool sna_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu,
143.19628 + 		    !kgem_check_reloc(kgem, 2)) {
143.19629 + 			_kgem_submit(kgem);
143.19630 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.19631 ++			kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
143.19632 + 		}
143.19633 + 
143.19634 + 		assert(sna->kgem.mode == KGEM_BLT);
143.19635 +@@ -4190,6 +4223,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
143.19636 + 		DBG(("%s: dst == src\n", __FUNCTION__));
143.19637 + 
143.19638 + 		if (src_bo->tiling == I915_TILING_Y &&
143.19639 ++		    !sna->kgem.can_blt_y &&
143.19640 + 		    kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
143.19641 + 			struct kgem_bo *bo;
143.19642 + 
143.19643 +@@ -4237,6 +4271,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
143.19644 + 		}
143.19645 + 	} else {
143.19646 + 		if (src_bo->tiling == I915_TILING_Y &&
143.19647 ++		    !sna->kgem.can_blt_y &&
143.19648 + 		    kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
143.19649 + 			DBG(("%s: src is y-tiled\n", __FUNCTION__));
143.19650 + 			if (src->type != DRAWABLE_PIXMAP)
143.19651 +@@ -4251,6 +4286,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
143.19652 + 		}
143.19653 + 
143.19654 + 		if (dst_bo->tiling == I915_TILING_Y &&
143.19655 ++		    !sna->kgem.can_blt_y &&
143.19656 + 		    kgem_bo_blt_pitch_is_ok(&sna->kgem, dst_bo)) {
143.19657 + 			DBG(("%s: dst is y-tiled\n", __FUNCTION__));
143.19658 + 			if (dst->type != DRAWABLE_PIXMAP)
143.19659 +diff --git a/src/sna/sna_composite.c b/src/sna/sna_composite.c
143.19660 +index f01f020e..1da8c291 100644
143.19661 +--- a/src/sna/sna_composite.c
143.19662 ++++ b/src/sna/sna_composite.c
143.19663 +@@ -452,6 +452,8 @@ static void apply_damage(struct sna_composite_op *op, RegionPtr region)
143.19664 + 		op->damage = NULL;
143.19665 + 	} else
143.19666 + 		sna_damage_add(op->damage, region);
143.19667 ++
143.19668 ++	assert(!op->damage || !DAMAGE_IS_ALL(*op->damage));
143.19669 + }
143.19670 + 
143.19671 + static inline bool use_cpu(PixmapPtr pixmap, struct sna_pixmap *priv,
143.19672 +@@ -653,8 +655,9 @@ sna_composite(CARD8 op,
143.19673 + 	RegionRec region;
143.19674 + 	int dx, dy;
143.19675 + 
143.19676 +-	DBG(("%s(%d src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n",
143.19677 +-	     __FUNCTION__, op,
143.19678 ++	DBG(("%s(pixmap=%ld, op=%d, src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n",
143.19679 ++	     __FUNCTION__,
143.19680 ++	     pixmap->drawable.serialNumber, op,
143.19681 + 	     get_picture_id(src), src_x, src_y,
143.19682 + 	     get_picture_id(mask), mask_x, mask_y,
143.19683 + 	     get_picture_id(dst), dst_x, dst_y,
143.19684 +@@ -673,13 +676,6 @@ sna_composite(CARD8 op,
143.19685 + 			src = sna->clear;
143.19686 + 	}
143.19687 + 
143.19688 +-	if (mask && sna_composite_mask_is_opaque(mask)) {
143.19689 +-		DBG(("%s: removing opaque %smask\n",
143.19690 +-		     __FUNCTION__,
143.19691 +-		     mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : ""));
143.19692 +-		mask = NULL;
143.19693 +-	}
143.19694 +-
143.19695 + 	if (!sna_compute_composite_region(&region,
143.19696 + 					  src, mask, dst,
143.19697 + 					  src_x,  src_y,
143.19698 +@@ -688,6 +684,13 @@ sna_composite(CARD8 op,
143.19699 + 					  width,  height))
143.19700 + 		return;
143.19701 + 
143.19702 ++	if (mask && sna_composite_mask_is_opaque(mask)) {
143.19703 ++		DBG(("%s: removing opaque %smask\n",
143.19704 ++		     __FUNCTION__,
143.19705 ++		     mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : ""));
143.19706 ++		mask = NULL;
143.19707 ++	}
143.19708 ++
143.19709 + 	if (NO_COMPOSITE)
143.19710 + 		goto fallback;
143.19711 + 
143.19712 +@@ -756,6 +759,7 @@ sna_composite(CARD8 op,
143.19713 + 		DBG(("%s: fallback due unhandled composite op\n", __FUNCTION__));
143.19714 + 		goto fallback;
143.19715 + 	}
143.19716 ++	assert(!tmp.damage || !DAMAGE_IS_ALL(*tmp.damage));
143.19717 + 
143.19718 + 	if (region.data == NULL)
143.19719 + 		tmp.box(sna, &tmp, &region.extents);
143.19720 +@@ -797,8 +801,10 @@ sna_composite_rectangles(CARD8		 op,
143.19721 + 	int i, num_boxes;
143.19722 + 	unsigned hint;
143.19723 + 
143.19724 +-	DBG(("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
143.19725 +-	     __FUNCTION__, op,
143.19726 ++	DBG(("%s(pixmap=%ld, op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
143.19727 ++	     __FUNCTION__,
143.19728 ++	     get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber,
143.19729 ++	     op,
143.19730 + 	     (color->alpha >> 8 << 24) |
143.19731 + 	     (color->red   >> 8 << 16) |
143.19732 + 	     (color->green >> 8 << 8) |
143.19733 +@@ -814,38 +820,40 @@ sna_composite_rectangles(CARD8		 op,
143.19734 + 		return;
143.19735 + 	}
143.19736 + 
143.19737 +-	if ((color->red|color->green|color->blue|color->alpha) <= 0x00ff) {
143.19738 +-		switch (op) {
143.19739 +-		case PictOpOver:
143.19740 +-		case PictOpOutReverse:
143.19741 +-		case PictOpAdd:
143.19742 +-			return;
143.19743 +-		case  PictOpInReverse:
143.19744 +-		case  PictOpSrc:
143.19745 +-			op = PictOpClear;
143.19746 +-			break;
143.19747 +-		case  PictOpAtopReverse:
143.19748 +-			op = PictOpOut;
143.19749 +-			break;
143.19750 +-		case  PictOpXor:
143.19751 +-			op = PictOpOverReverse;
143.19752 +-			break;
143.19753 +-		}
143.19754 +-	}
143.19755 + 	if (color->alpha <= 0x00ff) {
143.19756 +-		switch (op) {
143.19757 +-		case PictOpOver:
143.19758 +-		case PictOpOutReverse:
143.19759 +-			return;
143.19760 +-		case  PictOpInReverse:
143.19761 +-			op = PictOpClear;
143.19762 +-			break;
143.19763 +-		case  PictOpAtopReverse:
143.19764 +-			op = PictOpOut;
143.19765 +-			break;
143.19766 +-		case  PictOpXor:
143.19767 +-			op = PictOpOverReverse;
143.19768 +-			break;
143.19769 ++		if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A ||
143.19770 ++		    (color->red|color->green|color->blue) <= 0x00ff) {
143.19771 ++			switch (op) {
143.19772 ++			case PictOpOver:
143.19773 ++			case PictOpOutReverse:
143.19774 ++			case PictOpAdd:
143.19775 ++				return;
143.19776 ++			case  PictOpInReverse:
143.19777 ++			case  PictOpSrc:
143.19778 ++				op = PictOpClear;
143.19779 ++				break;
143.19780 ++			case  PictOpAtopReverse:
143.19781 ++				op = PictOpOut;
143.19782 ++				break;
143.19783 ++			case  PictOpXor:
143.19784 ++				op = PictOpOverReverse;
143.19785 ++				break;
143.19786 ++			}
143.19787 ++		} else {
143.19788 ++			switch (op) {
143.19789 ++			case PictOpOver:
143.19790 ++			case PictOpOutReverse:
143.19791 ++				return;
143.19792 ++			case  PictOpInReverse:
143.19793 ++				op = PictOpClear;
143.19794 ++				break;
143.19795 ++			case  PictOpAtopReverse:
143.19796 ++				op = PictOpOut;
143.19797 ++				break;
143.19798 ++			case  PictOpXor:
143.19799 ++				op = PictOpOverReverse;
143.19800 ++				break;
143.19801 ++			}
143.19802 + 		}
143.19803 + 	} else if (color->alpha >= 0xff00) {
143.19804 + 		switch (op) {
143.19805 +@@ -863,11 +871,16 @@ sna_composite_rectangles(CARD8		 op,
143.19806 + 		case  PictOpXor:
143.19807 + 			op = PictOpOut;
143.19808 + 			break;
143.19809 ++		case PictOpAdd:
143.19810 ++			if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A ||
143.19811 ++			    (color->red&color->green&color->blue) >= 0xff00)
143.19812 ++				op = PictOpSrc;
143.19813 ++			break;
143.19814 + 		}
143.19815 + 	}
143.19816 + 
143.19817 + 	/* Avoid reducing overlapping translucent rectangles */
143.19818 +-	if (op == PictOpOver &&
143.19819 ++	if ((op == PictOpOver || op == PictOpAdd) &&
143.19820 + 	    num_rects == 1 &&
143.19821 + 	    sna_drawable_is_clear(dst->pDrawable))
143.19822 + 		op = PictOpSrc;
143.19823 +@@ -979,6 +992,9 @@ sna_composite_rectangles(CARD8		 op,
143.19824 + 			bool ok;
143.19825 + 
143.19826 + 			if (op == PictOpClear) {
143.19827 ++				if (priv->clear_color == 0)
143.19828 ++					goto done;
143.19829 ++
143.19830 + 				ok = sna_get_pixel_from_rgba(&pixel,
143.19831 + 							     0, 0, 0, 0,
143.19832 + 							     dst->format);
143.19833 +@@ -990,8 +1006,11 @@ sna_composite_rectangles(CARD8		 op,
143.19834 + 							     color->alpha,
143.19835 + 							     dst->format);
143.19836 + 			}
143.19837 +-			if (ok && priv->clear_color == pixel)
143.19838 ++			if (ok && priv->clear_color == pixel) {
143.19839 ++				DBG(("%s: matches current clear, skipping\n",
143.19840 ++				     __FUNCTION__));
143.19841 + 				goto done;
143.19842 ++			}
143.19843 + 		}
143.19844 + 
143.19845 + 		if (region.data == NULL) {
143.19846 +diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h
143.19847 +index 272e83bc..d5c727ee 100644
143.19848 +--- a/src/sna/sna_damage.h
143.19849 ++++ b/src/sna/sna_damage.h
143.19850 +@@ -267,7 +267,7 @@ int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes);
143.19851 + static inline int
143.19852 + sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
143.19853 + {
143.19854 +-	assert(damage);
143.19855 ++	assert(DAMAGE_PTR(damage));
143.19856 + 
143.19857 + 	if (DAMAGE_IS_ALL(damage)) {
143.19858 + 		*boxes = &DAMAGE_PTR(damage)->extents;
143.19859 +@@ -322,7 +322,8 @@ static inline void sna_damage_destroy(struct sna_damage **damage)
143.19860 + 	if (*damage == NULL)
143.19861 + 		return;
143.19862 + 
143.19863 +-	__sna_damage_destroy(DAMAGE_PTR(*damage));
143.19864 ++	if (DAMAGE_PTR(*damage))
143.19865 ++		__sna_damage_destroy(DAMAGE_PTR(*damage));
143.19866 + 	*damage = NULL;
143.19867 + }
143.19868 + 
143.19869 +diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
143.19870 +index 4b218b70..9b77550e 100644
143.19871 +--- a/src/sna/sna_display.c
143.19872 ++++ b/src/sna/sna_display.c
143.19873 +@@ -39,6 +39,25 @@
143.19874 + #include <errno.h>
143.19875 + #include <poll.h>
143.19876 + #include <ctype.h>
143.19877 ++#include <dirent.h>
143.19878 ++
143.19879 ++#if HAVE_ALLOCA_H
143.19880 ++#include <alloca.h>
143.19881 ++#elif defined __GNUC__
143.19882 ++#define alloca __builtin_alloca
143.19883 ++#elif defined _AIX
143.19884 ++#define alloca __alloca
143.19885 ++#elif defined _MSC_VER
143.19886 ++#include <malloc.h>
143.19887 ++#define alloca _alloca
143.19888 ++#else
143.19889 ++void *alloca(size_t);
143.19890 ++#endif
143.19891 ++
143.19892 ++#define _PARSE_EDID_
143.19893 ++/* Jump through a few hoops in order to fixup EDIDs */
143.19894 ++#undef VERSION
143.19895 ++#undef REVISION
143.19896 + 
143.19897 + #include "sna.h"
143.19898 + #include "sna_reg.h"
143.19899 +@@ -72,6 +91,10 @@
143.19900 + #include <memcheck.h>
143.19901 + #endif
143.19902 + 
143.19903 ++#define FAIL_CURSOR_IOCTL 0
143.19904 ++
143.19905 ++#define COLDPLUG_DELAY_MS 2000
143.19906 ++
143.19907 + /* Minor discrepancy between 32-bit/64-bit ABI in old kernels */
143.19908 + union compat_mode_get_connector{
143.19909 + 	struct drm_mode_get_connector conn;
143.19910 +@@ -88,6 +111,8 @@ union compat_mode_get_connector{
143.19911 + #define DEFAULT_DPI 96
143.19912 + #endif
143.19913 + 
143.19914 ++#define OUTPUT_STATUS_CACHE_MS 15000
143.19915 ++
143.19916 + #define DRM_MODE_PAGE_FLIP_ASYNC 0x02
143.19917 + 
143.19918 + #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
143.19919 +@@ -106,33 +131,87 @@ struct local_mode_obj_get_properties {
143.19920 + };
143.19921 + #define LOCAL_MODE_OBJECT_PLANE 0xeeeeeeee
143.19922 + 
143.19923 +-#if 0
143.19924 ++struct local_mode_set_plane {
143.19925 ++	uint32_t plane_id;
143.19926 ++	uint32_t crtc_id;
143.19927 ++	uint32_t fb_id; /* fb object contains surface format type */
143.19928 ++	uint32_t flags;
143.19929 ++
143.19930 ++	/* Signed dest location allows it to be partially off screen */
143.19931 ++	int32_t crtc_x, crtc_y;
143.19932 ++	uint32_t crtc_w, crtc_h;
143.19933 ++
143.19934 ++	/* Source values are 16.16 fixed point */
143.19935 ++	uint32_t src_x, src_y;
143.19936 ++	uint32_t src_h, src_w;
143.19937 ++};
143.19938 ++#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)
143.19939 ++
143.19940 ++struct local_mode_get_plane {
143.19941 ++	uint32_t plane_id;
143.19942 ++
143.19943 ++	uint32_t crtc_id;
143.19944 ++	uint32_t fb_id;
143.19945 ++
143.19946 ++	uint32_t possible_crtcs;
143.19947 ++	uint32_t gamma_size;
143.19948 ++
143.19949 ++	uint32_t count_format_types;
143.19950 ++	uint64_t format_type_ptr;
143.19951 ++};
143.19952 ++#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)
143.19953 ++
143.19954 ++struct local_mode_get_plane_res {
143.19955 ++	uint64_t plane_id_ptr;
143.19956 ++	uint64_t count_planes;
143.19957 ++};
143.19958 ++#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)
143.19959 ++
143.19960 ++#if 1
143.19961 + #define __DBG DBG
143.19962 + #else
143.19963 + #define __DBG(x)
143.19964 + #endif
143.19965 + 
143.19966 ++#define DBG_NATIVE_ROTATION ~0 /* minimum RR_Rotate_0 */
143.19967 ++
143.19968 + extern XF86ConfigPtr xf86configptr;
143.19969 + 
143.19970 ++struct sna_cursor {
143.19971 ++	struct sna_cursor *next;
143.19972 ++	uint32_t *image;
143.19973 ++	bool transformed;
143.19974 ++	Rotation rotation;
143.19975 ++	int ref;
143.19976 ++	int size;
143.19977 ++	int last_width;
143.19978 ++	int last_height;
143.19979 ++	unsigned handle;
143.19980 ++	unsigned serial;
143.19981 ++	unsigned alloc;
143.19982 ++};
143.19983 ++
143.19984 + struct sna_crtc {
143.19985 ++	unsigned long flags;
143.19986 ++	uint32_t id;
143.19987 + 	xf86CrtcPtr base;
143.19988 + 	struct drm_mode_modeinfo kmode;
143.19989 +-	int dpms_mode;
143.19990 + 	PixmapPtr slave_pixmap;
143.19991 + 	DamagePtr slave_damage;
143.19992 +-	struct kgem_bo *bo, *shadow_bo, *client_bo;
143.19993 ++	struct kgem_bo *bo, *shadow_bo, *client_bo, *cache_bo;
143.19994 + 	struct sna_cursor *cursor;
143.19995 + 	unsigned int last_cursor_size;
143.19996 + 	uint32_t offset;
143.19997 + 	bool shadow;
143.19998 + 	bool fallback_shadow;
143.19999 + 	bool transform;
143.20000 ++	bool cursor_transform;
143.20001 ++	bool hwcursor;
143.20002 + 	bool flip_pending;
143.20003 +-	uint8_t id;
143.20004 +-	uint8_t pipe;
143.20005 + 
143.20006 +-	RegionRec client_damage; /* XXX overlap with shadow damage? */
143.20007 ++	struct pict_f_transform cursor_to_fb, fb_to_cursor;
143.20008 + 
143.20009 ++	RegionRec crtc_damage;
143.20010 + 	uint16_t shadow_bo_width, shadow_bo_height;
143.20011 + 
143.20012 + 	uint32_t rotation;
143.20013 +@@ -143,7 +222,9 @@ struct sna_crtc {
143.20014 + 			uint32_t supported;
143.20015 + 			uint32_t current;
143.20016 + 		} rotation;
143.20017 +-	} primary, sprite;
143.20018 ++		struct list link;
143.20019 ++	} primary;
143.20020 ++	struct list sprites;
143.20021 + 
143.20022 + 	uint32_t mode_serial, flip_serial;
143.20023 + 
143.20024 +@@ -173,21 +254,33 @@ struct sna_output {
143.20025 + 
143.20026 + 	unsigned int is_panel : 1;
143.20027 + 	unsigned int add_default_modes : 1;
143.20028 ++	int connector_type;
143.20029 ++	int connector_type_id;
143.20030 ++
143.20031 ++	uint32_t link_status_idx;
143.20032 + 
143.20033 + 	uint32_t edid_idx;
143.20034 + 	uint32_t edid_blob_id;
143.20035 + 	uint32_t edid_len;
143.20036 + 	void *edid_raw;
143.20037 ++	xf86MonPtr fake_edid_mon;
143.20038 ++	void *fake_edid_raw;
143.20039 + 
143.20040 + 	bool has_panel_limits;
143.20041 + 	int panel_hdisplay;
143.20042 + 	int panel_vdisplay;
143.20043 + 
143.20044 + 	uint32_t dpms_id;
143.20045 +-	int dpms_mode;
143.20046 ++	uint8_t dpms_mode;
143.20047 + 	struct backlight backlight;
143.20048 + 	int backlight_active_level;
143.20049 + 
143.20050 ++	uint32_t last_detect;
143.20051 ++	uint32_t status;
143.20052 ++	unsigned int hotplug_count;
143.20053 ++	bool update_properties;
143.20054 ++	bool reprobe;
143.20055 ++
143.20056 + 	int num_modes;
143.20057 + 	struct drm_mode_modeinfo *modes;
143.20058 + 
143.20059 +@@ -218,13 +311,91 @@ enum { /* XXX copied from hw/xfree86/modes/xf86Crtc.c */
143.20060 + 	OPTION_DEFAULT_MODES,
143.20061 + };
143.20062 + 
143.20063 ++static void __sna_output_dpms(xf86OutputPtr output, int dpms, int fixup);
143.20064 + static void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc);
143.20065 ++static bool sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc,
143.20066 ++			  struct kgem_bo *bo, int x, int y);
143.20067 + 
143.20068 + static bool is_zaphod(ScrnInfoPtr scrn)
143.20069 + {
143.20070 + 	return xf86IsEntityShared(scrn->entityList[0]);
143.20071 + }
143.20072 + 
143.20073 ++static bool
143.20074 ++sna_zaphod_match(struct sna *sna, const char *output)
143.20075 ++{
143.20076 ++	const char *s, *colon;
143.20077 ++	char t[20];
143.20078 ++	unsigned int i = 0;
143.20079 ++
143.20080 ++	s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
143.20081 ++	if (s == NULL)
143.20082 ++		return false;
143.20083 ++
143.20084 ++	colon = strchr(s, ':');
143.20085 ++	if (colon) /* Skip over the ZaphodPipes */
143.20086 ++		s = colon + 1;
143.20087 ++
143.20088 ++	do {
143.20089 ++		/* match any outputs in a comma list, stopping at whitespace */
143.20090 ++		switch (*s) {
143.20091 ++		case '\0':
143.20092 ++			t[i] = '\0';
143.20093 ++			return strcmp(t, output) == 0;
143.20094 ++
143.20095 ++		case ',':
143.20096 ++			t[i] ='\0';
143.20097 ++			if (strcmp(t, output) == 0)
143.20098 ++				return TRUE;
143.20099 ++			i = 0;
143.20100 ++			break;
143.20101 ++
143.20102 ++		case ' ':
143.20103 ++		case '\t':
143.20104 ++		case '\n':
143.20105 ++		case '\r':
143.20106 ++			break;
143.20107 ++
143.20108 ++		default:
143.20109 ++			t[i++] = *s;
143.20110 ++			break;
143.20111 ++		}
143.20112 ++
143.20113 ++		s++;
143.20114 ++	} while (i < sizeof(t));
143.20115 ++
143.20116 ++	return false;
143.20117 ++}
143.20118 ++
143.20119 ++static unsigned
143.20120 ++get_zaphod_crtcs(struct sna *sna)
143.20121 ++{
143.20122 ++	const char *str, *colon;
143.20123 ++	unsigned crtcs = 0;
143.20124 ++
143.20125 ++	str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
143.20126 ++	if (str == NULL || (colon = strchr(str, ':')) == NULL) {
143.20127 ++		DBG(("%s: no zaphod pipes, using screen number: %x\n",
143.20128 ++		     __FUNCTION__,
143.20129 ++		     sna->scrn->confScreen->device->screen));
143.20130 ++		return 1 << sna->scrn->confScreen->device->screen;
143.20131 ++	}
143.20132 ++
143.20133 ++	DBG(("%s: ZaphodHeads='%s'\n", __FUNCTION__, str));
143.20134 ++	while (str < colon) {
143.20135 ++		char *end;
143.20136 ++		unsigned crtc = strtoul(str, &end, 0);
143.20137 ++		if (end == str)
143.20138 ++			break;
143.20139 ++		DBG(("%s: adding CRTC %d to zaphod pipes\n",
143.20140 ++		     __FUNCTION__, crtc));
143.20141 ++		crtcs |= 1 << crtc;
143.20142 ++		str = end + 1;
143.20143 ++	}
143.20144 ++	DBG(("%s: ZaphodPipes=%x\n", __FUNCTION__, crtcs));
143.20145 ++	return crtcs;
143.20146 ++}
143.20147 ++
143.20148 + inline static unsigned count_to_mask(int x)
143.20149 + {
143.20150 + 	return (1 << x) - 1;
143.20151 +@@ -247,6 +418,21 @@ static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
143.20152 + 	return crtc->driver_private;
143.20153 + }
143.20154 + 
143.20155 ++static inline unsigned __sna_crtc_pipe(struct sna_crtc *crtc)
143.20156 ++{
143.20157 ++	return crtc->flags >> 8 & 0xff;
143.20158 ++}
143.20159 ++
143.20160 ++static inline unsigned __sna_crtc_id(struct sna_crtc *crtc)
143.20161 ++{
143.20162 ++	return crtc->id;
143.20163 ++}
143.20164 ++
143.20165 ++uint32_t sna_crtc_id(xf86CrtcPtr crtc)
143.20166 ++{
143.20167 ++	return __sna_crtc_id(to_sna_crtc(crtc));
143.20168 ++}
143.20169 ++
143.20170 + static inline bool event_pending(int fd)
143.20171 + {
143.20172 + 	struct pollfd pfd;
143.20173 +@@ -268,29 +454,37 @@ static inline uint32_t fb_id(struct kgem_bo *bo)
143.20174 + 	return bo->delta;
143.20175 + }
143.20176 + 
143.20177 +-uint32_t sna_crtc_id(xf86CrtcPtr crtc)
143.20178 ++unsigned sna_crtc_count_sprites(xf86CrtcPtr crtc)
143.20179 + {
143.20180 +-	if (to_sna_crtc(crtc) == NULL)
143.20181 +-		return 0;
143.20182 +-	return to_sna_crtc(crtc)->id;
143.20183 +-}
143.20184 ++	struct plane *sprite;
143.20185 ++	unsigned count;
143.20186 + 
143.20187 +-int sna_crtc_to_pipe(xf86CrtcPtr crtc)
143.20188 +-{
143.20189 +-	assert(to_sna_crtc(crtc));
143.20190 +-	return to_sna_crtc(crtc)->pipe;
143.20191 ++	count = 0;
143.20192 ++	list_for_each_entry(sprite, &to_sna_crtc(crtc)->sprites, link)
143.20193 ++		count++;
143.20194 ++
143.20195 ++	return count;
143.20196 + }
143.20197 + 
143.20198 +-uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc)
143.20199 ++static struct plane *lookup_sprite(struct sna_crtc *crtc, unsigned idx)
143.20200 + {
143.20201 +-	assert(to_sna_crtc(crtc));
143.20202 +-	return to_sna_crtc(crtc)->sprite.id;
143.20203 ++	struct plane *sprite;
143.20204 ++
143.20205 ++	list_for_each_entry(sprite, &crtc->sprites, link)
143.20206 ++		if (idx-- == 0)
143.20207 ++			return sprite;
143.20208 ++
143.20209 ++	return NULL;
143.20210 + }
143.20211 + 
143.20212 +-bool sna_crtc_is_on(xf86CrtcPtr crtc)
143.20213 ++uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc, unsigned idx)
143.20214 + {
143.20215 ++	struct plane *sprite;
143.20216 ++
143.20217 + 	assert(to_sna_crtc(crtc));
143.20218 +-	return to_sna_crtc(crtc)->bo != NULL;
143.20219 ++
143.20220 ++	sprite = lookup_sprite(to_sna_crtc(crtc), idx);
143.20221 ++	return sprite ? sprite->id : 0;
143.20222 + }
143.20223 + 
143.20224 + bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
143.20225 +@@ -299,34 +493,48 @@ bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
143.20226 + 	return to_sna_crtc(crtc)->transform;
143.20227 + }
143.20228 + 
143.20229 +-static inline uint64_t msc64(struct sna_crtc *sna_crtc, uint32_t seq)
143.20230 ++static inline bool msc64(struct sna_crtc *sna_crtc, uint32_t seq, uint64_t *msc)
143.20231 + {
143.20232 ++	bool record = true;
143.20233 + 	if (seq < sna_crtc->last_seq) {
143.20234 + 		if (sna_crtc->last_seq - seq > 0x40000000) {
143.20235 + 			sna_crtc->wrap_seq++;
143.20236 + 			DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n",
143.20237 +-			     __FUNCTION__, sna_crtc->pipe,
143.20238 ++			     __FUNCTION__, __sna_crtc_pipe(sna_crtc),
143.20239 + 			     sna_crtc->last_seq, seq, sna_crtc->wrap_seq));
143.20240 +-		} else  {
143.20241 +-			ERR(("%s: pipe=%d msc went backwards; was %u, now %u\n",
143.20242 +-			     __FUNCTION__, sna_crtc->pipe, sna_crtc->last_seq, seq));
143.20243 +-			seq = sna_crtc->last_seq;
143.20244 ++		} else {
143.20245 ++			DBG(("%s: pipe=%d msc went backwards; was %u, now %u; ignoring for last_swap\n",
143.20246 ++			     __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq));
143.20247 ++
143.20248 ++			record = false;
143.20249 + 		}
143.20250 + 	}
143.20251 +-	sna_crtc->last_seq = seq;
143.20252 +-	return (uint64_t)sna_crtc->wrap_seq << 32 | seq;
143.20253 ++	*msc = (uint64_t)sna_crtc->wrap_seq << 32 | seq;
143.20254 ++	return record;
143.20255 + }
143.20256 + 
143.20257 + uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
143.20258 + 			      int tv_sec, int tv_usec, unsigned seq)
143.20259 + {
143.20260 + 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.20261 ++	uint64_t msc;
143.20262 ++
143.20263 + 	assert(sna_crtc);
143.20264 +-	DBG(("%s: recording last swap on pipe=%d, frame %d, time %d.%06d\n",
143.20265 +-	     __FUNCTION__, sna_crtc->pipe, seq, tv_sec, tv_usec));
143.20266 +-	sna_crtc->swap.tv_sec = tv_sec;
143.20267 +-	sna_crtc->swap.tv_usec = tv_usec;
143.20268 +-	return sna_crtc->swap.msc = msc64(sna_crtc, seq);
143.20269 ++
143.20270 ++	if (msc64(sna_crtc, seq, &msc)) {
143.20271 ++		DBG(("%s: recording last swap on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
143.20272 ++		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
143.20273 ++		     tv_sec, tv_usec));
143.20274 ++		sna_crtc->swap.tv_sec = tv_sec;
143.20275 ++		sna_crtc->swap.tv_usec = tv_usec;
143.20276 ++		sna_crtc->swap.msc = msc;
143.20277 ++	} else {
143.20278 ++		DBG(("%s: swap event on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
143.20279 ++		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
143.20280 ++		     tv_sec, tv_usec));
143.20281 ++	}
143.20282 ++
143.20283 ++	return msc;
143.20284 + }
143.20285 + 
143.20286 + const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
143.20287 +@@ -342,15 +550,6 @@ const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
143.20288 + 	}
143.20289 + }
143.20290 + 
143.20291 +-xf86CrtcPtr sna_mode_first_crtc(struct sna *sna)
143.20292 +-{
143.20293 +-	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.20294 +-	if (sna->mode.num_real_crtc)
143.20295 +-		return config->crtc[0];
143.20296 +-	else
143.20297 +-		return NULL;
143.20298 +-}
143.20299 +-
143.20300 + #ifndef NDEBUG
143.20301 + static void gem_close(int fd, uint32_t handle);
143.20302 + static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
143.20303 +@@ -372,12 +571,24 @@ static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
143.20304 + #define assert_scanout(k, b, w, h)
143.20305 + #endif
143.20306 + 
143.20307 ++static void assert_crtc_fb(struct sna *sna, struct sna_crtc *crtc)
143.20308 ++{
143.20309 ++#ifndef NDEBUG
143.20310 ++	struct drm_mode_crtc mode = { .crtc_id = __sna_crtc_id(crtc) };
143.20311 ++	drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
143.20312 ++	assert(mode.fb_id == fb_id(crtc->bo));
143.20313 ++#endif
143.20314 ++}
143.20315 ++
143.20316 + static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
143.20317 + 		       int width, int height)
143.20318 + {
143.20319 + 	ScrnInfoPtr scrn = sna->scrn;
143.20320 + 	struct drm_mode_fb_cmd arg;
143.20321 + 
143.20322 ++	if (!kgem_bo_is_fenced(&sna->kgem, bo))
143.20323 ++		return 0;
143.20324 ++
143.20325 + 	assert(bo->refcnt);
143.20326 + 	assert(bo->proxy == NULL);
143.20327 + 	assert(!bo->snoop);
143.20328 +@@ -393,8 +604,9 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
143.20329 + 	DBG(("%s: create fb %dx%d@%d/%d\n",
143.20330 + 	     __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel));
143.20331 + 
143.20332 +-	assert(bo->tiling != I915_TILING_Y);
143.20333 ++	assert(bo->tiling != I915_TILING_Y || sna->kgem.can_scanout_y);
143.20334 + 	assert((bo->pitch & 63) == 0);
143.20335 ++	assert(scrn->vtSema); /* must be master */
143.20336 + 
143.20337 + 	VG_CLEAR(arg);
143.20338 + 	arg.width = width;
143.20339 +@@ -404,21 +616,83 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
143.20340 + 	arg.depth = scrn->depth;
143.20341 + 	arg.handle = bo->handle;
143.20342 + 
143.20343 +-	assert(sna->scrn->vtSema); /* must be master */
143.20344 + 	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg)) {
143.20345 +-		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
143.20346 +-			   "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
143.20347 +-			   __FUNCTION__, width, height,
143.20348 +-			   scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
143.20349 +-		return 0;
143.20350 ++		/* Try again with the fancy version */
143.20351 ++		struct local_mode_fb_cmd2 {
143.20352 ++			uint32_t fb_id;
143.20353 ++			uint32_t width, height;
143.20354 ++			uint32_t pixel_format;
143.20355 ++			uint32_t flags;
143.20356 ++
143.20357 ++			uint32_t handles[4];
143.20358 ++			uint32_t pitches[4]; /* pitch for each plane */
143.20359 ++			uint32_t offsets[4]; /* offset of each plane */
143.20360 ++			uint64_t modifiers[4];
143.20361 ++		} f;
143.20362 ++#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
143.20363 ++		memset(&f, 0, sizeof(f));
143.20364 ++		f.width = width;
143.20365 ++		f.height = height;
143.20366 ++		/* XXX interlaced */
143.20367 ++		f.flags = 1 << 1; /* +modifiers */
143.20368 ++		f.handles[0] = bo->handle;
143.20369 ++		f.pitches[0] = bo->pitch;
143.20370 ++
143.20371 ++		switch (bo->tiling) {
143.20372 ++		case I915_TILING_NONE:
143.20373 ++			break;
143.20374 ++		case I915_TILING_X:
143.20375 ++			/* I915_FORMAT_MOD_X_TILED */
143.20376 ++			f.modifiers[0] = (uint64_t)1 << 56 | 1;
143.20377 ++			break;
143.20378 ++		case I915_TILING_Y:
143.20379 ++			/* I915_FORMAT_MOD_X_TILED */
143.20380 ++			f.modifiers[0] = (uint64_t)1 << 56 | 2;
143.20381 ++			break;
143.20382 ++		}
143.20383 ++
143.20384 ++#define fourcc(a,b,c,d) ((a) | (b) << 8 | (c) << 16 | (d) << 24)
143.20385 ++		switch (scrn->depth) {
143.20386 ++		default:
143.20387 ++			ERR(("%s: unhandled screen format, depth=%d\n",
143.20388 ++			     __FUNCTION__, scrn->depth));
143.20389 ++			goto fail;
143.20390 ++		case 8:
143.20391 ++			f.pixel_format = fourcc('C', '8', ' ', ' ');
143.20392 ++			break;
143.20393 ++		case 15:
143.20394 ++			f.pixel_format = fourcc('X', 'R', '1', '5');
143.20395 ++			break;
143.20396 ++		case 16:
143.20397 ++			f.pixel_format = fourcc('R', 'G', '1', '6');
143.20398 ++			break;
143.20399 ++		case 24:
143.20400 ++			f.pixel_format = fourcc('X', 'R', '2', '4');
143.20401 ++			break;
143.20402 ++		case 30:
143.20403 ++			f.pixel_format = fourcc('X', 'R', '3', '0');
143.20404 ++			break;
143.20405 ++		}
143.20406 ++#undef fourcc
143.20407 ++
143.20408 ++		if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) {
143.20409 ++fail:
143.20410 ++			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
143.20411 ++				   "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
143.20412 ++				   __FUNCTION__, width, height,
143.20413 ++				   scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
143.20414 ++			return 0;
143.20415 ++		}
143.20416 ++
143.20417 ++		arg.fb_id = f.fb_id;
143.20418 + 	}
143.20419 + 	assert(arg.fb_id != 0);
143.20420 +-
143.20421 ++	bo->delta = arg.fb_id;
143.20422 + 	DBG(("%s: attached fb=%d to handle=%d\n",
143.20423 +-	     __FUNCTION__, arg.fb_id, arg.handle));
143.20424 ++	     __FUNCTION__, bo->delta, arg.handle));
143.20425 + 
143.20426 + 	bo->scanout = true;
143.20427 +-	return bo->delta = arg.fb_id;
143.20428 ++	return bo->delta;
143.20429 + }
143.20430 + 
143.20431 + static uint32_t gem_create(int fd, int size)
143.20432 +@@ -438,6 +712,7 @@ static uint32_t gem_create(int fd, int size)
143.20433 + static void *gem_mmap(int fd, int handle, int size)
143.20434 + {
143.20435 + 	struct drm_i915_gem_mmap_gtt mmap_arg;
143.20436 ++	struct drm_i915_gem_set_domain set_domain;
143.20437 + 	void *ptr;
143.20438 + 
143.20439 + 	VG_CLEAR(mmap_arg);
143.20440 +@@ -449,6 +724,15 @@ static void *gem_mmap(int fd, int handle, int size)
143.20441 + 	if (ptr == MAP_FAILED)
143.20442 + 		return NULL;
143.20443 + 
143.20444 ++	VG_CLEAR(set_domain);
143.20445 ++	set_domain.handle = handle;
143.20446 ++	set_domain.read_domains = I915_GEM_DOMAIN_GTT;
143.20447 ++	set_domain.write_domain = I915_GEM_DOMAIN_GTT;
143.20448 ++	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
143.20449 ++		munmap(ptr, size);
143.20450 ++		return NULL;
143.20451 ++	}
143.20452 ++
143.20453 + 	return ptr;
143.20454 + }
143.20455 + 
143.20456 +@@ -497,8 +781,6 @@ sna_backlight_uevent(int fd, void *closure)
143.20457 + 		if (sna_output->dpms_mode != DPMSModeOn)
143.20458 + 			continue;
143.20459 + 
143.20460 +-		assert(output->randr_output);
143.20461 +-
143.20462 + 		val = backlight_get(&sna_output->backlight);
143.20463 + 		if (val < 0)
143.20464 + 			continue;
143.20465 +@@ -523,6 +805,7 @@ sna_backlight_uevent(int fd, void *closure)
143.20466 + 					       TRUE, FALSE);
143.20467 + 		}
143.20468 + 	}
143.20469 ++	DBG(("%s: complete\n", __FUNCTION__));
143.20470 + }
143.20471 + 
143.20472 + static void sna_backlight_pre_init(struct sna *sna)
143.20473 +@@ -570,6 +853,7 @@ static void sna_backlight_drain_uevents(struct sna *sna)
143.20474 + 	if (sna->mode.backlight_monitor == NULL)
143.20475 + 		return;
143.20476 + 
143.20477 ++	DBG(("%s()\n", __FUNCTION__));
143.20478 + 	sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor),
143.20479 + 			     sna);
143.20480 + }
143.20481 +@@ -632,9 +916,22 @@ sna_output_backlight_set(struct sna_output *sna_output, int level)
143.20482 + 	return ret;
143.20483 + }
143.20484 + 
143.20485 ++static bool
143.20486 ++has_native_backlight(struct sna_output *sna_output)
143.20487 ++{
143.20488 ++	return sna_output->backlight.type == BL_RAW;
143.20489 ++}
143.20490 ++
143.20491 + static void
143.20492 + sna_output_backlight_off(struct sna_output *sna_output)
143.20493 + {
143.20494 ++	/* Trust the kernel to turn the native backlight off. However, we
143.20495 ++	 * do explicitly turn the backlight back on (when we wake the output)
143.20496 ++	 * just in case a third party turns it off!
143.20497 ++	 */
143.20498 ++	if (has_native_backlight(sna_output))
143.20499 ++		return;
143.20500 ++
143.20501 + 	DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name));
143.20502 + 	backlight_off(&sna_output->backlight);
143.20503 + 	sna_output_backlight_set(sna_output, 0);
143.20504 +@@ -674,7 +971,7 @@ has_user_backlight_override(xf86OutputPtr output)
143.20505 + 	if (*str == '\0')
143.20506 + 		return (char *)str;
143.20507 + 
143.20508 +-	if (backlight_exists(str) == BL_NONE) {
143.20509 ++	if (!backlight_exists(str)) {
143.20510 + 		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
143.20511 + 			   "Unrecognised backlight control interface '%s'\n",
143.20512 + 			   str);
143.20513 +@@ -684,6 +981,93 @@ has_user_backlight_override(xf86OutputPtr output)
143.20514 + 	return strdup(str);
143.20515 + }
143.20516 + 
143.20517 ++static int get_device_minor(int fd)
143.20518 ++{
143.20519 ++	struct stat st;
143.20520 ++
143.20521 ++	if (fstat(fd, &st) || !S_ISCHR(st.st_mode))
143.20522 ++		return -1;
143.20523 ++
143.20524 ++	return st.st_rdev & 0x63;
143.20525 ++}
143.20526 ++
143.20527 ++static const char * const sysfs_connector_types[] = {
143.20528 ++	/* DRM_MODE_CONNECTOR_Unknown */	"Unknown",
143.20529 ++	/* DRM_MODE_CONNECTOR_VGA */		"VGA",
143.20530 ++	/* DRM_MODE_CONNECTOR_DVII */		"DVI-I",
143.20531 ++	/* DRM_MODE_CONNECTOR_DVID */		"DVI-D",
143.20532 ++	/* DRM_MODE_CONNECTOR_DVIA */		"DVI-A",
143.20533 ++	/* DRM_MODE_CONNECTOR_Composite */	"Composite",
143.20534 ++	/* DRM_MODE_CONNECTOR_SVIDEO */		"SVIDEO",
143.20535 ++	/* DRM_MODE_CONNECTOR_LVDS */		"LVDS",
143.20536 ++	/* DRM_MODE_CONNECTOR_Component */	"Component",
143.20537 ++	/* DRM_MODE_CONNECTOR_9PinDIN */	"DIN",
143.20538 ++	/* DRM_MODE_CONNECTOR_DisplayPort */	"DP",
143.20539 ++	/* DRM_MODE_CONNECTOR_HDMIA */		"HDMI-A",
143.20540 ++	/* DRM_MODE_CONNECTOR_HDMIB */		"HDMI-B",
143.20541 ++	/* DRM_MODE_CONNECTOR_TV */		"TV",
143.20542 ++	/* DRM_MODE_CONNECTOR_eDP */		"eDP",
143.20543 ++	/* DRM_MODE_CONNECTOR_VIRTUAL */	"Virtual",
143.20544 ++	/* DRM_MODE_CONNECTOR_DSI */		"DSI",
143.20545 ++	/* DRM_MODE_CONNECTOR_DPI */		"DPI"
143.20546 ++};
143.20547 ++
143.20548 ++static char *has_connector_backlight(xf86OutputPtr output)
143.20549 ++{
143.20550 ++	struct sna_output *sna_output = output->driver_private;
143.20551 ++	struct sna *sna = to_sna(output->scrn);
143.20552 ++	char path[1024];
143.20553 ++	DIR *dir;
143.20554 ++	struct dirent *de;
143.20555 ++	int minor, len;
143.20556 ++	char *str = NULL;
143.20557 ++
143.20558 ++	if (sna_output->connector_type >= ARRAY_SIZE(sysfs_connector_types))
143.20559 ++		return NULL;
143.20560 ++
143.20561 ++	minor = get_device_minor(sna->kgem.fd);
143.20562 ++	if (minor < 0)
143.20563 ++		return NULL;
143.20564 ++
143.20565 ++	len = snprintf(path, sizeof(path),
143.20566 ++		       "/sys/class/drm/card%d-%s-%d",
143.20567 ++		       minor,
143.20568 ++		       sysfs_connector_types[sna_output->connector_type],
143.20569 ++		       sna_output->connector_type_id);
143.20570 ++	DBG(("%s: lookup %s\n", __FUNCTION__, path));
143.20571 ++
143.20572 ++	dir = opendir(path);
143.20573 ++	if (dir == NULL)
143.20574 ++		return NULL;
143.20575 ++
143.20576 ++	while ((de = readdir(dir))) {
143.20577 ++		struct stat st;
143.20578 ++
143.20579 ++		if (*de->d_name == '.')
143.20580 ++			continue;
143.20581 ++
143.20582 ++		snprintf(path + len, sizeof(path) - len,
143.20583 ++			 "/%s", de->d_name);
143.20584 ++
143.20585 ++		if (stat(path, &st))
143.20586 ++			continue;
143.20587 ++
143.20588 ++		if (!S_ISDIR(st.st_mode))
143.20589 ++			continue;
143.20590 ++
143.20591 ++		DBG(("%s: testing %s as backlight\n",
143.20592 ++		     __FUNCTION__, de->d_name));
143.20593 ++
143.20594 ++		if (backlight_exists(de->d_name)) {
143.20595 ++			str = strdup(de->d_name); /* leak! */
143.20596 ++			break;
143.20597 ++		}
143.20598 ++	}
143.20599 ++
143.20600 ++	closedir(dir);
143.20601 ++	return str;
143.20602 ++}
143.20603 ++
143.20604 + static void
143.20605 + sna_output_backlight_init(xf86OutputPtr output)
143.20606 + {
143.20607 +@@ -696,11 +1080,20 @@ sna_output_backlight_init(xf86OutputPtr output)
143.20608 + 	return;
143.20609 + #endif
143.20610 + 
143.20611 +-	from = X_CONFIG;
143.20612 +-	best_iface = has_user_backlight_override(output);
143.20613 ++	if (sna_output->is_panel) {
143.20614 ++		from = X_CONFIG;
143.20615 ++		best_iface = has_user_backlight_override(output);
143.20616 ++		if (best_iface)
143.20617 ++			goto done;
143.20618 ++	}
143.20619 ++
143.20620 ++	best_iface = has_connector_backlight(output);
143.20621 + 	if (best_iface)
143.20622 + 		goto done;
143.20623 + 
143.20624 ++	if (!sna_output->is_panel)
143.20625 ++		return;
143.20626 ++
143.20627 + 	/* XXX detect right backlight for multi-GPU/panels */
143.20628 + 	from = X_PROBED;
143.20629 + 	pci = xf86GetPciInfoForEntity(to_sna(output->scrn)->pEnt->index);
143.20630 +@@ -728,6 +1121,38 @@ done:
143.20631 + 		   sna_output->backlight.iface, best_iface, output->name);
143.20632 + }
143.20633 + 
143.20634 ++#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(22, 0)
143.20635 ++static inline int sigio_block(void)
143.20636 ++{
143.20637 ++	return 0;
143.20638 ++}
143.20639 ++static inline void sigio_unblock(int was_blocked)
143.20640 ++{
143.20641 ++	(void)was_blocked;
143.20642 ++}
143.20643 ++#elif XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
143.20644 ++static inline int sigio_block(void)
143.20645 ++{
143.20646 ++	OsBlockSIGIO();
143.20647 ++	return 0;
143.20648 ++}
143.20649 ++static inline void sigio_unblock(int was_blocked)
143.20650 ++{
143.20651 ++	OsReleaseSIGIO();
143.20652 ++	(void)was_blocked;
143.20653 ++}
143.20654 ++#else
143.20655 ++#include <xf86_OSproc.h>
143.20656 ++static inline int sigio_block(void)
143.20657 ++{
143.20658 ++	return xf86BlockSIGIO();
143.20659 ++}
143.20660 ++static inline void sigio_unblock(int was_blocked)
143.20661 ++{
143.20662 ++	xf86UnblockSIGIO(was_blocked);
143.20663 ++}
143.20664 ++#endif
143.20665 ++
143.20666 + static char *canonical_kmode_name(const struct drm_mode_modeinfo *kmode)
143.20667 + {
143.20668 + 	char tmp[32], *buf;
143.20669 +@@ -781,6 +1206,7 @@ mode_from_kmode(ScrnInfoPtr scrn,
143.20670 + 	mode->VTotal = kmode->vtotal;
143.20671 + 	mode->VScan = kmode->vscan;
143.20672 + 
143.20673 ++	mode->VRefresh = kmode->vrefresh;
143.20674 + 	mode->Flags = kmode->flags;
143.20675 + 	mode->name = get_kmode_name(kmode);
143.20676 + 
143.20677 +@@ -814,6 +1240,7 @@ mode_to_kmode(struct drm_mode_modeinfo *kmode, DisplayModePtr mode)
143.20678 + 	kmode->vtotal = mode->VTotal;
143.20679 + 	kmode->vscan = mode->VScan;
143.20680 + 
143.20681 ++	kmode->vrefresh = mode->VRefresh;
143.20682 + 	kmode->flags = mode->Flags;
143.20683 + 	if (mode->name)
143.20684 + 		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
143.20685 +@@ -824,11 +1251,12 @@ static void
143.20686 + sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
143.20687 + {
143.20688 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
143.20689 ++	/* All attached outputs are valid, so update our timestamps */
143.20690 ++	unsigned now = GetTimeInMillis();
143.20691 + 	int i;
143.20692 + 
143.20693 + 	assert(to_sna_crtc(crtc));
143.20694 +-	DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__,
143.20695 +-	     to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode));
143.20696 ++	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
143.20697 + 
143.20698 + 	/* DPMS handling by the kernel is inconsistent, so after setting a
143.20699 + 	 * mode on an output presume that we intend for it to be on, or that
143.20700 +@@ -843,10 +1271,11 @@ sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
143.20701 + 		if (output->crtc != crtc)
143.20702 + 			continue;
143.20703 + 
143.20704 +-		output->funcs->dpms(output, DPMSModeOn);
143.20705 ++		__sna_output_dpms(output, DPMSModeOn, false);
143.20706 ++		if (to_sna_output(output)->last_detect)
143.20707 ++			to_sna_output(output)->last_detect = now;
143.20708 + 	}
143.20709 + 
143.20710 +-	to_sna_crtc(crtc)->dpms_mode = DPMSModeOn;
143.20711 + #if XF86_CRTC_VERSION >= 3
143.20712 + 	crtc->active = TRUE;
143.20713 + #endif
143.20714 +@@ -859,8 +1288,7 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
143.20715 + 	int i;
143.20716 + 
143.20717 + 	assert(to_sna_crtc(crtc));
143.20718 +-	DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__,
143.20719 +-	     to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode));
143.20720 ++	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
143.20721 + 
143.20722 + 	/* DPMS handling by the kernel is inconsistent, so after setting a
143.20723 + 	 * mode on an output presume that we intend for it to be on, or that
143.20724 +@@ -875,35 +1303,47 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
143.20725 + 		if (output->crtc != crtc)
143.20726 + 			continue;
143.20727 + 
143.20728 +-		output->funcs->dpms(output, DPMSModeOff);
143.20729 ++		__sna_output_dpms(output, DPMSModeOff, false);
143.20730 + 	}
143.20731 +-
143.20732 +-	to_sna_crtc(crtc)->dpms_mode = DPMSModeOff;
143.20733 + }
143.20734 + 
143.20735 + static unsigned
143.20736 +-rotation_reduce(struct plane *p, unsigned rotation)
143.20737 ++rotation_reflect(unsigned rotation)
143.20738 + {
143.20739 +-	unsigned unsupported_rotations = rotation & ~p->rotation.supported;
143.20740 ++	unsigned other_bits;
143.20741 + 
143.20742 +-	if (unsupported_rotations == 0)
143.20743 +-		return rotation;
143.20744 ++	/* paranoia for future extensions */
143.20745 ++	other_bits = rotation & ~RR_Rotate_All;
143.20746 + 
143.20747 +-#define RR_Reflect_XY (RR_Reflect_X | RR_Reflect_Y)
143.20748 ++	/* flip the reflection to compensate for reflecting the rotation */
143.20749 ++	other_bits ^= RR_Reflect_X | RR_Reflect_Y;
143.20750 + 
143.20751 +-	if ((unsupported_rotations & RR_Reflect_XY) == RR_Reflect_XY &&
143.20752 +-	    p->rotation.supported& RR_Rotate_180) {
143.20753 +-		rotation &= ~RR_Reflect_XY;
143.20754 +-		rotation ^= RR_Rotate_180;
143.20755 +-	}
143.20756 ++	/* Reflect the screen by rotating the rotation bit,
143.20757 ++	 * which has to have at least RR_Rotate_0 set. This allows
143.20758 ++	 * us to reflect any of the rotation bits, not just 0.
143.20759 ++	 */
143.20760 ++	rotation &= RR_Rotate_All;
143.20761 ++	assert(rotation);
143.20762 ++	rotation <<= 2; /* RR_Rotate_0 -> RR_Rotate_180 etc */
143.20763 ++	rotation |= rotation >> 4; /* RR_Rotate_270' to RR_Rotate_90 */
143.20764 ++	rotation &= RR_Rotate_All;
143.20765 ++	assert(rotation);
143.20766 + 
143.20767 +-	if ((unsupported_rotations & RR_Rotate_180) &&
143.20768 +-	    (p->rotation.supported& RR_Reflect_XY) == RR_Reflect_XY) {
143.20769 +-		rotation ^= RR_Reflect_XY;
143.20770 +-		rotation &= ~RR_Rotate_180;
143.20771 ++	return rotation | other_bits;
143.20772 ++}
143.20773 ++
143.20774 ++static unsigned
143.20775 ++rotation_reduce(struct plane *p, unsigned rotation)
143.20776 ++{
143.20777 ++	/* If unsupported try exchanging rotation for a reflection */
143.20778 ++	if (rotation & ~p->rotation.supported) {
143.20779 ++		unsigned new_rotation = rotation_reflect(rotation);
143.20780 ++		if ((new_rotation & p->rotation.supported) == new_rotation)
143.20781 ++			rotation = new_rotation;
143.20782 + 	}
143.20783 + 
143.20784 +-#undef RR_Reflect_XY
143.20785 ++	/* Only one rotation bit should be set */
143.20786 ++	assert(is_power_of_two(rotation & RR_Rotate_All));
143.20787 + 
143.20788 + 	return rotation;
143.20789 + }
143.20790 +@@ -923,7 +1363,7 @@ rotation_set(struct sna *sna, struct plane *p, uint32_t desired)
143.20791 + 	if (desired == p->rotation.current)
143.20792 + 		return true;
143.20793 + 
143.20794 +-	if ((desired & p->rotation.supported) == 0) {
143.20795 ++	if ((desired & p->rotation.supported) != desired) {
143.20796 + 		errno = EINVAL;
143.20797 + 		return false;
143.20798 + 	}
143.20799 +@@ -956,20 +1396,105 @@ rotation_reset(struct plane *p)
143.20800 + 	p->rotation.current = 0;
143.20801 + }
143.20802 + 
143.20803 +-bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation)
143.20804 ++bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc,
143.20805 ++				  unsigned idx,
143.20806 ++				  uint32_t rotation)
143.20807 + {
143.20808 ++	struct plane *sprite;
143.20809 + 	assert(to_sna_crtc(crtc));
143.20810 ++
143.20811 ++	sprite = lookup_sprite(to_sna_crtc(crtc), idx);
143.20812 ++	if (!sprite)
143.20813 ++		return false;
143.20814 ++
143.20815 + 	DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n",
143.20816 + 	     __FUNCTION__,
143.20817 +-	     to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->sprite.id,
143.20818 +-	     rotation));
143.20819 ++	     sna_crtc_id(crtc), sna_crtc_pipe(crtc),
143.20820 ++	     sprite->id, rotation));
143.20821 + 
143.20822 +-	return rotation_set(to_sna(crtc->scrn),
143.20823 +-			    &to_sna_crtc(crtc)->sprite,
143.20824 +-			    rotation_reduce(&to_sna_crtc(crtc)->sprite, rotation));
143.20825 ++	return rotation_set(to_sna(crtc->scrn), sprite,
143.20826 ++			    rotation_reduce(sprite, rotation));
143.20827 + }
143.20828 + 
143.20829 +-static bool
143.20830 ++#if HAS_DEBUG_FULL
143.20831 ++#if !HAS_DEBUG_FULL
143.20832 ++#define LogF ErrorF
143.20833 ++#endif
143.20834 ++struct kmsg {
143.20835 ++	int fd;
143.20836 ++	int saved_loglevel;
143.20837 ++};
143.20838 ++
143.20839 ++static int kmsg_get_debug(void)
143.20840 ++{
143.20841 ++	FILE *file;
143.20842 ++	int v = -1;
143.20843 ++
143.20844 ++	file = fopen("/sys/module/drm/parameters/debug", "r");
143.20845 ++	if (file) {
143.20846 ++		fscanf(file, "%d", &v);
143.20847 ++		fclose(file);
143.20848 ++	}
143.20849 ++
143.20850 ++	return v;
143.20851 ++}
143.20852 ++
143.20853 ++static void kmsg_set_debug(int v)
143.20854 ++{
143.20855 ++	FILE *file;
143.20856 ++
143.20857 ++	file = fopen("/sys/module/drm/parameters/debug", "w");
143.20858 ++	if (file) {
143.20859 ++		fprintf(file, "%d\n", v);
143.20860 ++		fclose(file);
143.20861 ++	}
143.20862 ++}
143.20863 ++
143.20864 ++static void kmsg_open(struct kmsg *k)
143.20865 ++{
143.20866 ++	k->saved_loglevel = kmsg_get_debug();
143.20867 ++	if (k->saved_loglevel != -1)
143.20868 ++		kmsg_set_debug(0xff);
143.20869 ++
143.20870 ++	k->fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK);
143.20871 ++	if (k->fd != -1)
143.20872 ++		lseek(k->fd, 0, SEEK_END);
143.20873 ++}
143.20874 ++
143.20875 ++static void kmsg_close(struct kmsg *k, int dump)
143.20876 ++{
143.20877 ++	FILE *file;
143.20878 ++
143.20879 ++	file = NULL;
143.20880 ++	if (k->fd != -1 && dump)
143.20881 ++		file = fdopen(k->fd, "r");
143.20882 ++	if (file) {
143.20883 ++		size_t len = 0;
143.20884 ++		char *line = NULL;
143.20885 ++
143.20886 ++		while (getline(&line, &len, file) != -1) {
143.20887 ++			char *start = strchr(line, ';');
143.20888 ++			if (start)
143.20889 ++				LogF("KMSG: %s", start + 1);
143.20890 ++		}
143.20891 ++
143.20892 ++		free(line);
143.20893 ++		fclose(file);
143.20894 ++	}
143.20895 ++
143.20896 ++	if (k->fd != -1)
143.20897 ++		close(k->fd);
143.20898 ++
143.20899 ++	if (k->saved_loglevel != -1)
143.20900 ++		kmsg_set_debug(k->saved_loglevel);
143.20901 ++}
143.20902 ++#else
143.20903 ++struct kmsg { int unused; };
143.20904 ++static void kmsg_open(struct kmsg *k) {}
143.20905 ++static void kmsg_close(struct kmsg *k, int dump) {}
143.20906 ++#endif
143.20907 ++
143.20908 ++static int
143.20909 + sna_crtc_apply(xf86CrtcPtr crtc)
143.20910 + {
143.20911 + 	struct sna *sna = to_sna(crtc->scrn);
143.20912 +@@ -978,26 +1503,39 @@ sna_crtc_apply(xf86CrtcPtr crtc)
143.20913 + 	struct drm_mode_crtc arg;
143.20914 + 	uint32_t output_ids[32];
143.20915 + 	int output_count = 0;
143.20916 +-	int i;
143.20917 ++	int sigio, i;
143.20918 ++	struct kmsg kmsg;
143.20919 ++	int ret = EINVAL;
143.20920 + 
143.20921 +-	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle));
143.20922 ++	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__,
143.20923 ++	     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
143.20924 ++	     sna_crtc->bo->handle));
143.20925 + 	if (!sna_crtc->kmode.clock) {
143.20926 + 		ERR(("%s(CRTC:%d [pipe=%d]): attempted to set an invalid mode\n",
143.20927 +-		     __FUNCTION__, sna_crtc->id, sna_crtc->pipe));
143.20928 +-		return false;
143.20929 ++		     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc)));
143.20930 ++		return EINVAL;
143.20931 + 	}
143.20932 + 
143.20933 ++	kmsg_open(&kmsg);
143.20934 ++	sigio = sigio_block();
143.20935 ++
143.20936 + 	assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
143.20937 + 	sna_crtc_disable_cursor(sna, sna_crtc);
143.20938 + 
143.20939 + 	if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) {
143.20940 ++		memset(&arg, 0, sizeof(arg));
143.20941 ++		arg.crtc_id = __sna_crtc_id(sna_crtc);
143.20942 ++		(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
143.20943 ++	}
143.20944 ++
143.20945 ++	if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) {
143.20946 + 		ERR(("%s: set-primary-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n",
143.20947 +-		     __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, sna_crtc->id, sna_crtc->pipe, errno));
143.20948 ++		     __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
143.20949 + 		sna_crtc->primary.rotation.supported &= ~sna_crtc->rotation;
143.20950 +-		return false;
143.20951 ++		goto unblock;
143.20952 + 	}
143.20953 + 	DBG(("%s: CRTC:%d [pipe=%d] primary rotation set to %x\n",
143.20954 +-	     __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation));
143.20955 ++	     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna_crtc->rotation));
143.20956 + 
143.20957 + 	for (i = 0; i < sna->mode.num_real_output; i++) {
143.20958 + 		xf86OutputPtr output = config->output[i];
143.20959 +@@ -1008,7 +1546,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
143.20960 + 		 * and we lose track of the user settings.
143.20961 + 		 */
143.20962 + 		if (output->crtc == NULL)
143.20963 +-			output->funcs->dpms(output, DPMSModeOff);
143.20964 ++			__sna_output_dpms(output, DPMSModeOff, false);
143.20965 + 
143.20966 + 		if (output->crtc != crtc)
143.20967 + 			continue;
143.20968 +@@ -1022,29 +1560,27 @@ sna_crtc_apply(xf86CrtcPtr crtc)
143.20969 + 
143.20970 + 		DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
143.20971 + 		     __FUNCTION__, output->name, i, to_connector_id(output),
143.20972 +-		     sna_crtc->id, sna_crtc->pipe,
143.20973 ++		     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
143.20974 + 		     (uint32_t)output->possible_crtcs,
143.20975 + 		     (uint32_t)output->possible_clones));
143.20976 + 
143.20977 +-		assert(output->possible_crtcs & (1 << sna_crtc->pipe) ||
143.20978 ++		assert(output->possible_crtcs & (1 << __sna_crtc_pipe(sna_crtc)) ||
143.20979 + 		       is_zaphod(crtc->scrn));
143.20980 + 
143.20981 + 		output_ids[output_count] = to_connector_id(output);
143.20982 + 		if (++output_count == ARRAY_SIZE(output_ids)) {
143.20983 + 			DBG(("%s: too many outputs (%d) for me!\n",
143.20984 + 			     __FUNCTION__, output_count));
143.20985 +-			errno = EINVAL;
143.20986 +-			return false;
143.20987 ++			goto unblock;
143.20988 + 		}
143.20989 + 	}
143.20990 + 	if (output_count == 0) {
143.20991 + 		DBG(("%s: no outputs\n", __FUNCTION__));
143.20992 +-		errno = EINVAL;
143.20993 +-		return false;
143.20994 ++		goto unblock;
143.20995 + 	}
143.20996 + 
143.20997 + 	VG_CLEAR(arg);
143.20998 +-	arg.crtc_id = sna_crtc->id;
143.20999 ++	arg.crtc_id = __sna_crtc_id(sna_crtc);
143.21000 + 	arg.fb_id = fb_id(sna_crtc->bo);
143.21001 + 	if (sna_crtc->transform || sna_crtc->slave_pixmap) {
143.21002 + 		arg.x = 0;
143.21003 +@@ -1061,7 +1597,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
143.21004 + 	arg.mode_valid = 1;
143.21005 + 
143.21006 + 	DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d%s%s update to %d outputs [%d...]\n",
143.21007 +-	     __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
143.21008 ++	     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
143.21009 + 	     arg.mode.hdisplay,
143.21010 + 	     arg.mode.vdisplay,
143.21011 + 	     arg.x, arg.y,
143.21012 +@@ -1071,12 +1607,19 @@ sna_crtc_apply(xf86CrtcPtr crtc)
143.21013 + 	     sna_crtc->transform ? " [transformed]" : "",
143.21014 + 	     output_count, output_count ? output_ids[0] : 0));
143.21015 + 
143.21016 +-	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
143.21017 +-		return false;
143.21018 ++	ret = 0;
143.21019 ++	if (unlikely(drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))) {
143.21020 ++		ret = errno;
143.21021 ++		goto unblock;
143.21022 ++	}
143.21023 + 
143.21024 + 	sna_crtc->mode_serial++;
143.21025 + 	sna_crtc_force_outputs_on(crtc);
143.21026 +-	return true;
143.21027 ++
143.21028 ++unblock:
143.21029 ++	sigio_unblock(sigio);
143.21030 ++	kmsg_close(&kmsg, ret);
143.21031 ++	return ret;
143.21032 + }
143.21033 + 
143.21034 + static bool overlap(const BoxRec *a, const BoxRec *b)
143.21035 +@@ -1094,26 +1637,73 @@ static bool overlap(const BoxRec *a, const BoxRec *b)
143.21036 + 	return true;
143.21037 + }
143.21038 + 
143.21039 ++static void defer_event(struct sna *sna, struct drm_event *base)
143.21040 ++{
143.21041 ++	if (sna->mode.shadow_nevent == sna->mode.shadow_size) {
143.21042 ++		int size = sna->mode.shadow_size * 2;
143.21043 ++		void *ptr;
143.21044 ++
143.21045 ++		ptr = realloc(sna->mode.shadow_events,
143.21046 ++			      sizeof(struct drm_event_vblank)*size);
143.21047 ++		if (!ptr)
143.21048 ++			return;
143.21049 ++
143.21050 ++		sna->mode.shadow_events = ptr;
143.21051 ++		sna->mode.shadow_size = size;
143.21052 ++	}
143.21053 ++
143.21054 ++	memcpy(&sna->mode.shadow_events[sna->mode.shadow_nevent++],
143.21055 ++	       base, sizeof(struct drm_event_vblank));
143.21056 ++	DBG(("%s: deferring event count=%d\n",
143.21057 ++	     __func__, sna->mode.shadow_nevent));
143.21058 ++}
143.21059 ++
143.21060 ++static void flush_events(struct sna *sna)
143.21061 ++{
143.21062 ++	int n;
143.21063 ++
143.21064 ++	if (!sna->mode.shadow_nevent)
143.21065 ++		return;
143.21066 ++
143.21067 ++	DBG(("%s: flushing %d events=%d\n", __func__, sna->mode.shadow_nevent));
143.21068 ++
143.21069 ++	for (n = 0; n < sna->mode.shadow_nevent; n++) {
143.21070 ++		struct drm_event_vblank *vb = &sna->mode.shadow_events[n];
143.21071 ++
143.21072 ++		if ((uintptr_t)(vb->user_data) & 2)
143.21073 ++			sna_present_vblank_handler(vb);
143.21074 ++		else
143.21075 ++			sna_dri2_vblank_handler(vb);
143.21076 ++	}
143.21077 ++
143.21078 ++	sna->mode.shadow_nevent = 0;
143.21079 ++}
143.21080 ++
143.21081 ++
143.21082 + static bool wait_for_shadow(struct sna *sna,
143.21083 + 			    struct sna_pixmap *priv,
143.21084 + 			    unsigned flags)
143.21085 + {
143.21086 + 	PixmapPtr pixmap = priv->pixmap;
143.21087 +-	DamagePtr damage;
143.21088 + 	struct kgem_bo *bo, *tmp;
143.21089 + 	int flip_active;
143.21090 + 	bool ret = true;
143.21091 + 
143.21092 +-	DBG(("%s: flags=%x, flips=%d, handle=%d, shadow=%d\n",
143.21093 +-	     __FUNCTION__, flags, sna->mode.flip_active,
143.21094 ++	DBG(("%s: enabled? %d waiting? %d, flags=%x, flips=%d, pixmap=%ld [front?=%d], handle=%d, shadow=%d\n",
143.21095 ++	     __FUNCTION__, sna->mode.shadow_enabled, sna->mode.shadow_wait,
143.21096 ++	     flags, sna->mode.flip_active,
143.21097 ++	     pixmap->drawable.serialNumber, pixmap == sna->front,
143.21098 + 	     priv->gpu_bo->handle, sna->mode.shadow->handle));
143.21099 + 
143.21100 + 	assert(priv->move_to_gpu_data == sna);
143.21101 + 	assert(sna->mode.shadow != priv->gpu_bo);
143.21102 + 
143.21103 +-	if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_damage)
143.21104 ++	if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_enabled)
143.21105 + 		goto done;
143.21106 + 
143.21107 ++	assert(sna->mode.shadow_damage);
143.21108 ++	assert(!sna->mode.shadow_wait);
143.21109 ++
143.21110 + 	if ((flags & MOVE_WRITE) == 0) {
143.21111 + 		if ((flags & __MOVE_SCANOUT) == 0) {
143.21112 + 			struct sna_crtc *crtc;
143.21113 +@@ -1154,9 +1744,7 @@ static bool wait_for_shadow(struct sna *sna,
143.21114 + 	}
143.21115 + 
143.21116 + 	assert(sna->mode.shadow_active);
143.21117 +-
143.21118 +-	damage = sna->mode.shadow_damage;
143.21119 +-	sna->mode.shadow_damage = NULL;
143.21120 ++	sna->mode.shadow_wait = true;
143.21121 + 
143.21122 + 	flip_active = sna->mode.flip_active;
143.21123 + 	if (flip_active) {
143.21124 +@@ -1208,6 +1796,8 @@ static bool wait_for_shadow(struct sna *sna,
143.21125 + 			bo = sna->mode.shadow;
143.21126 + 		}
143.21127 + 	}
143.21128 ++	assert(sna->mode.shadow_wait);
143.21129 ++	sna->mode.shadow_wait = false;
143.21130 + 
143.21131 + 	if (bo->refcnt > 1) {
143.21132 + 		bo = kgem_create_2d(&sna->kgem,
143.21133 +@@ -1230,8 +1820,6 @@ static bool wait_for_shadow(struct sna *sna,
143.21134 + 			bo = sna->mode.shadow;
143.21135 + 	}
143.21136 + 
143.21137 +-	sna->mode.shadow_damage = damage;
143.21138 +-
143.21139 + 	RegionSubtract(&sna->mode.shadow_region,
143.21140 + 		       &sna->mode.shadow_region,
143.21141 + 		       &sna->mode.shadow_cancel);
143.21142 +@@ -1269,6 +1857,7 @@ static bool wait_for_shadow(struct sna *sna,
143.21143 + 			RegionSubtract(&sna->mode.shadow_region, &sna->mode.shadow_region, &region);
143.21144 + 		}
143.21145 + 
143.21146 ++		crtc->client_bo->active_scanout--;
143.21147 + 		kgem_bo_destroy(&sna->kgem, crtc->client_bo);
143.21148 + 		crtc->client_bo = NULL;
143.21149 + 		list_del(&crtc->shadow_link);
143.21150 +@@ -1281,12 +1870,13 @@ static bool wait_for_shadow(struct sna *sna,
143.21151 + 		     sna->mode.shadow_region.extents.y1,
143.21152 + 		     sna->mode.shadow_region.extents.x2,
143.21153 + 		     sna->mode.shadow_region.extents.y2));
143.21154 +-		ret = sna->render.copy_boxes(sna, GXcopy,
143.21155 +-					     &pixmap->drawable, priv->gpu_bo, 0, 0,
143.21156 +-					     &pixmap->drawable, bo, 0, 0,
143.21157 +-					     region_rects(&sna->mode.shadow_region),
143.21158 +-					     region_num_rects(&sna->mode.shadow_region),
143.21159 +-					     0);
143.21160 ++		if (!sna->render.copy_boxes(sna, GXcopy,
143.21161 ++					    &pixmap->drawable, priv->gpu_bo, 0, 0,
143.21162 ++					    &pixmap->drawable, bo, 0, 0,
143.21163 ++					    region_rects(&sna->mode.shadow_region),
143.21164 ++					    region_num_rects(&sna->mode.shadow_region),
143.21165 ++					    0))
143.21166 ++			ERR(("%s: copy failed\n", __FUNCTION__));
143.21167 + 	}
143.21168 + 
143.21169 + 	if (priv->cow)
143.21170 +@@ -1295,11 +1885,13 @@ static bool wait_for_shadow(struct sna *sna,
143.21171 + 	sna_pixmap_unmap(pixmap, priv);
143.21172 + 
143.21173 + 	DBG(("%s: setting front pixmap to handle=%d\n", __FUNCTION__, bo->handle));
143.21174 ++	sna->mode.shadow->active_scanout--;
143.21175 + 	tmp = priv->gpu_bo;
143.21176 + 	priv->gpu_bo = bo;
143.21177 + 	if (bo != sna->mode.shadow)
143.21178 + 		kgem_bo_destroy(&sna->kgem, sna->mode.shadow);
143.21179 + 	sna->mode.shadow = tmp;
143.21180 ++	sna->mode.shadow->active_scanout++;
143.21181 + 
143.21182 + 	sna_dri2_pixmap_update_bo(sna, pixmap, bo);
143.21183 + 
143.21184 +@@ -1311,6 +1903,9 @@ done:
143.21185 + 	priv->move_to_gpu_data = NULL;
143.21186 + 	priv->move_to_gpu = NULL;
143.21187 + 
143.21188 ++	assert(!sna->mode.shadow_wait);
143.21189 ++	flush_events(sna);
143.21190 ++
143.21191 + 	return ret;
143.21192 + }
143.21193 + 
143.21194 +@@ -1358,22 +1953,43 @@ bool sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv,
143.21195 + 	return RegionNil(&sna->mode.shadow_region);
143.21196 + }
143.21197 + 
143.21198 ++static void sna_mode_damage(DamagePtr damage, RegionPtr region, void *closure)
143.21199 ++{
143.21200 ++	struct sna *sna = closure;
143.21201 ++
143.21202 ++	if (sna->mode.rr_active)
143.21203 ++		return;
143.21204 ++
143.21205 ++	/* Throw away the rectangles if the region grows too big */
143.21206 ++	region = DamageRegion(damage);
143.21207 ++	if (region->data) {
143.21208 ++		RegionRec dup;
143.21209 ++
143.21210 ++		dup = *region;
143.21211 ++		RegionUninit(&dup);
143.21212 ++
143.21213 ++		region->data = NULL;
143.21214 ++	}
143.21215 ++}
143.21216 ++
143.21217 + static bool sna_mode_enable_shadow(struct sna *sna)
143.21218 + {
143.21219 +-	ScreenPtr screen = sna->scrn->pScreen;
143.21220 ++	ScreenPtr screen = to_screen_from_sna(sna);
143.21221 + 
143.21222 + 	DBG(("%s\n", __FUNCTION__));
143.21223 + 	assert(sna->mode.shadow == NULL);
143.21224 + 	assert(sna->mode.shadow_damage == NULL);
143.21225 + 	assert(sna->mode.shadow_active == 0);
143.21226 ++	assert(!sna->mode.shadow_enabled);
143.21227 + 
143.21228 +-	sna->mode.shadow_damage = DamageCreate(NULL, NULL,
143.21229 +-					       DamageReportNone, TRUE,
143.21230 +-					       screen, screen);
143.21231 ++	sna->mode.shadow_damage = DamageCreate(sna_mode_damage, NULL,
143.21232 ++					       DamageReportRawRegion,
143.21233 ++					       TRUE, screen, sna);
143.21234 + 	if (!sna->mode.shadow_damage)
143.21235 + 		return false;
143.21236 + 
143.21237 + 	DamageRegister(&sna->front->drawable, sna->mode.shadow_damage);
143.21238 ++	sna->mode.shadow_enabled = true;
143.21239 + 	return true;
143.21240 + }
143.21241 + 
143.21242 +@@ -1381,8 +1997,10 @@ static void sna_mode_disable_shadow(struct sna *sna)
143.21243 + {
143.21244 + 	struct sna_pixmap *priv;
143.21245 + 
143.21246 +-	if (!sna->mode.shadow_damage)
143.21247 ++	if (!sna->mode.shadow_damage) {
143.21248 ++		assert(!sna->mode.shadow_enabled);
143.21249 + 		return;
143.21250 ++	}
143.21251 + 
143.21252 + 	DBG(("%s\n", __FUNCTION__));
143.21253 + 
143.21254 +@@ -1393,8 +2011,10 @@ static void sna_mode_disable_shadow(struct sna *sna)
143.21255 + 	DamageUnregister(&sna->front->drawable, sna->mode.shadow_damage);
143.21256 + 	DamageDestroy(sna->mode.shadow_damage);
143.21257 + 	sna->mode.shadow_damage = NULL;
143.21258 ++	sna->mode.shadow_enabled = false;
143.21259 + 
143.21260 + 	if (sna->mode.shadow) {
143.21261 ++		sna->mode.shadow->active_scanout--;
143.21262 + 		kgem_bo_destroy(&sna->kgem, sna->mode.shadow);
143.21263 + 		sna->mode.shadow = NULL;
143.21264 + 	}
143.21265 +@@ -1413,7 +2033,7 @@ static void sna_crtc_slave_damage(DamagePtr damage, RegionPtr region, void *clos
143.21266 + 	     __FUNCTION__,
143.21267 + 	     region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2,
143.21268 + 	     region_num_rects(region),
143.21269 +-	     crtc->pipe, crtc->base->x, crtc->base->y));
143.21270 ++	     __sna_crtc_pipe(crtc), crtc->base->x, crtc->base->y));
143.21271 + 
143.21272 + 	assert(crtc->slave_damage == damage);
143.21273 + 	assert(sna->mode.shadow_damage);
143.21274 +@@ -1431,7 +2051,7 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
143.21275 + 		return true;
143.21276 + 	}
143.21277 + 
143.21278 +-	DBG(("%s: enabling for crtc %d\n", __FUNCTION__, crtc->id));
143.21279 ++	DBG(("%s: enabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
143.21280 + 
143.21281 + 	if (!sna->mode.shadow_active) {
143.21282 + 		if (!sna_mode_enable_shadow(sna))
143.21283 +@@ -1443,9 +2063,12 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
143.21284 + 	if (crtc->slave_pixmap) {
143.21285 + 		assert(crtc->slave_damage == NULL);
143.21286 + 
143.21287 ++		DBG(("%s: enabling PRIME slave tracking on CRTC %d [pipe=%d], pixmap=%ld\n",
143.21288 ++		     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->slave_pixmap->drawable.serialNumber));
143.21289 + 		crtc->slave_damage = DamageCreate(sna_crtc_slave_damage, NULL,
143.21290 + 						  DamageReportRawRegion, TRUE,
143.21291 +-						  sna->scrn->pScreen, crtc);
143.21292 ++						  to_screen_from_sna(sna),
143.21293 ++						  crtc);
143.21294 + 		if (crtc->slave_damage == NULL) {
143.21295 + 			if (!--sna->mode.shadow_active)
143.21296 + 				sna_mode_disable_shadow(sna);
143.21297 +@@ -1465,6 +2088,9 @@ static void sna_crtc_disable_override(struct sna *sna, struct sna_crtc *crtc)
143.21298 + 	if (crtc->client_bo == NULL)
143.21299 + 		return;
143.21300 + 
143.21301 ++	assert(crtc->client_bo->refcnt >= crtc->client_bo->active_scanout);
143.21302 ++	crtc->client_bo->active_scanout--;
143.21303 ++
143.21304 + 	if (!crtc->transform) {
143.21305 + 		DrawableRec tmp;
143.21306 + 
143.21307 +@@ -1489,7 +2115,7 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc)
143.21308 + 	if (!crtc->shadow)
143.21309 + 		return;
143.21310 + 
143.21311 +-	DBG(("%s: disabling for crtc %d\n", __FUNCTION__, crtc->id));
143.21312 ++	DBG(("%s: disabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
143.21313 + 	assert(sna->mode.shadow_active > 0);
143.21314 + 
143.21315 + 	if (crtc->slave_damage) {
143.21316 +@@ -1517,14 +2143,24 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc)
143.21317 + 	sna_crtc_disable_shadow(sna, sna_crtc);
143.21318 + 
143.21319 + 	if (sna_crtc->bo) {
143.21320 ++		DBG(("%s: releasing handle=%d from scanout, active=%d\n",
143.21321 ++		     __FUNCTION__,sna_crtc->bo->handle, sna_crtc->bo->active_scanout-1));
143.21322 ++		assert(sna_crtc->flags & CRTC_ON);
143.21323 + 		assert(sna_crtc->bo->active_scanout);
143.21324 + 		assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
143.21325 + 		sna_crtc->bo->active_scanout--;
143.21326 + 		kgem_bo_destroy(&sna->kgem, sna_crtc->bo);
143.21327 + 		sna_crtc->bo = NULL;
143.21328 ++		sna_crtc->flags &= ~CRTC_ON;
143.21329 + 
143.21330 +-		assert(sna->mode.front_active);
143.21331 +-		sna->mode.front_active--;
143.21332 ++		if (sna->mode.hidden) {
143.21333 ++			sna->mode.hidden--;
143.21334 ++			assert(sna->mode.hidden);
143.21335 ++			assert(sna->mode.front_active == 0);
143.21336 ++		} else {
143.21337 ++			assert(sna->mode.front_active);
143.21338 ++			sna->mode.front_active--;
143.21339 ++		}
143.21340 + 		sna->mode.dirty = true;
143.21341 + 	}
143.21342 + 
143.21343 +@@ -1532,13 +2168,19 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc)
143.21344 + 		kgem_bo_destroy(&sna->kgem, sna_crtc->shadow_bo);
143.21345 + 		sna_crtc->shadow_bo = NULL;
143.21346 + 	}
143.21347 +-	sna_crtc->transform = false;
143.21348 ++	if (sna_crtc->transform) {
143.21349 ++		assert(sna->mode.rr_active);
143.21350 ++		sna->mode.rr_active--;
143.21351 ++		sna_crtc->transform = false;
143.21352 ++	}
143.21353 + 
143.21354 ++	sna_crtc->cursor_transform = false;
143.21355 ++	sna_crtc->hwcursor = true;
143.21356 + 	assert(!sna_crtc->shadow);
143.21357 + }
143.21358 + 
143.21359 + static void
143.21360 +-sna_crtc_disable(xf86CrtcPtr crtc)
143.21361 ++sna_crtc_disable(xf86CrtcPtr crtc, bool force)
143.21362 + {
143.21363 + 	struct sna *sna = to_sna(crtc->scrn);
143.21364 + 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.21365 +@@ -1547,14 +2189,16 @@ sna_crtc_disable(xf86CrtcPtr crtc)
143.21366 + 	if (sna_crtc == NULL)
143.21367 + 		return;
143.21368 + 
143.21369 +-	DBG(("%s: disabling crtc [%d, pipe=%d]\n", __FUNCTION__,
143.21370 +-	     sna_crtc->id, sna_crtc->pipe));
143.21371 ++	if (!force && sna_crtc->bo == NULL)
143.21372 ++		return;
143.21373 ++
143.21374 ++	DBG(("%s: disabling crtc [%d, pipe=%d], force?=%d\n", __FUNCTION__,
143.21375 ++	     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), force));
143.21376 + 
143.21377 + 	sna_crtc_force_outputs_off(crtc);
143.21378 +-	assert(sna_crtc->dpms_mode == DPMSModeOff);
143.21379 + 
143.21380 + 	memset(&arg, 0, sizeof(arg));
143.21381 +-	arg.crtc_id = sna_crtc->id;
143.21382 ++	arg.crtc_id = __sna_crtc_id(sna_crtc);
143.21383 + 	(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
143.21384 + 
143.21385 + 	__sna_crtc_disable(sna, sna_crtc);
143.21386 +@@ -1574,19 +2218,19 @@ static void update_flush_interval(struct sna *sna)
143.21387 + 
143.21388 + 		if (!crtc->enabled) {
143.21389 + 			DBG(("%s: CRTC:%d (pipe %d) disabled\n",
143.21390 +-			     __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
143.21391 ++			     __FUNCTION__,i, sna_crtc_pipe(crtc)));
143.21392 + 			assert(to_sna_crtc(crtc)->bo == NULL);
143.21393 + 			continue;
143.21394 + 		}
143.21395 + 
143.21396 +-		if (to_sna_crtc(crtc)->dpms_mode != DPMSModeOn) {
143.21397 ++		if (to_sna_crtc(crtc)->bo == NULL) {
143.21398 + 			DBG(("%s: CRTC:%d (pipe %d) turned off\n",
143.21399 +-			     __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
143.21400 ++			     __FUNCTION__,i, sna_crtc_pipe(crtc)));
143.21401 + 			continue;
143.21402 + 		}
143.21403 + 
143.21404 + 		DBG(("%s: CRTC:%d (pipe %d) vrefresh=%f\n",
143.21405 +-		     __FUNCTION__, i, to_sna_crtc(crtc)->pipe,
143.21406 ++		     __FUNCTION__, i, sna_crtc_pipe(crtc),
143.21407 + 		     xf86ModeVRefresh(&crtc->mode)));
143.21408 + 		max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(&crtc->mode));
143.21409 + 	}
143.21410 +@@ -1642,7 +2286,7 @@ void sna_copy_fbcon(struct sna *sna)
143.21411 + 	int dx, dy;
143.21412 + 	int i;
143.21413 + 
143.21414 +-	if (wedged(sna))
143.21415 ++	if (wedged(sna) || isGPU(sna->scrn))
143.21416 + 		return;
143.21417 + 
143.21418 + 	DBG(("%s\n", __FUNCTION__));
143.21419 +@@ -1662,7 +2306,7 @@ void sna_copy_fbcon(struct sna *sna)
143.21420 + 		assert(crtc != NULL);
143.21421 + 
143.21422 + 		VG_CLEAR(mode);
143.21423 +-		mode.crtc_id = crtc->id;
143.21424 ++		mode.crtc_id = __sna_crtc_id(crtc);
143.21425 + 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
143.21426 + 			continue;
143.21427 + 		if (!mode.fb_id)
143.21428 +@@ -1726,7 +2370,7 @@ void sna_copy_fbcon(struct sna *sna)
143.21429 + 	kgem_bo_destroy(&sna->kgem, bo);
143.21430 + 
143.21431 + #if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(10, 0)
143.21432 +-	sna->scrn->pScreen->canDoBGNoneRoot = ok;
143.21433 ++	to_screen_from_sna(sna)->canDoBGNoneRoot = ok;
143.21434 + #endif
143.21435 + }
143.21436 + 
143.21437 +@@ -1736,7 +2380,6 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
143.21438 + 	PictTransform crtc_to_fb;
143.21439 + 	struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
143.21440 + 	unsigned pitch_limit;
143.21441 +-	struct sna_pixmap *priv;
143.21442 + 	BoxRec b;
143.21443 + 
143.21444 + 	assert(sna->scrn->virtualX && sna->scrn->virtualY);
143.21445 +@@ -1765,27 +2408,31 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
143.21446 + 		return true;
143.21447 + 	}
143.21448 + 
143.21449 +-	priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | __MOVE_SCANOUT);
143.21450 +-	if (priv == NULL)
143.21451 +-		return true; /* maybe we can create a bo for the scanout? */
143.21452 +-
143.21453 +-	if (sna->kgem.gen == 071)
143.21454 +-		pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
143.21455 +-	else if ((sna->kgem.gen >> 3) > 4)
143.21456 +-		pitch_limit = 32 * 1024;
143.21457 +-	else if ((sna->kgem.gen >> 3) == 4)
143.21458 +-		pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
143.21459 +-	else if ((sna->kgem.gen >> 3) == 3)
143.21460 +-		pitch_limit = priv->gpu_bo->tiling ? 8 * 1024 : 16 * 1024;
143.21461 +-	else
143.21462 +-		pitch_limit = 8 * 1024;
143.21463 +-	DBG(("%s: gpu bo handle=%d tiling=%d pitch=%d, limit=%d\n", __FUNCTION__, priv->gpu_bo->handle, priv->gpu_bo->tiling, priv->gpu_bo->pitch, pitch_limit));
143.21464 +-	if (priv->gpu_bo->pitch > pitch_limit)
143.21465 +-		return true;
143.21466 ++	if (!isGPU(sna->scrn)) {
143.21467 ++		struct sna_pixmap *priv;
143.21468 + 
143.21469 +-	if (priv->gpu_bo->tiling && sna->flags & SNA_LINEAR_FB) {
143.21470 +-		DBG(("%s: gpu bo is tiled, need linear, forcing shadow\n", __FUNCTION__));
143.21471 +-		return true;
143.21472 ++		priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | __MOVE_SCANOUT);
143.21473 ++		if (priv == NULL)
143.21474 ++			return true; /* maybe we can create a bo for the scanout? */
143.21475 ++
143.21476 ++		if (sna->kgem.gen == 071)
143.21477 ++			pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
143.21478 ++		else if ((sna->kgem.gen >> 3) > 4)
143.21479 ++			pitch_limit = 32 * 1024;
143.21480 ++		else if ((sna->kgem.gen >> 3) == 4)
143.21481 ++			pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
143.21482 ++		else if ((sna->kgem.gen >> 3) == 3)
143.21483 ++			pitch_limit = priv->gpu_bo->tiling ? 8 * 1024 : 16 * 1024;
143.21484 ++		else
143.21485 ++			pitch_limit = 8 * 1024;
143.21486 ++		DBG(("%s: gpu bo handle=%d tiling=%d pitch=%d, limit=%d\n", __FUNCTION__, priv->gpu_bo->handle, priv->gpu_bo->tiling, priv->gpu_bo->pitch, pitch_limit));
143.21487 ++		if (priv->gpu_bo->pitch > pitch_limit)
143.21488 ++			return true;
143.21489 ++
143.21490 ++		if (priv->gpu_bo->tiling && sna->flags & SNA_LINEAR_FB) {
143.21491 ++			DBG(("%s: gpu bo is tiled, need linear, forcing shadow\n", __FUNCTION__));
143.21492 ++			return true;
143.21493 ++		}
143.21494 + 	}
143.21495 + 
143.21496 + 	transform = NULL;
143.21497 +@@ -1800,9 +2447,9 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
143.21498 + 		bool needs_transform = true;
143.21499 + 		unsigned rotation = rotation_reduce(&to_sna_crtc(crtc)->primary, crtc->rotation);
143.21500 + 		DBG(("%s: natively supported rotation? rotation=%x & supported=%x == %d\n",
143.21501 +-		     __FUNCTION__, crtc->rotation, to_sna_crtc(crtc)->primary.rotation.supported,
143.21502 +-		     !!(crtc->rotation & to_sna_crtc(crtc)->primary.rotation.supported)));
143.21503 +-		if (to_sna_crtc(crtc)->primary.rotation.supported & rotation)
143.21504 ++		     __FUNCTION__, rotation, to_sna_crtc(crtc)->primary.rotation.supported,
143.21505 ++		     rotation == (rotation & to_sna_crtc(crtc)->primary.rotation.supported)));
143.21506 ++		if ((to_sna_crtc(crtc)->primary.rotation.supported & rotation) == rotation)
143.21507 + 			needs_transform = RRTransformCompute(crtc->x, crtc->y,
143.21508 + 							     crtc->mode.HDisplay, crtc->mode.VDisplay,
143.21509 + 							     RR_Rotate_0, transform,
143.21510 +@@ -1839,6 +2486,7 @@ static void set_shadow(struct sna *sna, RegionPtr region)
143.21511 + 
143.21512 + 	assert(priv->gpu_bo);
143.21513 + 	assert(sna->mode.shadow);
143.21514 ++	assert(sna->mode.shadow->active_scanout);
143.21515 + 
143.21516 + 	DBG(("%s: waiting for region %dx[(%d, %d), (%d, %d)], front handle=%d, shadow handle=%d\n",
143.21517 + 	     __FUNCTION__,
143.21518 +@@ -1912,6 +2560,28 @@ get_scanout_bo(struct sna *sna, PixmapPtr pixmap)
143.21519 + 	return priv->gpu_bo;
143.21520 + }
143.21521 + 
143.21522 ++static void shadow_clear(struct sna *sna,
143.21523 ++			 PixmapPtr front, struct kgem_bo *bo,
143.21524 ++			 xf86CrtcPtr crtc)
143.21525 ++{
143.21526 ++	bool ok = false;
143.21527 ++	if (!wedged(sna))
143.21528 ++		ok = sna->render.fill_one(sna, front, bo, 0,
143.21529 ++					  0, 0, crtc->mode.HDisplay, crtc->mode.VDisplay,
143.21530 ++					  GXclear);
143.21531 ++	if (!ok) {
143.21532 ++		void *ptr = kgem_bo_map__gtt(&sna->kgem, bo);
143.21533 ++		if (ptr)
143.21534 ++			memset(ptr, 0, bo->pitch * crtc->mode.HDisplay);
143.21535 ++	}
143.21536 ++	sna->mode.shadow_dirty = true;
143.21537 ++}
143.21538 ++
143.21539 ++static bool rr_active(xf86CrtcPtr crtc)
143.21540 ++{
143.21541 ++	return crtc->transformPresent || crtc->rotation != RR_Rotate_0;
143.21542 ++}
143.21543 ++
143.21544 + static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
143.21545 + {
143.21546 + 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.21547 +@@ -1919,10 +2589,15 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
143.21548 + 	struct sna *sna = to_sna(scrn);
143.21549 + 	struct kgem_bo *bo;
143.21550 + 
143.21551 +-	sna_crtc->transform = false;
143.21552 ++	if (sna_crtc->transform) {
143.21553 ++		assert(sna->mode.rr_active);
143.21554 ++		sna_crtc->transform = false;
143.21555 ++		sna->mode.rr_active--;
143.21556 ++	}
143.21557 + 	sna_crtc->rotation = RR_Rotate_0;
143.21558 + 
143.21559 + 	if (use_shadow(sna, crtc)) {
143.21560 ++		PixmapPtr front;
143.21561 + 		unsigned long tiled_limit;
143.21562 + 		int tiling;
143.21563 + 
143.21564 +@@ -1949,6 +2624,10 @@ force_shadow:
143.21565 + 		}
143.21566 + 
143.21567 + 		tiling = I915_TILING_X;
143.21568 ++		if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270) &&
143.21569 ++		    sna->kgem.can_scanout_y)
143.21570 ++			tiling = I915_TILING_Y;
143.21571 ++
143.21572 + 		if (sna->kgem.gen == 071)
143.21573 + 			tiled_limit = 16 * 1024 * 8;
143.21574 + 		else if ((sna->kgem.gen >> 3) > 4)
143.21575 +@@ -1977,8 +2656,8 @@ force_shadow:
143.21576 + 			return NULL;
143.21577 + 		}
143.21578 + 
143.21579 +-		if (__sna_pixmap_get_bo(sna->front) && !crtc->transformPresent) {
143.21580 +-			DrawableRec tmp;
143.21581 ++		front = sna_crtc->slave_pixmap ?: sna->front;
143.21582 ++		if (__sna_pixmap_get_bo(front) && !rr_active(crtc)) {
143.21583 + 			BoxRec b;
143.21584 + 
143.21585 + 			b.x1 = crtc->x;
143.21586 +@@ -1986,28 +2665,48 @@ force_shadow:
143.21587 + 			b.x2 = crtc->x + crtc->mode.HDisplay;
143.21588 + 			b.y2 = crtc->y + crtc->mode.VDisplay;
143.21589 + 
143.21590 +-			DBG(("%s: copying onto shadow CRTC: (%d, %d)x(%d, %d), handle=%d\n",
143.21591 +-			     __FUNCTION__,
143.21592 +-			     b.x1, b.y1,
143.21593 +-			     b.x2, b.y2,
143.21594 +-			     bo->handle));
143.21595 +-
143.21596 +-			tmp.width = crtc->mode.HDisplay;
143.21597 +-			tmp.height = crtc->mode.VDisplay;
143.21598 +-			tmp.depth = sna->front->drawable.depth;
143.21599 +-			tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel;
143.21600 +-
143.21601 +-			(void)sna->render.copy_boxes(sna, GXcopy,
143.21602 +-						     &sna->front->drawable, __sna_pixmap_get_bo(sna->front), 0, 0,
143.21603 +-						     &tmp, bo, -b.x1, -b.y1,
143.21604 +-						     &b, 1, 0);
143.21605 +-		}
143.21606 ++			if (b.x1 < 0)
143.21607 ++				b.x1 = 0;
143.21608 ++			if (b.y1 < 0)
143.21609 ++				b.y1 = 0;
143.21610 ++			if (b.x2 > scrn->virtualX)
143.21611 ++				b.x2 = scrn->virtualX;
143.21612 ++			if (b.y2 > scrn->virtualY)
143.21613 ++				b.y2 = scrn->virtualY;
143.21614 ++			if (b.x2 - b.x1 < crtc->mode.HDisplay ||
143.21615 ++			    b.y2 - b.y1 < crtc->mode.VDisplay)
143.21616 ++				shadow_clear(sna, front, bo, crtc);
143.21617 ++
143.21618 ++			if (b.y2 > b.y1 && b.x2 > b.x1) {
143.21619 ++				DrawableRec tmp;
143.21620 ++
143.21621 ++				DBG(("%s: copying onto shadow CRTC: (%d, %d)x(%d, %d) [fb=%dx%d], handle=%d\n",
143.21622 ++				     __FUNCTION__,
143.21623 ++				     b.x1, b.y1,
143.21624 ++				     b.x2-b.x1, b.y2-b.y1,
143.21625 ++				     scrn->virtualX, scrn->virtualY,
143.21626 ++				     bo->handle));
143.21627 ++
143.21628 ++				tmp.width = crtc->mode.HDisplay;
143.21629 ++				tmp.height = crtc->mode.VDisplay;
143.21630 ++				tmp.depth = front->drawable.depth;
143.21631 ++				tmp.bitsPerPixel = front->drawable.bitsPerPixel;
143.21632 ++
143.21633 ++				if (!sna->render.copy_boxes(sna, GXcopy,
143.21634 ++							     &front->drawable, __sna_pixmap_get_bo(front), 0, 0,
143.21635 ++							     &tmp, bo, -crtc->x, -crtc->y,
143.21636 ++							     &b, 1, COPY_LAST))
143.21637 ++					shadow_clear(sna, front, bo, crtc);
143.21638 ++			}
143.21639 ++		} else
143.21640 ++			shadow_clear(sna, front, bo, crtc);
143.21641 + 
143.21642 + 		sna_crtc->shadow_bo_width = crtc->mode.HDisplay;
143.21643 + 		sna_crtc->shadow_bo_height = crtc->mode.VDisplay;
143.21644 + 		sna_crtc->shadow_bo = bo;
143.21645 + out_shadow:
143.21646 + 		sna_crtc->transform = true;
143.21647 ++		sna->mode.rr_active++;
143.21648 + 		return kgem_bo_reference(bo);
143.21649 + 	} else {
143.21650 + 		if (sna_crtc->shadow_bo) {
143.21651 +@@ -2048,26 +2747,26 @@ out_shadow:
143.21652 + 		}
143.21653 + 
143.21654 + 		if (sna->flags & SNA_TEAR_FREE) {
143.21655 ++			RegionRec region;
143.21656 ++
143.21657 + 			assert(sna_crtc->slave_pixmap == NULL);
143.21658 + 
143.21659 + 			DBG(("%s: enabling TearFree shadow\n", __FUNCTION__));
143.21660 ++			region.extents.x1 = 0;
143.21661 ++			region.extents.y1 = 0;
143.21662 ++			region.extents.x2 = sna->scrn->virtualX;
143.21663 ++			region.extents.y2 = sna->scrn->virtualY;
143.21664 ++			region.data = NULL;
143.21665 ++
143.21666 + 			if (!sna_crtc_enable_shadow(sna, sna_crtc)) {
143.21667 + 				DBG(("%s: failed to enable crtc shadow\n", __FUNCTION__));
143.21668 + 				return NULL;
143.21669 + 			}
143.21670 + 
143.21671 +-			if (sna->mode.shadow == NULL && !wedged(sna)) {
143.21672 +-				RegionRec region;
143.21673 ++			if (sna->mode.shadow == NULL) {
143.21674 + 				struct kgem_bo *shadow;
143.21675 + 
143.21676 + 				DBG(("%s: creating TearFree shadow bo\n", __FUNCTION__));
143.21677 +-
143.21678 +-				region.extents.x1 = 0;
143.21679 +-				region.extents.y1 = 0;
143.21680 +-				region.extents.x2 = sna->scrn->virtualX;
143.21681 +-				region.extents.y2 = sna->scrn->virtualY;
143.21682 +-				region.data = NULL;
143.21683 +-
143.21684 + 				shadow = kgem_create_2d(&sna->kgem,
143.21685 + 							region.extents.x2,
143.21686 + 							region.extents.y2,
143.21687 +@@ -2093,9 +2792,12 @@ out_shadow:
143.21688 + 					goto force_shadow;
143.21689 + 				}
143.21690 + 
143.21691 ++				assert(__sna_pixmap_get_bo(sna->front) == NULL ||
143.21692 ++				       __sna_pixmap_get_bo(sna->front)->pitch == shadow->pitch);
143.21693 + 				sna->mode.shadow = shadow;
143.21694 +-				set_shadow(sna, &region);
143.21695 ++				sna->mode.shadow->active_scanout++;
143.21696 + 			}
143.21697 ++			set_shadow(sna, &region);
143.21698 + 
143.21699 + 			sna_crtc_disable_override(sna, sna_crtc);
143.21700 + 		} else
143.21701 +@@ -2107,6 +2809,37 @@ out_shadow:
143.21702 + 	}
143.21703 + }
143.21704 + 
143.21705 ++#define SCALING_EPSILON (1./256)
143.21706 ++
143.21707 ++static bool
143.21708 ++is_affine(const struct pixman_f_transform *t)
143.21709 ++{
143.21710 ++	return (fabs(t->m[2][0]) < SCALING_EPSILON &&
143.21711 ++		fabs(t->m[2][1]) < SCALING_EPSILON);
143.21712 ++}
143.21713 ++
143.21714 ++static double determinant(const struct pixman_f_transform *t)
143.21715 ++{
143.21716 ++	return t->m[0][0]*t->m[1][1] - t->m[1][0]*t->m[0][1];
143.21717 ++}
143.21718 ++
143.21719 ++static bool
143.21720 ++affine_is_pixel_exact(const struct pixman_f_transform *t)
143.21721 ++{
143.21722 ++	double det = t->m[2][2] * determinant(t);
143.21723 ++	if (fabs (det * det - 1.0) < SCALING_EPSILON) {
143.21724 ++		if (fabs(t->m[0][1]) < SCALING_EPSILON &&
143.21725 ++		    fabs(t->m[1][0]) < SCALING_EPSILON)
143.21726 ++			return true;
143.21727 ++
143.21728 ++		if (fabs(t->m[0][0]) < SCALING_EPSILON &&
143.21729 ++		    fabs(t->m[1][1]) < SCALING_EPSILON)
143.21730 ++			return true;
143.21731 ++	}
143.21732 ++
143.21733 ++	return false;
143.21734 ++}
143.21735 ++
143.21736 + static void sna_crtc_randr(xf86CrtcPtr crtc)
143.21737 + {
143.21738 + 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.21739 +@@ -2152,6 +2885,25 @@ static void sna_crtc_randr(xf86CrtcPtr crtc)
143.21740 + 	} else
143.21741 + 		crtc->transform_in_use = sna_crtc->rotation != RR_Rotate_0;
143.21742 + 
143.21743 ++	/* Recompute the cursor after a potential change in transform */
143.21744 ++	if (sna_crtc->cursor) {
143.21745 ++		assert(sna_crtc->cursor->ref > 0);
143.21746 ++		sna_crtc->cursor->ref--;
143.21747 ++		sna_crtc->cursor = NULL;
143.21748 ++	}
143.21749 ++
143.21750 ++	if (needs_transform) {
143.21751 ++		sna_crtc->hwcursor = is_affine(&f_fb_to_crtc);
143.21752 ++		sna_crtc->cursor_transform =
143.21753 ++			sna_crtc->hwcursor &&
143.21754 ++			!affine_is_pixel_exact(&f_fb_to_crtc);
143.21755 ++	} else {
143.21756 ++		sna_crtc->hwcursor = true;
143.21757 ++		sna_crtc->cursor_transform = false;
143.21758 ++	}
143.21759 ++	DBG(("%s: hwcursor?=%d, cursor_transform?=%d\n",
143.21760 ++	     __FUNCTION__, sna_crtc->hwcursor, sna_crtc->cursor_transform));
143.21761 ++
143.21762 + 	crtc->crtc_to_framebuffer = crtc_to_fb;
143.21763 + 	crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
143.21764 + 	crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
143.21765 +@@ -2184,7 +2936,7 @@ static void sna_crtc_randr(xf86CrtcPtr crtc)
143.21766 + static void
143.21767 + sna_crtc_damage(xf86CrtcPtr crtc)
143.21768 + {
143.21769 +-	ScreenPtr screen = crtc->scrn->pScreen;
143.21770 ++	ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
143.21771 + 	struct sna *sna = to_sna(crtc->scrn);
143.21772 + 	RegionRec region, *damage;
143.21773 + 
143.21774 +@@ -2200,15 +2952,21 @@ sna_crtc_damage(xf86CrtcPtr crtc)
143.21775 + 	if (region.extents.y2 > screen->height)
143.21776 + 		region.extents.y2 = screen->height;
143.21777 + 
143.21778 ++	if (region.extents.x2 <= region.extents.x1 ||
143.21779 ++	    region.extents.y2 <= region.extents.y1) {
143.21780 ++		DBG(("%s: crtc not damaged, all-clipped\n", __FUNCTION__));
143.21781 ++		return;
143.21782 ++	}
143.21783 ++
143.21784 + 	DBG(("%s: marking crtc %d as completely damaged (%d, %d), (%d, %d)\n",
143.21785 +-	     __FUNCTION__, to_sna_crtc(crtc)->id,
143.21786 ++	     __FUNCTION__, sna_crtc_id(crtc),
143.21787 + 	     region.extents.x1, region.extents.y1,
143.21788 + 	     region.extents.x2, region.extents.y2));
143.21789 +-	to_sna_crtc(crtc)->client_damage = region;
143.21790 + 
143.21791 + 	assert(sna->mode.shadow_damage && sna->mode.shadow_active);
143.21792 + 	damage = DamageRegion(sna->mode.shadow_damage);
143.21793 + 	RegionUnion(damage, damage, &region);
143.21794 ++	to_sna_crtc(crtc)->crtc_damage = region;
143.21795 + 
143.21796 + 	DBG(("%s: damage now %dx[(%d, %d), (%d, %d)]\n",
143.21797 + 	     __FUNCTION__,
143.21798 +@@ -2260,6 +3018,21 @@ static const char *reflection_to_str(Rotation rotation)
143.21799 + 	}
143.21800 + }
143.21801 + 
143.21802 ++static void reprobe_connectors(xf86CrtcPtr crtc)
143.21803 ++{
143.21804 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
143.21805 ++	struct sna *sna = to_sna(crtc->scrn);
143.21806 ++	int i;
143.21807 ++
143.21808 ++	for (i = 0; i < sna->mode.num_real_output; i++) {
143.21809 ++		xf86OutputPtr output = config->output[i];
143.21810 ++		if (output->crtc == crtc)
143.21811 ++			to_sna_output(output)->reprobe = true;
143.21812 ++	}
143.21813 ++
143.21814 ++	sna_mode_discover(sna, true);
143.21815 ++}
143.21816 ++
143.21817 + static Bool
143.21818 + __sna_crtc_set_mode(xf86CrtcPtr crtc)
143.21819 + {
143.21820 +@@ -2268,11 +3041,19 @@ __sna_crtc_set_mode(xf86CrtcPtr crtc)
143.21821 + 	struct kgem_bo *saved_bo, *bo;
143.21822 + 	uint32_t saved_offset;
143.21823 + 	bool saved_transform;
143.21824 ++	bool saved_hwcursor;
143.21825 ++	bool saved_cursor_transform;
143.21826 ++	int ret;
143.21827 + 
143.21828 +-	DBG(("%s\n", __FUNCTION__));
143.21829 ++	DBG(("%s: CRTC=%d, pipe=%d, hidden?=%d\n", __FUNCTION__,
143.21830 ++	     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna->mode.hidden));
143.21831 ++	if (sna->mode.hidden)
143.21832 ++		return TRUE;
143.21833 + 
143.21834 + 	saved_bo = sna_crtc->bo;
143.21835 + 	saved_transform = sna_crtc->transform;
143.21836 ++	saved_cursor_transform = sna_crtc->cursor_transform;
143.21837 ++	saved_hwcursor = sna_crtc->hwcursor;
143.21838 + 	saved_offset = sna_crtc->offset;
143.21839 + 
143.21840 + 	sna_crtc->fallback_shadow = false;
143.21841 +@@ -2285,26 +3066,31 @@ retry: /* Attach per-crtc pixmap or direct */
143.21842 + 	}
143.21843 + 
143.21844 + 	/* Prevent recursion when enabling outputs during execbuffer */
143.21845 +-	if (bo->exec && RQ(bo->rq)->bo == NULL)
143.21846 ++	if (bo->exec && RQ(bo->rq)->bo == NULL) {
143.21847 + 		_kgem_submit(&sna->kgem);
143.21848 ++		__kgem_bo_clear_dirty(bo);
143.21849 ++	}
143.21850 + 
143.21851 + 	sna_crtc->bo = bo;
143.21852 +-	if (!sna_crtc_apply(crtc)) {
143.21853 +-		int err = errno;
143.21854 +-
143.21855 ++	ret = sna_crtc_apply(crtc);
143.21856 ++	if (ret) {
143.21857 + 		kgem_bo_destroy(&sna->kgem, bo);
143.21858 + 
143.21859 +-		if (!sna_crtc->shadow) {
143.21860 ++		if (!sna_crtc->fallback_shadow) {
143.21861 + 			sna_crtc->fallback_shadow = true;
143.21862 + 			goto retry;
143.21863 + 		}
143.21864 + 
143.21865 + 		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
143.21866 +-			   "failed to set mode: %s [%d]\n", strerror(err), err);
143.21867 ++			   "failed to set mode: %s [%d]\n", strerror(ret), ret);
143.21868 + 		goto error;
143.21869 + 	}
143.21870 + 
143.21871 ++	sna_crtc->flags |= CRTC_ON;
143.21872 + 	bo->active_scanout++;
143.21873 ++	DBG(("%s: marking handle=%d as active=%d (removing %d from scanout, active=%d)\n",
143.21874 ++	     __FUNCTION__, bo->handle, bo->active_scanout,
143.21875 ++	     saved_bo ? saved_bo->handle : 0, saved_bo ? saved_bo->active_scanout - 1: -1));
143.21876 + 	if (saved_bo) {
143.21877 + 		assert(saved_bo->active_scanout);
143.21878 + 		assert(saved_bo->refcnt >= saved_bo->active_scanout);
143.21879 +@@ -2315,17 +3101,34 @@ retry: /* Attach per-crtc pixmap or direct */
143.21880 + 	sna_crtc_randr(crtc);
143.21881 + 	if (sna_crtc->transform)
143.21882 + 		sna_crtc_damage(crtc);
143.21883 ++	if (sna_crtc->cursor &&  /* Reload cursor if RandR maybe changed */
143.21884 ++	    (!sna_crtc->hwcursor ||
143.21885 ++	     saved_cursor_transform || sna_crtc->cursor_transform ||
143.21886 ++	     sna_crtc->cursor->rotation != crtc->rotation))
143.21887 ++		sna_crtc_disable_cursor(sna, sna_crtc);
143.21888 ++
143.21889 ++	assert(!sna->mode.hidden);
143.21890 + 	sna->mode.front_active += saved_bo == NULL;
143.21891 + 	sna->mode.dirty = true;
143.21892 +-	DBG(("%s: front_active=%d\n", __FUNCTION__, sna->mode.front_active));
143.21893 ++	DBG(("%s: handle=%d, scanout_active=%d, front_active=%d\n",
143.21894 ++	     __FUNCTION__, bo->handle, bo->active_scanout, sna->mode.front_active));
143.21895 + 
143.21896 + 	return TRUE;
143.21897 + 
143.21898 + error:
143.21899 + 	sna_crtc->offset = saved_offset;
143.21900 ++	if (sna_crtc->transform) {
143.21901 ++		assert(sna->mode.rr_active);
143.21902 ++		sna->mode.rr_active--;
143.21903 ++	}
143.21904 ++	if (saved_transform)
143.21905 ++		sna->mode.rr_active++;
143.21906 + 	sna_crtc->transform = saved_transform;
143.21907 ++	sna_crtc->cursor_transform = saved_cursor_transform;
143.21908 ++	sna_crtc->hwcursor = saved_hwcursor;
143.21909 + 	sna_crtc->bo = saved_bo;
143.21910 +-	sna_mode_discover(sna);
143.21911 ++
143.21912 ++	reprobe_connectors(crtc);
143.21913 + 	return FALSE;
143.21914 + }
143.21915 + 
143.21916 +@@ -2346,14 +3149,14 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
143.21917 + 	xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO,
143.21918 + 		   "switch to mode %dx%d@%.1f on %s using pipe %d, position (%d, %d), rotation %s, reflection %s\n",
143.21919 + 		   mode->HDisplay, mode->VDisplay, xf86ModeVRefresh(mode),
143.21920 +-		   outputs_for_crtc(crtc, outputs, sizeof(outputs)), sna_crtc->pipe,
143.21921 ++		   outputs_for_crtc(crtc, outputs, sizeof(outputs)), __sna_crtc_pipe(sna_crtc),
143.21922 + 		   x, y, rotation_to_str(rotation), reflection_to_str(rotation));
143.21923 + 
143.21924 + 	assert(mode->HDisplay <= sna->mode.max_crtc_width &&
143.21925 + 	       mode->VDisplay <= sna->mode.max_crtc_height);
143.21926 + 
143.21927 + #if HAS_GAMMA
143.21928 +-	drmModeCrtcSetGamma(sna->kgem.fd, sna_crtc->id,
143.21929 ++	drmModeCrtcSetGamma(sna->kgem.fd, __sna_crtc_id(sna_crtc),
143.21930 + 			    crtc->gamma_size,
143.21931 + 			    crtc->gamma_red,
143.21932 + 			    crtc->gamma_green,
143.21933 +@@ -2372,17 +3175,10 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
143.21934 + static void
143.21935 + sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
143.21936 + {
143.21937 +-	struct sna_crtc *priv = to_sna_crtc(crtc);
143.21938 +-
143.21939 + 	DBG(("%s(pipe %d, dpms mode -> %d):= active=%d\n",
143.21940 +-	     __FUNCTION__, priv->pipe, mode, mode == DPMSModeOn));
143.21941 +-	if (priv->dpms_mode == mode)
143.21942 +-		return;
143.21943 +-
143.21944 +-	assert(priv);
143.21945 +-	priv->dpms_mode = mode;
143.21946 ++	     __FUNCTION__, sna_crtc_pipe(crtc), mode, mode == DPMSModeOn));
143.21947 + 
143.21948 +-	if (mode == DPMSModeOn && crtc->enabled && priv->bo == NULL) {
143.21949 ++	if (mode == DPMSModeOn && crtc->enabled) {
143.21950 + 		if (__sna_crtc_set_mode(crtc))
143.21951 + 			update_flush_interval(to_sna(crtc->scrn));
143.21952 + 		else
143.21953 +@@ -2390,7 +3186,7 @@ sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
143.21954 + 	}
143.21955 + 
143.21956 + 	if (mode != DPMSModeOn)
143.21957 +-		sna_crtc_disable(crtc);
143.21958 ++		sna_crtc_disable(crtc, false);
143.21959 + }
143.21960 + 
143.21961 + void sna_mode_adjust_frame(struct sna *sna, int x, int y)
143.21962 +@@ -2426,7 +3222,7 @@ sna_crtc_gamma_set(xf86CrtcPtr crtc,
143.21963 + {
143.21964 + 	assert(to_sna_crtc(crtc));
143.21965 + 	drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd,
143.21966 +-			    to_sna_crtc(crtc)->id,
143.21967 ++			    sna_crtc_id(crtc),
143.21968 + 			    size, red, green, blue);
143.21969 + }
143.21970 + 
143.21971 +@@ -2434,10 +3230,14 @@ static void
143.21972 + sna_crtc_destroy(xf86CrtcPtr crtc)
143.21973 + {
143.21974 + 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.21975 ++	struct plane *sprite, *sn;
143.21976 + 
143.21977 + 	if (sna_crtc == NULL)
143.21978 + 		return;
143.21979 + 
143.21980 ++	list_for_each_entry_safe(sprite, sn, &sna_crtc->sprites, link)
143.21981 ++		free(sprite);
143.21982 ++
143.21983 + 	free(sna_crtc);
143.21984 + 	crtc->driver_private = NULL;
143.21985 + }
143.21986 +@@ -2455,7 +3255,7 @@ sna_crtc_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap)
143.21987 + 		return TRUE;
143.21988 + 
143.21989 + 	DBG(("%s: CRTC:%d, pipe=%d setting scanout pixmap=%ld\n",
143.21990 +-	     __FUNCTION__, sna_crtc->id,  sna_crtc->pipe,
143.21991 ++	     __FUNCTION__, __sna_crtc_id(sna_crtc),  __sna_crtc_pipe(sna_crtc),
143.21992 + 	     pixmap ? pixmap->drawable.serialNumber : 0));
143.21993 + 
143.21994 + 	/* Disable first so that we can unregister the damage tracking */
143.21995 +@@ -2576,6 +3376,10 @@ static int plane_details(struct sna *sna, struct plane *p)
143.21996 + 		}
143.21997 + 	}
143.21998 + 
143.21999 ++	p->rotation.supported &= DBG_NATIVE_ROTATION;
143.22000 ++	if (!xf86ReturnOptValBool(sna->Options, OPTION_ROTATION, TRUE))
143.22001 ++		p->rotation.supported = RR_Rotate_0;
143.22002 ++
143.22003 + 	if (props != (uint32_t *)stack_props)
143.22004 + 		free(props);
143.22005 + 
143.22006 +@@ -2583,20 +3387,26 @@ static int plane_details(struct sna *sna, struct plane *p)
143.22007 + 	return type;
143.22008 + }
143.22009 + 
143.22010 ++static void add_sprite_plane(struct sna_crtc *crtc,
143.22011 ++			     struct plane *details)
143.22012 ++{
143.22013 ++	struct plane *sprite = malloc(sizeof(*sprite));
143.22014 ++	if (!sprite)
143.22015 ++		return;
143.22016 ++
143.22017 ++	memcpy(sprite, details, sizeof(*sprite));
143.22018 ++	list_add(&sprite->link, &crtc->sprites);
143.22019 ++}
143.22020 ++
143.22021 + static void
143.22022 + sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
143.22023 + {
143.22024 + #define LOCAL_IOCTL_SET_CAP	DRM_IOWR(0x0d, struct local_set_cap)
143.22025 +-#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)
143.22026 +-#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)
143.22027 + 	struct local_set_cap {
143.22028 + 		uint64_t name;
143.22029 + 		uint64_t value;
143.22030 + 	} cap;
143.22031 +-	struct local_mode_get_plane_res {
143.22032 +-		uint64_t plane_id_ptr;
143.22033 +-		uint64_t count_planes;
143.22034 +-	} r;
143.22035 ++	struct local_mode_get_plane_res r;
143.22036 + 	uint32_t stack_planes[32];
143.22037 + 	uint32_t *planes = stack_planes;
143.22038 + 	int i;
143.22039 +@@ -2629,18 +3439,7 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
143.22040 + 	VG(VALGRIND_MAKE_MEM_DEFINED(planes, sizeof(uint32_t)*r.count_planes));
143.22041 + 
143.22042 + 	for (i = 0; i < r.count_planes; i++) {
143.22043 +-		struct local_mode_get_plane {
143.22044 +-			uint32_t plane_id;
143.22045 +-
143.22046 +-			uint32_t crtc_id;
143.22047 +-			uint32_t fb_id;
143.22048 +-
143.22049 +-			uint32_t possible_crtcs;
143.22050 +-			uint32_t gamma_size;
143.22051 +-
143.22052 +-			uint32_t count_format_types;
143.22053 +-			uint64_t format_type_ptr;
143.22054 +-		} p;
143.22055 ++		struct local_mode_get_plane p;
143.22056 + 		struct plane details;
143.22057 + 
143.22058 + 		VG_CLEAR(p);
143.22059 +@@ -2649,11 +3448,11 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
143.22060 + 		if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANE, &p))
143.22061 + 			continue;
143.22062 + 
143.22063 +-		if ((p.possible_crtcs & (1 << crtc->pipe)) == 0)
143.22064 ++		if ((p.possible_crtcs & (1 << __sna_crtc_pipe(crtc))) == 0)
143.22065 + 			continue;
143.22066 + 
143.22067 + 		DBG(("%s: plane %d is attached to our pipe=%d\n",
143.22068 +-		     __FUNCTION__, planes[i], crtc->pipe));
143.22069 ++		     __FUNCTION__, planes[i], __sna_crtc_pipe(crtc)));
143.22070 + 
143.22071 + 		details.id = p.plane_id;
143.22072 + 		details.rotation.prop = 0;
143.22073 +@@ -2672,8 +3471,7 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
143.22074 + 			break;
143.22075 + 
143.22076 + 		case DRM_PLANE_TYPE_OVERLAY:
143.22077 +-			if (crtc->sprite.id == 0)
143.22078 +-				crtc->sprite = details;
143.22079 ++			add_sprite_plane(crtc, &details);
143.22080 + 			break;
143.22081 + 		}
143.22082 + 	}
143.22083 +@@ -2688,7 +3486,6 @@ sna_crtc_init__rotation(struct sna *sna, struct sna_crtc *crtc)
143.22084 + 	crtc->rotation = RR_Rotate_0;
143.22085 + 	crtc->primary.rotation.supported = RR_Rotate_0;
143.22086 + 	crtc->primary.rotation.current = RR_Rotate_0;
143.22087 +-	crtc->sprite.rotation = crtc->primary.rotation;
143.22088 + }
143.22089 + 
143.22090 + static void
143.22091 +@@ -2698,55 +3495,55 @@ sna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc)
143.22092 + 
143.22093 + 	VG_CLEAR(arg);
143.22094 + 	arg.flags = DRM_MODE_CURSOR_BO;
143.22095 +-	arg.crtc_id = crtc->id;
143.22096 ++	arg.crtc_id = __sna_crtc_id(crtc);
143.22097 + 	arg.width = arg.height = 0;
143.22098 + 	arg.handle = 0;
143.22099 + 
143.22100 + 	(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
143.22101 ++	crtc->hwcursor = true;
143.22102 + }
143.22103 + 
143.22104 + static bool
143.22105 +-sna_crtc_add(ScrnInfoPtr scrn, int id)
143.22106 ++sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
143.22107 + {
143.22108 + 	struct sna *sna = to_sna(scrn);
143.22109 + 	xf86CrtcPtr crtc;
143.22110 + 	struct sna_crtc *sna_crtc;
143.22111 + 	struct drm_i915_get_pipe_from_crtc_id get_pipe;
143.22112 + 
143.22113 +-	DBG(("%s(%d)\n", __FUNCTION__, id));
143.22114 ++	DBG(("%s(%d): is-zaphod? %d\n", __FUNCTION__, id, is_zaphod(scrn)));
143.22115 + 
143.22116 + 	sna_crtc = calloc(sizeof(struct sna_crtc), 1);
143.22117 + 	if (sna_crtc == NULL)
143.22118 + 		return false;
143.22119 + 
143.22120 + 	sna_crtc->id = id;
143.22121 +-	sna_crtc->dpms_mode = -1;
143.22122 + 
143.22123 + 	VG_CLEAR(get_pipe);
143.22124 + 	get_pipe.pipe = 0;
143.22125 +-	get_pipe.crtc_id = sna_crtc->id;
143.22126 ++	get_pipe.crtc_id = id;
143.22127 + 	if (drmIoctl(sna->kgem.fd,
143.22128 + 		     DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID,
143.22129 + 		     &get_pipe)) {
143.22130 + 		free(sna_crtc);
143.22131 + 		return false;
143.22132 + 	}
143.22133 +-	sna_crtc->pipe = get_pipe.pipe;
143.22134 ++	assert((unsigned)get_pipe.pipe < 256);
143.22135 ++	sna_crtc->flags |= get_pipe.pipe << 8;
143.22136 + 
143.22137 + 	if (is_zaphod(scrn) &&
143.22138 +-	    scrn->confScreen->device->screen != sna_crtc->pipe) {
143.22139 ++	    (get_zaphod_crtcs(sna) & (1 << get_pipe.pipe)) == 0) {
143.22140 + 		free(sna_crtc);
143.22141 + 		return true;
143.22142 + 	}
143.22143 + 
143.22144 ++	list_init(&sna_crtc->sprites);
143.22145 + 	sna_crtc_init__rotation(sna, sna_crtc);
143.22146 +-
143.22147 + 	sna_crtc_find_planes(sna, sna_crtc);
143.22148 + 
143.22149 +-	DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x, sprite id=%x: supported-rotations=%x, current-rotation=%x\n",
143.22150 +-	     __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
143.22151 +-	     sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current,
143.22152 +-	     sna_crtc->sprite.id, sna_crtc->sprite.rotation.supported, sna_crtc->sprite.rotation.current));
143.22153 ++	DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x\n",
143.22154 ++	     __FUNCTION__, id, get_pipe.pipe,
143.22155 ++	     sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current));
143.22156 + 
143.22157 + 	list_init(&sna_crtc->shadow_link);
143.22158 + 
143.22159 +@@ -2761,7 +3558,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
143.22160 + 	crtc->driver_private = sna_crtc;
143.22161 + 	sna_crtc->base = crtc;
143.22162 + 	DBG(("%s: attached crtc[%d] pipe=%d\n",
143.22163 +-	     __FUNCTION__, id, sna_crtc->pipe));
143.22164 ++	     __FUNCTION__, id, __sna_crtc_pipe(sna_crtc)));
143.22165 + 
143.22166 + 	return true;
143.22167 + }
143.22168 +@@ -2798,20 +3595,56 @@ find_property(struct sna *sna, struct sna_output *output, const char *name)
143.22169 + 	return -1;
143.22170 + }
143.22171 + 
143.22172 ++static void update_properties(struct sna *sna, struct sna_output *output)
143.22173 ++{
143.22174 ++	union compat_mode_get_connector compat_conn;
143.22175 ++	struct drm_mode_modeinfo dummy;
143.22176 ++
143.22177 ++	VG_CLEAR(compat_conn);
143.22178 ++
143.22179 ++	compat_conn.conn.connector_id = output->id;
143.22180 ++	compat_conn.conn.count_props = output->num_props;
143.22181 ++	compat_conn.conn.props_ptr = (uintptr_t)output->prop_ids;
143.22182 ++	compat_conn.conn.prop_values_ptr = (uintptr_t)output->prop_values;
143.22183 ++	compat_conn.conn.count_modes = 1; /* skip detect */
143.22184 ++	compat_conn.conn.modes_ptr = (uintptr_t)&dummy;
143.22185 ++	compat_conn.conn.count_encoders = 0;
143.22186 ++
143.22187 ++	(void)drmIoctl(sna->kgem.fd,
143.22188 ++		       DRM_IOCTL_MODE_GETCONNECTOR,
143.22189 ++		       &compat_conn.conn);
143.22190 ++
143.22191 ++	assert(compat_conn.conn.count_props == output->num_props);
143.22192 ++	output->update_properties = false;
143.22193 ++}
143.22194 ++
143.22195 + static xf86OutputStatus
143.22196 + sna_output_detect(xf86OutputPtr output)
143.22197 + {
143.22198 + 	struct sna *sna = to_sna(output->scrn);
143.22199 + 	struct sna_output *sna_output = output->driver_private;
143.22200 + 	union compat_mode_get_connector compat_conn;
143.22201 ++	uint32_t now;
143.22202 + 
143.22203 + 	DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id));
143.22204 ++	sna_output->update_properties = false;
143.22205 + 
143.22206 + 	if (!sna_output->id) {
143.22207 + 		DBG(("%s(%s) hiding due to lost connection\n", __FUNCTION__, output->name));
143.22208 + 		return XF86OutputStatusDisconnected;
143.22209 + 	}
143.22210 + 
143.22211 ++	/* Cache detections for 15s or hotplug event  */
143.22212 ++	now = GetTimeInMillis();
143.22213 ++	if (sna_output->last_detect != 0 &&
143.22214 ++	    (int32_t)(now - sna_output->last_detect) <= OUTPUT_STATUS_CACHE_MS) {
143.22215 ++		DBG(("%s(%s) reporting cached status (since %dms): %d\n",
143.22216 ++		     __FUNCTION__, output->name, now - sna_output->last_detect,
143.22217 ++		     sna_output->status));
143.22218 ++		sna_output->update_properties = true;
143.22219 ++		return sna_output->status;
143.22220 ++	}
143.22221 ++
143.22222 + 	VG_CLEAR(compat_conn);
143.22223 + 	compat_conn.conn.connector_id = sna_output->id;
143.22224 + 	sna_output->num_modes = compat_conn.conn.count_modes = 0; /* reprobe */
143.22225 +@@ -2854,15 +3687,23 @@ sna_output_detect(xf86OutputPtr output)
143.22226 + 	DBG(("%s(%s): found %d modes, connection status=%d\n",
143.22227 + 	     __FUNCTION__, output->name, sna_output->num_modes, compat_conn.conn.connection));
143.22228 + 
143.22229 ++	sna_output->reprobe = false;
143.22230 ++	sna_output->last_detect = now;
143.22231 + 	switch (compat_conn.conn.connection) {
143.22232 + 	case DRM_MODE_CONNECTED:
143.22233 +-		return XF86OutputStatusConnected;
143.22234 ++		sna_output->status = XF86OutputStatusConnected;
143.22235 ++		output->mm_width = compat_conn.conn.mm_width;
143.22236 ++		output->mm_height = compat_conn.conn.mm_height;
143.22237 ++		break;
143.22238 + 	case DRM_MODE_DISCONNECTED:
143.22239 +-		return XF86OutputStatusDisconnected;
143.22240 ++		sna_output->status = XF86OutputStatusDisconnected;
143.22241 ++		break;
143.22242 + 	default:
143.22243 + 	case DRM_MODE_UNKNOWNCONNECTION:
143.22244 +-		return XF86OutputStatusUnknown;
143.22245 ++		sna_output->status = XF86OutputStatusUnknown;
143.22246 ++		break;
143.22247 + 	}
143.22248 ++	return sna_output->status;
143.22249 + }
143.22250 + 
143.22251 + static Bool
143.22252 +@@ -2895,6 +3736,27 @@ sna_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
143.22253 + 	return MODE_OK;
143.22254 + }
143.22255 + 
143.22256 ++static void sna_output_set_parsed_edid(xf86OutputPtr output, xf86MonPtr mon)
143.22257 ++{
143.22258 ++	unsigned conn_mm_width, conn_mm_height;
143.22259 ++
143.22260 ++	/* We set the output size based on values from the kernel */
143.22261 ++	conn_mm_width = output->mm_width;
143.22262 ++	conn_mm_height = output->mm_height;
143.22263 ++
143.22264 ++	xf86OutputSetEDID(output, mon);
143.22265 ++
143.22266 ++	if (output->mm_width != conn_mm_width || output->mm_height != conn_mm_height) {
143.22267 ++		DBG(("%s)%s): kernel and Xorg disagree over physical size: kernel=%dx%dmm, Xorg=%dx%dmm\n",
143.22268 ++		     __FUNCTION__, output->name,
143.22269 ++		     conn_mm_width, conn_mm_height,
143.22270 ++		     output->mm_width, output->mm_height));
143.22271 ++	}
143.22272 ++
143.22273 ++	output->mm_width = conn_mm_width;
143.22274 ++	output->mm_height = conn_mm_height;
143.22275 ++}
143.22276 ++
143.22277 + static void
143.22278 + sna_output_attach_edid(xf86OutputPtr output)
143.22279 + {
143.22280 +@@ -2907,6 +3769,13 @@ sna_output_attach_edid(xf86OutputPtr output)
143.22281 + 	if (sna_output->edid_idx == -1)
143.22282 + 		return;
143.22283 + 
143.22284 ++	/* Always refresh the blob as the kernel may randomly update the
143.22285 ++	 * id even if the contents of the blob doesn't change, and a
143.22286 ++	 * request for the stale id will return nothing.
143.22287 ++	 */
143.22288 ++	if (sna_output->update_properties)
143.22289 ++		update_properties(sna, sna_output);
143.22290 ++
143.22291 + 	raw = sna_output->edid_raw;
143.22292 + 	blob.length = sna_output->edid_len;
143.22293 + 
143.22294 +@@ -2917,8 +3786,12 @@ sna_output_attach_edid(xf86OutputPtr output)
143.22295 + 		old = NULL;
143.22296 + 
143.22297 + 	blob.blob_id = sna_output->prop_values[sna_output->edid_idx];
143.22298 +-	DBG(("%s: attaching EDID id=%d, current=%d\n",
143.22299 +-	     __FUNCTION__, blob.blob_id, sna_output->edid_blob_id));
143.22300 ++	if (!blob.blob_id)
143.22301 ++		goto done;
143.22302 ++
143.22303 ++	DBG(("%s(%s): attaching EDID id=%d, current=%d\n",
143.22304 ++	     __FUNCTION__, output->name,
143.22305 ++	     blob.blob_id, sna_output->edid_blob_id));
143.22306 + 	if (blob.blob_id == sna_output->edid_blob_id && 0) { /* sigh */
143.22307 + 		if (output->MonInfo) {
143.22308 + 			/* XXX the property keeps on disappearing... */
143.22309 +@@ -2936,26 +3809,45 @@ sna_output_attach_edid(xf86OutputPtr output)
143.22310 + 	}
143.22311 + 
143.22312 + 	blob.data = (uintptr_t)raw;
143.22313 +-	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
143.22314 +-		goto done;
143.22315 ++	do {
143.22316 ++		while (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
143.22317 ++			update_properties(sna, sna_output);
143.22318 ++			if (blob.blob_id == sna_output->prop_values[sna_output->edid_idx]) {
143.22319 ++				DBG(("%s(%s): failed to read blob, reusing previous\n",
143.22320 ++				     __FUNCTION__, output->name));
143.22321 ++				goto done;
143.22322 ++			}
143.22323 ++			blob.blob_id = sna_output->prop_values[sna_output->edid_idx];
143.22324 ++		}
143.22325 + 
143.22326 +-	DBG(("%s: retrieving blob id=%d, length=%d\n",
143.22327 +-	     __FUNCTION__, blob.blob_id, blob.length));
143.22328 ++		DBG(("%s(%s): retrieving blob id=%d, length=%d\n",
143.22329 ++		     __FUNCTION__, output->name, blob.blob_id, blob.length));
143.22330 + 
143.22331 +-	if (blob.length > sna_output->edid_len) {
143.22332 +-		raw = realloc(raw, blob.length);
143.22333 +-		if (raw == NULL)
143.22334 ++		if (blob.length < 128)
143.22335 + 			goto done;
143.22336 + 
143.22337 +-		VG(memset(raw, 0, blob.length));
143.22338 +-		blob.data = (uintptr_t)raw;
143.22339 +-		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
143.22340 +-			goto done;
143.22341 ++		if (blob.length > sna_output->edid_len) {
143.22342 ++			raw = realloc(raw, blob.length);
143.22343 ++			if (raw == NULL)
143.22344 ++				goto done;
143.22345 ++
143.22346 ++			VG(memset(raw, 0, blob.length));
143.22347 ++			blob.data = (uintptr_t)raw;
143.22348 ++		}
143.22349 ++	} while (blob.length != sna_output->edid_len &&
143.22350 ++		 drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob));
143.22351 ++
143.22352 ++	if (blob.length & 127) {
143.22353 ++		/* Truncated EDID! Make sure no one reads too far */
143.22354 ++		*SECTION(NO_EDID, (uint8_t*)raw) = blob.length/128 - 1;
143.22355 ++		blob.length &= -128;
143.22356 + 	}
143.22357 + 
143.22358 + 	if (old &&
143.22359 + 	    blob.length == sna_output->edid_len &&
143.22360 + 	    memcmp(old, raw, blob.length) == 0) {
143.22361 ++		DBG(("%s(%s): EDID + MonInfo is unchanged\n",
143.22362 ++		     __FUNCTION__, output->name));
143.22363 + 		assert(sna_output->edid_raw == raw);
143.22364 + 		sna_output->edid_blob_id = blob.blob_id;
143.22365 + 		RRChangeOutputProperty(output->randr_output,
143.22366 +@@ -2974,31 +3866,186 @@ skip_read:
143.22367 + 			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
143.22368 + 	}
143.22369 + 
143.22370 +-done:
143.22371 +-	xf86OutputSetEDID(output, mon);
143.22372 +-	if (raw) {
143.22373 +-		sna_output->edid_raw = raw;
143.22374 +-		sna_output->edid_len = blob.length;
143.22375 +-		sna_output->edid_blob_id = blob.blob_id;
143.22376 ++done:
143.22377 ++	sna_output_set_parsed_edid(output, mon);
143.22378 ++	if (raw) {
143.22379 ++		sna_output->edid_raw = raw;
143.22380 ++		sna_output->edid_len = blob.length;
143.22381 ++		sna_output->edid_blob_id = blob.blob_id;
143.22382 ++	}
143.22383 ++}
143.22384 ++
143.22385 ++static void
143.22386 ++sna_output_attach_tile(xf86OutputPtr output)
143.22387 ++{
143.22388 ++#if XF86_OUTPUT_VERSION >= 3
143.22389 ++	struct sna *sna = to_sna(output->scrn);
143.22390 ++	struct sna_output *sna_output = output->driver_private;
143.22391 ++	struct drm_mode_get_blob blob;
143.22392 ++	struct xf86CrtcTileInfo tile_info, *set = NULL;
143.22393 ++	char *tile;
143.22394 ++	int id;
143.22395 ++
143.22396 ++	id = find_property(sna, sna_output, "TILE");
143.22397 ++	DBG(("%s: found? TILE=%d\n", __FUNCTION__, id));
143.22398 ++	if (id == -1)
143.22399 ++		goto out;
143.22400 ++
143.22401 ++	if (sna_output->update_properties)
143.22402 ++		update_properties(sna, sna_output);
143.22403 ++
143.22404 ++	VG_CLEAR(blob);
143.22405 ++	blob.blob_id = sna_output->prop_values[id];
143.22406 ++	blob.length = 0;
143.22407 ++	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
143.22408 ++		goto out;
143.22409 ++
143.22410 ++	do {
143.22411 ++		id = blob.length;
143.22412 ++		tile = alloca(id + 1);
143.22413 ++		blob.data = (uintptr_t)tile;
143.22414 ++		VG(memset(tile, 0, id));
143.22415 ++		DBG(("%s: reading %d bytes for TILE blob\n", __FUNCTION__, id));
143.22416 ++		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
143.22417 ++			goto out;
143.22418 ++	} while (id != blob.length);
143.22419 ++
143.22420 ++	tile[blob.length] = '\0'; /* paranoia */
143.22421 ++	DBG(("%s: TILE='%s'\n", __FUNCTION__, tile));
143.22422 ++	if (xf86OutputParseKMSTile(tile, blob.length, &tile_info))
143.22423 ++		set = &tile_info;
143.22424 ++out:
143.22425 ++	xf86OutputSetTile(output, set);
143.22426 ++#endif
143.22427 ++}
143.22428 ++
143.22429 ++static bool duplicate_mode(DisplayModePtr modes, DisplayModePtr m)
143.22430 ++{
143.22431 ++	if (m == NULL)
143.22432 ++		return false;
143.22433 ++
143.22434 ++	while (modes) {
143.22435 ++		if (xf86ModesEqual(modes, m))
143.22436 ++			return true;
143.22437 ++
143.22438 ++		modes = modes->next;
143.22439 ++	}
143.22440 ++
143.22441 ++	return false;
143.22442 ++}
143.22443 ++
143.22444 ++static struct pixel_count {
143.22445 ++	int16_t width, height;
143.22446 ++} common_16_9[] = {
143.22447 ++	{ 640, 360 },
143.22448 ++	{ 720, 405 },
143.22449 ++	{ 864, 486 },
143.22450 ++	{ 960, 540 },
143.22451 ++	{ 1024, 576 },
143.22452 ++	{ 1280, 720 },
143.22453 ++	{ 1366, 768 },
143.22454 ++	{ 1600, 900 },
143.22455 ++	{ 1920, 1080 },
143.22456 ++	{ 2048, 1152 },
143.22457 ++	{ 2560, 1440 },
143.22458 ++	{ 2880, 1620 },
143.22459 ++	{ 3200, 1800 },
143.22460 ++	{ 3840, 2160 },
143.22461 ++	{ 4096, 2304 },
143.22462 ++	{ 5120, 2880 },
143.22463 ++	{ 7680, 4320 },
143.22464 ++	{ 15360, 8640 },
143.22465 ++}, common_16_10[] = {
143.22466 ++	{ 1280, 800 },
143.22467 ++	{ 1400, 900 },
143.22468 ++	{ 1680, 1050 },
143.22469 ++	{ 1920, 1200 },
143.22470 ++	{ 2560, 1600 },
143.22471 ++};
143.22472 ++
143.22473 ++static DisplayModePtr
143.22474 ++default_modes(DisplayModePtr preferred)
143.22475 ++{
143.22476 ++	DisplayModePtr modes;
143.22477 ++	int n;
143.22478 ++
143.22479 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
143.22480 ++	modes = xf86GetDefaultModes();
143.22481 ++#else
143.22482 ++	modes = xf86GetDefaultModes(0, 0);
143.22483 ++#endif
143.22484 ++
143.22485 ++	/* XXX O(n^2) mode list generation :( */
143.22486 ++
143.22487 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,4,99,901,0)
143.22488 ++	if (preferred) {
143.22489 ++		DisplayModePtr m;
143.22490 ++
143.22491 ++		/* Add a half-resolution mode useful for large panels */
143.22492 ++		m = xf86GTFMode(preferred->HDisplay/2,
143.22493 ++				preferred->VDisplay/2,
143.22494 ++				xf86ModeVRefresh(preferred),
143.22495 ++				FALSE, FALSE);
143.22496 ++		if (!duplicate_mode(modes, m))
143.22497 ++			modes = xf86ModesAdd(modes, m);
143.22498 ++		else
143.22499 ++			free(m);
143.22500 ++
143.22501 ++		if (preferred->VDisplay * 16 > preferred->HDisplay*9 - preferred->HDisplay/32 &&
143.22502 ++		    preferred->VDisplay * 16 < preferred->HDisplay*9 + preferred->HDisplay/32) {
143.22503 ++			DBG(("Adding 16:9 modes -- %d < %d > %d\n",
143.22504 ++			     preferred->HDisplay*9 - preferred->HDisplay/32,
143.22505 ++			     preferred->VDisplay * 16,
143.22506 ++			     preferred->HDisplay*9 + preferred->HDisplay/32));
143.22507 ++			for (n = 0; n < ARRAY_SIZE(common_16_9); n++) {
143.22508 ++				if (preferred->HDisplay <= common_16_9[n].width ||
143.22509 ++				    preferred->VDisplay <= common_16_9[n].height)
143.22510 ++					break;
143.22511 ++
143.22512 ++				m = xf86GTFMode(common_16_9[n].width,
143.22513 ++						common_16_9[n].height,
143.22514 ++						xf86ModeVRefresh(preferred),
143.22515 ++						FALSE, FALSE);
143.22516 ++				if (!duplicate_mode(modes, m))
143.22517 ++					modes = xf86ModesAdd(modes, m);
143.22518 ++				else
143.22519 ++					free(m);
143.22520 ++			}
143.22521 ++		}
143.22522 ++
143.22523 ++		if (preferred->VDisplay * 16 > preferred->HDisplay*10 - preferred->HDisplay/32 &&
143.22524 ++		    preferred->VDisplay * 16 < preferred->HDisplay*10 + preferred->HDisplay/32) {
143.22525 ++			DBG(("Adding 16:10 modes -- %d < %d > %d\n",
143.22526 ++			     preferred->HDisplay*10 - preferred->HDisplay/32,
143.22527 ++			     preferred->VDisplay * 16,
143.22528 ++			     preferred->HDisplay*10 + preferred->HDisplay/32));
143.22529 ++			for (n = 0; n < ARRAY_SIZE(common_16_10); n++) {
143.22530 ++				if (preferred->HDisplay <= common_16_10[n].width ||
143.22531 ++				    preferred->VDisplay <= common_16_10[n].height)
143.22532 ++					break;
143.22533 ++
143.22534 ++				m = xf86GTFMode(common_16_10[n].width,
143.22535 ++						common_16_10[n].height,
143.22536 ++						xf86ModeVRefresh(preferred),
143.22537 ++						FALSE, FALSE);
143.22538 ++				if (!duplicate_mode(modes, m))
143.22539 ++					modes = xf86ModesAdd(modes, m);
143.22540 ++				else
143.22541 ++					free(m);
143.22542 ++			}
143.22543 ++		}
143.22544 + 	}
143.22545 +-}
143.22546 +-
143.22547 +-static DisplayModePtr
143.22548 +-default_modes(void)
143.22549 +-{
143.22550 +-#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
143.22551 +-	return xf86GetDefaultModes();
143.22552 +-#else
143.22553 +-	return xf86GetDefaultModes(0, 0);
143.22554 + #endif
143.22555 ++
143.22556 ++	return modes;
143.22557 + }
143.22558 + 
143.22559 + static DisplayModePtr
143.22560 +-sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
143.22561 ++sna_output_add_default_modes(xf86OutputPtr output, DisplayModePtr modes)
143.22562 + {
143.22563 + 	xf86MonPtr mon = output->MonInfo;
143.22564 + 	DisplayModePtr i, m, preferred = NULL;
143.22565 +-	int max_x = 0, max_y = 0;
143.22566 ++	int max_x = 0, max_y = 0, max_clock = 0;
143.22567 + 	float max_vrefresh = 0.0;
143.22568 + 
143.22569 + 	if (mon && GTF_SUPPORTED(mon->features.msc))
143.22570 +@@ -3009,16 +4056,17 @@ sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
143.22571 + 			preferred = m;
143.22572 + 		max_x = max(max_x, m->HDisplay);
143.22573 + 		max_y = max(max_y, m->VDisplay);
143.22574 ++		max_clock = max(max_clock, m->Clock);
143.22575 + 		max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
143.22576 + 	}
143.22577 +-
143.22578 +-	max_vrefresh = max(max_vrefresh, 60.0);
143.22579 + 	max_vrefresh *= (1 + SYNC_TOLERANCE);
143.22580 + 
143.22581 +-	m = default_modes();
143.22582 ++	m = default_modes(preferred);
143.22583 + 	xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
143.22584 + 
143.22585 + 	for (i = m; i; i = i->next) {
143.22586 ++		if (i->Clock > max_clock)
143.22587 ++			i->status = MODE_CLOCK_HIGH;
143.22588 + 		if (xf86ModeVRefresh(i) > max_vrefresh)
143.22589 + 			i->status = MODE_VSYNC;
143.22590 + 		if (preferred &&
143.22591 +@@ -3034,28 +4082,47 @@ sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
143.22592 + }
143.22593 + 
143.22594 + static DisplayModePtr
143.22595 ++sna_output_override_edid(xf86OutputPtr output)
143.22596 ++{
143.22597 ++	struct sna_output *sna_output = output->driver_private;
143.22598 ++
143.22599 ++	if (sna_output->fake_edid_mon == NULL)
143.22600 ++		return NULL;
143.22601 ++
143.22602 ++	xf86OutputSetEDID(output, sna_output->fake_edid_mon);
143.22603 ++	return xf86DDCGetModes(output->scrn->scrnIndex,
143.22604 ++			       sna_output->fake_edid_mon);
143.22605 ++}
143.22606 ++
143.22607 ++static DisplayModePtr
143.22608 + sna_output_get_modes(xf86OutputPtr output)
143.22609 + {
143.22610 + 	struct sna_output *sna_output = output->driver_private;
143.22611 +-	DisplayModePtr Modes = NULL, current = NULL;
143.22612 ++	DisplayModePtr Modes, current;
143.22613 + 	int i;
143.22614 + 
143.22615 + 	DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id));
143.22616 + 	assert(sna_output->id);
143.22617 + 
143.22618 ++	Modes = sna_output_override_edid(output);
143.22619 ++	if (Modes)
143.22620 ++		return Modes;
143.22621 ++
143.22622 + 	sna_output_attach_edid(output);
143.22623 ++	sna_output_attach_tile(output);
143.22624 + 
143.22625 +-	if (output->crtc) {
143.22626 ++	current = NULL;
143.22627 ++	if (output->crtc && !sna_output->hotplug_count) {
143.22628 + 		struct drm_mode_crtc mode;
143.22629 + 
143.22630 + 		VG_CLEAR(mode);
143.22631 + 		assert(to_sna_crtc(output->crtc));
143.22632 +-		mode.crtc_id = to_sna_crtc(output->crtc)->id;
143.22633 ++		mode.crtc_id = sna_crtc_id(output->crtc);
143.22634 + 
143.22635 + 		if (drmIoctl(to_sna(output->scrn)->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode) == 0) {
143.22636 + 			DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
143.22637 +-			     to_sna_crtc(output->crtc)->id,
143.22638 +-			     to_sna_crtc(output->crtc)->pipe,
143.22639 ++			     sna_crtc_id(output->crtc),
143.22640 ++			     sna_crtc_pipe(output->crtc),
143.22641 + 			     mode.mode_valid && mode.mode.clock));
143.22642 + 
143.22643 + 			if (mode.mode_valid && mode.mode.clock) {
143.22644 +@@ -3117,7 +4184,7 @@ sna_output_get_modes(xf86OutputPtr output)
143.22645 + 	}
143.22646 + 
143.22647 + 	if (sna_output->add_default_modes)
143.22648 +-		Modes = sna_output_panel_edid(output, Modes);
143.22649 ++		Modes = sna_output_add_default_modes(output, Modes);
143.22650 + 
143.22651 + 	return Modes;
143.22652 + }
143.22653 +@@ -3132,6 +4199,8 @@ sna_output_destroy(xf86OutputPtr output)
143.22654 + 		return;
143.22655 + 
143.22656 + 	free(sna_output->edid_raw);
143.22657 ++	free(sna_output->fake_edid_raw);
143.22658 ++
143.22659 + 	for (i = 0; i < sna_output->num_props; i++) {
143.22660 + 		if (sna_output->props[i].kprop == NULL)
143.22661 + 			continue;
143.22662 +@@ -3155,7 +4224,7 @@ sna_output_destroy(xf86OutputPtr output)
143.22663 + }
143.22664 + 
143.22665 + static void
143.22666 +-sna_output_dpms(xf86OutputPtr output, int dpms)
143.22667 ++__sna_output_dpms(xf86OutputPtr output, int dpms, int fixup)
143.22668 + {
143.22669 + 	struct sna *sna = to_sna(output->scrn);
143.22670 + 	struct sna_output *sna_output = output->driver_private;
143.22671 +@@ -3182,8 +4251,9 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
143.22672 + 	if (sna_output->backlight.iface && dpms != DPMSModeOn) {
143.22673 + 		if (old_dpms == DPMSModeOn) {
143.22674 + 			sna_output->backlight_active_level = sna_output_backlight_get(output);
143.22675 +-			DBG(("%s: saving current backlight %d\n",
143.22676 +-			     __FUNCTION__, sna_output->backlight_active_level));
143.22677 ++			DBG(("%s(%s:%d): saving current backlight %d\n",
143.22678 ++			     __FUNCTION__, output->name, sna_output->id,
143.22679 ++			     sna_output->backlight_active_level));
143.22680 + 		}
143.22681 + 		sna_output->dpms_mode = dpms;
143.22682 + 		sna_output_backlight_off(sna_output);
143.22683 +@@ -3193,18 +4263,31 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
143.22684 + 	    drmModeConnectorSetProperty(sna->kgem.fd,
143.22685 + 					sna_output->id,
143.22686 + 					sna_output->dpms_id,
143.22687 +-					dpms))
143.22688 +-		dpms = old_dpms;
143.22689 ++					dpms)) {
143.22690 ++		DBG(("%s(%s:%d): failed to set DPMS to %d (fixup? %d)\n",
143.22691 ++		     __FUNCTION__, output->name, sna_output->id, dpms, fixup));
143.22692 ++		if (fixup && dpms != DPMSModeOn) {
143.22693 ++			sna_crtc_disable(output->crtc, false);
143.22694 ++			return;
143.22695 ++		}
143.22696 ++	}
143.22697 + 
143.22698 + 	if (sna_output->backlight.iface && dpms == DPMSModeOn) {
143.22699 +-		DBG(("%s: restoring previous backlight %d\n",
143.22700 +-		     __FUNCTION__, sna_output->backlight_active_level));
143.22701 ++		DBG(("%s(%d:%d: restoring previous backlight %d\n",
143.22702 ++		     __FUNCTION__, output->name, sna_output->id,
143.22703 ++		     sna_output->backlight_active_level));
143.22704 + 		sna_output_backlight_on(sna_output);
143.22705 + 	}
143.22706 + 
143.22707 + 	sna_output->dpms_mode = dpms;
143.22708 + }
143.22709 + 
143.22710 ++static void
143.22711 ++sna_output_dpms(xf86OutputPtr output, int dpms)
143.22712 ++{
143.22713 ++	__sna_output_dpms(output, dpms, true);
143.22714 ++}
143.22715 ++
143.22716 + static bool
143.22717 + sna_property_ignore(drmModePropertyPtr prop)
143.22718 + {
143.22719 +@@ -3239,14 +4322,14 @@ sna_output_create_ranged_atom(xf86OutputPtr output, Atom *atom,
143.22720 + 	err = RRConfigureOutputProperty(output->randr_output, *atom, FALSE,
143.22721 + 					TRUE, immutable, 2, atom_range);
143.22722 + 	if (err != 0)
143.22723 +-		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
143.22724 ++		xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
143.22725 + 			   "RRConfigureOutputProperty error, %d\n", err);
143.22726 + 
143.22727 + 	err = RRChangeOutputProperty(output->randr_output, *atom, XA_INTEGER,
143.22728 + 				     32, PropModeReplace, 1, &value,
143.22729 + 				     FALSE, FALSE);
143.22730 + 	if (err != 0)
143.22731 +-		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
143.22732 ++		xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
143.22733 + 			   "RRChangeOutputProperty error, %d\n", err);
143.22734 + }
143.22735 + 
143.22736 +@@ -3303,7 +4386,7 @@ sna_output_create_resources(xf86OutputPtr output)
143.22737 + 							p->kprop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
143.22738 + 							p->num_atoms - 1, (INT32 *)&p->atoms[1]);
143.22739 + 			if (err != 0) {
143.22740 +-				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
143.22741 ++				xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
143.22742 + 					   "RRConfigureOutputProperty error, %d\n", err);
143.22743 + 			}
143.22744 + 
143.22745 +@@ -3315,7 +4398,7 @@ sna_output_create_resources(xf86OutputPtr output)
143.22746 + 						     XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1],
143.22747 + 						     FALSE, FALSE);
143.22748 + 			if (err != 0) {
143.22749 +-				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
143.22750 ++				xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
143.22751 + 					   "RRChangeOutputProperty error, %d\n", err);
143.22752 + 			}
143.22753 + 		}
143.22754 +@@ -3385,18 +4468,19 @@ sna_output_set_property(xf86OutputPtr output, Atom property,
143.22755 + 			if (value->type != XA_INTEGER || value->format != 32 ||
143.22756 + 			    value->size != 1)
143.22757 + 				return FALSE;
143.22758 +-			val = *(uint32_t *)value->data;
143.22759 + 
143.22760 ++			val = *(uint32_t *)value->data;
143.22761 + 			drmModeConnectorSetProperty(sna->kgem.fd, sna_output->id,
143.22762 + 						    p->kprop->prop_id, (uint64_t)val);
143.22763 + 			return TRUE;
143.22764 + 		} else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
143.22765 +-			Atom	atom;
143.22766 +-			const char	*name;
143.22767 +-			int		j;
143.22768 ++			Atom atom;
143.22769 ++			const char *name;
143.22770 ++			int j;
143.22771 + 
143.22772 + 			if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
143.22773 + 				return FALSE;
143.22774 ++
143.22775 + 			memcpy(&atom, value->data, 4);
143.22776 + 			name = NameForAtom(atom);
143.22777 + 			if (name == NULL)
143.22778 +@@ -3425,7 +4509,7 @@ static Bool
143.22779 + sna_output_get_property(xf86OutputPtr output, Atom property)
143.22780 + {
143.22781 + 	struct sna_output *sna_output = output->driver_private;
143.22782 +-	int err;
143.22783 ++	int err, i, j;
143.22784 + 
143.22785 + 	if (property == backlight_atom || property == backlight_deprecated_atom) {
143.22786 + 		INT32 val;
143.22787 +@@ -3449,7 +4533,7 @@ sna_output_get_property(xf86OutputPtr output, Atom property)
143.22788 + 					     XA_INTEGER, 32, PropModeReplace, 1, &val,
143.22789 + 					     FALSE, FALSE);
143.22790 + 		if (err != 0) {
143.22791 +-			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
143.22792 ++			xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
143.22793 + 				   "RRChangeOutputProperty error, %d\n", err);
143.22794 + 			return FALSE;
143.22795 + 		}
143.22796 +@@ -3457,6 +4541,40 @@ sna_output_get_property(xf86OutputPtr output, Atom property)
143.22797 + 		return TRUE;
143.22798 + 	}
143.22799 + 
143.22800 ++	for (i = 0; i < sna_output->num_props; i++) {
143.22801 ++		struct sna_property *p = &sna_output->props[i];
143.22802 ++
143.22803 ++		if (p->atoms == NULL || p->atoms[0] != property)
143.22804 ++			continue;
143.22805 ++
143.22806 ++		if (sna_output->update_properties && output->scrn->vtSema)
143.22807 ++			update_properties(to_sna(output->scrn), sna_output);
143.22808 ++
143.22809 ++		err = 0;
143.22810 ++		if (p->kprop->flags & DRM_MODE_PROP_RANGE) {
143.22811 ++			err = RRChangeOutputProperty(output->randr_output,
143.22812 ++						     property, XA_INTEGER, 32,
143.22813 ++						     PropModeReplace, 1,
143.22814 ++						     &sna_output->prop_values[i],
143.22815 ++						     FALSE, FALSE);
143.22816 ++		} else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
143.22817 ++			for (j = 0; j < p->kprop->count_enums; j++) {
143.22818 ++				if (p->kprop->enums[j].value == sna_output->prop_values[i])
143.22819 ++					break;
143.22820 ++			}
143.22821 ++			err = RRChangeOutputProperty(output->randr_output,
143.22822 ++						     property, XA_ATOM, 32,
143.22823 ++						     PropModeReplace, 1,
143.22824 ++						     &p->atoms[j+1],
143.22825 ++						     FALSE, FALSE);
143.22826 ++		}
143.22827 ++
143.22828 ++		if (err != 0)
143.22829 ++			xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
143.22830 ++				   "RRChangeOutputProperty error, %d\n", err);
143.22831 ++		return TRUE;
143.22832 ++	}
143.22833 ++
143.22834 + 	return FALSE;
143.22835 + }
143.22836 + 
143.22837 +@@ -3500,47 +4618,11 @@ static const char * const output_names[] = {
143.22838 + 	/* DRM_MODE_CONNECTOR_TV */		"TV",
143.22839 + 	/* DRM_MODE_CONNECTOR_eDP */		"eDP",
143.22840 + 	/* DRM_MODE_CONNECTOR_VIRTUAL */	"Virtual",
143.22841 +-	/* DRM_MODE_CONNECTOR_DSI */		"DSI"
143.22842 ++	/* DRM_MODE_CONNECTOR_DSI */		"DSI",
143.22843 ++	/* DRM_MODE_CONNECTOR_DPI */		"DPI"
143.22844 + };
143.22845 + 
143.22846 + static bool
143.22847 +-sna_zaphod_match(const char *s, const char *output)
143.22848 +-{
143.22849 +-	char t[20];
143.22850 +-	unsigned int i = 0;
143.22851 +-
143.22852 +-	do {
143.22853 +-		/* match any outputs in a comma list, stopping at whitespace */
143.22854 +-		switch (*s) {
143.22855 +-		case '\0':
143.22856 +-			t[i] = '\0';
143.22857 +-			return strcmp(t, output) == 0;
143.22858 +-
143.22859 +-		case ',':
143.22860 +-			t[i] ='\0';
143.22861 +-			if (strcmp(t, output) == 0)
143.22862 +-				return TRUE;
143.22863 +-			i = 0;
143.22864 +-			break;
143.22865 +-
143.22866 +-		case ' ':
143.22867 +-		case '\t':
143.22868 +-		case '\n':
143.22869 +-		case '\r':
143.22870 +-			break;
143.22871 +-
143.22872 +-		default:
143.22873 +-			t[i++] = *s;
143.22874 +-			break;
143.22875 +-		}
143.22876 +-
143.22877 +-		s++;
143.22878 +-	} while (i < sizeof(t));
143.22879 +-
143.22880 +-	return false;
143.22881 +-}
143.22882 +-
143.22883 +-static bool
143.22884 + output_ignored(ScrnInfoPtr scrn, const char *name)
143.22885 + {
143.22886 + 	char monitor_name[64];
143.22887 +@@ -3572,14 +4654,21 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
143.22888 + 	struct drm_mode_get_encoder enc;
143.22889 + 	uint32_t *ids = NULL;
143.22890 + 
143.22891 ++	DBG(("%s(%d): expected count=%d\n", __FUNCTION__, id, count));
143.22892 ++
143.22893 + 	VG_CLEAR(compat_conn);
143.22894 ++	VG_CLEAR(enc);
143.22895 + 	memset(out, 0, sizeof(*out));
143.22896 + 
143.22897 + 	do {
143.22898 +-		free(ids);
143.22899 +-		ids = malloc(sizeof(*ids) * count);
143.22900 +-		if (ids == 0)
143.22901 ++		uint32_t *nids;
143.22902 ++
143.22903 ++		nids = realloc(ids, sizeof(*ids) * count);
143.22904 ++		if (nids == NULL) {
143.22905 ++			free(ids);
143.22906 + 			return false;
143.22907 ++		}
143.22908 ++		ids = nids;
143.22909 + 
143.22910 + 		compat_conn.conn.connector_id = id;
143.22911 + 		compat_conn.conn.count_props = 0;
143.22912 +@@ -3593,12 +4682,14 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
143.22913 + 			compat_conn.conn.count_encoders = count = 0;
143.22914 + 		}
143.22915 + 
143.22916 ++		VG(VALGRIND_MAKE_MEM_DEFINED(ids, sizeof(uint32_t)*compat_conn.conn.count_encoders));
143.22917 + 		if (count == compat_conn.conn.count_encoders)
143.22918 + 			break;
143.22919 + 
143.22920 + 		count = compat_conn.conn.count_encoders;
143.22921 + 	} while (1);
143.22922 + 
143.22923 ++	DBG(("%s(%d): gathering %d encoders\n", __FUNCTION__, id, count));
143.22924 + 	for (count = 0; count < compat_conn.conn.count_encoders; count++) {
143.22925 + 		enc.encoder_id = ids[count];
143.22926 + 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETENCODER, &enc)) {
143.22927 +@@ -3606,6 +4697,8 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
143.22928 + 			count = 0;
143.22929 + 			break;
143.22930 + 		}
143.22931 ++		DBG(("%s(%d): encoder=%d, possible_crtcs=%x, possible_clones=%x\n",
143.22932 ++		     __FUNCTION__, id, enc.encoder_id, enc.possible_crtcs, enc.possible_clones));
143.22933 + 		out->possible_crtcs |= enc.possible_crtcs;
143.22934 + 		out->possible_clones |= enc.possible_clones;
143.22935 + 
143.22936 +@@ -3731,6 +4824,116 @@ static int name_from_path(struct sna *sna,
143.22937 + 	return 0;
143.22938 + }
143.22939 + 
143.22940 ++static char *fake_edid_name(xf86OutputPtr output)
143.22941 ++{
143.22942 ++	struct sna *sna = to_sna(output->scrn);
143.22943 ++	const char *str, *colon;
143.22944 ++
143.22945 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
143.22946 ++	str = xf86GetOptValString(sna->Options, OPTION_EDID);
143.22947 ++#else
143.22948 ++	str = NULL;
143.22949 ++#endif
143.22950 ++	if (str == NULL)
143.22951 ++		return NULL;
143.22952 ++
143.22953 ++	do {
143.22954 ++		colon = strchr(str, ':');
143.22955 ++		if (colon == NULL)
143.22956 ++			return NULL;
143.22957 ++
143.22958 ++		if (strncmp(str, output->name, colon-str) == 0 &&
143.22959 ++		    output->name[colon-str] == '\0') {
143.22960 ++			char *path;
143.22961 ++			int len;
143.22962 ++
143.22963 ++			str = colon + 1;
143.22964 ++			colon = strchr(str, ',');
143.22965 ++			if (colon)
143.22966 ++				len = colon - str;
143.22967 ++			else
143.22968 ++				len = strlen(str);
143.22969 ++
143.22970 ++			path = malloc(len + 1);
143.22971 ++			if (path == NULL)
143.22972 ++				return NULL;
143.22973 ++
143.22974 ++			memcpy(path, str, len);
143.22975 ++			path[len] = '\0';
143.22976 ++			return path;
143.22977 ++		}
143.22978 ++
143.22979 ++		str = strchr(colon + 1, ',');
143.22980 ++		if (str == NULL)
143.22981 ++			return NULL;
143.22982 ++
143.22983 ++		str++;
143.22984 ++	} while (1);
143.22985 ++}
143.22986 ++
143.22987 ++static void
143.22988 ++sna_output_load_fake_edid(xf86OutputPtr output)
143.22989 ++{
143.22990 ++	struct sna_output *sna_output = output->driver_private;
143.22991 ++	const char *filename;
143.22992 ++	FILE *file;
143.22993 ++	void *raw;
143.22994 ++	int size;
143.22995 ++	xf86MonPtr mon;
143.22996 ++
143.22997 ++	filename = fake_edid_name(output);
143.22998 ++	if (filename == NULL)
143.22999 ++		return;
143.23000 ++
143.23001 ++	file = fopen(filename, "rb");
143.23002 ++	if (file == NULL)
143.23003 ++		goto err;
143.23004 ++
143.23005 ++	fseek(file, 0, SEEK_END);
143.23006 ++	size = ftell(file);
143.23007 ++	if (size % 128) {
143.23008 ++		fclose(file);
143.23009 ++		goto err;
143.23010 ++	}
143.23011 ++
143.23012 ++	raw = malloc(size);
143.23013 ++	if (raw == NULL) {
143.23014 ++		fclose(file);
143.23015 ++		free(raw);
143.23016 ++		goto err;
143.23017 ++	}
143.23018 ++
143.23019 ++	fseek(file, 0, SEEK_SET);
143.23020 ++	if (fread(raw, size, 1, file) != 1) {
143.23021 ++		fclose(file);
143.23022 ++		free(raw);
143.23023 ++		goto err;
143.23024 ++	}
143.23025 ++	fclose(file);
143.23026 ++
143.23027 ++	mon = xf86InterpretEDID(output->scrn->scrnIndex, raw);
143.23028 ++	if (mon == NULL) {
143.23029 ++		free(raw);
143.23030 ++		goto err;
143.23031 ++	}
143.23032 ++
143.23033 ++	if (mon && size > 128)
143.23034 ++		mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
143.23035 ++
143.23036 ++	sna_output->fake_edid_mon = mon;
143.23037 ++	sna_output->fake_edid_raw = raw;
143.23038 ++
143.23039 ++	xf86DrvMsg(output->scrn->scrnIndex, X_CONFIG,
143.23040 ++		   "Loading EDID from \"%s\" for output %s\n",
143.23041 ++		   filename, output->name);
143.23042 ++	return;
143.23043 ++
143.23044 ++err:
143.23045 ++	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
143.23046 ++		   "Could not read EDID file \"%s\" for output %s\n",
143.23047 ++		   filename, output->name);
143.23048 ++}
143.23049 ++
143.23050 + static int
143.23051 + sna_output_add(struct sna *sna, unsigned id, unsigned serial)
143.23052 + {
143.23053 +@@ -3765,6 +4968,7 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
143.23054 + 		return -1;
143.23055 + 	}
143.23056 + 	assert(compat_conn.conn.connector_id == id);
143.23057 ++	DBG(("%s(%d): has %d associated encoders\n", __FUNCTION__, id, compat_conn.conn.count_encoders));
143.23058 + 
143.23059 + 	if (compat_conn.conn.connector_type < ARRAY_SIZE(output_names))
143.23060 + 		output_name = output_names[compat_conn.conn.connector_type];
143.23061 +@@ -3813,34 +5017,43 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
143.23062 + 	}
143.23063 + 
143.23064 + 	if (is_zaphod(scrn)) {
143.23065 +-		const char *str;
143.23066 ++		unsigned zaphod_crtcs;
143.23067 + 
143.23068 +-		str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
143.23069 +-		if (str && !sna_zaphod_match(str, name)) {
143.23070 +-			DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
143.23071 ++		if (!sna_zaphod_match(sna, name)) {
143.23072 ++			DBG(("%s: zaphod mismatch, want %s, have %s\n",
143.23073 ++			     __FUNCTION__,
143.23074 ++			     xf86GetOptValString(sna->Options, OPTION_ZAPHOD) ?: "???",
143.23075 ++			     name));
143.23076 + 			return 0;
143.23077 + 		}
143.23078 + 
143.23079 +-		if ((possible_crtcs & (1 << scrn->confScreen->device->screen)) == 0) {
143.23080 +-			if (str) {
143.23081 +-				xf86DrvMsg(scrn->scrnIndex, X_ERROR,
143.23082 +-					   "%s is an invalid output for screen (pipe) %d\n",
143.23083 +-					   name, scrn->confScreen->device->screen);
143.23084 +-				return -1;
143.23085 +-			} else
143.23086 +-				return 0;
143.23087 ++		zaphod_crtcs = get_zaphod_crtcs(sna);
143.23088 ++		possible_crtcs &= zaphod_crtcs;
143.23089 ++		if (possible_crtcs == 0) {
143.23090 ++			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
143.23091 ++				   "%s is an invalid output for screen %d\n",
143.23092 ++				   name, scrn->confScreen->device->screen);
143.23093 ++			return -1;
143.23094 + 		}
143.23095 + 
143.23096 +-		possible_crtcs = 1;
143.23097 ++		possible_crtcs >>= ffs(zaphod_crtcs) - 1;
143.23098 + 	}
143.23099 + 
143.23100 + 	sna_output = calloc(sizeof(struct sna_output), 1);
143.23101 + 	if (!sna_output)
143.23102 + 		return -1;
143.23103 + 
143.23104 ++	sna_output->connector_type = compat_conn.conn.connector_type;
143.23105 ++	sna_output->connector_type_id = compat_conn.conn.connector_type_id;
143.23106 + 	sna_output->num_props = compat_conn.conn.count_props;
143.23107 + 	sna_output->prop_ids = malloc(sizeof(uint32_t)*compat_conn.conn.count_props);
143.23108 + 	sna_output->prop_values = malloc(sizeof(uint64_t)*compat_conn.conn.count_props);
143.23109 ++	if (sna_output->prop_ids == NULL || sna_output->prop_values == NULL) {
143.23110 ++		free(sna_output->prop_ids);
143.23111 ++		free(sna_output->prop_values);
143.23112 ++		free(sna_output);
143.23113 ++		return -1;
143.23114 ++	}
143.23115 + 
143.23116 + 	compat_conn.conn.count_encoders = 0;
143.23117 + 
143.23118 +@@ -3865,16 +5078,16 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
143.23119 + 	/* Construct name from topology, and recheck if output is acceptable */
143.23120 + 	path = name_from_path(sna, sna_output, name);
143.23121 + 	if (path) {
143.23122 +-		const char *str;
143.23123 +-
143.23124 + 		if (output_ignored(scrn, name)) {
143.23125 + 			len = 0;
143.23126 + 			goto skip;
143.23127 + 		}
143.23128 + 
143.23129 +-		str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
143.23130 +-		if (str && !sna_zaphod_match(str, name)) {
143.23131 +-			DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
143.23132 ++		if (is_zaphod(scrn) && !sna_zaphod_match(sna, name)) {
143.23133 ++			DBG(("%s: zaphod mismatch, want %s, have %s\n",
143.23134 ++			     __FUNCTION__,
143.23135 ++			     xf86GetOptValString(sna->Options, OPTION_ZAPHOD) ?: "???",
143.23136 ++			     name));
143.23137 + 			len = 0;
143.23138 + 			goto skip;
143.23139 + 		}
143.23140 +@@ -3889,7 +5102,6 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
143.23141 + 			if (strcmp(output->name, name) == 0) {
143.23142 + 				assert(output->scrn == scrn);
143.23143 + 				assert(output->funcs == &sna_output_funcs);
143.23144 +-				assert(to_sna_output(output)->id == 0);
143.23145 + 				sna_output_destroy(output);
143.23146 + 				goto reset;
143.23147 + 			}
143.23148 +@@ -3935,6 +5147,8 @@ reset:
143.23149 + 	sna_output->id = compat_conn.conn.connector_id;
143.23150 + 	sna_output->is_panel = is_panel(compat_conn.conn.connector_type);
143.23151 + 	sna_output->edid_idx = find_property(sna, sna_output, "EDID");
143.23152 ++	sna_output->link_status_idx =
143.23153 ++		find_property(sna, sna_output, "link-status");
143.23154 + 	if (find_property(sna, sna_output, "scaling mode") != -1)
143.23155 + 		sna_output->add_default_modes =
143.23156 + 			xf86ReturnOptValBool(output->options, OPTION_DEFAULT_MODES, TRUE);
143.23157 +@@ -3945,10 +5159,8 @@ reset:
143.23158 + 		sna_output->dpms_mode = sna_output->prop_values[i];
143.23159 + 		DBG(("%s: found 'DPMS' (idx=%d, id=%d), initial value=%d\n",
143.23160 + 		     __FUNCTION__, i, sna_output->dpms_id, sna_output->dpms_mode));
143.23161 +-	} else {
143.23162 +-		sna_output->dpms_id = -1;
143.23163 ++	} else
143.23164 + 		sna_output->dpms_mode = DPMSModeOff;
143.23165 +-	}
143.23166 + 
143.23167 + 	sna_output->possible_encoders = possible_encoders;
143.23168 + 	sna_output->attached_encoders = attached_encoders;
143.23169 +@@ -3963,12 +5175,13 @@ reset:
143.23170 + 	sna_output->base = output;
143.23171 + 
143.23172 + 	backlight_init(&sna_output->backlight);
143.23173 +-	if (sna_output->is_panel)
143.23174 +-		sna_output_backlight_init(output);
143.23175 ++	sna_output_backlight_init(output);
143.23176 + 
143.23177 + 	output->possible_crtcs = possible_crtcs & count_to_mask(sna->mode.num_real_crtc);
143.23178 + 	output->interlaceAllowed = TRUE;
143.23179 + 
143.23180 ++	sna_output_load_fake_edid(output);
143.23181 ++
143.23182 + 	if (serial) {
143.23183 + 		if (output->randr_output == NULL) {
143.23184 + 			output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), name, len, output);
143.23185 +@@ -3976,6 +5189,7 @@ reset:
143.23186 + 				goto cleanup;
143.23187 + 		}
143.23188 + 
143.23189 ++		RROutputChanged(output->randr_output, TRUE);
143.23190 + 		sna_output_create_resources(output);
143.23191 + 		RRPostPendingProperties(output->randr_output);
143.23192 + 
143.23193 +@@ -4009,38 +5223,6 @@ skip:
143.23194 + 	return len;
143.23195 + }
143.23196 + 
143.23197 +-static void sna_output_del(xf86OutputPtr output)
143.23198 +-{
143.23199 +-	ScrnInfoPtr scrn = output->scrn;
143.23200 +-	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
143.23201 +-	int i;
143.23202 +-
143.23203 +-	DBG(("%s(%s)\n", __FUNCTION__, output->name));
143.23204 +-	assert(to_sna_output(output));
143.23205 +-
143.23206 +-	RROutputDestroy(output->randr_output);
143.23207 +-	sna_output_destroy(output);
143.23208 +-
143.23209 +-	while (output->probed_modes)
143.23210 +-		xf86DeleteMode(&output->probed_modes, output->probed_modes);
143.23211 +-
143.23212 +-	free(output);
143.23213 +-
143.23214 +-	for (i = 0; i < config->num_output; i++)
143.23215 +-		if (config->output[i] == output)
143.23216 +-			break;
143.23217 +-	assert(i < to_sna(scrn)->mode.num_real_output);
143.23218 +-	DBG(("%s: removing output #%d of %d\n",
143.23219 +-	     __FUNCTION__, i, to_sna(scrn)->mode.num_real_output));
143.23220 +-
143.23221 +-	for (; i < config->num_output; i++) {
143.23222 +-		config->output[i] = config->output[i+1];
143.23223 +-		config->output[i]->possible_clones >>= 1;
143.23224 +-	}
143.23225 +-	config->num_output--;
143.23226 +-	to_sna(scrn)->mode.num_real_output--;
143.23227 +-}
143.23228 +-
143.23229 + static int output_rank(const void *A, const void *B)
143.23230 + {
143.23231 + 	const xf86OutputPtr *a = A;
143.23232 +@@ -4058,6 +5240,7 @@ static void sort_config_outputs(struct sna *sna)
143.23233 + {
143.23234 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.23235 + 	qsort(config->output, sna->mode.num_real_output, sizeof(*config->output), output_rank);
143.23236 ++	config->compat_output = 0; /* make sure it is a sane value */
143.23237 + 	sna_mode_compute_possible_outputs(sna);
143.23238 + }
143.23239 + 
143.23240 +@@ -4080,11 +5263,15 @@ static bool disable_unused_crtc(struct sna *sna)
143.23241 + 	bool update = false;
143.23242 + 	int o, c;
143.23243 + 
143.23244 ++	DBG(("%s\n", __FUNCTION__));
143.23245 ++
143.23246 + 	for (c = 0; c < sna->mode.num_real_crtc; c++) {
143.23247 + 		xf86CrtcPtr crtc = config->crtc[c];
143.23248 + 
143.23249 +-		if (!crtc->enabled)
143.23250 ++		if (!crtc->enabled) {
143.23251 ++			sna_crtc_disable(crtc, false);
143.23252 + 			continue;
143.23253 ++		}
143.23254 + 
143.23255 + 		for (o = 0; o < sna->mode.num_real_output; o++) {
143.23256 + 			xf86OutputPtr output = config->output[o];
143.23257 +@@ -4094,7 +5281,7 @@ static bool disable_unused_crtc(struct sna *sna)
143.23258 + 
143.23259 + 		if (o == sna->mode.num_real_output) {
143.23260 + 			DBG(("%s: CRTC:%d was enabled with no outputs\n",
143.23261 +-			     __FUNCTION__, to_sna_crtc(crtc)->id));
143.23262 ++			     __FUNCTION__, sna_crtc_id(crtc)));
143.23263 + 			crtc->enabled = false;
143.23264 + 			update = true;
143.23265 + 		}
143.23266 +@@ -4108,17 +5295,145 @@ static bool disable_unused_crtc(struct sna *sna)
143.23267 + 	return update;
143.23268 + }
143.23269 + 
143.23270 +-void sna_mode_discover(struct sna *sna)
143.23271 ++bool sna_mode_find_hotplug_connector(struct sna *sna, unsigned id)
143.23272 ++{
143.23273 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.23274 ++	int i;
143.23275 ++
143.23276 ++	for (i = 0; i < sna->mode.num_real_output; i++) {
143.23277 ++		struct sna_output *output = to_sna_output(config->output[i]);
143.23278 ++		if (output->id == id) {
143.23279 ++			output->reprobe = true;
143.23280 ++			return true;
143.23281 ++		}
143.23282 ++	}
143.23283 ++
143.23284 ++	return false;
143.23285 ++}
143.23286 ++
143.23287 ++static bool
143.23288 ++output_retrain_link(struct sna *sna, struct sna_output *output)
143.23289 ++{
143.23290 ++	struct sna_crtc *crtc = to_sna_crtc(output->base->crtc);
143.23291 ++	int crtc_x = crtc->offset & 0xffff;
143.23292 ++	int crtc_y = crtc->offset >> 16;
143.23293 ++
143.23294 ++	return sna_crtc_flip(sna, crtc, crtc->bo, crtc_x, crtc_y);
143.23295 ++}
143.23296 ++
143.23297 ++static bool
143.23298 ++output_check_link(struct sna *sna, struct sna_output *output)
143.23299 ++{
143.23300 ++	uint64_t link_status;
143.23301 ++
143.23302 ++	if (!output->base->crtc)
143.23303 ++		return true;
143.23304 ++
143.23305 ++	if (output->link_status_idx == -1)
143.23306 ++		return true;
143.23307 ++
143.23308 ++#define LINK_STATUS_GOOD 0
143.23309 ++	link_status = output->prop_values[output->link_status_idx];
143.23310 ++	DBG(("%s: link_status=%d\n", __FUNCTION__, link_status));
143.23311 ++	if (link_status == LINK_STATUS_GOOD)
143.23312 ++		return true;
143.23313 ++
143.23314 ++	/* Perform a modeset as required for "link-status" = BAD */
143.23315 ++	if (!output_retrain_link(sna, output))
143.23316 ++		return false;
143.23317 ++
143.23318 ++	/* Query the "link-status" again to confirm the modeset */
143.23319 ++	update_properties(sna, output);
143.23320 ++
143.23321 ++	link_status = output->prop_values[output->link_status_idx];
143.23322 ++	DBG(("%s: link_status=%d after modeset\n", __FUNCTION__, link_status));
143.23323 ++	return link_status == LINK_STATUS_GOOD;
143.23324 ++}
143.23325 ++
143.23326 ++static bool
143.23327 ++output_check_status(struct sna *sna, struct sna_output *output)
143.23328 ++{
143.23329 ++	union compat_mode_get_connector compat_conn;
143.23330 ++	struct drm_mode_modeinfo dummy;
143.23331 ++	struct drm_mode_get_blob blob;
143.23332 ++	xf86OutputStatus status;
143.23333 ++	char *edid;
143.23334 ++
143.23335 ++	VG_CLEAR(compat_conn);
143.23336 ++
143.23337 ++	compat_conn.conn.connection = -1;
143.23338 ++	compat_conn.conn.connector_id = output->id;
143.23339 ++	compat_conn.conn.count_modes = 1; /* skip detect */
143.23340 ++	compat_conn.conn.modes_ptr = (uintptr_t)&dummy;
143.23341 ++	compat_conn.conn.count_encoders = 0;
143.23342 ++	compat_conn.conn.props_ptr = (uintptr_t)output->prop_ids;
143.23343 ++	compat_conn.conn.prop_values_ptr = (uintptr_t)output->prop_values;
143.23344 ++	compat_conn.conn.count_props = output->num_props;
143.23345 ++
143.23346 ++	if (drmIoctl(sna->kgem.fd,
143.23347 ++		     DRM_IOCTL_MODE_GETCONNECTOR,
143.23348 ++		     &compat_conn.conn) == 0)
143.23349 ++		output->update_properties = false;
143.23350 ++
143.23351 ++	if (!output_check_link(sna, output))
143.23352 ++		return false;
143.23353 ++
143.23354 ++	if (output->reprobe)
143.23355 ++		return false;
143.23356 ++
143.23357 ++	switch (compat_conn.conn.connection) {
143.23358 ++	case DRM_MODE_CONNECTED:
143.23359 ++		status = XF86OutputStatusConnected;
143.23360 ++		break;
143.23361 ++	case DRM_MODE_DISCONNECTED:
143.23362 ++		status = XF86OutputStatusDisconnected;
143.23363 ++		break;
143.23364 ++	default:
143.23365 ++	case DRM_MODE_UNKNOWNCONNECTION:
143.23366 ++		status = XF86OutputStatusUnknown;
143.23367 ++		break;
143.23368 ++	}
143.23369 ++	if (output->status != status)
143.23370 ++		return false;
143.23371 ++
143.23372 ++	if (status != XF86OutputStatusConnected)
143.23373 ++		return true;
143.23374 ++
143.23375 ++	if (output->num_modes != compat_conn.conn.count_modes)
143.23376 ++		return false;
143.23377 ++
143.23378 ++	if (output->edid_len == 0)
143.23379 ++		return false;
143.23380 ++
143.23381 ++	edid = alloca(output->edid_len);
143.23382 ++
143.23383 ++	VG_CLEAR(blob);
143.23384 ++	blob.blob_id = output->prop_values[output->edid_idx];
143.23385 ++	blob.length = output->edid_len;
143.23386 ++	blob.data = (uintptr_t)edid;
143.23387 ++	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
143.23388 ++		return false;
143.23389 ++
143.23390 ++	if (blob.length != output->edid_len)
143.23391 ++		return false;
143.23392 ++
143.23393 ++	return memcmp(edid, output->edid_raw, output->edid_len) == 0;
143.23394 ++}
143.23395 ++
143.23396 ++void sna_mode_discover(struct sna *sna, bool tell)
143.23397 + {
143.23398 + 	ScreenPtr screen = xf86ScrnToScreen(sna->scrn);
143.23399 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.23400 ++	bool force = sna->flags & SNA_REPROBE;
143.23401 + 	struct drm_mode_card_res res;
143.23402 +-	uint32_t connectors[32];
143.23403 ++	uint32_t connectors[32], now;
143.23404 + 	unsigned changed = 0;
143.23405 + 	unsigned serial;
143.23406 + 	int i, j;
143.23407 + 
143.23408 + 	DBG(("%s()\n", __FUNCTION__));
143.23409 ++	sna->flags &= ~SNA_REPROBE;
143.23410 ++
143.23411 + 	VG_CLEAR(connectors);
143.23412 + 
143.23413 + 	memset(&res, 0, sizeof(res));
143.23414 +@@ -4128,10 +5443,11 @@ void sna_mode_discover(struct sna *sna)
143.23415 + 	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
143.23416 + 		return;
143.23417 + 
143.23418 +-	DBG(("%s: now %d (was %d) connectors\n", __FUNCTION__,
143.23419 +-	     res.count_connectors, sna->mode.num_real_output));
143.23420 ++	DBG(("%s: now %d (was %d) connectors, %d encoders, %d crtc\n", __FUNCTION__,
143.23421 ++	     res.count_connectors, sna->mode.num_real_output,
143.23422 ++	     res.count_encoders, res.count_crtcs));
143.23423 + 	if (res.count_connectors > 32)
143.23424 +-		return;
143.23425 ++		res.count_connectors = 32;
143.23426 + 
143.23427 + 	assert(sna->mode.num_real_crtc == res.count_crtcs || is_zaphod(sna->scrn));
143.23428 + 	assert(sna->mode.max_crtc_width  == res.max_width);
143.23429 +@@ -4142,6 +5458,11 @@ void sna_mode_discover(struct sna *sna)
143.23430 + 	if (serial == 0)
143.23431 + 		serial = ++sna->mode.serial;
143.23432 + 
143.23433 ++	if (force) {
143.23434 ++		changed = 4;
143.23435 ++		now = 0;
143.23436 ++	} else
143.23437 ++		now = GetTimeInMillis();
143.23438 + 	for (i = 0; i < res.count_connectors; i++) {
143.23439 + 		DBG(("%s: connector[%d] = %d\n", __FUNCTION__, i, connectors[i]));
143.23440 + 		for (j = 0; j < sna->mode.num_real_output; j++) {
143.23441 +@@ -4161,32 +5482,42 @@ void sna_mode_discover(struct sna *sna)
143.23442 + 
143.23443 + 	for (i = 0; i < sna->mode.num_real_output; i++) {
143.23444 + 		xf86OutputPtr output = config->output[i];
143.23445 ++		struct sna_output *sna_output = to_sna_output(output);
143.23446 + 
143.23447 +-		if (to_sna_output(output)->id == 0)
143.23448 ++		if (sna_output->id == 0)
143.23449 + 			continue;
143.23450 + 
143.23451 +-		if (to_sna_output(output)->serial == serial)
143.23452 ++		if (sna_output->serial == serial) {
143.23453 ++			if (output_check_status(sna, sna_output)) {
143.23454 ++				DBG(("%s: output %s (id=%d), retained state\n",
143.23455 ++				     __FUNCTION__, output->name, sna_output->id));
143.23456 ++				sna_output->last_detect = now;
143.23457 ++			} else {
143.23458 ++				DBG(("%s: output %s (id=%d), changed state, reprobing\n",
143.23459 ++				     __FUNCTION__, output->name, sna_output->id));
143.23460 ++				sna_output->hotplug_count++;
143.23461 ++				sna_output->last_detect = 0;
143.23462 ++				changed |= 4;
143.23463 ++			}
143.23464 + 			continue;
143.23465 ++		}
143.23466 + 
143.23467 + 		DBG(("%s: removing output %s (id=%d), serial=%u [now %u]\n",
143.23468 +-		     __FUNCTION__, output->name, to_sna_output(output)->id,
143.23469 +-		    to_sna_output(output)->serial, serial));
143.23470 ++		     __FUNCTION__, output->name, sna_output->id,
143.23471 ++		    sna_output->serial, serial));
143.23472 + 
143.23473 + 		xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
143.23474 +-			   "%s output %s\n",
143.23475 +-			   sna->flags & SNA_REMOVE_OUTPUTS ? "Removed" : "Disabled",
143.23476 ++			   "Disabled output %s\n",
143.23477 + 			   output->name);
143.23478 +-		if (sna->flags & SNA_REMOVE_OUTPUTS) {
143.23479 +-			sna_output_del(output);
143.23480 +-			i--;
143.23481 +-		} else {
143.23482 +-			to_sna_output(output)->id = 0;
143.23483 +-			output->crtc = NULL;
143.23484 +-		}
143.23485 ++		sna_output->id = 0;
143.23486 ++		sna_output->last_detect = 0;
143.23487 ++		output->crtc = NULL;
143.23488 ++		RROutputChanged(output->randr_output, TRUE);
143.23489 + 		changed |= 2;
143.23490 + 	}
143.23491 + 
143.23492 +-	if (changed) {
143.23493 ++	/* Have the list of available outputs been updated? */
143.23494 ++	if (changed & 3) {
143.23495 + 		DBG(("%s: outputs changed, broadcasting\n", __FUNCTION__));
143.23496 + 
143.23497 + 		sna_mode_set_primary(sna);
143.23498 +@@ -4200,6 +5531,51 @@ void sna_mode_discover(struct sna *sna)
143.23499 + 
143.23500 + 		xf86RandR12TellChanged(screen);
143.23501 + 	}
143.23502 ++
143.23503 ++	/* If anything has changed, refresh the RandR information.
143.23504 ++	 * Note this could recurse once from udevless RRGetInfo() probes,
143.23505 ++	 * but only once.
143.23506 ++	 */
143.23507 ++	if (changed && tell)
143.23508 ++		RRGetInfo(screen, TRUE);
143.23509 ++}
143.23510 ++
143.23511 ++/* Since we only probe the current mode on startup, we may not have the full
143.23512 ++ * list of modes available until the user explicitly requests them. Fake a
143.23513 ++ * hotplug event after a second after starting to fill in any missing modes.
143.23514 ++ */
143.23515 ++static CARD32 sna_mode_coldplug(OsTimerPtr timer, CARD32 now, void *data)
143.23516 ++{
143.23517 ++	struct sna *sna = data;
143.23518 ++	ScreenPtr screen = xf86ScrnToScreen(sna->scrn);
143.23519 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.23520 ++	bool reprobe = false;
143.23521 ++	int i;
143.23522 ++
143.23523 ++	DBG(("%s()\n", __FUNCTION__));
143.23524 ++
143.23525 ++	for (i = 0; i < sna->mode.num_real_output; i++) {
143.23526 ++		xf86OutputPtr output = config->output[i];
143.23527 ++		struct sna_output *sna_output = to_sna_output(output);
143.23528 ++
143.23529 ++		if (sna_output->id == 0)
143.23530 ++			continue;
143.23531 ++		if (sna_output->last_detect)
143.23532 ++			continue;
143.23533 ++		if (output->status == XF86OutputStatusDisconnected)
143.23534 ++			continue;
143.23535 ++
143.23536 ++		DBG(("%s: output %s connected, needs reprobe\n",
143.23537 ++		     __FUNCTION__, output->name));
143.23538 ++		reprobe = true;
143.23539 ++	}
143.23540 ++
143.23541 ++	if (reprobe) {
143.23542 ++		RRGetInfo(screen, TRUE);
143.23543 ++		RRTellChanged(screen);
143.23544 ++	}
143.23545 ++	free(timer);
143.23546 ++	return 0;
143.23547 + }
143.23548 + 
143.23549 + static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
143.23550 +@@ -4208,7 +5584,7 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
143.23551 + 
143.23552 + 	DBG(("%s\n", __FUNCTION__));
143.23553 + 
143.23554 +-	if (wedged(sna))
143.23555 ++	if (wedged(sna) || isGPU(sna->scrn))
143.23556 + 		return;
143.23557 + 
143.23558 + 	old_priv = sna_pixmap_force_to_gpu(old, MOVE_READ);
143.23559 +@@ -4220,12 +5596,19 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
143.23560 + 		return;
143.23561 + 
143.23562 + 	if (old_priv->clear) {
143.23563 +-		(void)sna->render.fill_one(sna, new, new_priv->gpu_bo,
143.23564 +-					   old_priv->clear_color,
143.23565 +-					   0, 0,
143.23566 +-					   new->drawable.width,
143.23567 +-					   new->drawable.height,
143.23568 +-					   GXcopy);
143.23569 ++		bool ok = false;
143.23570 ++		if (!wedged(sna))
143.23571 ++			ok = sna->render.fill_one(sna, new, new_priv->gpu_bo,
143.23572 ++						  old_priv->clear_color,
143.23573 ++						  0, 0,
143.23574 ++						  new->drawable.width,
143.23575 ++						  new->drawable.height,
143.23576 ++						  GXcopy);
143.23577 ++		if (!ok) {
143.23578 ++			void *ptr = kgem_bo_map__gtt(&sna->kgem, new_priv->gpu_bo);
143.23579 ++			if (ptr)
143.23580 ++				memset(ptr, 0, new_priv->gpu_bo->pitch*new->drawable.height);
143.23581 ++		}
143.23582 + 		new_priv->clear = true;
143.23583 + 		new_priv->clear_color = old_priv->clear_color;
143.23584 + 	} else {
143.23585 +@@ -4281,11 +5664,18 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
143.23586 + 			     __FUNCTION__, box.x2, box.y2, sx, sy, dx, dy));
143.23587 + 
143.23588 + 			if (box.x2 != new->drawable.width || box.y2 != new->drawable.height) {
143.23589 +-				(void)sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
143.23590 +-							   0, 0,
143.23591 +-							   new->drawable.width,
143.23592 +-							   new->drawable.height,
143.23593 +-							   GXclear);
143.23594 ++				bool ok = false;
143.23595 ++				if (!wedged(sna))
143.23596 ++					ok = sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
143.23597 ++								  0, 0,
143.23598 ++								  new->drawable.width,
143.23599 ++								  new->drawable.height,
143.23600 ++								  GXclear);
143.23601 ++				if (!ok) {
143.23602 ++					void *ptr = kgem_bo_map__gtt(&sna->kgem, new_priv->gpu_bo);
143.23603 ++					if (ptr)
143.23604 ++						memset(ptr, 0, new_priv->gpu_bo->pitch*new->drawable.height);
143.23605 ++				}
143.23606 + 			}
143.23607 + 			(void)sna->render.copy_boxes(sna, GXcopy,
143.23608 + 						     &old->drawable, old_priv->gpu_bo, sx, sy,
143.23609 +@@ -4302,7 +5692,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
143.23610 + {
143.23611 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
143.23612 + 	struct sna *sna = to_sna(scrn);
143.23613 +-	ScreenPtr screen = scrn->pScreen;
143.23614 ++	ScreenPtr screen = xf86ScrnToScreen(scrn);
143.23615 + 	PixmapPtr new_front;
143.23616 + 	int i;
143.23617 + 
143.23618 +@@ -4337,9 +5727,20 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
143.23619 + 	for (i = 0; i < sna->mode.num_real_crtc; i++)
143.23620 + 		sna_crtc_disable_shadow(sna, to_sna_crtc(config->crtc[i]));
143.23621 + 	assert(sna->mode.shadow_active == 0);
143.23622 ++	assert(!sna->mode.shadow_enabled);
143.23623 + 	assert(sna->mode.shadow_damage == NULL);
143.23624 + 	assert(sna->mode.shadow == NULL);
143.23625 + 
143.23626 ++	/* Flush pending shadow updates */
143.23627 ++	if (sna->mode.flip_active) {
143.23628 ++		DBG(("%s: waiting for %d outstanding TearFree flips\n",
143.23629 ++		     __FUNCTION__, sna->mode.flip_active));
143.23630 ++		while (sna->mode.flip_active && sna_mode_wait_for_event(sna))
143.23631 ++			sna_mode_wakeup(sna);
143.23632 ++	}
143.23633 ++
143.23634 ++	/* Cancel a pending [un]flip (as the pixmaps no longer match) */
143.23635 ++	sna_present_cancel_flip(sna);
143.23636 + 	copy_front(sna, sna->front, new_front);
143.23637 + 
143.23638 + 	screen->SetScreenPixmap(new_front);
143.23639 +@@ -4351,14 +5752,6 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
143.23640 + 	scrn->virtualY = height;
143.23641 + 	scrn->displayWidth = width;
143.23642 + 
143.23643 +-	/* Flush pending shadow updates */
143.23644 +-	if (sna->mode.flip_active) {
143.23645 +-		DBG(("%s: waiting for %d outstanding TearFree flips\n",
143.23646 +-		     __FUNCTION__, sna->mode.flip_active));
143.23647 +-		while (sna->mode.flip_active && sna_mode_wait_for_event(sna))
143.23648 +-			sna_mode_wakeup(sna);
143.23649 +-	}
143.23650 +-
143.23651 + 	/* Only update the CRTCs if we are in control */
143.23652 + 	if (!scrn->vtSema)
143.23653 + 		return TRUE;
143.23654 +@@ -4371,7 +5764,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
143.23655 + 			continue;
143.23656 + 
143.23657 + 		if (!__sna_crtc_set_mode(crtc))
143.23658 +-			sna_crtc_disable(crtc);
143.23659 ++			sna_crtc_disable(crtc, false);
143.23660 + 	}
143.23661 + 
143.23662 + 	sna_mode_wakeup(sna);
143.23663 +@@ -4381,19 +5774,6 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
143.23664 + }
143.23665 + 
143.23666 + /* cursor handling */
143.23667 +-struct sna_cursor {
143.23668 +-	struct sna_cursor *next;
143.23669 +-	uint32_t *image;
143.23670 +-	Rotation rotation;
143.23671 +-	int ref;
143.23672 +-	int size;
143.23673 +-	int last_width;
143.23674 +-	int last_height;
143.23675 +-	unsigned handle;
143.23676 +-	unsigned serial;
143.23677 +-	unsigned alloc;
143.23678 +-};
143.23679 +-
143.23680 + static void
143.23681 + rotate_coord(Rotation rotation, int size,
143.23682 + 	     int x_dst, int y_dst,
143.23683 +@@ -4429,36 +5809,6 @@ rotate_coord(Rotation rotation, int size,
143.23684 + 	*y_src = y_dst;
143.23685 + }
143.23686 + 
143.23687 +-static void
143.23688 +-rotate_coord_back(Rotation rotation, int size, int *x, int *y)
143.23689 +-{
143.23690 +-	int t;
143.23691 +-
143.23692 +-	if (rotation & RR_Reflect_X)
143.23693 +-		*x = size - *x - 1;
143.23694 +-	if (rotation & RR_Reflect_Y)
143.23695 +-		*y = size - *y - 1;
143.23696 +-
143.23697 +-	switch (rotation & 0xf) {
143.23698 +-	case RR_Rotate_0:
143.23699 +-		break;
143.23700 +-	case RR_Rotate_90:
143.23701 +-		t = *x;
143.23702 +-		*x = *y;
143.23703 +-		*y = size - t - 1;
143.23704 +-		break;
143.23705 +-	case RR_Rotate_180:
143.23706 +-		*x = size - *x - 1;
143.23707 +-		*y = size - *y - 1;
143.23708 +-		break;
143.23709 +-	case RR_Rotate_270:
143.23710 +-		t = *x;
143.23711 +-		*x = size - *y - 1;
143.23712 +-		*y = t;
143.23713 +-		break;
143.23714 +-	}
143.23715 +-}
143.23716 +-
143.23717 + static struct sna_cursor *__sna_create_cursor(struct sna *sna, int size)
143.23718 + {
143.23719 + 	struct sna_cursor *c;
143.23720 +@@ -4519,6 +5869,17 @@ static uint32_t *get_cursor_argb(CursorPtr c)
143.23721 + #endif
143.23722 + }
143.23723 + 
143.23724 ++static int __cursor_size(int width, int height)
143.23725 ++{
143.23726 ++	int i, size;
143.23727 ++
143.23728 ++	i = MAX(width, height);
143.23729 ++	for (size = 64; size < i; size <<= 1)
143.23730 ++		;
143.23731 ++
143.23732 ++	return size;
143.23733 ++}
143.23734 ++
143.23735 + static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23736 + {
143.23737 + 	struct sna_cursor *cursor;
143.23738 +@@ -4526,6 +5887,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23739 + 	const uint32_t *argb;
143.23740 + 	uint32_t *image;
143.23741 + 	int width, height, pitch, size, x, y;
143.23742 ++	bool transformed;
143.23743 + 	Rotation rotation;
143.23744 + 
143.23745 + 	assert(sna->cursor.ref);
143.23746 +@@ -4537,8 +5899,8 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23747 + 	       cursor ? cursor->serial : 0,
143.23748 + 	       sna->cursor.serial));
143.23749 + 	if (cursor && cursor->serial == sna->cursor.serial) {
143.23750 +-		assert(cursor->size == sna->cursor.size);
143.23751 +-		assert(cursor->rotation == crtc->transform_in_use ? crtc->rotation : RR_Rotate_0);
143.23752 ++		assert(cursor->size == sna->cursor.size || cursor->transformed);
143.23753 ++		assert(cursor->rotation == (!to_sna_crtc(crtc)->cursor_transform && crtc->transform_in_use) ? crtc->rotation : RR_Rotate_0);
143.23754 + 		assert(cursor->ref);
143.23755 + 		return cursor;
143.23756 + 	}
143.23757 +@@ -4550,22 +5912,81 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23758 + 	       sna->cursor.serial,
143.23759 + 	       get_cursor_argb(sna->cursor.ref) != NULL));
143.23760 + 
143.23761 +-	rotation = crtc->transform_in_use ? crtc->rotation : RR_Rotate_0;
143.23762 ++	transformed = to_sna_crtc(crtc)->cursor_transform;
143.23763 ++	rotation = (!transformed && crtc->transform_in_use) ? crtc->rotation : RR_Rotate_0;
143.23764 ++
143.23765 ++	if (transformed) {
143.23766 ++		struct pixman_box16 box;
143.23767 ++
143.23768 ++		box.x1 = box.y1 = 0;
143.23769 ++		box.x2 = sna->cursor.ref->bits->width;
143.23770 ++		box.y2 = sna->cursor.ref->bits->height;
143.23771 + 
143.23772 +-	if (sna->cursor.use_gtt) { /* Don't allow phys cursor sharing */
143.23773 ++		pixman_f_transform_bounds(&crtc->f_crtc_to_framebuffer, &box);
143.23774 ++		size = __cursor_size(box.x2 - box.x1, box.y2 - box.y1);
143.23775 ++		__DBG(("%s: transformed cursor %dx%d -> %dx%d\n",
143.23776 ++		       __FUNCTION__ ,
143.23777 ++		       sna->cursor.ref->bits->width,
143.23778 ++		       sna->cursor.ref->bits->height,
143.23779 ++		       box.x2 - box.x1, box.y2 - box.y1));
143.23780 ++	} else
143.23781 ++		size = sna->cursor.size;
143.23782 ++
143.23783 ++	if (crtc->transform_in_use) {
143.23784 ++		RRTransformPtr T = NULL;
143.23785 ++		struct pixman_vector v;
143.23786 ++
143.23787 ++		if (crtc->transformPresent) {
143.23788 ++			T = &crtc->transform;
143.23789 ++
143.23790 ++			/* Cancel any translation from this affine
143.23791 ++			 * transformation. We just want to rotate and scale
143.23792 ++			 * the cursor image.
143.23793 ++			 */
143.23794 ++			v.vector[0] = 0;
143.23795 ++			v.vector[1] = 0;
143.23796 ++			v.vector[2] = pixman_fixed_1;
143.23797 ++			pixman_transform_point(&crtc->transform.transform, &v);
143.23798 ++		}
143.23799 ++
143.23800 ++		RRTransformCompute(0, 0, size, size, crtc->rotation, T, NULL,
143.23801 ++				   &to_sna_crtc(crtc)->cursor_to_fb,
143.23802 ++				   &to_sna_crtc(crtc)->fb_to_cursor);
143.23803 ++		if (T)
143.23804 ++			pixman_f_transform_translate(
143.23805 ++					&to_sna_crtc(crtc)->cursor_to_fb,
143.23806 ++					&to_sna_crtc(crtc)->fb_to_cursor,
143.23807 ++					-pixman_fixed_to_double(v.vector[0]),
143.23808 ++					-pixman_fixed_to_double(v.vector[1]));
143.23809 ++
143.23810 ++		__DBG(("%s: cursor_to_fb [%f %f %f, %f %f %f, %f %f %f]\n",
143.23811 ++		       __FUNCTION__,
143.23812 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[0][0],
143.23813 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[0][1],
143.23814 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[0][2],
143.23815 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[1][0],
143.23816 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[1][1],
143.23817 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[1][2],
143.23818 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[2][0],
143.23819 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[2][1],
143.23820 ++		       to_sna_crtc(crtc)->cursor_to_fb.m[2][2]));
143.23821 ++	}
143.23822 ++
143.23823 ++	/* Don't allow phys cursor sharing */
143.23824 ++	if (sna->cursor.use_gtt && !transformed) {
143.23825 + 		for (cursor = sna->cursor.cursors; cursor; cursor = cursor->next) {
143.23826 +-			if (cursor->serial == sna->cursor.serial && cursor->rotation == rotation) {
143.23827 ++			if (cursor->serial == sna->cursor.serial &&
143.23828 ++			    cursor->rotation == rotation &&
143.23829 ++			    !cursor->transformed) {
143.23830 + 				__DBG(("%s: reusing handle=%d, serial=%d, rotation=%d, size=%d\n",
143.23831 + 				       __FUNCTION__, cursor->handle, cursor->serial, cursor->rotation, cursor->size));
143.23832 + 				assert(cursor->size == sna->cursor.size);
143.23833 + 				return cursor;
143.23834 + 			}
143.23835 + 		}
143.23836 +-
143.23837 +-		cursor = to_sna_crtc(crtc)->cursor;
143.23838 + 	}
143.23839 + 
143.23840 +-	size = sna->cursor.size;
143.23841 ++	cursor = to_sna_crtc(crtc)->cursor;
143.23842 + 	if (cursor && cursor->alloc < 4*size*size)
143.23843 + 		cursor = NULL;
143.23844 + 
143.23845 +@@ -4577,7 +5998,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23846 + 		}
143.23847 + 	}
143.23848 + 
143.23849 +-	width = sna->cursor.ref->bits->width;
143.23850 ++	width  = sna->cursor.ref->bits->width;
143.23851 + 	height = sna->cursor.ref->bits->height;
143.23852 + 	source = sna->cursor.ref->bits->source;
143.23853 + 	mask = sna->cursor.ref->bits->mask;
143.23854 +@@ -4585,7 +6006,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23855 + 	pitch = BitmapBytePad(width);
143.23856 + 
143.23857 + 	image = cursor->image;
143.23858 +-	if (image == NULL) {
143.23859 ++	if (image == NULL || transformed) {
143.23860 + 		image = sna->cursor.scratch;
143.23861 + 		cursor->last_width = cursor->last_height = size;
143.23862 + 	}
143.23863 +@@ -4616,6 +6037,21 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23864 + 				mask += pitch;
143.23865 + 				source += pitch;
143.23866 + 			}
143.23867 ++			if (transformed) {
143.23868 ++				__DBG(("%s: Applying affine BLT to bitmap\n", __FUNCTION__));
143.23869 ++				affine_blt(image, cursor->image, 32,
143.23870 ++					   0, 0, width, height, size * 4,
143.23871 ++					   0, 0, size, size, size * 4,
143.23872 ++					   &to_sna_crtc(crtc)->cursor_to_fb);
143.23873 ++				image = cursor->image;
143.23874 ++			}
143.23875 ++		} else if (transformed) {
143.23876 ++			__DBG(("%s: Applying affine BLT to ARGB\n", __FUNCTION__));
143.23877 ++			affine_blt(argb, cursor->image, 32,
143.23878 ++				   0, 0, width, height, width * 4,
143.23879 ++				   0, 0, size, size, size * 4,
143.23880 ++				   &to_sna_crtc(crtc)->cursor_to_fb);
143.23881 ++			image = cursor->image;
143.23882 + 		} else
143.23883 + 			memcpy_blt(argb, image, 32,
143.23884 + 				   width * 4, size * 4,
143.23885 +@@ -4662,9 +6098,16 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
143.23886 + 
143.23887 + 	cursor->size = size;
143.23888 + 	cursor->rotation = rotation;
143.23889 ++	cursor->transformed = transformed;
143.23890 + 	cursor->serial = sna->cursor.serial;
143.23891 +-	cursor->last_width = width;
143.23892 +-	cursor->last_height = height;
143.23893 ++	if (transformed) {
143.23894 ++		/* mark the transformed rectangle as dirty, not input */
143.23895 ++		cursor->last_width = size;
143.23896 ++		cursor->last_height = size;
143.23897 ++	} else {
143.23898 ++		cursor->last_width = width;
143.23899 ++		cursor->last_height = height;
143.23900 ++	}
143.23901 + 	return cursor;
143.23902 + }
143.23903 + 
143.23904 +@@ -4674,40 +6117,55 @@ sna_realize_cursor(xf86CursorInfoPtr info, CursorPtr cursor)
143.23905 + 	return NULL;
143.23906 + }
143.23907 + 
143.23908 +-#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
143.23909 +-static inline int sigio_block(void)
143.23910 +-{
143.23911 +-	OsBlockSIGIO();
143.23912 +-	return 0;
143.23913 +-}
143.23914 +-static inline void sigio_unblock(int was_blocked)
143.23915 ++static void enable_fb_access(ScrnInfoPtr scrn, int state)
143.23916 + {
143.23917 +-	OsReleaseSIGIO();
143.23918 +-	(void)was_blocked;
143.23919 +-}
143.23920 ++	scrn->EnableDisableFBAccess(
143.23921 ++#ifdef XF86_HAS_SCRN_CONV
143.23922 ++				    scrn,
143.23923 + #else
143.23924 +-#include <xf86_OSproc.h>
143.23925 +-static inline int sigio_block(void)
143.23926 ++				    scrn->scrnIndex,
143.23927 ++#endif
143.23928 ++				    state);
143.23929 ++}
143.23930 ++
143.23931 ++
143.23932 ++static void __restore_swcursor(ScrnInfoPtr scrn)
143.23933 + {
143.23934 +-	return xf86BlockSIGIO();
143.23935 ++	DBG(("%s: attempting to restore SW cursor\n", __FUNCTION__));
143.23936 ++	enable_fb_access(scrn, FALSE);
143.23937 ++	enable_fb_access(scrn, TRUE);
143.23938 ++
143.23939 ++	RemoveBlockAndWakeupHandlers((void *)__restore_swcursor,
143.23940 ++				     (void *)NoopDDA,
143.23941 ++				     scrn);
143.23942 + }
143.23943 +-static inline void sigio_unblock(int was_blocked)
143.23944 ++
143.23945 ++static void restore_swcursor(struct sna *sna)
143.23946 + {
143.23947 +-	xf86UnblockSIGIO(was_blocked);
143.23948 ++	sna->cursor.info->HideCursor(sna->scrn);
143.23949 ++
143.23950 ++	/* XXX Force the cursor to be restored (avoiding recursion) */
143.23951 ++	FreeCursor(sna->cursor.ref, None);
143.23952 ++	sna->cursor.ref = NULL;
143.23953 ++
143.23954 ++	RegisterBlockAndWakeupHandlers((void *)__restore_swcursor,
143.23955 ++				       (void *)NoopDDA,
143.23956 ++				       sna->scrn);
143.23957 + }
143.23958 +-#endif
143.23959 + 
143.23960 + static void
143.23961 + sna_show_cursors(ScrnInfoPtr scrn)
143.23962 + {
143.23963 + 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
143.23964 + 	struct sna *sna = to_sna(scrn);
143.23965 ++	struct kmsg kmsg;
143.23966 + 	int sigio, c;
143.23967 + 
143.23968 + 	DBG(("%s: cursor?=%d\n", __FUNCTION__, sna->cursor.ref != NULL));
143.23969 + 	if (sna->cursor.ref == NULL)
143.23970 + 		return;
143.23971 + 
143.23972 ++	kmsg_open(&kmsg);
143.23973 + 	sigio = sigio_block();
143.23974 + 	for (c = 0; c < sna->mode.num_real_crtc; c++) {
143.23975 + 		xf86CrtcPtr crtc = xf86_config->crtc[c];
143.23976 +@@ -4721,7 +6179,7 @@ sna_show_cursors(ScrnInfoPtr scrn)
143.23977 + 
143.23978 + 		if (!crtc->cursor_in_range) {
143.23979 + 			DBG(("%s: skipping cursor outside CRTC (pipe=%d)\n",
143.23980 +-			     __FUNCTION__, sna_crtc->pipe));
143.23981 ++			     __FUNCTION__, sna_crtc_pipe(crtc)));
143.23982 + 			continue;
143.23983 + 		}
143.23984 + 
143.23985 +@@ -4729,20 +6187,21 @@ sna_show_cursors(ScrnInfoPtr scrn)
143.23986 + 		if (cursor == NULL ||
143.23987 + 		    (sna_crtc->cursor == cursor && sna_crtc->last_cursor_size == cursor->size)) {
143.23988 + 			DBG(("%s: skipping cursor already show on CRTC (pipe=%d)\n",
143.23989 +-			     __FUNCTION__, sna_crtc->pipe));
143.23990 ++			     __FUNCTION__, sna_crtc_pipe(crtc)));
143.23991 + 			continue;
143.23992 + 		}
143.23993 + 
143.23994 + 		DBG(("%s: CRTC pipe=%d, handle->%d\n", __FUNCTION__,
143.23995 +-		     sna_crtc->pipe, cursor->handle));
143.23996 ++		     sna_crtc_pipe(crtc), cursor->handle));
143.23997 + 
143.23998 + 		VG_CLEAR(arg);
143.23999 + 		arg.flags = DRM_MODE_CURSOR_BO;
143.24000 +-		arg.crtc_id = sna_crtc->id;
143.24001 ++		arg.crtc_id = __sna_crtc_id(sna_crtc);
143.24002 + 		arg.width = arg.height = cursor->size;
143.24003 + 		arg.handle = cursor->handle;
143.24004 + 
143.24005 +-		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
143.24006 ++		if (!FAIL_CURSOR_IOCTL &&
143.24007 ++		    drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
143.24008 + 			if (sna_crtc->cursor) {
143.24009 + 				assert(sna_crtc->cursor->ref > 0);
143.24010 + 				sna_crtc->cursor->ref--;
143.24011 +@@ -4750,10 +6209,18 @@ sna_show_cursors(ScrnInfoPtr scrn)
143.24012 + 			cursor->ref++;
143.24013 + 			sna_crtc->cursor = cursor;
143.24014 + 			sna_crtc->last_cursor_size = cursor->size;
143.24015 ++		} else {
143.24016 ++			ERR(("%s: failed to show cursor on CRTC:%d [pipe=%d], disabling hwcursor: errno=%d\n",
143.24017 ++			     __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc), errno));
143.24018 ++			sna->cursor.disable = true;
143.24019 + 		}
143.24020 + 	}
143.24021 + 	sigio_unblock(sigio);
143.24022 + 	sna->cursor.active = true;
143.24023 ++	kmsg_close(&kmsg, sna->cursor.disable);
143.24024 ++
143.24025 ++	if (unlikely(sna->cursor.disable))
143.24026 ++		restore_swcursor(sna);
143.24027 + }
143.24028 + 
143.24029 + static void
143.24030 +@@ -4789,24 +6256,45 @@ static void
143.24031 + sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc)
143.24032 + {
143.24033 + 	struct drm_mode_cursor arg;
143.24034 ++	int sigio;
143.24035 + 
143.24036 + 	if (!crtc->cursor)
143.24037 + 		return;
143.24038 + 
143.24039 +-	DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, crtc->id, crtc->cursor->handle));
143.24040 +-	assert(crtc->cursor->ref);
143.24041 ++	sigio = sigio_block();
143.24042 ++	if (crtc->cursor) {
143.24043 ++		DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), crtc->cursor->handle));
143.24044 ++		assert(crtc->cursor->ref > 0);
143.24045 ++		crtc->cursor->ref--;
143.24046 ++		crtc->cursor = NULL;
143.24047 ++		crtc->last_cursor_size = 0;
143.24048 + 
143.24049 +-	VG_CLEAR(arg);
143.24050 +-	arg.flags = DRM_MODE_CURSOR_BO;
143.24051 +-	arg.crtc_id = crtc->id;
143.24052 +-	arg.width = arg.height = 0;
143.24053 +-	arg.handle = 0;
143.24054 ++		VG_CLEAR(arg);
143.24055 ++		arg.flags = DRM_MODE_CURSOR_BO;
143.24056 ++		arg.crtc_id = __sna_crtc_id(crtc);
143.24057 ++		arg.width = arg.height = 0;
143.24058 ++		arg.handle = 0;
143.24059 + 
143.24060 +-	(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
143.24061 +-	assert(crtc->cursor->ref > 0);
143.24062 +-	crtc->cursor->ref--;
143.24063 +-	crtc->cursor = NULL;
143.24064 +-	crtc->last_cursor_size = 0;
143.24065 ++		(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
143.24066 ++	}
143.24067 ++	sigio_unblock(sigio);
143.24068 ++}
143.24069 ++
143.24070 ++static void
143.24071 ++sna_disable_cursors(ScrnInfoPtr scrn)
143.24072 ++{
143.24073 ++	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
143.24074 ++	struct sna *sna = to_sna(scrn);
143.24075 ++	int sigio, c;
143.24076 ++
143.24077 ++	DBG(("%s\n", __FUNCTION__));
143.24078 ++
143.24079 ++	sigio = sigio_block();
143.24080 ++	for (c = 0; c < sna->mode.num_real_crtc; c++) {
143.24081 ++		assert(to_sna_crtc(xf86_config->crtc[c]));
143.24082 ++		sna_crtc_disable_cursor(sna, to_sna_crtc(xf86_config->crtc[c]));
143.24083 ++	}
143.24084 ++	sigio_unblock(sigio);
143.24085 + }
143.24086 + 
143.24087 + static void
143.24088 +@@ -4852,6 +6340,7 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
143.24089 + {
143.24090 + 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
143.24091 + 	struct sna *sna = to_sna(scrn);
143.24092 ++	struct kmsg kmsg;
143.24093 + 	int sigio, c;
143.24094 + 
143.24095 + 	__DBG(("%s(%d, %d), cursor? %d\n", __FUNCTION__,
143.24096 +@@ -4859,6 +6348,7 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
143.24097 + 	if (sna->cursor.ref == NULL)
143.24098 + 		return;
143.24099 + 
143.24100 ++	kmsg_open(&kmsg);
143.24101 + 	sigio = sigio_block();
143.24102 + 	sna->cursor.last_x = x;
143.24103 + 	sna->cursor.last_y = y;
143.24104 +@@ -4876,27 +6366,37 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
143.24105 + 
143.24106 + 		VG_CLEAR(arg);
143.24107 + 		arg.flags = 0;
143.24108 +-		arg.crtc_id = sna_crtc->id;
143.24109 ++		arg.crtc_id = __sna_crtc_id(sna_crtc);
143.24110 + 		arg.handle = 0;
143.24111 + 
143.24112 + 		if (sna_crtc->bo == NULL)
143.24113 + 			goto disable;
143.24114 + 
143.24115 ++		cursor = __sna_get_cursor(sna, crtc);
143.24116 ++		if (cursor == NULL)
143.24117 ++			cursor = sna_crtc->cursor;
143.24118 ++		if (cursor == NULL) {
143.24119 ++			__DBG(("%s: failed to grab cursor, disabling\n", __FUNCTION__));
143.24120 ++			goto disable;
143.24121 ++		}
143.24122 ++
143.24123 + 		if (crtc->transform_in_use) {
143.24124 + 			int xhot = sna->cursor.ref->bits->xhot;
143.24125 + 			int yhot = sna->cursor.ref->bits->yhot;
143.24126 +-			struct pict_f_vector v;
143.24127 ++			struct pict_f_vector v, hot;
143.24128 + 
143.24129 +-			v.v[0] = (x + xhot) + 0.5;
143.24130 +-			v.v[1] = (y + yhot) + 0.5;
143.24131 +-			v.v[2] = 1;
143.24132 ++			v.v[0] = x + xhot + .5;
143.24133 ++			v.v[1] = y + yhot + .5;
143.24134 ++			v.v[2] = 1.;
143.24135 + 			pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &v);
143.24136 + 
143.24137 +-			rotate_coord_back(crtc->rotation, sna->cursor.size, &xhot, &yhot);
143.24138 ++			hot.v[0] = xhot;
143.24139 ++			hot.v[1] = yhot;
143.24140 ++			hot.v[2] = 1.;
143.24141 ++			pixman_f_transform_point(&sna_crtc->fb_to_cursor, &hot);
143.24142 + 
143.24143 +-			/* cursor will have 0.5 added to it already so floor is sufficent */
143.24144 +-			arg.x = floor(v.v[0]) - xhot;
143.24145 +-			arg.y = floor(v.v[1]) - yhot;
143.24146 ++			arg.x = floor(v.v[0] - hot.v[0]);
143.24147 ++			arg.y = floor(v.v[1] - hot.v[1]);
143.24148 + 		} else {
143.24149 + 			arg.x = x - crtc->x;
143.24150 + 			arg.y = y - crtc->y;
143.24151 +@@ -4904,15 +6404,6 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
143.24152 + 
143.24153 + 		if (arg.x < crtc->mode.HDisplay && arg.x > -sna->cursor.size &&
143.24154 + 		    arg.y < crtc->mode.VDisplay && arg.y > -sna->cursor.size) {
143.24155 +-			cursor = __sna_get_cursor(sna, crtc);
143.24156 +-			if (cursor == NULL)
143.24157 +-				cursor = sna_crtc->cursor;
143.24158 +-			if (cursor == NULL) {
143.24159 +-				__DBG(("%s: failed to grab cursor, disabling\n",
143.24160 +-				       __FUNCTION__));
143.24161 +-				goto disable;
143.24162 +-			}
143.24163 +-
143.24164 + 			if (sna_crtc->cursor != cursor || sna_crtc->last_cursor_size != cursor->size) {
143.24165 + 				arg.flags |= DRM_MODE_CURSOR_BO;
143.24166 + 				arg.handle = cursor->handle;
143.24167 +@@ -4932,10 +6423,13 @@ disable:
143.24168 + 		}
143.24169 + 
143.24170 + 		__DBG(("%s: CRTC:%d (%d, %d), handle=%d, flags=%x (old cursor handle=%d), move? %d, update handle? %d\n",
143.24171 +-		       __FUNCTION__, sna_crtc->id, arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
143.24172 ++		       __FUNCTION__, __sna_crtc_id(sna_crtc), arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
143.24173 + 		       arg.flags & DRM_MODE_CURSOR_MOVE, arg.flags & DRM_MODE_CURSOR_BO));
143.24174 + 
143.24175 +-		if (arg.flags &&
143.24176 ++		if (arg.flags == 0)
143.24177 ++			continue;
143.24178 ++
143.24179 ++		if (!FAIL_CURSOR_IOCTL &&
143.24180 + 		    drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
143.24181 + 			if (arg.flags & DRM_MODE_CURSOR_BO) {
143.24182 + 				if (sna_crtc->cursor) {
143.24183 +@@ -4949,9 +6443,21 @@ disable:
143.24184 + 				} else
143.24185 + 					sna_crtc->last_cursor_size = 0;
143.24186 + 			}
143.24187 ++		} else {
143.24188 ++			ERR(("%s: failed to update cursor on CRTC:%d [pipe=%d], disabling hwcursor: errno=%d\n",
143.24189 ++			     __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc), errno));
143.24190 ++			/* XXX How to force switch back to SW cursor?
143.24191 ++			 * Right now we just want until the next cursor image
143.24192 ++			 * change, which is fairly frequent.
143.24193 ++			 */
143.24194 ++			sna->cursor.disable = true;
143.24195 + 		}
143.24196 + 	}
143.24197 + 	sigio_unblock(sigio);
143.24198 ++	kmsg_close(&kmsg, sna->cursor.disable);
143.24199 ++
143.24200 ++	if (unlikely(sna->cursor.disable))
143.24201 ++		restore_swcursor(sna);
143.24202 + }
143.24203 + 
143.24204 + #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
143.24205 +@@ -4978,17 +6484,6 @@ sna_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
143.24206 + {
143.24207 + }
143.24208 + 
143.24209 +-static int __cursor_size(CursorPtr cursor)
143.24210 +-{
143.24211 +-	int i, size;
143.24212 +-
143.24213 +-	i = MAX(cursor->bits->width, cursor->bits->height);
143.24214 +-	for (size = 64; size < i; size <<= 1)
143.24215 +-		;
143.24216 +-
143.24217 +-	return size;
143.24218 +-}
143.24219 +-
143.24220 + static bool
143.24221 + sna_cursor_preallocate(struct sna *sna)
143.24222 + {
143.24223 +@@ -5006,6 +6501,50 @@ sna_cursor_preallocate(struct sna *sna)
143.24224 + 	return true;
143.24225 + }
143.24226 + 
143.24227 ++static bool
143.24228 ++transformable_cursor(struct sna *sna, CursorPtr cursor)
143.24229 ++{
143.24230 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.24231 ++	int i;
143.24232 ++
143.24233 ++	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.24234 ++		xf86CrtcPtr crtc = config->crtc[i];
143.24235 ++		struct pixman_box16 box;
143.24236 ++		int size;
143.24237 ++
143.24238 ++		if (!to_sna_crtc(crtc)->hwcursor) {
143.24239 ++			DBG(("%s: hwcursor disabled on CRTC:%d [pipe=%d]\n",
143.24240 ++			     __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc)));
143.24241 ++			return false;
143.24242 ++		}
143.24243 ++
143.24244 ++		if (!sna->cursor.use_gtt || !sna->cursor.scratch) {
143.24245 ++			DBG(("%s: unable to use GTT curosor access [%d] or no scratch [%d]\n",
143.24246 ++			     __FUNCTION__, sna->cursor.use_gtt, sna->cursor.scratch));
143.24247 ++			return false;
143.24248 ++		}
143.24249 ++
143.24250 ++		box.x1 = box.y1 = 0;
143.24251 ++		box.x2 = cursor->bits->width;
143.24252 ++		box.y2 = cursor->bits->height;
143.24253 ++
143.24254 ++		if (!pixman_f_transform_bounds(&crtc->f_crtc_to_framebuffer,
143.24255 ++					       &box)) {
143.24256 ++			DBG(("%s: unable to transform bounds\n", __FUNCTION__));
143.24257 ++			return false;
143.24258 ++		}
143.24259 ++
143.24260 ++		size = __cursor_size(box.x2 - box.x1, box.y2 - box.y1);
143.24261 ++		if (size > sna->cursor.max_size) {
143.24262 ++			DBG(("%s: transformed cursor size=%d too large, max=%d\n",
143.24263 ++			     __FUNCTION__, size, sna->cursor.max_size));
143.24264 ++			return false;
143.24265 ++		}
143.24266 ++	}
143.24267 ++
143.24268 ++	return true;
143.24269 ++}
143.24270 ++
143.24271 + static Bool
143.24272 + sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
143.24273 + {
143.24274 +@@ -5014,6 +6553,9 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
143.24275 + 	DBG(("%s (%dx%d)?\n", __FUNCTION__,
143.24276 + 	     cursor->bits->width, cursor->bits->height));
143.24277 + 
143.24278 ++	if (sna->cursor.disable)
143.24279 ++		return FALSE;
143.24280 ++
143.24281 + 	/* cursors are invariant */
143.24282 + 	if (cursor == sna->cursor.ref)
143.24283 + 		return TRUE;
143.24284 +@@ -5023,12 +6565,24 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
143.24285 + 		sna->cursor.ref = NULL;
143.24286 + 	}
143.24287 + 
143.24288 +-	sna->cursor.size = __cursor_size(cursor);
143.24289 +-	if (sna->cursor.size > sna->cursor.max_size)
143.24290 ++	sna->cursor.size =
143.24291 ++		__cursor_size(cursor->bits->width, cursor->bits->height);
143.24292 ++	if (sna->cursor.size > sna->cursor.max_size) {
143.24293 ++		DBG(("%s: cursor size=%d too large, max %d: using sw cursor\n",
143.24294 ++		     __FUNCTION__, sna->cursor.size, sna->cursor.max_size));
143.24295 + 		return FALSE;
143.24296 ++	}
143.24297 ++
143.24298 ++	if (sna->mode.rr_active && !transformable_cursor(sna, cursor)) {
143.24299 ++		DBG(("%s: RandR active [%d] and non-transformable cursor: using sw cursor\n",
143.24300 ++		     __FUNCTION__, sna->mode.rr_active));
143.24301 ++		return FALSE;
143.24302 ++	}
143.24303 + 
143.24304 +-	if (!sna_cursor_preallocate(sna))
143.24305 ++	if (!sna_cursor_preallocate(sna)) {
143.24306 ++		DBG(("%s: cursor preallocation failed: using sw cursor\n", __FUNCTION__));
143.24307 + 		return FALSE;
143.24308 ++	}
143.24309 + 
143.24310 + 	sna->cursor.ref = cursor;
143.24311 + 	cursor->refcnt++;
143.24312 +@@ -5056,8 +6610,12 @@ sna_cursor_pre_init(struct sna *sna)
143.24313 + 		return;
143.24314 + 
143.24315 + #define LOCAL_IOCTL_GET_CAP	DRM_IOWR(0x0c, struct local_get_cap)
143.24316 +-#define DRM_CAP_CURSOR_WIDTH	8
143.24317 +-#define DRM_CAP_CURSOR_HEIGHT	9
143.24318 ++#ifndef DRM_CAP_CURSOR_WIDTH
143.24319 ++#define DRM_CAP_CURSOR_WIDTH	0x8
143.24320 ++#endif
143.24321 ++#ifndef DRM_CAP_CURSOR_HEIGHT
143.24322 ++#define DRM_CAP_CURSOR_HEIGHT	0x9
143.24323 ++#endif
143.24324 + 
143.24325 + #define I915_PARAM_HAS_COHERENT_PHYS_GTT 29
143.24326 + 
143.24327 +@@ -5087,11 +6645,9 @@ sna_cursor_pre_init(struct sna *sna)
143.24328 + 	DBG(("%s: cursor updates use_gtt?=%d\n",
143.24329 + 	     __FUNCTION__, sna->cursor.use_gtt));
143.24330 + 
143.24331 +-	if (!sna->cursor.use_gtt) {
143.24332 +-		sna->cursor.scratch = malloc(sna->cursor.max_size * sna->cursor.max_size * 4);
143.24333 +-		if (!sna->cursor.scratch)
143.24334 +-			sna->cursor.max_size = 0;
143.24335 +-	}
143.24336 ++	sna->cursor.scratch = malloc(sna->cursor.max_size * sna->cursor.max_size * 4);
143.24337 ++	if (!sna->cursor.scratch && !sna->cursor.use_gtt)
143.24338 ++		sna->cursor.max_size = 0;
143.24339 + 
143.24340 + 	sna->cursor.num_stash = -sna->mode.num_real_crtc;
143.24341 + 
143.24342 +@@ -5193,7 +6749,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
143.24343 + 	int output_count = 0;
143.24344 + 	int i;
143.24345 + 
143.24346 +-	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle));
143.24347 ++	DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), bo->handle));
143.24348 + 
143.24349 + 	assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
143.24350 + 	assert(crtc->bo);
143.24351 +@@ -5207,11 +6763,11 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
143.24352 + 
143.24353 + 		DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
143.24354 + 		     __FUNCTION__, output->name, i, to_connector_id(output),
143.24355 +-		     crtc->id, crtc->pipe,
143.24356 ++		     __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
143.24357 + 		     (uint32_t)output->possible_crtcs,
143.24358 + 		     (uint32_t)output->possible_clones));
143.24359 + 
143.24360 +-		assert(output->possible_crtcs & (1 << crtc->pipe) ||
143.24361 ++		assert(output->possible_crtcs & (1 << __sna_crtc_pipe(crtc)) ||
143.24362 + 		       is_zaphod(sna->scrn));
143.24363 + 
143.24364 + 		output_ids[output_count] = to_connector_id(output);
143.24365 +@@ -5221,7 +6777,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
143.24366 + 	assert(output_count);
143.24367 + 
143.24368 + 	VG_CLEAR(arg);
143.24369 +-	arg.crtc_id = crtc->id;
143.24370 ++	arg.crtc_id = __sna_crtc_id(crtc);
143.24371 + 	arg.fb_id = fb_id(bo);
143.24372 + 	assert(arg.fb_id);
143.24373 + 	arg.x = x;
143.24374 +@@ -5231,20 +6787,74 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
143.24375 + 	arg.mode = crtc->kmode;
143.24376 + 	arg.mode_valid = 1;
143.24377 + 
143.24378 +-	DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n",
143.24379 +-	     __FUNCTION__, crtc->id, crtc->pipe,
143.24380 +-	     arg.mode.hdisplay,
143.24381 +-	     arg.mode.vdisplay,
143.24382 +-	     arg.x, arg.y,
143.24383 +-	     arg.mode.clock,
143.24384 +-	     arg.fb_id,
143.24385 +-	     output_count, output_count ? output_ids[0] : 0));
143.24386 ++	DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n",
143.24387 ++	     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
143.24388 ++	     arg.mode.hdisplay,
143.24389 ++	     arg.mode.vdisplay,
143.24390 ++	     arg.x, arg.y,
143.24391 ++	     arg.mode.clock,
143.24392 ++	     arg.fb_id,
143.24393 ++	     output_count, output_count ? output_ids[0] : 0));
143.24394 ++
143.24395 ++	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
143.24396 ++		return false;
143.24397 ++
143.24398 ++	crtc->offset = y << 16 | x;
143.24399 ++	__kgem_bo_clear_dirty(bo);
143.24400 ++	return true;
143.24401 ++}
143.24402 ++
143.24403 ++static void sna_mode_restore(struct sna *sna)
143.24404 ++{
143.24405 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.24406 ++	int error = 0;
143.24407 ++	int i;
143.24408 ++
143.24409 ++	assert(!sna->mode.hidden);
143.24410 ++
143.24411 ++	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.24412 ++		xf86CrtcPtr crtc = config->crtc[i];
143.24413 ++
143.24414 ++		assert(to_sna_crtc(crtc) != NULL);
143.24415 ++		if (to_sna_crtc(crtc)->bo == NULL)
143.24416 ++			continue;
143.24417 ++
143.24418 ++		assert(crtc->enabled);
143.24419 ++		if (!__sna_crtc_set_mode(crtc)) {
143.24420 ++			sna_crtc_disable(crtc, false);
143.24421 ++			error++;
143.24422 ++		}
143.24423 ++	}
143.24424 ++	sna_mode_wakeup(sna);
143.24425 ++	while (sna->mode.flip_active && sna_mode_wakeup(sna))
143.24426 ++		;
143.24427 ++	update_flush_interval(sna);
143.24428 ++	sna_cursors_reload(sna);
143.24429 ++	sna->mode.dirty = false;
143.24430 ++
143.24431 ++	if (error)
143.24432 ++		xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.24433 ++			   "Failed to restore display configuration\n");
143.24434 ++}
143.24435 ++
143.24436 ++bool sna_needs_page_flip(struct sna *sna, struct kgem_bo *bo)
143.24437 ++{
143.24438 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.24439 ++	int i;
143.24440 ++
143.24441 ++	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.24442 ++		struct sna_crtc *crtc = config->crtc[i]->driver_private;
143.24443 ++
143.24444 ++		if (crtc->bo == NULL)
143.24445 ++			continue;
143.24446 + 
143.24447 +-	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
143.24448 +-		return false;
143.24449 ++		if (crtc->bo == bo)
143.24450 ++			continue;
143.24451 + 
143.24452 +-	crtc->offset = y << 16 | x;
143.24453 +-	return true;
143.24454 ++		return true;
143.24455 ++	}
143.24456 ++
143.24457 ++	return false;
143.24458 + }
143.24459 + 
143.24460 + int
143.24461 +@@ -5256,6 +6866,7 @@ sna_page_flip(struct sna *sna,
143.24462 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.24463 + 	const int width = sna->scrn->virtualX;
143.24464 + 	const int height = sna->scrn->virtualY;
143.24465 ++	int sigio;
143.24466 + 	int count = 0;
143.24467 + 	int i;
143.24468 + 
143.24469 +@@ -5263,23 +6874,26 @@ sna_page_flip(struct sna *sna,
143.24470 + 	assert(bo->refcnt);
143.24471 + 
143.24472 + 	assert((sna->flags & SNA_IS_HOSTED) == 0);
143.24473 +-	assert((sna->flags & SNA_TEAR_FREE) == 0);
143.24474 + 	assert(sna->mode.flip_active == 0);
143.24475 + 	assert(sna->mode.front_active);
143.24476 ++	assert(!sna->mode.hidden);
143.24477 + 	assert(sna->scrn->vtSema);
143.24478 + 
143.24479 + 	if ((sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) == 0)
143.24480 + 		return 0;
143.24481 + 
143.24482 + 	kgem_bo_submit(&sna->kgem, bo);
143.24483 ++	__kgem_bo_clear_dirty(bo);
143.24484 + 
143.24485 ++	sigio = sigio_block();
143.24486 + 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.24487 + 		struct sna_crtc *crtc = config->crtc[i]->driver_private;
143.24488 + 		struct drm_mode_crtc_page_flip arg;
143.24489 + 		uint32_t crtc_offset;
143.24490 ++		int fixup;
143.24491 + 
143.24492 + 		DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n",
143.24493 +-		     __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL));
143.24494 ++		     __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo != NULL));
143.24495 + 		if (crtc->bo == NULL)
143.24496 + 			continue;
143.24497 + 		assert(!crtc->transform);
143.24498 +@@ -5288,13 +6902,18 @@ sna_page_flip(struct sna *sna,
143.24499 + 		assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
143.24500 + 		assert(crtc->flip_bo == NULL);
143.24501 + 
143.24502 +-		arg.crtc_id = crtc->id;
143.24503 ++		assert_crtc_fb(sna, crtc);
143.24504 ++		if (data == NULL && crtc->bo == bo)
143.24505 ++			goto next_crtc;
143.24506 ++
143.24507 ++		arg.crtc_id = __sna_crtc_id(crtc);
143.24508 + 		arg.fb_id = get_fb(sna, bo, width, height);
143.24509 + 		if (arg.fb_id == 0) {
143.24510 + 			assert(count == 0);
143.24511 +-			return 0;
143.24512 ++			break;
143.24513 + 		}
143.24514 + 
143.24515 ++		fixup = 0;
143.24516 + 		crtc_offset = crtc->base->y << 16 | crtc->base->x;
143.24517 + 
143.24518 + 		if (bo->pitch != crtc->bo->pitch || crtc_offset != crtc->offset) {
143.24519 +@@ -5303,7 +6922,12 @@ sna_page_flip(struct sna *sna,
143.24520 + 			     bo->pitch, crtc->bo->pitch,
143.24521 + 			     crtc_offset, crtc->offset));
143.24522 + fixup_flip:
143.24523 ++			fixup = 1;
143.24524 + 			if (crtc->bo != bo && sna_crtc_flip(sna, crtc, bo, crtc->base->x, crtc->base->y)) {
143.24525 ++update_scanout:
143.24526 ++				DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
143.24527 ++				     __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout,
143.24528 ++				     bo->handle, bo->active_scanout));
143.24529 + 				assert(crtc->bo->active_scanout);
143.24530 + 				assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
143.24531 + 				crtc->bo->active_scanout--;
143.24532 +@@ -5321,15 +6945,8 @@ fixup_flip:
143.24533 + 					goto next_crtc;
143.24534 + 
143.24535 + 				/* queue a flip in order to send the event */
143.24536 +-			} else {
143.24537 +-				if (count && !xf86SetDesiredModes(sna->scrn)) {
143.24538 +-					xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.24539 +-						   "failed to restore display configuration\n");
143.24540 +-					for (; i < sna->mode.num_real_crtc; i++)
143.24541 +-						sna_crtc_disable(config->crtc[i]);
143.24542 +-				}
143.24543 +-				return 0;
143.24544 +-			}
143.24545 ++			} else
143.24546 ++				goto error;
143.24547 + 		}
143.24548 + 
143.24549 + 		/* Only the reference crtc will finally deliver its page flip
143.24550 +@@ -5346,7 +6963,7 @@ fixup_flip:
143.24551 + 
143.24552 + retry_flip:
143.24553 + 		DBG(("%s: crtc %d id=%d, pipe=%d  --> fb %d\n",
143.24554 +-		     __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id));
143.24555 ++		     __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), arg.fb_id));
143.24556 + 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
143.24557 + 			ERR(("%s: pageflip failed with err=%d\n", __FUNCTION__, errno));
143.24558 + 
143.24559 +@@ -5354,7 +6971,7 @@ retry_flip:
143.24560 + 				struct drm_mode_crtc mode;
143.24561 + 
143.24562 + 				memset(&mode, 0, sizeof(mode));
143.24563 +-				mode.crtc_id = crtc->id;
143.24564 ++				mode.crtc_id = __sna_crtc_id(crtc);
143.24565 + 				drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
143.24566 + 
143.24567 + 				DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n",
143.24568 +@@ -5366,7 +6983,7 @@ retry_flip:
143.24569 + 					goto fixup_flip;
143.24570 + 
143.24571 + 				if (count == 0)
143.24572 +-					return 0;
143.24573 ++					break;
143.24574 + 
143.24575 + 				DBG(("%s: throttling on busy flip / waiting for kernel to catch up\n", __FUNCTION__));
143.24576 + 				drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_THROTTLE, 0);
143.24577 +@@ -5375,15 +6992,25 @@ retry_flip:
143.24578 + 				goto retry_flip;
143.24579 + 			}
143.24580 + 
143.24581 ++			if (!fixup)
143.24582 ++				goto fixup_flip;
143.24583 ++
143.24584 ++error:
143.24585 + 			xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.24586 +-				   "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
143.24587 +-				   crtc->id, crtc->pipe, data ? "synchronous": "asynchronous");
143.24588 ++					"page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
143.24589 ++					__sna_crtc_id(crtc), __sna_crtc_pipe(crtc), data ? "synchronous": "asynchronous");
143.24590 ++
143.24591 ++			if (count || crtc->bo == bo)
143.24592 ++				sna_mode_restore(sna);
143.24593 ++
143.24594 + 			sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP);
143.24595 +-			goto fixup_flip;
143.24596 ++			count = 0;
143.24597 ++			break;
143.24598 + 		}
143.24599 + 
143.24600 + 		if (data) {
143.24601 + 			assert(crtc->flip_bo == NULL);
143.24602 ++			assert(handler);
143.24603 + 			crtc->flip_handler = handler;
143.24604 + 			crtc->flip_data = data;
143.24605 + 			crtc->flip_bo = kgem_bo_reference(bo);
143.24606 +@@ -5391,11 +7018,15 @@ retry_flip:
143.24607 + 			crtc->flip_serial = crtc->mode_serial;
143.24608 + 			crtc->flip_pending = true;
143.24609 + 			sna->mode.flip_active++;
143.24610 +-		}
143.24611 + 
143.24612 ++			DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
143.24613 ++			     __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
143.24614 ++		} else
143.24615 ++			goto update_scanout;
143.24616 + next_crtc:
143.24617 + 		count++;
143.24618 + 	}
143.24619 ++	sigio_unblock(sigio);
143.24620 + 
143.24621 + 	DBG(("%s: page flipped %d crtcs\n", __FUNCTION__, count));
143.24622 + 	return count;
143.24623 +@@ -5471,7 +7102,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
143.24624 + 
143.24625 + 		assert(sna_crtc);
143.24626 + 
143.24627 +-		lut.crtc_id = sna_crtc->id;
143.24628 ++		lut.crtc_id = __sna_crtc_id(sna_crtc);
143.24629 + 		lut.gamma_size = 256;
143.24630 + 		lut.red = (uintptr_t)(gamma);
143.24631 + 		lut.green = (uintptr_t)(gamma + 256);
143.24632 +@@ -5485,7 +7116,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
143.24633 + 		}
143.24634 + 
143.24635 + 		DBG(("%s: CRTC:%d, pipe=%d: gamma set?=%d\n",
143.24636 +-		     __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
143.24637 ++		     __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
143.24638 + 		     gamma_set));
143.24639 + 		if (!gamma_set) {
143.24640 + 			int i;
143.24641 +@@ -5502,6 +7133,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
143.24642 + 			crtc->gamma_red = gamma;
143.24643 + 			crtc->gamma_green = gamma + 256;
143.24644 + 			crtc->gamma_blue = gamma + 2*256;
143.24645 ++			crtc->gamma_size = 256;
143.24646 + 		}
143.24647 + 	}
143.24648 + }
143.24649 +@@ -5528,6 +7160,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24650 + {
143.24651 + 	ScrnInfoPtr scrn = sna->scrn;
143.24652 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
143.24653 ++	int crtc_active, crtc_enabled;
143.24654 + 	int width, height;
143.24655 + 	int i, j;
143.24656 + 
143.24657 +@@ -5565,6 +7198,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24658 + 	}
143.24659 + 
143.24660 + 	/* Copy the existing modes on each CRTCs */
143.24661 ++	crtc_active = crtc_enabled = 0;
143.24662 + 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.24663 + 		xf86CrtcPtr crtc = config->crtc[i];
143.24664 + 		struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.24665 +@@ -5577,12 +7211,12 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24666 + 
143.24667 + 		/* Retrieve the current mode */
143.24668 + 		VG_CLEAR(mode);
143.24669 +-		mode.crtc_id = sna_crtc->id;
143.24670 ++		mode.crtc_id = __sna_crtc_id(sna_crtc);
143.24671 + 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
143.24672 + 			continue;
143.24673 + 
143.24674 + 		DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
143.24675 +-		     sna_crtc->id, sna_crtc->pipe,
143.24676 ++		     __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
143.24677 + 		     mode.mode_valid && mode.mode.clock));
143.24678 + 
143.24679 + 		if (!mode.mode_valid || mode.mode.clock == 0)
143.24680 +@@ -5593,6 +7227,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24681 + 		crtc->desiredX = mode.x;
143.24682 + 		crtc->desiredY = mode.y;
143.24683 + 		crtc->desiredTransformPresent = FALSE;
143.24684 ++		crtc_active++;
143.24685 + 	}
143.24686 + 
143.24687 + 	/* Reconstruct outputs pointing to active CRTC */
143.24688 +@@ -5604,6 +7239,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24689 + 
143.24690 + 		crtc_id = (uintptr_t)output->crtc;
143.24691 + 		output->crtc = NULL;
143.24692 ++		output->status = XF86OutputStatusUnknown;
143.24693 + 		if (sna->flags & SNA_IS_SLAVED)
143.24694 + 			continue;
143.24695 + 
143.24696 +@@ -5623,7 +7259,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24697 + 			xf86CrtcPtr crtc = config->crtc[j];
143.24698 + 
143.24699 + 			assert(to_sna_crtc(crtc));
143.24700 +-			if (to_sna_crtc(crtc)->id != crtc_id)
143.24701 ++			if (sna_crtc_id(crtc) != crtc_id)
143.24702 + 				continue;
143.24703 + 
143.24704 + 			if (crtc->desiredMode.status == MODE_OK) {
143.24705 +@@ -5641,18 +7277,30 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24706 + 					   "Output %s using initial mode %s on pipe %d\n",
143.24707 + 					   output->name,
143.24708 + 					   crtc->desiredMode.name,
143.24709 +-					   to_sna_crtc(crtc)->pipe);
143.24710 ++					   sna_crtc_pipe(crtc));
143.24711 + 
143.24712 + 				output->crtc = crtc;
143.24713 ++				output->status = XF86OutputStatusConnected;
143.24714 + 				crtc->enabled = TRUE;
143.24715 ++				crtc_enabled++;
143.24716 ++
143.24717 ++				output_set_gamma(output, crtc);
143.24718 ++
143.24719 ++				if (output->conf_monitor) {
143.24720 ++					output->mm_width = output->conf_monitor->mon_width;
143.24721 ++					output->mm_height = output->conf_monitor->mon_height;
143.24722 ++				}
143.24723 ++
143.24724 ++#if 0
143.24725 ++				sna_output_attach_edid(output);
143.24726 ++				sna_output_attach_tile(output);
143.24727 ++#endif
143.24728 + 
143.24729 + 				if (output->mm_width == 0 || output->mm_height == 0) {
143.24730 + 					output->mm_height = (crtc->desiredMode.VDisplay * 254) / (10*DEFAULT_DPI);
143.24731 + 					output->mm_width = (crtc->desiredMode.HDisplay * 254) / (10*DEFAULT_DPI);
143.24732 + 				}
143.24733 + 
143.24734 +-				output_set_gamma(output, crtc);
143.24735 +-
143.24736 + 				M = calloc(1, sizeof(DisplayModeRec));
143.24737 + 				if (M) {
143.24738 + 					*M = crtc->desiredMode;
143.24739 +@@ -5673,6 +7321,12 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24740 + 		}
143.24741 + 	}
143.24742 + 
143.24743 ++	if (crtc_active != crtc_enabled) {
143.24744 ++		DBG(("%s: only enabled %d out of %d active CRTC, forcing a reconfigure\n",
143.24745 ++		     __FUNCTION__, crtc_enabled, crtc_active));
143.24746 ++		return false;
143.24747 ++	}
143.24748 ++
143.24749 + 	width = height = 0;
143.24750 + 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.24751 + 		xf86CrtcPtr crtc = config->crtc[i];
143.24752 +@@ -5707,8 +7361,8 @@ static bool sna_probe_initial_configuration(struct sna *sna)
143.24753 + 			if (sna_output->num_modes == 0)
143.24754 + 				continue;
143.24755 + 
143.24756 +-			width = sna_output->modes[0].hdisplay;
143.24757 +-			height= sna_output->modes[0].vdisplay;
143.24758 ++			width  = sna_output->modes[0].hdisplay;
143.24759 ++			height = sna_output->modes[0].vdisplay;
143.24760 + 
143.24761 + 			DBG(("%s: panel '%s' is %dx%d\n",
143.24762 + 			     __FUNCTION__, output->name, width, height));
143.24763 +@@ -5788,7 +7442,7 @@ probe_capabilities(struct sna *sna)
143.24764 + 	sna->flags &= ~(SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP);
143.24765 + 	if (has_flip(sna))
143.24766 + 		sna->flags |= SNA_HAS_FLIP;
143.24767 +-	if (has_flip__async(sna))
143.24768 ++	if (has_flip__async(sna) && (sna->flags & SNA_TEAR_FREE) == 0)
143.24769 + 		sna->flags |= SNA_HAS_ASYNC_FLIP;
143.24770 + 	DBG(("%s: page flips? %s, async? %s\n", __FUNCTION__,
143.24771 + 	     sna->flags & SNA_HAS_FLIP ? "enabled" : "disabled",
143.24772 +@@ -5813,12 +7467,25 @@ sna_crtc_config_notify(ScreenPtr screen)
143.24773 + 		return;
143.24774 + 	}
143.24775 + 
143.24776 ++	/* Flush any events completed by the modeset */
143.24777 ++	sna_mode_wakeup(sna);
143.24778 ++
143.24779 + 	update_flush_interval(sna);
143.24780 ++	sna->cursor.disable = false; /* Reset HW cursor until the next fail */
143.24781 + 	sna_cursors_reload(sna);
143.24782 + 
143.24783 + 	probe_capabilities(sna);
143.24784 + 	sna_present_update(sna);
143.24785 + 
143.24786 ++	/* Allow TearFree to come back on when everything is off */
143.24787 ++	if (!sna->mode.front_active && sna->flags & SNA_WANT_TEAR_FREE) {
143.24788 ++		if ((sna->flags & SNA_TEAR_FREE) == 0)
143.24789 ++			DBG(("%s: enable TearFree next modeset\n",
143.24790 ++			     __FUNCTION__));
143.24791 ++
143.24792 ++		sna->flags |= SNA_TEAR_FREE;
143.24793 ++	}
143.24794 ++
143.24795 + 	sna->mode.dirty = false;
143.24796 + }
143.24797 + 
143.24798 +@@ -5840,6 +7507,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
143.24799 + 	}
143.24800 + 
143.24801 + 	probe_capabilities(sna);
143.24802 ++	sna->mode.hidden = 1;
143.24803 + 
143.24804 + 	if (!xf86GetOptValInteger(sna->Options, OPTION_VIRTUAL, &num_fake))
143.24805 + 		num_fake = 1;
143.24806 +@@ -5855,6 +7523,9 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
143.24807 + 	if (res) {
143.24808 + 		xf86CrtcConfigPtr xf86_config;
143.24809 + 
143.24810 ++		DBG(("%s: found %d CRTC, %d encoders, %d connectors\n",
143.24811 ++		     __FUNCTION__, res->count_crtcs, res->count_encoders, res->count_connectors));
143.24812 ++
143.24813 + 		assert(res->count_crtcs);
143.24814 + 		assert(res->count_connectors);
143.24815 + 
143.24816 +@@ -5862,6 +7533,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
143.24817 + 
143.24818 + 		xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
143.24819 + 		xf86_config->xf86_crtc_notify = sna_crtc_config_notify;
143.24820 ++		xf86_config->compat_output = 0;
143.24821 + 
143.24822 + 		for (i = 0; i < res->count_crtcs; i++)
143.24823 + 			if (!sna_crtc_add(scrn, res->crtcs[i]))
143.24824 +@@ -5900,6 +7572,11 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
143.24825 + 	if (!sna_mode_fake_init(sna, num_fake))
143.24826 + 		return false;
143.24827 + 
143.24828 ++	sna->mode.shadow_size = 256;
143.24829 ++	sna->mode.shadow_events = malloc(sna->mode.shadow_size * sizeof(struct drm_event_vblank));
143.24830 ++	if (!sna->mode.shadow_events)
143.24831 ++		return false;
143.24832 ++
143.24833 + 	if (!sna_probe_initial_configuration(sna)) {
143.24834 + 		xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
143.24835 + 
143.24836 +@@ -5912,6 +7589,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
143.24837 + 		}
143.24838 + 	}
143.24839 + 	sort_config_outputs(sna);
143.24840 ++	TimerSet(NULL, 0, COLDPLUG_DELAY_MS, sna_mode_coldplug, sna);
143.24841 + 
143.24842 + 	sna_setup_provider(scrn);
143.24843 + 	return scrn->modes != NULL;
143.24844 +@@ -5921,18 +7599,58 @@ bool
143.24845 + sna_mode_wants_tear_free(struct sna *sna)
143.24846 + {
143.24847 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.24848 ++	bool found = false;
143.24849 ++	FILE *file;
143.24850 + 	int i;
143.24851 + 
143.24852 ++	file = fopen("/sys/module/i915/parameters/enable_fbc", "r");
143.24853 ++	if (file) {
143.24854 ++		int fbc_enabled = 0;
143.24855 ++		int value;
143.24856 ++
143.24857 ++		if (fscanf(file, "%d", &value) == 1)
143.24858 ++			fbc_enabled = value > 0;
143.24859 ++		fclose(file);
143.24860 ++
143.24861 ++		DBG(("%s: module parameter 'enable_fbc' enabled? %d\n",
143.24862 ++		     __FUNCTION__, fbc_enabled));
143.24863 ++
143.24864 ++		if (fbc_enabled)
143.24865 ++			return true;
143.24866 ++	}
143.24867 ++
143.24868 + 	for (i = 0; i < sna->mode.num_real_output; i++) {
143.24869 + 		struct sna_output *output = to_sna_output(config->output[i]);
143.24870 + 		int id = find_property(sna, output, "Panel Self-Refresh");
143.24871 +-		if (id !=-1 && output->prop_values[id] != -1) {
143.24872 ++		if (id == -1)
143.24873 ++			continue;
143.24874 ++
143.24875 ++		found = true;
143.24876 ++		if (output->prop_values[id] != -1) {
143.24877 + 			DBG(("%s: Panel Self-Refresh detected on %s\n",
143.24878 + 			     __FUNCTION__, config->output[i]->name));
143.24879 + 			return true;
143.24880 + 		}
143.24881 + 	}
143.24882 + 
143.24883 ++	if (!found) {
143.24884 ++		file = fopen("/sys/module/i915/parameters/enable_psr", "r");
143.24885 ++		if (file) {
143.24886 ++			int psr_enabled = 0;
143.24887 ++			int value;
143.24888 ++
143.24889 ++			if (fscanf(file, "%d", &value) == 1)
143.24890 ++				psr_enabled = value > 0;
143.24891 ++			fclose(file);
143.24892 ++
143.24893 ++			DBG(("%s: module parameter 'enable_psr' enabled? %d\n",
143.24894 ++			     __FUNCTION__, psr_enabled));
143.24895 ++
143.24896 ++			if (psr_enabled)
143.24897 ++				return true;
143.24898 ++		}
143.24899 ++	}
143.24900 ++
143.24901 + 	return false;
143.24902 + }
143.24903 + 
143.24904 +@@ -5955,7 +7673,7 @@ sna_mode_set_primary(struct sna *sna)
143.24905 + 
143.24906 + 		DBG(("%s: setting PrimaryOutput %s\n", __FUNCTION__, output->name));
143.24907 + 		rr->primaryOutput = output->randr_output;
143.24908 +-		RROutputChanged(rr->primaryOutput, 0);
143.24909 ++		RROutputChanged(rr->primaryOutput, FALSE);
143.24910 + 		rr->layoutChanged = TRUE;
143.24911 + 		break;
143.24912 + 	}
143.24913 +@@ -5974,12 +7692,9 @@ sna_mode_disable(struct sna *sna)
143.24914 + 	if (!sna->scrn->vtSema)
143.24915 + 		return false;
143.24916 + 
143.24917 +-	/* XXX we will cause previously hidden cursors to be reshown, but
143.24918 +-	 * this should be a rare fixup case for severe fragmentation.
143.24919 +-	 */
143.24920 +-	sna_hide_cursors(sna->scrn);
143.24921 ++	sna_disable_cursors(sna->scrn);
143.24922 + 	for (i = 0; i < sna->mode.num_real_crtc; i++)
143.24923 +-		sna_crtc_disable(config->crtc[i]);
143.24924 ++		sna_crtc_disable(config->crtc[i], false);
143.24925 + 	assert(sna->mode.front_active == 0);
143.24926 + 
143.24927 + 	sna_mode_wakeup(sna);
143.24928 +@@ -6001,6 +7716,11 @@ sna_mode_enable(struct sna *sna)
143.24929 + 	if (!sna->scrn->vtSema)
143.24930 + 		return;
143.24931 + 
143.24932 ++	if (sna->mode.hidden) {
143.24933 ++		DBG(("%s: hidden outputs\n", __FUNCTION__));
143.24934 ++		return;
143.24935 ++	}
143.24936 ++
143.24937 + 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.24938 + 		xf86CrtcPtr crtc = config->crtc[i];
143.24939 + 
143.24940 +@@ -6016,13 +7736,30 @@ sna_mode_enable(struct sna *sna)
143.24941 + 	}
143.24942 + 
143.24943 + 	update_flush_interval(sna);
143.24944 +-	sna_show_cursors(sna->scrn);
143.24945 ++	sna_cursors_reload(sna);
143.24946 + 	sna->mode.dirty = false;
143.24947 + }
143.24948 + 
143.24949 ++static void sna_randr_close(struct sna *sna)
143.24950 ++{
143.24951 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.24952 ++	int n;
143.24953 ++
143.24954 ++	/* The RR structs are freed early during CloseScreen as they
143.24955 ++	 * are tracked as Resources. However, we may be tempted to
143.24956 ++	 * access them during shutdown so decouple them now.
143.24957 ++	 */
143.24958 ++	  for (n = 0; n < config->num_output; n++)
143.24959 ++		  config->output[n]->randr_output = NULL;
143.24960 ++
143.24961 ++	  for (n = 0; n < config->num_crtc; n++)
143.24962 ++		  config->crtc[n]->randr_crtc = NULL;
143.24963 ++}
143.24964 ++
143.24965 + void
143.24966 + sna_mode_close(struct sna *sna)
143.24967 + {
143.24968 ++	sna_randr_close(sna);
143.24969 + 	sna_mode_wakeup(sna);
143.24970 + 
143.24971 + 	if (sna->flags & SNA_IS_HOSTED)
143.24972 +@@ -6077,15 +7814,22 @@ xf86CrtcPtr
143.24973 + sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
143.24974 + {
143.24975 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.24976 +-	xf86CrtcPtr best_crtc;
143.24977 +-	int best_coverage, c;
143.24978 ++	xf86CrtcPtr best_crtc = NULL;
143.24979 ++	int best_coverage = -1, c;
143.24980 + 
143.24981 + 	if (sna->flags & SNA_IS_HOSTED)
143.24982 + 		return NULL;
143.24983 + 
143.24984 + 	/* If we do not own the VT, we do not own the CRTC either */
143.24985 +-	if (!sna->scrn->vtSema)
143.24986 ++	if (!sna->scrn->vtSema) {
143.24987 ++		DBG(("%s: none, VT switched\n", __FUNCTION__));
143.24988 ++		return NULL;
143.24989 ++	}
143.24990 ++
143.24991 ++	if (sna->mode.hidden) {
143.24992 ++		DBG(("%s: none, hidden outputs\n", __FUNCTION__));
143.24993 + 		return NULL;
143.24994 ++	}
143.24995 + 
143.24996 + 	DBG(("%s for box=(%d, %d), (%d, %d)\n",
143.24997 + 	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
143.24998 +@@ -6107,10 +7851,10 @@ sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
143.24999 + 			     cover_box.x2, cover_box.y2));
143.25000 + 			return desired;
143.25001 + 		}
143.25002 ++		best_crtc = desired;
143.25003 ++		best_coverage = 0;
143.25004 + 	}
143.25005 + 
143.25006 +-	best_crtc = NULL;
143.25007 +-	best_coverage = 0;
143.25008 + 	for (c = 0; c < sna->mode.num_real_crtc; c++) {
143.25009 + 		xf86CrtcPtr crtc = config->crtc[c];
143.25010 + 		BoxRec cover_box;
143.25011 +@@ -6156,6 +7900,38 @@ sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
143.25012 + 	return best_crtc;
143.25013 + }
143.25014 + 
143.25015 ++static xf86CrtcPtr first_active_crtc(struct sna *sna)
143.25016 ++{
143.25017 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.25018 ++	int n;
143.25019 ++
143.25020 ++	for (n = 0; n < sna->mode.num_real_crtc; n++) {
143.25021 ++		xf86CrtcPtr crtc = config->crtc[n];
143.25022 ++		if (to_sna_crtc(crtc)->bo)
143.25023 ++			return crtc;
143.25024 ++	}
143.25025 ++
143.25026 ++	/* No active, use the first as a placeholder */
143.25027 ++	if (sna->mode.num_real_crtc)
143.25028 ++		return config->crtc[0];
143.25029 ++
143.25030 ++	return NULL;
143.25031 ++}
143.25032 ++
143.25033 ++xf86CrtcPtr sna_primary_crtc(struct sna *sna)
143.25034 ++{
143.25035 ++	rrScrPrivPtr rr = rrGetScrPriv(xf86ScrnToScreen(sna->scrn));
143.25036 ++	if (rr && rr->primaryOutput) {
143.25037 ++		xf86OutputPtr output = rr->primaryOutput->devPrivate;
143.25038 ++		if (output->crtc &&
143.25039 ++		    output->scrn == sna->scrn &&
143.25040 ++		    to_sna_crtc(output->crtc))
143.25041 ++			return output->crtc;
143.25042 ++	}
143.25043 ++
143.25044 ++	return first_active_crtc(sna);
143.25045 ++}
143.25046 ++
143.25047 + #define MI_LOAD_REGISTER_IMM			(0x22<<23)
143.25048 + 
143.25049 + static bool sna_emit_wait_for_scanline_hsw(struct sna *sna,
143.25050 +@@ -6433,7 +8209,7 @@ sna_wait_for_scanline(struct sna *sna,
143.25051 + 		y2 /= 2;
143.25052 + 	}
143.25053 + 
143.25054 +-	pipe = sna_crtc_to_pipe(crtc);
143.25055 ++	pipe = sna_crtc_pipe(crtc);
143.25056 + 	DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n",
143.25057 + 	     __FUNCTION__, pipe, y1, y2, full_height));
143.25058 + 
143.25059 +@@ -6457,19 +8233,101 @@ sna_wait_for_scanline(struct sna *sna,
143.25060 + 	return ret;
143.25061 + }
143.25062 + 
143.25063 ++static bool sna_mode_shutdown_crtc(xf86CrtcPtr crtc)
143.25064 ++{
143.25065 ++	struct sna *sna = to_sna(crtc->scrn);
143.25066 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
143.25067 ++	bool disabled = false;
143.25068 ++	int o;
143.25069 ++
143.25070 ++	xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
143.25071 ++		   "%s: invalid state found on pipe %d, disabling CRTC:%d\n",
143.25072 ++		   __FUNCTION__,
143.25073 ++		   __sna_crtc_pipe(to_sna_crtc(crtc)),
143.25074 ++		   __sna_crtc_id(to_sna_crtc(crtc)));
143.25075 ++	sna_crtc_disable(crtc, true);
143.25076 ++#if XF86_CRTC_VERSION >= 3
143.25077 ++	crtc->active = FALSE;
143.25078 ++#endif
143.25079 ++	if (crtc->enabled) {
143.25080 ++		crtc->enabled = FALSE;
143.25081 ++		disabled = true;
143.25082 ++	}
143.25083 ++
143.25084 ++	for (o = 0; o < sna->mode.num_real_output; o++) {
143.25085 ++		xf86OutputPtr output = config->output[o];
143.25086 ++
143.25087 ++		if (output->crtc != crtc)
143.25088 ++			continue;
143.25089 ++
143.25090 ++		output->funcs->dpms(output, DPMSModeOff);
143.25091 ++		output->crtc = NULL;
143.25092 ++	}
143.25093 ++
143.25094 ++	return disabled;
143.25095 ++}
143.25096 ++
143.25097 ++static bool
143.25098 ++sna_mode_disable_secondary_planes(struct sna *sna)
143.25099 ++{
143.25100 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.25101 ++	bool disabled = false;
143.25102 ++	int c;
143.25103 ++
143.25104 ++	/* Disable all secondary planes on our CRTCs, just in case
143.25105 ++	 * other userspace left garbage in them.
143.25106 ++	 */
143.25107 ++	for (c = 0; c < sna->mode.num_real_crtc; c++) {
143.25108 ++		xf86CrtcPtr crtc = config->crtc[c];
143.25109 ++		struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.25110 ++		struct plane *plane;
143.25111 ++
143.25112 ++		list_for_each_entry(plane, &sna_crtc->sprites, link) {
143.25113 ++			struct local_mode_get_plane p;
143.25114 ++			struct local_mode_set_plane s;
143.25115 ++
143.25116 ++			VG_CLEAR(p);
143.25117 ++			p.plane_id = plane->id;
143.25118 ++			p.count_format_types = 0;
143.25119 ++			if (drmIoctl(sna->kgem.fd,
143.25120 ++				     LOCAL_IOCTL_MODE_GETPLANE,
143.25121 ++				     &p))
143.25122 ++				continue;
143.25123 ++
143.25124 ++			if (p.fb_id == 0 || p.crtc_id == 0)
143.25125 ++				continue;
143.25126 ++
143.25127 ++			memset(&s, 0, sizeof(s));
143.25128 ++			s.plane_id = p.plane_id;
143.25129 ++			s.crtc_id = p.crtc_id;
143.25130 ++			if (drmIoctl(sna->kgem.fd,
143.25131 ++				     LOCAL_IOCTL_MODE_SETPLANE,
143.25132 ++				     &s))
143.25133 ++				disabled |= sna_mode_shutdown_crtc(crtc);
143.25134 ++		}
143.25135 ++	}
143.25136 ++
143.25137 ++	return disabled;
143.25138 ++}
143.25139 ++
143.25140 + void sna_mode_check(struct sna *sna)
143.25141 + {
143.25142 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.25143 +-	int i;
143.25144 ++	bool disabled;
143.25145 ++	int c, o;
143.25146 + 
143.25147 + 	if (sna->flags & SNA_IS_HOSTED)
143.25148 + 		return;
143.25149 + 
143.25150 +-	DBG(("%s\n", __FUNCTION__));
143.25151 ++	DBG(("%s: hidden?=%d\n", __FUNCTION__, sna->mode.hidden));
143.25152 ++	if (sna->mode.hidden)
143.25153 ++		return;
143.25154 ++
143.25155 ++	disabled = sna_mode_disable_secondary_planes(sna);
143.25156 + 
143.25157 + 	/* Validate CRTC attachments and force consistency upon the kernel */
143.25158 +-	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.25159 +-		xf86CrtcPtr crtc = config->crtc[i];
143.25160 ++	for (c = 0; c < sna->mode.num_real_crtc; c++) {
143.25161 ++		xf86CrtcPtr crtc = config->crtc[c];
143.25162 + 		struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.25163 + 		struct drm_mode_crtc mode;
143.25164 + 		uint32_t expected[2];
143.25165 +@@ -6483,7 +8341,7 @@ void sna_mode_check(struct sna *sna)
143.25166 + 		expected[1] = sna_crtc->flip_bo ? fb_id(sna_crtc->flip_bo) : -1;
143.25167 + 
143.25168 + 		VG_CLEAR(mode);
143.25169 +-		mode.crtc_id = sna_crtc->id;
143.25170 ++		mode.crtc_id = __sna_crtc_id(sna_crtc);
143.25171 + 		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
143.25172 + 			continue;
143.25173 + 
143.25174 +@@ -6492,16 +8350,12 @@ void sna_mode_check(struct sna *sna)
143.25175 + 		     mode.crtc_id, mode.mode_valid,
143.25176 + 		     mode.fb_id, expected[0], expected[1]));
143.25177 + 
143.25178 +-		if (mode.fb_id != expected[0] && mode.fb_id != expected[1]) {
143.25179 +-			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
143.25180 +-				   "%s: invalid state found on pipe %d, disabling CRTC:%d\n",
143.25181 +-				   __FUNCTION__, sna_crtc->pipe, sna_crtc->id);
143.25182 +-			sna_crtc_disable(crtc);
143.25183 +-		}
143.25184 ++		if (mode.fb_id != expected[0] && mode.fb_id != expected[1])
143.25185 ++			disabled |= sna_mode_shutdown_crtc(crtc);
143.25186 + 	}
143.25187 + 
143.25188 +-	for (i = 0; i < config->num_output; i++) {
143.25189 +-		xf86OutputPtr output = config->output[i];
143.25190 ++	for (o = 0; o < config->num_output; o++) {
143.25191 ++		xf86OutputPtr output = config->output[o];
143.25192 + 		struct sna_output *sna_output;
143.25193 + 
143.25194 + 		if (output->crtc)
143.25195 +@@ -6515,26 +8369,16 @@ void sna_mode_check(struct sna *sna)
143.25196 + 	}
143.25197 + 
143.25198 + 	update_flush_interval(sna);
143.25199 ++
143.25200 ++	if (disabled)
143.25201 ++		xf86RandR12TellChanged(xf86ScrnToScreen(sna->scrn));
143.25202 + }
143.25203 + 
143.25204 + static bool
143.25205 + sna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc)
143.25206 + {
143.25207 +-#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)
143.25208 +-	struct local_mode_set_plane {
143.25209 +-		uint32_t plane_id;
143.25210 +-		uint32_t crtc_id;
143.25211 +-		uint32_t fb_id; /* fb object contains surface format type */
143.25212 +-		uint32_t flags;
143.25213 +-
143.25214 +-		/* Signed dest location allows it to be partially off screen */
143.25215 +-		int32_t crtc_x, crtc_y;
143.25216 +-		uint32_t crtc_w, crtc_h;
143.25217 +-
143.25218 +-		/* Source values are 16.16 fixed point */
143.25219 +-		uint32_t src_x, src_y;
143.25220 +-		uint32_t src_h, src_w;
143.25221 +-	} s;
143.25222 ++	struct local_mode_set_plane s;
143.25223 ++	struct plane *plane;
143.25224 + 
143.25225 + 	if (crtc->primary.id == 0)
143.25226 + 		return false;
143.25227 +@@ -6544,8 +8388,10 @@ sna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc)
143.25228 + 	if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
143.25229 + 		return false;
143.25230 + 
143.25231 +-	s.plane_id = crtc->sprite.id;
143.25232 +-	(void)drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s);
143.25233 ++	list_for_each_entry(plane, &crtc->sprites, link) {
143.25234 ++		s.plane_id = plane->id;
143.25235 ++		(void)drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s);
143.25236 ++	}
143.25237 + 
143.25238 + 	__sna_crtc_disable(sna, crtc);
143.25239 + 	return true;
143.25240 +@@ -6561,21 +8407,22 @@ void sna_mode_reset(struct sna *sna)
143.25241 + 
143.25242 + 	DBG(("%s\n", __FUNCTION__));
143.25243 + 
143.25244 +-	sna_hide_cursors(sna->scrn);
143.25245 ++	sna_disable_cursors(sna->scrn);
143.25246 + 	for (i = 0; i < sna->mode.num_real_crtc; i++)
143.25247 + 		if (!sna_crtc_hide_planes(sna, to_sna_crtc(config->crtc[i])))
143.25248 +-			sna_crtc_disable(config->crtc[i]);
143.25249 ++			sna_crtc_disable(config->crtc[i], true);
143.25250 + 	assert(sna->mode.front_active == 0);
143.25251 + 
143.25252 + 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.25253 + 		struct sna_crtc *sna_crtc = to_sna_crtc(config->crtc[i]);
143.25254 ++		struct plane *plane;
143.25255 + 
143.25256 + 		assert(sna_crtc != NULL);
143.25257 +-		sna_crtc->dpms_mode = -1;
143.25258 + 
143.25259 + 		/* Force the rotation property to be reset on next use */
143.25260 + 		rotation_reset(&sna_crtc->primary);
143.25261 +-		rotation_reset(&sna_crtc->sprite);
143.25262 ++		list_for_each_entry(plane, &sna_crtc->sprites, link)
143.25263 ++			rotation_reset(plane);
143.25264 + 	}
143.25265 + 
143.25266 + 	/* VT switching, likely to be fbcon so make the backlight usable */
143.25267 +@@ -6641,9 +8488,10 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
143.25268 + {
143.25269 + 	int16_t sx, sy;
143.25270 + 	struct sna *sna = to_sna(crtc->scrn);
143.25271 +-	ScreenPtr screen = sna->scrn->pScreen;
143.25272 ++	ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
143.25273 + 	DrawablePtr draw = crtc_source(crtc, &sx, &sy);
143.25274 + 	PictFormatPtr format;
143.25275 ++	PictTransform T;
143.25276 + 	PicturePtr src, dst;
143.25277 + 	PixmapPtr pixmap;
143.25278 + 	int depth, error;
143.25279 +@@ -6664,6 +8512,14 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
143.25280 + 	     __FUNCTION__, format->format, depth, draw->bitsPerPixel,
143.25281 + 	     bo->pitch, crtc->mode.HDisplay, crtc->mode.VDisplay));
143.25282 + 
143.25283 ++	if (sx | sy)
143.25284 ++		RegionTranslate(region, sx, sy);
143.25285 ++	error = !sna_drawable_move_region_to_cpu(draw, region, MOVE_READ);
143.25286 ++	if (sx | sy)
143.25287 ++		RegionTranslate(region, -sx, -sy);
143.25288 ++	if (error)
143.25289 ++		return;
143.25290 ++
143.25291 + 	ptr = kgem_bo_map__gtt(&sna->kgem, bo);
143.25292 + 	if (ptr == NULL)
143.25293 + 		return;
143.25294 +@@ -6683,9 +8539,37 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
143.25295 + 	if (!src)
143.25296 + 		goto free_pixmap;
143.25297 + 
143.25298 +-	error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
143.25299 +-	if (error)
143.25300 +-		goto free_src;
143.25301 ++	pixman_transform_init_translate(&T, sx << 16, sy << 16);
143.25302 ++	pixman_transform_multiply(&T, &T, &crtc->crtc_to_framebuffer);
143.25303 ++	if (!sna_transform_is_integer_translation(&T, &sx, &sy)) {
143.25304 ++#define f2d(x) (((double)(x))/65536.)
143.25305 ++		DBG(("%s: transform=[[%f %f %f], [%f %f %f], [%f %f %f]] (raw [[%x %x %x], [%x %x %x], [%x %x %x]])\n",
143.25306 ++		     __FUNCTION__,
143.25307 ++		     f2d(T.matrix[0][0]),
143.25308 ++		     f2d(T.matrix[0][1]),
143.25309 ++		     f2d(T.matrix[0][2]),
143.25310 ++		     f2d(T.matrix[1][0]),
143.25311 ++		     f2d(T.matrix[1][1]),
143.25312 ++		     f2d(T.matrix[1][2]),
143.25313 ++		     f2d(T.matrix[2][0]),
143.25314 ++		     f2d(T.matrix[2][1]),
143.25315 ++		     f2d(T.matrix[2][2]),
143.25316 ++		     T.matrix[0][0],
143.25317 ++		     T.matrix[0][1],
143.25318 ++		     T.matrix[0][2],
143.25319 ++		     T.matrix[1][0],
143.25320 ++		     T.matrix[1][1],
143.25321 ++		     T.matrix[1][2],
143.25322 ++		     T.matrix[2][0],
143.25323 ++		     T.matrix[2][1],
143.25324 ++		     T.matrix[2][2]));
143.25325 ++#undef f2d
143.25326 ++
143.25327 ++		error = SetPictureTransform(src, &T);
143.25328 ++		if (error)
143.25329 ++			goto free_src;
143.25330 ++		sx = sy = 0;
143.25331 ++	}
143.25332 + 
143.25333 + 	if (crtc->filter && crtc->transform_in_use)
143.25334 + 		SetPicturePictFilter(src, crtc->filter,
143.25335 +@@ -6733,10 +8617,11 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
143.25336 + {
143.25337 + 	int16_t sx, sy;
143.25338 + 	struct sna *sna = to_sna(crtc->scrn);
143.25339 +-	ScreenPtr screen = crtc->scrn->pScreen;
143.25340 ++	ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
143.25341 + 	DrawablePtr draw = crtc_source(crtc, &sx, &sy);
143.25342 + 	struct sna_composite_op tmp;
143.25343 + 	PictFormatPtr format;
143.25344 ++	PictTransform T;
143.25345 + 	PicturePtr src, dst;
143.25346 + 	PixmapPtr pixmap;
143.25347 + 	const BoxRec *b;
143.25348 +@@ -6777,9 +8662,14 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
143.25349 + 	if (!src)
143.25350 + 		goto free_pixmap;
143.25351 + 
143.25352 +-	error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
143.25353 +-	if (error)
143.25354 +-		goto free_src;
143.25355 ++	pixman_transform_init_translate(&T, sx << 16, sy << 16);
143.25356 ++	pixman_transform_multiply(&T, &T, &crtc->crtc_to_framebuffer);
143.25357 ++	if (!sna_transform_is_integer_translation(&T, &sx, &sy)) {
143.25358 ++		error = SetPictureTransform(src, &T);
143.25359 ++		if (error)
143.25360 ++			goto free_src;
143.25361 ++		sx = sy = 0;
143.25362 ++	}
143.25363 + 
143.25364 + 	if (crtc->filter && crtc->transform_in_use)
143.25365 + 		SetPicturePictFilter(src, crtc->filter,
143.25366 +@@ -6793,36 +8683,38 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
143.25367 + 	ValidatePicture(src);
143.25368 + 	ValidatePicture(dst);
143.25369 + 
143.25370 +-	if (!sna->render.composite(sna,
143.25371 +-				   PictOpSrc, src, NULL, dst,
143.25372 +-				   sx, sy,
143.25373 +-				   0, 0,
143.25374 +-				   0, 0,
143.25375 +-				   crtc->mode.HDisplay, crtc->mode.VDisplay,
143.25376 +-				   COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) {
143.25377 +-		DBG(("%s: unsupported operation!\n", __FUNCTION__));
143.25378 +-		sna_crtc_redisplay__fallback(crtc, region, bo);
143.25379 +-		goto free_dst;
143.25380 +-	}
143.25381 +-
143.25382 ++	/* Composite each box individually as if we are dealing with a rotation
143.25383 ++	 * on a large display, we may have to perform intermediate copies. We
143.25384 ++	 * can then minimise the overdraw by looking at individual boxes rather
143.25385 ++	 * than the bbox.
143.25386 ++	 */
143.25387 + 	n = region_num_rects(region);
143.25388 + 	b = region_rects(region);
143.25389 + 	do {
143.25390 +-		BoxRec box;
143.25391 +-
143.25392 +-		box = *b++;
143.25393 ++		BoxRec box = *b;
143.25394 + 		transformed_box(&box, crtc);
143.25395 + 
143.25396 + 		DBG(("%s: (%d, %d)x(%d, %d) -> (%d, %d), (%d, %d)\n",
143.25397 + 		     __FUNCTION__,
143.25398 +-		     b[-1].x1, b[-1].y1, b[-1].x2-b[-1].x1, b[-1].y2-b[-1].y1,
143.25399 ++		     b->x1, b->y1, b->x2-b->x1, b->y2-b->y1,
143.25400 + 		     box.x1, box.y1, box.x2, box.y2));
143.25401 + 
143.25402 +-		tmp.box(sna, &tmp, &box);
143.25403 +-	} while (--n);
143.25404 +-	tmp.done(sna, &tmp);
143.25405 ++		if (!sna->render.composite(sna,
143.25406 ++					   PictOpSrc, src, NULL, dst,
143.25407 ++					   sx + box.x1, sy + box.y1,
143.25408 ++					   0, 0,
143.25409 ++					   box.x1, box.y1,
143.25410 ++					   box.x2 - box.x1, box.y2 - box.y1,
143.25411 ++					   0, memset(&tmp, 0, sizeof(tmp)))) {
143.25412 ++			DBG(("%s: unsupported operation!\n", __FUNCTION__));
143.25413 ++			sna_crtc_redisplay__fallback(crtc, region, bo);
143.25414 ++			break;
143.25415 ++		} else {
143.25416 ++			tmp.box(sna, &tmp, &box);
143.25417 ++			tmp.done(sna, &tmp);
143.25418 ++		}
143.25419 ++	} while (b++, --n);
143.25420 + 
143.25421 +-free_dst:
143.25422 + 	FreePicture(dst, None);
143.25423 + free_src:
143.25424 + 	FreePicture(src, None);
143.25425 +@@ -6839,7 +8731,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
143.25426 + 	struct sna_pixmap *priv = sna_pixmap((PixmapPtr)draw);
143.25427 + 
143.25428 + 	DBG(("%s: crtc %d [pipe=%d], damage (%d, %d), (%d, %d) x %d\n",
143.25429 +-	     __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe,
143.25430 ++	     __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc),
143.25431 + 	     region->extents.x1, region->extents.y1,
143.25432 + 	     region->extents.x2, region->extents.y2,
143.25433 + 	     region_num_rects(region)));
143.25434 +@@ -6898,7 +8790,10 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
143.25435 + static void shadow_flip_handler(struct drm_event_vblank *e,
143.25436 + 				void *data)
143.25437 + {
143.25438 +-	sna_mode_redisplay(data);
143.25439 ++	struct sna *sna = data;
143.25440 ++
143.25441 ++	if (!sna->mode.shadow_wait)
143.25442 ++		sna_mode_redisplay(sna);
143.25443 + }
143.25444 + 
143.25445 + void sna_shadow_set_crtc(struct sna *sna,
143.25446 +@@ -6908,18 +8803,23 @@ void sna_shadow_set_crtc(struct sna *sna,
143.25447 + 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.25448 + 	struct sna_pixmap *priv;
143.25449 + 
143.25450 ++	assert(sna_crtc);
143.25451 + 	DBG(("%s: setting shadow override for CRTC:%d to handle=%d\n",
143.25452 +-	     __FUNCTION__, sna_crtc->id, bo->handle));
143.25453 ++	     __FUNCTION__, __sna_crtc_id(sna_crtc), bo->handle));
143.25454 + 
143.25455 + 	assert(sna->flags & SNA_TEAR_FREE);
143.25456 +-	assert(sna_crtc);
143.25457 + 	assert(!sna_crtc->transform);
143.25458 + 
143.25459 + 	if (sna_crtc->client_bo != bo) {
143.25460 +-		if (sna_crtc->client_bo)
143.25461 ++		if (sna_crtc->client_bo) {
143.25462 ++			assert(sna_crtc->client_bo->refcnt >= sna_crtc->client_bo->active_scanout);
143.25463 ++			sna_crtc->client_bo->active_scanout--;
143.25464 + 			kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
143.25465 ++		}
143.25466 + 
143.25467 + 		sna_crtc->client_bo = kgem_bo_reference(bo);
143.25468 ++		sna_crtc->client_bo->active_scanout++;
143.25469 ++		assert(sna_crtc->client_bo->refcnt >= sna_crtc->client_bo->active_scanout);
143.25470 + 		sna_crtc_damage(crtc);
143.25471 + 	}
143.25472 + 
143.25473 +@@ -6969,11 +8869,13 @@ void sna_shadow_unset_crtc(struct sna *sna,
143.25474 + 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.25475 + 
143.25476 + 	DBG(("%s: clearin shadow override for CRTC:%d\n",
143.25477 +-	     __FUNCTION__, sna_crtc->id));
143.25478 ++	     __FUNCTION__, __sna_crtc_id(sna_crtc)));
143.25479 + 
143.25480 + 	if (sna_crtc->client_bo == NULL)
143.25481 + 		return;
143.25482 + 
143.25483 ++	assert(sna_crtc->client_bo->refcnt >= sna_crtc->client_bo->active_scanout);
143.25484 ++	sna_crtc->client_bo->active_scanout--;
143.25485 + 	kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
143.25486 + 	sna_crtc->client_bo = NULL;
143.25487 + 	list_del(&sna_crtc->shadow_link);
143.25488 +@@ -6982,15 +8884,57 @@ void sna_shadow_unset_crtc(struct sna *sna,
143.25489 + 	sna_crtc_damage(crtc);
143.25490 + }
143.25491 + 
143.25492 ++static bool move_crtc_to_gpu(struct sna *sna)
143.25493 ++{
143.25494 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.25495 ++	int i;
143.25496 ++
143.25497 ++	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.25498 ++		struct sna_crtc *crtc = to_sna_crtc(config->crtc[i]);
143.25499 ++		unsigned hint;
143.25500 ++
143.25501 ++		assert(crtc);
143.25502 ++
143.25503 ++		if (crtc->bo == NULL)
143.25504 ++			continue;
143.25505 ++
143.25506 ++		if (crtc->slave_pixmap)
143.25507 ++			continue;
143.25508 ++
143.25509 ++		if (crtc->client_bo)
143.25510 ++			continue;
143.25511 ++
143.25512 ++		if (crtc->shadow_bo)
143.25513 ++			continue;
143.25514 ++
143.25515 ++		hint = MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT;
143.25516 ++		if (sna->flags & SNA_TEAR_FREE)
143.25517 ++			hint |= __MOVE_FORCE;
143.25518 ++
143.25519 ++		DBG(("%s: CRTC %d [pipe=%d] requires frontbuffer\n",
143.25520 ++		     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc)));
143.25521 ++		return sna_pixmap_move_to_gpu(sna->front, hint);
143.25522 ++	}
143.25523 ++
143.25524 ++	return true;
143.25525 ++}
143.25526 ++
143.25527 + void sna_mode_redisplay(struct sna *sna)
143.25528 + {
143.25529 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.25530 + 	RegionPtr region;
143.25531 + 	int i;
143.25532 + 
143.25533 +-	if (!sna->mode.shadow_damage)
143.25534 ++	if (sna->mode.hidden) {
143.25535 ++		DBG(("%s: hidden outputs, skipping\n", __FUNCTION__));
143.25536 ++		return;
143.25537 ++	}
143.25538 ++
143.25539 ++	if (!sna->mode.shadow_enabled)
143.25540 + 		return;
143.25541 + 
143.25542 ++	assert(sna->mode.shadow_damage);
143.25543 ++
143.25544 + 	DBG(("%s: posting shadow damage? %d (flips pending? %d, mode reconfiguration pending? %d)\n",
143.25545 + 	     __FUNCTION__,
143.25546 + 	     !RegionNil(DamageRegion(sna->mode.shadow_damage)),
143.25547 +@@ -7012,21 +8956,23 @@ void sna_mode_redisplay(struct sna *sna)
143.25548 + 	     region->extents.x2, region->extents.y2));
143.25549 + 
143.25550 + 	if (sna->mode.flip_active) {
143.25551 +-		DamagePtr damage;
143.25552 +-
143.25553 +-		damage = sna->mode.shadow_damage;
143.25554 +-		sna->mode.shadow_damage = NULL;
143.25555 ++		DBG(("%s: checking for %d outstanding flip completions\n",
143.25556 ++		     __FUNCTION__, sna->mode.flip_active));
143.25557 + 
143.25558 ++		sna->mode.dirty = true;
143.25559 + 		while (sna->mode.flip_active && sna_mode_wakeup(sna))
143.25560 + 			;
143.25561 ++		sna->mode.dirty = false;
143.25562 + 
143.25563 +-		sna->mode.shadow_damage = damage;
143.25564 ++		DBG(("%s: now %d outstanding flip completions (enabled? %d)\n",
143.25565 ++		     __FUNCTION__,
143.25566 ++		     sna->mode.flip_active,
143.25567 ++		     sna->mode.shadow_enabled));
143.25568 ++		if (sna->mode.flip_active || !sna->mode.shadow_enabled)
143.25569 ++			return;
143.25570 + 	}
143.25571 + 
143.25572 +-	if (sna->mode.flip_active)
143.25573 +-		return;
143.25574 +-
143.25575 +-	if (wedged(sna) || !sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) {
143.25576 ++	if (!move_crtc_to_gpu(sna)) {
143.25577 + 		DBG(("%s: forcing scanout update using the CPU\n", __FUNCTION__));
143.25578 + 		if (!sna_pixmap_move_to_cpu(sna->front, MOVE_READ))
143.25579 + 			return;
143.25580 +@@ -7047,90 +8993,14 @@ void sna_mode_redisplay(struct sna *sna)
143.25581 + 			damage.data = NULL;
143.25582 + 			RegionIntersect(&damage, &damage, region);
143.25583 + 			if (!box_empty(&damage.extents)) {
143.25584 +-				struct kgem_bo *bo = NULL;
143.25585 +-
143.25586 + 				DBG(("%s: fallback intersects pipe=%d [(%d, %d), (%d, %d)]\n",
143.25587 +-				     __FUNCTION__, sna_crtc->pipe,
143.25588 ++				     __FUNCTION__, __sna_crtc_pipe(sna_crtc),
143.25589 + 				     damage.extents.x1, damage.extents.y1,
143.25590 + 				     damage.extents.x2, damage.extents.y2));
143.25591 + 
143.25592 +-				if (sna->flags & SNA_TEAR_FREE) {
143.25593 +-					RegionRec new_damage;
143.25594 +-
143.25595 +-					RegionNull(&new_damage);
143.25596 +-					RegionCopy(&new_damage, &damage);
143.25597 +-
143.25598 +-					bo = sna_crtc->client_bo;
143.25599 +-					if (bo == NULL) {
143.25600 +-						damage.extents = crtc->bounds;
143.25601 +-						damage.data = NULL;
143.25602 +-						bo = kgem_create_2d(&sna->kgem,
143.25603 +-								crtc->mode.HDisplay,
143.25604 +-								crtc->mode.VDisplay,
143.25605 +-								crtc->scrn->bitsPerPixel,
143.25606 +-								sna_crtc->bo->tiling,
143.25607 +-								CREATE_SCANOUT);
143.25608 +-					} else
143.25609 +-						RegionUnion(&damage, &damage, &sna_crtc->client_damage);
143.25610 +-
143.25611 +-					DBG(("%s: TearFree fallback, shadow handle=%d, crtc handle=%d\n", __FUNCTION__, bo->handle, sna_crtc->bo->handle));
143.25612 +-
143.25613 +-					sna_crtc->client_damage = new_damage;
143.25614 +-				}
143.25615 +-
143.25616 +-				if (bo == NULL)
143.25617 +-					bo = sna_crtc->bo;
143.25618 +-				sna_crtc_redisplay__fallback(crtc, &damage, bo);
143.25619 +-
143.25620 +-				if (bo != sna_crtc->bo) {
143.25621 +-					struct drm_mode_crtc_page_flip arg;
143.25622 +-
143.25623 +-					arg.crtc_id = sna_crtc->id;
143.25624 +-					arg.fb_id = get_fb(sna, bo,
143.25625 +-							   crtc->mode.HDisplay,
143.25626 +-							   crtc->mode.VDisplay);
143.25627 +-
143.25628 +-					arg.user_data = (uintptr_t)sna_crtc;
143.25629 +-					arg.flags = DRM_MODE_PAGE_FLIP_EVENT;
143.25630 +-					arg.reserved = 0;
143.25631 +-
143.25632 +-					if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
143.25633 +-						if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) {
143.25634 +-							assert(sna_crtc->bo->active_scanout);
143.25635 +-							assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
143.25636 +-							sna_crtc->bo->active_scanout--;
143.25637 +-							kgem_bo_destroy(&sna->kgem, sna_crtc->bo);
143.25638 +-
143.25639 +-							sna_crtc->bo = bo;
143.25640 +-							sna_crtc->bo->active_scanout++;
143.25641 +-							sna_crtc->client_bo = NULL;
143.25642 +-						} else {
143.25643 +-							DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
143.25644 +-							     __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
143.25645 +-							xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.25646 +-								   "Page flipping failed, disabling TearFree\n");
143.25647 +-							sna->flags &= ~SNA_TEAR_FREE;
143.25648 +-
143.25649 +-							damage.extents = crtc->bounds;
143.25650 +-							damage.data = NULL;
143.25651 +-							sna_crtc_redisplay__fallback(crtc, &damage, sna_crtc->bo);
143.25652 +-
143.25653 +-							kgem_bo_destroy(&sna->kgem, bo);
143.25654 +-							sna_crtc->client_bo = NULL;
143.25655 +-						}
143.25656 +-					} else {
143.25657 +-						sna->mode.flip_active++;
143.25658 +-
143.25659 +-						assert(sna_crtc->flip_bo == NULL);
143.25660 +-						sna_crtc->flip_handler = shadow_flip_handler;
143.25661 +-						sna_crtc->flip_data = sna;
143.25662 +-						sna_crtc->flip_bo = bo;
143.25663 +-						sna_crtc->flip_bo->active_scanout++;
143.25664 +-						sna_crtc->flip_serial = sna_crtc->mode_serial;
143.25665 +-
143.25666 +-						sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo);
143.25667 +-					}
143.25668 +-				}
143.25669 ++				sna_crtc_redisplay__fallback(crtc,
143.25670 ++							     &damage,
143.25671 ++							     sna_crtc->bo);
143.25672 + 			}
143.25673 + 			RegionUninit(&damage);
143.25674 + 
143.25675 +@@ -7171,6 +9041,7 @@ void sna_mode_redisplay(struct sna *sna)
143.25676 + 		xf86CrtcPtr crtc = config->crtc[i];
143.25677 + 		struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
143.25678 + 		RegionRec damage;
143.25679 ++		int sigio;
143.25680 + 
143.25681 + 		assert(sna_crtc != NULL);
143.25682 + 		DBG(("%s: crtc[%d] transformed? %d\n",
143.25683 +@@ -7192,30 +9063,38 @@ void sna_mode_redisplay(struct sna *sna)
143.25684 + 		     region_num_rects(&damage),
143.25685 + 		     damage.extents.x1, damage.extents.y1,
143.25686 + 		     damage.extents.x2, damage.extents.y2));
143.25687 ++		sigio = sigio_block();
143.25688 + 		if (!box_empty(&damage.extents)) {
143.25689 + 			if (sna->flags & SNA_TEAR_FREE) {
143.25690 ++				RegionRec new_damage;
143.25691 + 				struct drm_mode_crtc_page_flip arg;
143.25692 + 				struct kgem_bo *bo;
143.25693 + 
143.25694 +-				RegionUninit(&damage);
143.25695 +-				damage.extents = crtc->bounds;
143.25696 +-				damage.data = NULL;
143.25697 ++				RegionNull(&new_damage);
143.25698 ++				RegionCopy(&new_damage, &damage);
143.25699 + 
143.25700 +-				bo = sna_crtc->client_bo;
143.25701 +-				if (bo == NULL)
143.25702 ++				bo = sna_crtc->cache_bo;
143.25703 ++				if (bo == NULL) {
143.25704 ++					damage.extents = crtc->bounds;
143.25705 ++					damage.data = NULL;
143.25706 + 					bo = kgem_create_2d(&sna->kgem,
143.25707 + 							    crtc->mode.HDisplay,
143.25708 + 							    crtc->mode.VDisplay,
143.25709 + 							    crtc->scrn->bitsPerPixel,
143.25710 + 							    sna_crtc->bo->tiling,
143.25711 + 							    CREATE_SCANOUT);
143.25712 +-				if (bo == NULL)
143.25713 +-					goto disable1;
143.25714 ++					if (bo == NULL)
143.25715 ++						continue;
143.25716 ++				} else
143.25717 ++					RegionUnion(&damage, &damage, &sna_crtc->crtc_damage);
143.25718 ++				sna_crtc->crtc_damage = new_damage;
143.25719 + 
143.25720 + 				sna_crtc_redisplay(crtc, &damage, bo);
143.25721 + 				kgem_bo_submit(&sna->kgem, bo);
143.25722 ++				__kgem_bo_clear_dirty(bo);
143.25723 + 
143.25724 +-				arg.crtc_id = sna_crtc->id;
143.25725 ++				assert_crtc_fb(sna, sna_crtc);
143.25726 ++				arg.crtc_id = __sna_crtc_id(sna_crtc);
143.25727 + 				arg.fb_id = get_fb(sna, bo,
143.25728 + 						   crtc->mode.HDisplay,
143.25729 + 						   crtc->mode.VDisplay);
143.25730 +@@ -7228,6 +9107,9 @@ void sna_mode_redisplay(struct sna *sna)
143.25731 + 
143.25732 + 				if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
143.25733 + 					if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) {
143.25734 ++						DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
143.25735 ++						     __FUNCTION__, sna_crtc->bo->handle, sna_crtc->bo->active_scanout - 1,
143.25736 ++						     bo->handle, bo->active_scanout));
143.25737 + 						assert(sna_crtc->bo->active_scanout);
143.25738 + 						assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
143.25739 + 						sna_crtc->bo->active_scanout--;
143.25740 +@@ -7235,13 +9117,12 @@ void sna_mode_redisplay(struct sna *sna)
143.25741 + 
143.25742 + 						sna_crtc->bo = kgem_bo_reference(bo);
143.25743 + 						sna_crtc->bo->active_scanout++;
143.25744 +-						sna_crtc->client_bo = kgem_bo_reference(bo);
143.25745 + 					} else {
143.25746 + 						BoxRec box;
143.25747 + 						DrawableRec tmp;
143.25748 + 
143.25749 + 						DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
143.25750 +-						     __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
143.25751 ++						     __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
143.25752 + 						xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.25753 + 							   "Page flipping failed, disabling TearFree\n");
143.25754 + 						sna->flags &= ~SNA_TEAR_FREE;
143.25755 +@@ -7260,13 +9141,13 @@ disable1:
143.25756 + 									    &box, 1, COPY_LAST)) {
143.25757 + 							xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
143.25758 + 								   "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
143.25759 +-								   __FUNCTION__, sna_crtc->id, sna_crtc->pipe);
143.25760 +-							sna_crtc_disable(crtc);
143.25761 ++								   __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc));
143.25762 ++							sna_crtc_disable(crtc, false);
143.25763 + 						}
143.25764 +-
143.25765 +-						kgem_bo_destroy(&sna->kgem, bo);
143.25766 +-						sna_crtc->client_bo = NULL;
143.25767 + 					}
143.25768 ++
143.25769 ++					kgem_bo_destroy(&sna->kgem, bo);
143.25770 ++					sna_crtc->cache_bo = NULL;
143.25771 + 					continue;
143.25772 + 				}
143.25773 + 				sna->mode.flip_active++;
143.25774 +@@ -7279,13 +9160,20 @@ disable1:
143.25775 + 				sna_crtc->flip_serial = sna_crtc->mode_serial;
143.25776 + 				sna_crtc->flip_pending = true;
143.25777 + 
143.25778 +-				sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo);
143.25779 ++				if (sna_crtc->bo != sna->mode.shadow) {
143.25780 ++					assert_scanout(&sna->kgem, sna_crtc->bo,
143.25781 ++						       crtc->mode.HDisplay, crtc->mode.VDisplay);
143.25782 ++					sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo);
143.25783 ++				}
143.25784 ++				DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
143.25785 ++				     __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
143.25786 + 			} else {
143.25787 + 				sna_crtc_redisplay(crtc, &damage, sna_crtc->bo);
143.25788 + 				kgem_scanout_flush(&sna->kgem, sna_crtc->bo);
143.25789 + 			}
143.25790 + 		}
143.25791 + 		RegionUninit(&damage);
143.25792 ++		sigio_unblock(sigio);
143.25793 + 
143.25794 + 		if (sna_crtc->slave_damage)
143.25795 + 			DamageEmpty(sna_crtc->slave_damage);
143.25796 +@@ -7296,6 +9184,7 @@ disable1:
143.25797 + 		struct kgem_bo *old = sna->mode.shadow;
143.25798 + 		struct drm_mode_crtc_page_flip arg;
143.25799 + 		uint32_t fb = 0;
143.25800 ++		int sigio;
143.25801 + 
143.25802 + 		DBG(("%s: flipping TearFree outputs, current scanout handle=%d [active?=%d], new handle=%d [active=%d]\n",
143.25803 + 		     __FUNCTION__, old->handle, old->active_scanout, new->handle, new->active_scanout));
143.25804 +@@ -7307,7 +9196,9 @@ disable1:
143.25805 + 		arg.reserved = 0;
143.25806 + 
143.25807 + 		kgem_bo_submit(&sna->kgem, new);
143.25808 ++		__kgem_bo_clear_dirty(new);
143.25809 + 
143.25810 ++		sigio = sigio_block();
143.25811 + 		for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.25812 + 			struct sna_crtc *crtc = config->crtc[i]->driver_private;
143.25813 + 			struct kgem_bo *flip_bo;
143.25814 +@@ -7315,20 +9206,20 @@ disable1:
143.25815 + 
143.25816 + 			assert(crtc != NULL);
143.25817 + 			DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n",
143.25818 +-			     __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo ? crtc->bo->handle : 0, crtc->transform));
143.25819 ++			     __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo ? crtc->bo->handle : 0, crtc->transform));
143.25820 + 			if (crtc->bo == NULL || crtc->transform)
143.25821 + 				continue;
143.25822 + 
143.25823 + 			assert(config->crtc[i]->enabled);
143.25824 +-			assert(crtc->dpms_mode <= DPMSModeOn);
143.25825 + 			assert(crtc->flip_bo == NULL);
143.25826 ++			assert_crtc_fb(sna, crtc);
143.25827 + 
143.25828 +-			arg.crtc_id = crtc->id;
143.25829 ++			arg.crtc_id = __sna_crtc_id(crtc);
143.25830 + 			arg.user_data = (uintptr_t)crtc;
143.25831 + 
143.25832 + 			if (crtc->client_bo) {
143.25833 + 				DBG(("%s: apply shadow override bo for CRTC:%d on pipe=%d, handle=%d\n",
143.25834 +-				     __FUNCTION__, crtc->id, crtc->pipe, crtc->client_bo->handle));
143.25835 ++				     __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->client_bo->handle));
143.25836 + 				arg.fb_id = get_fb(sna, crtc->client_bo,
143.25837 + 						   crtc->base->mode.HDisplay,
143.25838 + 						   crtc->base->mode.VDisplay);
143.25839 +@@ -7356,6 +9247,7 @@ fixup_shadow:
143.25840 + 						}
143.25841 + 					}
143.25842 + 
143.25843 ++					sigio_unblock(sigio);
143.25844 + 					return;
143.25845 + 				}
143.25846 + 
143.25847 +@@ -7365,8 +9257,12 @@ fixup_shadow:
143.25848 + 				y = crtc->base->y;
143.25849 + 			}
143.25850 + 
143.25851 +-			if (crtc->bo == flip_bo)
143.25852 ++			if (crtc->bo == flip_bo) {
143.25853 ++				assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
143.25854 ++				DBG(("%s: flip handle=%d is already on the CRTC\n",
143.25855 ++				     __FUNCTION__, flip_bo->handle));
143.25856 + 				continue;
143.25857 ++			}
143.25858 + 
143.25859 + 			if (flip_bo->pitch != crtc->bo->pitch || (y << 16 | x)  != crtc->offset) {
143.25860 + 				DBG(("%s: changing pitch (new %d =?= old %d) or offset (new %x =?= old %x)\n",
143.25861 +@@ -7375,6 +9271,9 @@ fixup_shadow:
143.25862 + 				     y << 16 | x, crtc->offset));
143.25863 + fixup_flip:
143.25864 + 				if (sna_crtc_flip(sna, crtc, flip_bo, x, y)) {
143.25865 ++					DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
143.25866 ++					     __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout-1,
143.25867 ++					     flip_bo->handle, flip_bo->active_scanout));
143.25868 + 					assert(flip_bo != crtc->bo);
143.25869 + 					assert(crtc->bo->active_scanout);
143.25870 + 					assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
143.25871 +@@ -7389,9 +9288,11 @@ fixup_flip:
143.25872 + 					crtc->bo = kgem_bo_reference(flip_bo);
143.25873 + 					crtc->bo->active_scanout++;
143.25874 + 				} else {
143.25875 +-					xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.25876 +-						   "Failed to prepare CRTC for page flipping, disabling TearFree\n");
143.25877 +-					sna->flags &= ~SNA_TEAR_FREE;
143.25878 ++					if (sna->flags & SNA_TEAR_FREE) {
143.25879 ++						xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.25880 ++								"Failed to prepare CRTC for page flipping, disabling TearFree\n");
143.25881 ++						sna->flags &= ~SNA_TEAR_FREE;
143.25882 ++					}
143.25883 + 
143.25884 + 					if (sna->mode.flip_active == 0) {
143.25885 + 						DBG(("%s: abandoning flip attempt\n", __FUNCTION__));
143.25886 +@@ -7400,15 +9301,15 @@ fixup_flip:
143.25887 + 
143.25888 + 					xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
143.25889 + 						   "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
143.25890 +-						   __FUNCTION__, crtc->id, crtc->pipe);
143.25891 +-					sna_crtc_disable(crtc->base);
143.25892 ++						   __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc));
143.25893 ++					sna_crtc_disable(crtc->base, false);
143.25894 + 				}
143.25895 + 				continue;
143.25896 + 			}
143.25897 + 
143.25898 + 			if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
143.25899 + 				ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
143.25900 +-				     __FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno));
143.25901 ++				     __FUNCTION__, arg.fb_id, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), errno));
143.25902 + 				goto fixup_flip;
143.25903 + 			}
143.25904 + 			sna->mode.flip_active++;
143.25905 +@@ -7421,6 +9322,9 @@ fixup_flip:
143.25906 + 			crtc->flip_serial = crtc->mode_serial;
143.25907 + 			crtc->flip_pending = true;
143.25908 + 
143.25909 ++			DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
143.25910 ++			     __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
143.25911 ++
143.25912 + 			{
143.25913 + 				struct drm_i915_gem_busy busy = { flip_bo->handle };
143.25914 + 				if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy) == 0) {
143.25915 +@@ -7435,6 +9339,7 @@ fixup_flip:
143.25916 + 				}
143.25917 + 			}
143.25918 + 		}
143.25919 ++		sigio_unblock(sigio);
143.25920 + 
143.25921 + 		DBG(("%s: flipped %d outputs, shadow active? %d\n",
143.25922 + 		     __FUNCTION__,
143.25923 +@@ -7486,7 +9391,9 @@ again:
143.25924 + 		struct drm_event *e = (struct drm_event *)&buffer[i];
143.25925 + 		switch (e->type) {
143.25926 + 		case DRM_EVENT_VBLANK:
143.25927 +-			if (((uintptr_t)((struct drm_event_vblank *)e)->user_data) & 2)
143.25928 ++			if (sna->mode.shadow_wait)
143.25929 ++				defer_event(sna, e);
143.25930 ++			else if (((uintptr_t)((struct drm_event_vblank *)e)->user_data) & 2)
143.25931 + 				sna_present_vblank_handler((struct drm_event_vblank *)e);
143.25932 + 			else
143.25933 + 				sna_dri2_vblank_handler((struct drm_event_vblank *)e);
143.25934 +@@ -7495,13 +9402,19 @@ again:
143.25935 + 			{
143.25936 + 				struct drm_event_vblank *vbl = (struct drm_event_vblank *)e;
143.25937 + 				struct sna_crtc *crtc = (void *)(uintptr_t)vbl->user_data;
143.25938 ++				uint64_t msc;
143.25939 + 
143.25940 + 				/* Beware Zaphod! */
143.25941 + 				sna = to_sna(crtc->base->scrn);
143.25942 + 
143.25943 +-				crtc->swap.tv_sec = vbl->tv_sec;
143.25944 +-				crtc->swap.tv_usec = vbl->tv_usec;
143.25945 +-				crtc->swap.msc = msc64(crtc, vbl->sequence);
143.25946 ++				if (msc64(crtc, vbl->sequence, &msc)) {
143.25947 ++					DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n",
143.25948 ++					     __FUNCTION__, __sna_crtc_pipe(crtc), vbl->sequence, (long long)msc, vbl->tv_sec, vbl->tv_usec));
143.25949 ++					crtc->swap.tv_sec = vbl->tv_sec;
143.25950 ++					crtc->swap.tv_usec = vbl->tv_usec;
143.25951 ++					crtc->swap.msc = msc;
143.25952 ++				}
143.25953 ++				assert(crtc->flip_pending);
143.25954 + 				crtc->flip_pending = false;
143.25955 + 
143.25956 + 				assert(crtc->flip_bo);
143.25957 +@@ -7509,10 +9422,12 @@ again:
143.25958 + 				assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout);
143.25959 + 
143.25960 + 				if (crtc->flip_serial == crtc->mode_serial) {
143.25961 +-					DBG(("%s: removing handle=%d from scanout, installing handle=%d\n",
143.25962 +-					     __FUNCTION__, crtc->bo->handle, crtc->flip_bo->handle));
143.25963 ++					DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
143.25964 ++					     __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout - 1,
143.25965 ++					     crtc->flip_bo->handle, crtc->flip_bo->active_scanout));
143.25966 + 					assert(crtc->bo->active_scanout);
143.25967 + 					assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
143.25968 ++
143.25969 + 					crtc->bo->active_scanout--;
143.25970 + 					kgem_bo_destroy(&sna->kgem, crtc->bo);
143.25971 + 
143.25972 +@@ -7523,6 +9438,8 @@ again:
143.25973 + 
143.25974 + 					crtc->bo = crtc->flip_bo;
143.25975 + 					crtc->flip_bo = NULL;
143.25976 ++
143.25977 ++					assert_crtc_fb(sna, crtc);
143.25978 + 				} else {
143.25979 + 					crtc->flip_bo->active_scanout--;
143.25980 + 					kgem_bo_destroy(&sna->kgem, crtc->flip_bo);
143.25981 +@@ -7531,8 +9448,10 @@ again:
143.25982 + 
143.25983 + 				DBG(("%s: flip complete, pending? %d\n", __FUNCTION__, sna->mode.flip_active));
143.25984 + 				assert(sna->mode.flip_active);
143.25985 +-				if (--sna->mode.flip_active == 0)
143.25986 ++				if (--sna->mode.flip_active == 0) {
143.25987 ++					assert(crtc->flip_handler);
143.25988 + 					crtc->flip_handler(vbl, crtc->flip_data);
143.25989 ++				}
143.25990 + 			}
143.25991 + 			break;
143.25992 + 		default:
143.25993 +diff --git a/src/sna/sna_display_fake.c b/src/sna/sna_display_fake.c
143.25994 +index 4d74c38d..fa26bda1 100644
143.25995 +--- a/src/sna/sna_display_fake.c
143.25996 ++++ b/src/sna/sna_display_fake.c
143.25997 +@@ -96,12 +96,6 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
143.25998 + }
143.25999 + 
143.26000 + static void
143.26001 +-sna_crtc_gamma_set(xf86CrtcPtr crtc,
143.26002 +-		       CARD16 *red, CARD16 *green, CARD16 *blue, int size)
143.26003 +-{
143.26004 +-}
143.26005 +-
143.26006 +-static void
143.26007 + sna_crtc_destroy(xf86CrtcPtr crtc)
143.26008 + {
143.26009 + }
143.26010 +@@ -109,7 +103,6 @@ sna_crtc_destroy(xf86CrtcPtr crtc)
143.26011 + static const xf86CrtcFuncsRec sna_crtc_funcs = {
143.26012 + 	.dpms = sna_crtc_dpms,
143.26013 + 	.set_mode_major = sna_crtc_set_mode_major,
143.26014 +-	.gamma_set = sna_crtc_gamma_set,
143.26015 + 	.destroy = sna_crtc_destroy,
143.26016 + };
143.26017 + 
143.26018 +@@ -192,7 +185,7 @@ static const xf86OutputFuncsRec sna_output_funcs = {
143.26019 + static Bool
143.26020 + sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
143.26021 + {
143.26022 +-	ScreenPtr screen = scrn->pScreen;
143.26023 ++	ScreenPtr screen = xf86ScrnToScreen(scrn);
143.26024 + 	PixmapPtr new_front;
143.26025 + 
143.26026 + 	DBG(("%s (%d, %d) -> (%d, %d)\n", __FUNCTION__,
143.26027 +@@ -262,6 +255,7 @@ static bool add_fake_output(struct sna *sna, bool late)
143.26028 + 	output->mm_height = 0;
143.26029 + 	output->interlaceAllowed = FALSE;
143.26030 + 	output->subpixel_order = SubPixelNone;
143.26031 ++	output->status = XF86OutputStatusDisconnected;
143.26032 + 
143.26033 + 	output->possible_crtcs = ~((1 << sna->mode.num_real_crtc) - 1);
143.26034 + 	output->possible_clones = ~((1 << sna->mode.num_real_output) - 1);
143.26035 +@@ -297,6 +291,8 @@ static bool add_fake_output(struct sna *sna, bool late)
143.26036 + 
143.26037 + 		RRCrtcSetRotations(crtc->randr_crtc,
143.26038 + 				   RR_Rotate_All | RR_Reflect_All);
143.26039 ++		if (!RRCrtcGammaSetSize(crtc->randr_crtc, 256))
143.26040 ++			goto err;
143.26041 + 	}
143.26042 + 
143.26043 + 	sna->mode.num_fake++;
143.26044 +@@ -312,13 +308,16 @@ err:
143.26045 + 			continue;
143.26046 + 
143.26047 + 		xf86OutputDestroy(output);
143.26048 ++		i--;
143.26049 + 	}
143.26050 + 
143.26051 + 	for (i = 0; i < xf86_config->num_crtc; i++) {
143.26052 + 		crtc = xf86_config->crtc[i];
143.26053 + 		if (crtc->driver_private)
143.26054 + 			continue;
143.26055 ++
143.26056 + 		xf86CrtcDestroy(crtc);
143.26057 ++		i--;
143.26058 + 	}
143.26059 + 	sna->mode.num_fake = -1;
143.26060 + 	return false;
143.26061 +diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
143.26062 +index e5c4d53e..d89525cc 100644
143.26063 +--- a/src/sna/sna_dri2.c
143.26064 ++++ b/src/sna/sna_dri2.c
143.26065 +@@ -82,12 +82,23 @@ get_private(void *buffer)
143.26066 + 	return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1);
143.26067 + }
143.26068 + 
143.26069 ++pure static inline DRI2BufferPtr sna_pixmap_get_buffer(PixmapPtr pixmap)
143.26070 ++{
143.26071 ++	assert(pixmap->refcnt);
143.26072 ++	return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
143.26073 ++}
143.26074 ++
143.26075 ++static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
143.26076 ++{
143.26077 ++	assert(pixmap->refcnt);
143.26078 ++	((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
143.26079 ++}
143.26080 ++
143.26081 + #if DRI2INFOREC_VERSION >= 4
143.26082 + enum event_type {
143.26083 + 	WAITMSC = 0,
143.26084 + 	SWAP,
143.26085 +-	SWAP_WAIT,
143.26086 +-	SWAP_THROTTLE,
143.26087 ++	SWAP_COMPLETE,
143.26088 + 	FLIP,
143.26089 + 	FLIP_THROTTLE,
143.26090 + 	FLIP_COMPLETE,
143.26091 +@@ -98,6 +109,7 @@ struct dri_bo {
143.26092 + 	struct list link;
143.26093 + 	struct kgem_bo *bo;
143.26094 + 	uint32_t name;
143.26095 ++	unsigned flags;
143.26096 + };
143.26097 + 
143.26098 + struct sna_dri2_event {
143.26099 +@@ -108,6 +120,8 @@ struct sna_dri2_event {
143.26100 + 	xf86CrtcPtr crtc;
143.26101 + 	int pipe;
143.26102 + 	bool queued;
143.26103 ++	bool sync;
143.26104 ++	bool chained;
143.26105 + 
143.26106 + 	/* for swaps & flips only */
143.26107 + 	DRI2SwapEventPtr event_complete;
143.26108 +@@ -116,35 +130,146 @@ struct sna_dri2_event {
143.26109 + 	DRI2BufferPtr back;
143.26110 + 	struct kgem_bo *bo;
143.26111 + 
143.26112 ++	struct copy {
143.26113 ++		struct kgem_bo *bo;
143.26114 ++		unsigned flags;
143.26115 ++		uint32_t name;
143.26116 ++		uint32_t size;
143.26117 ++	} pending;
143.26118 ++
143.26119 + 	struct sna_dri2_event *chain;
143.26120 + 
143.26121 +-	struct list cache;
143.26122 + 	struct list link;
143.26123 + 
143.26124 +-	int mode;
143.26125 ++	int flip_continue;
143.26126 ++	int keepalive;
143.26127 ++	int signal;
143.26128 + };
143.26129 + 
143.26130 ++#if DRI2INFOREC_VERSION < 10
143.26131 ++#undef USE_ASYNC_SWAP
143.26132 ++#endif
143.26133 ++
143.26134 ++#if USE_ASYNC_SWAP
143.26135 ++#define KEEPALIVE 8 /* wait ~100ms before discarding swap caches */
143.26136 ++#define APPLY_DAMAGE 0
143.26137 ++#else
143.26138 ++#define USE_ASYNC_SWAP 0
143.26139 ++#define KEEPALIVE 1
143.26140 ++#define APPLY_DAMAGE 1
143.26141 ++#endif
143.26142 ++
143.26143 + static void sna_dri2_flip_event(struct sna_dri2_event *flip);
143.26144 ++inline static DRI2BufferPtr dri2_window_get_front(WindowPtr win);
143.26145 ++
143.26146 ++static struct kgem_bo *
143.26147 ++__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.26148 ++		      DRI2BufferPtr src, DRI2BufferPtr dst,
143.26149 ++		      unsigned flags);
143.26150 ++
143.26151 ++inline static void
143.26152 ++__sna_dri2_copy_event(struct sna_dri2_event *info, unsigned flags)
143.26153 ++{
143.26154 ++	DBG(("%s: flags = %x\n", __FUNCTION__, flags));
143.26155 ++	assert(info->front != info->back);
143.26156 ++	info->bo = __sna_dri2_copy_region(info->sna, info->draw, NULL,
143.26157 ++					  info->back, info->front,
143.26158 ++					  flags);
143.26159 ++	info->front->flags = info->back->flags;
143.26160 ++}
143.26161 ++
143.26162 ++static int front_pitch(DrawablePtr draw)
143.26163 ++{
143.26164 ++	DRI2BufferPtr buffer;
143.26165 ++
143.26166 ++	buffer = NULL;
143.26167 ++	if (draw->type != DRAWABLE_PIXMAP)
143.26168 ++		buffer = dri2_window_get_front((WindowPtr)draw);
143.26169 ++	if (buffer == NULL)
143.26170 ++		buffer = sna_pixmap_get_buffer(get_drawable_pixmap(draw));
143.26171 ++
143.26172 ++	return buffer ? buffer->pitch : 0;
143.26173 ++}
143.26174 ++
143.26175 ++struct dri2_window {
143.26176 ++	DRI2BufferPtr front;
143.26177 ++	struct sna_dri2_event *chain;
143.26178 ++	xf86CrtcPtr crtc;
143.26179 ++	int64_t msc_delta;
143.26180 ++	struct list cache;
143.26181 ++	uint32_t cache_size;
143.26182 ++	int scanout;
143.26183 ++};
143.26184 ++
143.26185 ++static struct dri2_window *dri2_window(WindowPtr win)
143.26186 ++{
143.26187 ++	assert(win->drawable.type != DRAWABLE_PIXMAP);
143.26188 ++	return ((void **)__get_private(win, sna_window_key))[1];
143.26189 ++}
143.26190 ++
143.26191 ++static bool use_scanout(struct sna *sna,
143.26192 ++			DrawablePtr draw,
143.26193 ++			struct dri2_window *priv)
143.26194 ++{
143.26195 ++	if (priv->front)
143.26196 ++		return true;
143.26197 ++
143.26198 ++	if (priv->scanout < 0)
143.26199 ++		priv->scanout =
143.26200 ++			(sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0 &&
143.26201 ++			draw->width  == sna->front->drawable.width &&
143.26202 ++			draw->height == sna->front->drawable.height &&
143.26203 ++			draw->bitsPerPixel == sna->front->drawable.bitsPerPixel;
143.26204 ++
143.26205 ++	return priv->scanout;
143.26206 ++}
143.26207 + 
143.26208 + static void
143.26209 + sna_dri2_get_back(struct sna *sna,
143.26210 + 		  DrawablePtr draw,
143.26211 +-		  DRI2BufferPtr back,
143.26212 +-		  struct sna_dri2_event *info)
143.26213 ++		  DRI2BufferPtr back)
143.26214 + {
143.26215 ++	struct dri2_window *priv = dri2_window((WindowPtr)draw);
143.26216 ++	uint32_t size;
143.26217 + 	struct kgem_bo *bo;
143.26218 ++	struct dri_bo *c;
143.26219 + 	uint32_t name;
143.26220 ++	int flags;
143.26221 + 	bool reuse;
143.26222 + 
143.26223 +-	DBG(("%s: draw size=%dx%d, buffer size=%dx%d\n",
143.26224 ++	DBG(("%s: draw size=%dx%d, back buffer handle=%d size=%dx%d, is-scanout? %d, active?=%d, pitch=%d, front pitch=%d\n",
143.26225 + 	     __FUNCTION__, draw->width, draw->height,
143.26226 +-	     get_private(back)->size & 0xffff, get_private(back)->size >> 16));
143.26227 +-	reuse = (draw->height << 16 | draw->width) == get_private(back)->size;
143.26228 ++	     get_private(back)->bo->handle,
143.26229 ++	     get_private(back)->size & 0xffff, get_private(back)->size >> 16,
143.26230 ++	     get_private(back)->bo->scanout,
143.26231 ++	     get_private(back)->bo->active_scanout,
143.26232 ++	     back->pitch, front_pitch(draw)));
143.26233 ++	assert(priv);
143.26234 ++
143.26235 ++	size = draw->height << 16 | draw->width;
143.26236 ++	if (size != priv->cache_size) {
143.26237 ++		while (!list_is_empty(&priv->cache)) {
143.26238 ++			c = list_first_entry(&priv->cache, struct dri_bo, link);
143.26239 ++			list_del(&c->link);
143.26240 ++
143.26241 ++			DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
143.26242 ++			assert(c->bo);
143.26243 ++			kgem_bo_destroy(&sna->kgem, c->bo);
143.26244 ++
143.26245 ++			free(c);
143.26246 ++		}
143.26247 ++		priv->cache_size = size;
143.26248 ++	}
143.26249 ++
143.26250 ++	reuse = size == get_private(back)->size;
143.26251 ++	if (reuse)
143.26252 ++		reuse = get_private(back)->bo->scanout == use_scanout(sna, draw, priv);
143.26253 ++	DBG(("%s: reuse backbuffer? %d\n", __FUNCTION__, reuse));
143.26254 + 	if (reuse) {
143.26255 + 		bo = get_private(back)->bo;
143.26256 + 		assert(bo->refcnt);
143.26257 +-		DBG(("%s: back buffer handle=%d, scanout?=%d, refcnt=%d\n",
143.26258 +-					__FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
143.26259 ++		DBG(("%s: back buffer handle=%d, active?=%d, refcnt=%d\n",
143.26260 ++		     __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
143.26261 + 		if (bo->active_scanout == 0) {
143.26262 + 			DBG(("%s: reuse unattached back\n", __FUNCTION__));
143.26263 + 			get_private(back)->stale = false;
143.26264 +@@ -153,24 +278,37 @@ sna_dri2_get_back(struct sna *sna,
143.26265 + 	}
143.26266 + 
143.26267 + 	bo = NULL;
143.26268 +-	if (info) {
143.26269 +-		struct dri_bo *c;
143.26270 +-		list_for_each_entry(c, &info->cache, link) {
143.26271 +-			if (c->bo && c->bo->scanout == 0) {
143.26272 +-				bo = c->bo;
143.26273 +-				name = c->name;
143.26274 +-				DBG(("%s: reuse cache handle=%d\n", __FUNCTION__, bo->handle));
143.26275 +-				list_move_tail(&c->link, &info->cache);
143.26276 +-				c->bo = NULL;
143.26277 ++	list_for_each_entry(c, &priv->cache, link) {
143.26278 ++		DBG(("%s: cache: handle=%d, active=%d\n",
143.26279 ++		     __FUNCTION__, c->bo ? c->bo->handle : 0, c->bo ? c->bo->active_scanout : -1));
143.26280 ++		assert(c->bo);
143.26281 ++		if (c->bo->active_scanout == 0) {
143.26282 ++			_list_del(&c->link);
143.26283 ++			if (c->bo == NULL) {
143.26284 ++				free(c);
143.26285 ++				goto out;
143.26286 + 			}
143.26287 ++			bo = c->bo;
143.26288 ++			name = c->name;
143.26289 ++			flags = c->flags;
143.26290 ++			DBG(("%s: reuse cache handle=%d, name=%d, flags=%d\n", __FUNCTION__, bo->handle, name, flags));
143.26291 ++			c->bo = NULL;
143.26292 ++			break;
143.26293 + 		}
143.26294 + 	}
143.26295 + 	if (bo == NULL) {
143.26296 + 		DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
143.26297 ++		flags = CREATE_EXACT;
143.26298 ++
143.26299 ++		if (use_scanout(sna, draw, priv)) {
143.26300 ++			DBG(("%s: requesting scanout compatible back\n", __FUNCTION__));
143.26301 ++			flags |= CREATE_SCANOUT;
143.26302 ++		}
143.26303 ++
143.26304 + 		bo = kgem_create_2d(&sna->kgem,
143.26305 + 				    draw->width, draw->height, draw->bitsPerPixel,
143.26306 + 				    get_private(back)->bo->tiling,
143.26307 +-				    get_private(back)->bo->scanout ? CREATE_SCANOUT : 0);
143.26308 ++				    flags);
143.26309 + 		if (bo == NULL)
143.26310 + 			return;
143.26311 + 
143.26312 +@@ -179,30 +317,42 @@ sna_dri2_get_back(struct sna *sna,
143.26313 + 			kgem_bo_destroy(&sna->kgem, bo);
143.26314 + 			return;
143.26315 + 		}
143.26316 ++
143.26317 ++		flags = 0;
143.26318 ++		if (USE_ASYNC_SWAP && back->flags) {
143.26319 ++			BoxRec box;
143.26320 ++
143.26321 ++			box.x1 = 0;
143.26322 ++			box.y1 = 0;
143.26323 ++			box.x2 = draw->width;
143.26324 ++			box.y2 = draw->height;
143.26325 ++
143.26326 ++			DBG(("%s: filling new buffer with old back\n", __FUNCTION__));
143.26327 ++			if (sna->render.copy_boxes(sna, GXcopy,
143.26328 ++						   draw, get_private(back)->bo, 0, 0,
143.26329 ++						   draw, bo, 0, 0,
143.26330 ++						   &box, 1, COPY_LAST | COPY_DRI))
143.26331 ++				flags = back->flags;
143.26332 ++		}
143.26333 + 	}
143.26334 + 	assert(bo->active_scanout == 0);
143.26335 + 
143.26336 +-	if (info && reuse) {
143.26337 +-		bool found = false;
143.26338 +-		struct dri_bo *c;
143.26339 +-
143.26340 +-		list_for_each_entry_reverse(c, &info->cache, link) {
143.26341 +-			if (c->bo == NULL) {
143.26342 +-				found = true;
143.26343 +-				_list_del(&c->link);
143.26344 +-				break;
143.26345 +-			}
143.26346 +-		}
143.26347 +-		if (!found)
143.26348 ++	if (reuse && get_private(back)->bo->refcnt == 1 + get_private(back)->bo->active_scanout) {
143.26349 ++		if (&c->link == &priv->cache)
143.26350 + 			c = malloc(sizeof(*c));
143.26351 + 		if (c != NULL) {
143.26352 + 			c->bo = ref(get_private(back)->bo);
143.26353 + 			c->name = back->name;
143.26354 +-			list_add(&c->link, &info->cache);
143.26355 +-			DBG(("%s: cacheing handle=%d (name=%d)\n", __FUNCTION__, c->bo->handle, c->name));
143.26356 ++			c->flags = back->flags;
143.26357 ++			list_add(&c->link, &priv->cache);
143.26358 ++			DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, c->bo->handle, c->name, c->flags, c->bo->active_scanout));
143.26359 + 		}
143.26360 ++	} else {
143.26361 ++		if (&c->link != &priv->cache)
143.26362 ++			free(c);
143.26363 + 	}
143.26364 + 
143.26365 ++	assert(bo->active_scanout == 0);
143.26366 + 	assert(bo != get_private(back)->bo);
143.26367 + 	kgem_bo_destroy(&sna->kgem, get_private(back)->bo);
143.26368 + 
143.26369 +@@ -210,21 +360,13 @@ sna_dri2_get_back(struct sna *sna,
143.26370 + 	get_private(back)->size = draw->height << 16 | draw->width;
143.26371 + 	back->pitch = bo->pitch;
143.26372 + 	back->name = name;
143.26373 ++	back->flags = flags;
143.26374 + 
143.26375 +-	get_private(back)->stale = false;
143.26376 +-}
143.26377 +-
143.26378 +-struct dri2_window {
143.26379 +-	DRI2BufferPtr front;
143.26380 +-	struct sna_dri2_event *chain;
143.26381 +-	xf86CrtcPtr crtc;
143.26382 +-	int64_t msc_delta;
143.26383 +-};
143.26384 ++	assert(back->pitch);
143.26385 ++	assert(back->name);
143.26386 + 
143.26387 +-static struct dri2_window *dri2_window(WindowPtr win)
143.26388 +-{
143.26389 +-	assert(win->drawable.type != DRAWABLE_PIXMAP);
143.26390 +-	return ((void **)__get_private(win, sna_window_key))[1];
143.26391 ++out:
143.26392 ++	get_private(back)->stale = false;
143.26393 + }
143.26394 + 
143.26395 + static struct sna_dri2_event *
143.26396 +@@ -232,21 +374,25 @@ dri2_chain(DrawablePtr d)
143.26397 + {
143.26398 + 	struct dri2_window *priv = dri2_window((WindowPtr)d);
143.26399 + 	assert(priv != NULL);
143.26400 ++	assert(priv->chain == NULL || priv->chain->chained);
143.26401 + 	return priv->chain;
143.26402 + }
143.26403 + inline static DRI2BufferPtr dri2_window_get_front(WindowPtr win)
143.26404 + {
143.26405 + 	struct dri2_window *priv = dri2_window(win);
143.26406 ++	assert(priv->front == NULL || get_private(priv->front)->bo->active_scanout);
143.26407 + 	return priv ? priv->front : NULL;
143.26408 + }
143.26409 + #else
143.26410 + inline static void *dri2_window_get_front(WindowPtr win) { return NULL; }
143.26411 ++#define APPLY_DAMAGE 1
143.26412 + #endif
143.26413 + 
143.26414 + #if DRI2INFOREC_VERSION < 6
143.26415 + 
143.26416 + #define xorg_can_triple_buffer() 0
143.26417 + #define swap_limit(d, l) false
143.26418 ++#define mark_stale(b)
143.26419 + 
143.26420 + #else
143.26421 + 
143.26422 +@@ -273,6 +419,8 @@ mark_stale(DRI2BufferPtr back)
143.26423 + 	 * stale frame. (This is mostly useful for tracking down
143.26424 + 	 * driver bugs!)
143.26425 + 	 */
143.26426 ++	DBG(("%s(handle=%d) => %d\n", __FUNCTION__,
143.26427 ++	     get_private(back)->bo->handle, xorg_can_triple_buffer()));
143.26428 + 	get_private(back)->stale = xorg_can_triple_buffer();
143.26429 + }
143.26430 + 
143.26431 +@@ -286,21 +434,29 @@ sna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
143.26432 + static void
143.26433 + sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
143.26434 + {
143.26435 ++	struct sna *sna = to_sna_from_drawable(draw);
143.26436 ++
143.26437 + 	DBG(("%s: reusing buffer pixmap=%ld, attachment=%d, handle=%d, name=%d\n",
143.26438 + 	     __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber,
143.26439 + 	     buffer->attachment, get_private(buffer)->bo->handle, buffer->name));
143.26440 + 	assert(get_private(buffer)->refcnt);
143.26441 +-	assert(get_private(buffer)->bo->refcnt > get_private(buffer)->bo->active_scanout);
143.26442 ++	assert(get_private(buffer)->bo->refcnt >= get_private(buffer)->bo->active_scanout);
143.26443 ++	assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name);
143.26444 + 
143.26445 + 	if (buffer->attachment == DRI2BufferBackLeft &&
143.26446 + 	    draw->type != DRAWABLE_PIXMAP) {
143.26447 +-		DBG(("%s: replacing back buffer\n", __FUNCTION__));
143.26448 +-		sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw));
143.26449 ++		DBG(("%s: replacing back buffer on window %ld\n", __FUNCTION__, draw->id));
143.26450 ++		sna_dri2_get_back(sna, draw, buffer);
143.26451 + 
143.26452 +-		assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
143.26453 + 		assert(get_private(buffer)->bo->refcnt);
143.26454 + 		assert(get_private(buffer)->bo->active_scanout == 0);
143.26455 ++		assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name);
143.26456 ++		DBG(("%s: reusing back buffer handle=%d, name=%d, pitch=%d, age=%d\n",
143.26457 ++		     __FUNCTION__, get_private(buffer)->bo->handle,
143.26458 ++		     buffer->name, buffer->pitch, buffer->flags));
143.26459 + 	}
143.26460 ++
143.26461 ++	kgem_bo_submit(&sna->kgem, get_private(buffer)->bo);
143.26462 + }
143.26463 + 
143.26464 + static bool swap_limit(DrawablePtr draw, int limit)
143.26465 +@@ -314,11 +470,6 @@ static bool swap_limit(DrawablePtr draw, int limit)
143.26466 + }
143.26467 + #endif
143.26468 + 
143.26469 +-#if DRI2INFOREC_VERSION < 10
143.26470 +-#undef USE_ASYNC_SWAP
143.26471 +-#define USE_ASYNC_SWAP 0
143.26472 +-#endif
143.26473 +-
143.26474 + #define COLOR_PREFER_TILING_Y 0
143.26475 + 
143.26476 + /* Prefer to enable TILING_Y if this buffer will never be a
143.26477 +@@ -328,6 +479,9 @@ static uint32_t color_tiling(struct sna *sna, DrawablePtr draw)
143.26478 + {
143.26479 + 	uint32_t tiling;
143.26480 + 
143.26481 ++	if (!sna->kgem.can_fence)
143.26482 ++		return I915_TILING_NONE;
143.26483 ++
143.26484 + 	if (COLOR_PREFER_TILING_Y &&
143.26485 + 	    (draw->width  != sna->front->drawable.width ||
143.26486 + 	     draw->height != sna->front->drawable.height))
143.26487 +@@ -355,7 +509,6 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
143.26488 + 					  PixmapPtr pixmap)
143.26489 + {
143.26490 + 	struct sna_pixmap *priv;
143.26491 +-	int tiling;
143.26492 + 
143.26493 + 	DBG(("%s: attaching DRI client to pixmap=%ld\n",
143.26494 + 	     __FUNCTION__, pixmap->drawable.serialNumber));
143.26495 +@@ -373,31 +526,29 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
143.26496 + 		return NULL;
143.26497 + 	}
143.26498 + 
143.26499 +-	assert(priv->flush == false);
143.26500 ++	assert(priv->flush == false || priv->pinned & PIN_DRI3);
143.26501 ++	assert(priv->gpu_bo->flush == false || priv->pinned & PIN_DRI3);
143.26502 + 	assert(priv->cpu_damage == NULL);
143.26503 + 	assert(priv->gpu_bo);
143.26504 + 	assert(priv->gpu_bo->proxy == NULL);
143.26505 +-	assert(priv->gpu_bo->flush == false);
143.26506 +-
143.26507 +-	tiling = color_tiling(sna, &pixmap->drawable);
143.26508 +-	if (tiling < 0)
143.26509 +-		tiling = -tiling;
143.26510 +-	if (priv->gpu_bo->tiling != tiling)
143.26511 +-		sna_pixmap_change_tiling(pixmap, tiling);
143.26512 + 
143.26513 +-	return priv->gpu_bo;
143.26514 +-}
143.26515 ++	if (!kgem_bo_is_fenced(&sna->kgem, priv->gpu_bo)) {
143.26516 ++		if (priv->gpu_bo->tiling &&
143.26517 ++		    !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
143.26518 ++			DBG(("%s: failed to discard tiling (%d) for DRI2 protocol\n", __FUNCTION__, priv->gpu_bo->tiling));
143.26519 ++			return NULL;
143.26520 ++		}
143.26521 ++	} else {
143.26522 ++		int tiling = color_tiling(sna, &pixmap->drawable);
143.26523 ++		if (tiling < 0)
143.26524 ++			tiling = -tiling;
143.26525 ++		if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout)
143.26526 ++			sna_pixmap_change_tiling(pixmap, tiling);
143.26527 ++	}
143.26528 + 
143.26529 +-pure static inline void *sna_pixmap_get_buffer(PixmapPtr pixmap)
143.26530 +-{
143.26531 +-	assert(pixmap->refcnt);
143.26532 +-	return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
143.26533 +-}
143.26534 ++	priv->gpu_bo->active_scanout++;
143.26535 + 
143.26536 +-static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
143.26537 +-{
143.26538 +-	assert(pixmap->refcnt);
143.26539 +-	((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
143.26540 ++	return priv->gpu_bo;
143.26541 + }
143.26542 + 
143.26543 + void
143.26544 +@@ -422,13 +573,18 @@ sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo)
143.26545 + 	if (private->bo == bo)
143.26546 + 		return;
143.26547 + 
143.26548 ++	assert(private->bo->active_scanout > 0);
143.26549 ++	private->bo->active_scanout--;
143.26550 ++
143.26551 + 	DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
143.26552 + 	private->bo->flush = false;
143.26553 + 	kgem_bo_destroy(&sna->kgem, private->bo);
143.26554 + 
143.26555 ++
143.26556 + 	buffer->name = kgem_bo_flink(&sna->kgem, bo);
143.26557 + 	buffer->pitch = bo->pitch;
143.26558 + 	private->bo = ref(bo);
143.26559 ++	bo->active_scanout++;
143.26560 + 
143.26561 + 	DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle));
143.26562 + 	bo->flush = true;
143.26563 +@@ -449,9 +605,9 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26564 + 	struct sna_dri2_private *private;
143.26565 + 	PixmapPtr pixmap;
143.26566 + 	struct kgem_bo *bo;
143.26567 +-	unsigned flags = 0;
143.26568 ++	unsigned bpp = format ?: draw->bitsPerPixel;
143.26569 ++	unsigned flags = CREATE_EXACT;
143.26570 + 	uint32_t size;
143.26571 +-	int bpp;
143.26572 + 
143.26573 + 	DBG(("%s pixmap=%ld, (attachment=%d, format=%d, drawable=%dx%d), window?=%d\n",
143.26574 + 	     __FUNCTION__,
143.26575 +@@ -468,11 +624,11 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26576 + 		if (draw->type != DRAWABLE_PIXMAP)
143.26577 + 			buffer = dri2_window_get_front((WindowPtr)draw);
143.26578 + 		if (buffer == NULL)
143.26579 +-			buffer = sna_pixmap_get_buffer(pixmap);
143.26580 ++			buffer = (DRI2Buffer2Ptr)sna_pixmap_get_buffer(pixmap);
143.26581 + 		if (buffer) {
143.26582 + 			private = get_private(buffer);
143.26583 + 
143.26584 +-			DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d\n",
143.26585 ++			DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d, active_scanout=%d\n",
143.26586 + 			     __FUNCTION__,
143.26587 + 			     draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0,
143.26588 + 			     draw->width, draw->height,
143.26589 +@@ -480,12 +636,22 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26590 + 			     private->pixmap->drawable.serialNumber,
143.26591 + 			     pixmap->drawable.width,
143.26592 + 			     pixmap->drawable.height,
143.26593 +-			     private->bo->handle, buffer->name));
143.26594 ++			     private->bo->handle, buffer->name,
143.26595 ++			     private->bo->active_scanout));
143.26596 + 
143.26597 ++			assert(buffer->attachment == DRI2BufferFrontLeft);
143.26598 + 			assert(private->pixmap == pixmap);
143.26599 + 			assert(sna_pixmap(pixmap)->flush);
143.26600 + 			assert(sna_pixmap(pixmap)->pinned & PIN_DRI2);
143.26601 + 			assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name);
143.26602 ++			assert(private->bo->pitch == buffer->pitch);
143.26603 ++			assert(private->bo->active_scanout);
143.26604 ++
143.26605 ++			sna_pixmap_move_to_gpu(pixmap,
143.26606 ++					       MOVE_READ |
143.26607 ++					       __MOVE_FORCE |
143.26608 ++					       __MOVE_DRI);
143.26609 ++			kgem_bo_submit(&sna->kgem, private->bo);
143.26610 + 
143.26611 + 			private->refcnt++;
143.26612 + 			return buffer;
143.26613 +@@ -498,7 +664,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26614 + 		assert(sna_pixmap(pixmap) != NULL);
143.26615 + 
143.26616 + 		bo = ref(bo);
143.26617 +-		bpp = pixmap->drawable.bitsPerPixel;
143.26618 + 		if (pixmap == sna->front && !(sna->flags & SNA_LINEAR_FB))
143.26619 + 			flags |= CREATE_SCANOUT;
143.26620 + 		DBG(("%s: attaching to front buffer %dx%d [%p:%d], scanout? %d\n",
143.26621 +@@ -506,6 +671,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26622 + 		     pixmap->drawable.width, pixmap->drawable.height,
143.26623 + 		     pixmap, pixmap->refcnt, flags & CREATE_SCANOUT));
143.26624 + 		size = (uint32_t)pixmap->drawable.height << 16 | pixmap->drawable.width;
143.26625 ++		bpp = pixmap->drawable.bitsPerPixel;
143.26626 + 		break;
143.26627 + 
143.26628 + 	case DRI2BufferBackLeft:
143.26629 +@@ -514,6 +680,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26630 + 				flags |= CREATE_SCANOUT;
143.26631 + 			if (draw->width  == sna->front->drawable.width &&
143.26632 + 			    draw->height == sna->front->drawable.height &&
143.26633 ++			    draw->bitsPerPixel == bpp &&
143.26634 + 			    (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0)
143.26635 + 				flags |= CREATE_SCANOUT;
143.26636 + 		}
143.26637 +@@ -521,7 +688,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26638 + 	case DRI2BufferFrontRight:
143.26639 + 	case DRI2BufferFakeFrontLeft:
143.26640 + 	case DRI2BufferFakeFrontRight:
143.26641 +-		bpp = draw->bitsPerPixel;
143.26642 + 		DBG(("%s: creating back buffer %dx%d, suitable for scanout? %d\n",
143.26643 + 		     __FUNCTION__,
143.26644 + 		     draw->width, draw->height,
143.26645 +@@ -530,7 +696,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26646 + 		bo = kgem_create_2d(&sna->kgem,
143.26647 + 				    draw->width,
143.26648 + 				    draw->height,
143.26649 +-				    draw->bitsPerPixel,
143.26650 ++				    bpp,
143.26651 + 				    color_tiling(sna, draw),
143.26652 + 				    flags);
143.26653 + 		break;
143.26654 +@@ -558,7 +724,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26655 + 		 * not understand W tiling and the GTT is incapable of
143.26656 + 		 * W fencing.
143.26657 + 		 */
143.26658 +-		bpp = format ? format : draw->bitsPerPixel;
143.26659 + 		bpp *= 2;
143.26660 + 		bo = kgem_create_2d(&sna->kgem,
143.26661 + 				    ALIGN(draw->width, 64),
143.26662 +@@ -570,7 +735,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26663 + 	case DRI2BufferDepthStencil:
143.26664 + 	case DRI2BufferHiz:
143.26665 + 	case DRI2BufferAccum:
143.26666 +-		bpp = format ? format : draw->bitsPerPixel,
143.26667 + 		bo = kgem_create_2d(&sna->kgem,
143.26668 + 				    draw->width, draw->height, bpp,
143.26669 + 				    other_tiling(sna, draw),
143.26670 +@@ -614,7 +778,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26671 + 		pixmap->refcnt++;
143.26672 + 
143.26673 + 		priv = sna_pixmap(pixmap);
143.26674 +-		assert(priv->flush == false);
143.26675 ++		assert(priv->flush == false || priv->pinned & PIN_DRI3);
143.26676 + 		assert((priv->pinned & PIN_DRI2) == 0);
143.26677 + 
143.26678 + 		/* Don't allow this named buffer to be replaced */
143.26679 +@@ -630,17 +794,17 @@ sna_dri2_create_buffer(DrawablePtr draw,
143.26680 + 		if (priv->gpu_bo->exec)
143.26681 + 			sna->kgem.flush = 1;
143.26682 + 
143.26683 +-		priv->flush |= 1;
143.26684 ++		priv->flush |= FLUSH_READ;
143.26685 + 		if (draw->type == DRAWABLE_PIXMAP) {
143.26686 + 			/* DRI2 renders directly into GLXPixmaps, treat as hostile */
143.26687 + 			kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
143.26688 + 			sna_damage_all(&priv->gpu_damage, pixmap);
143.26689 + 			priv->clear = false;
143.26690 + 			priv->cpu = false;
143.26691 +-			priv->flush |= 2;
143.26692 ++			priv->flush |= FLUSH_WRITE;
143.26693 + 		}
143.26694 + 
143.26695 +-		sna_accel_watch_flush(sna, 1);
143.26696 ++		sna_watch_flush(sna, 1);
143.26697 + 	}
143.26698 + 
143.26699 + 	return buffer;
143.26700 +@@ -651,16 +815,80 @@ err:
143.26701 + 	return NULL;
143.26702 + }
143.26703 + 
143.26704 +-static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
143.26705 ++static void
143.26706 ++sna_dri2_cache_bo(struct sna *sna,
143.26707 ++		  DrawablePtr draw,
143.26708 ++		  struct kgem_bo *bo,
143.26709 ++		  uint32_t name,
143.26710 ++		  uint32_t size,
143.26711 ++		  uint32_t flags)
143.26712 ++{
143.26713 ++	struct dri_bo *c;
143.26714 ++
143.26715 ++	DBG(("%s(handle=%d, name=%d)\n", __FUNCTION__, bo->handle, name));
143.26716 ++
143.26717 ++	if (draw == NULL) {
143.26718 ++		DBG(("%s: no draw, releasing handle=%d\n",
143.26719 ++		     __FUNCTION__, bo->handle));
143.26720 ++		goto err;
143.26721 ++	}
143.26722 ++
143.26723 ++	if (draw->type == DRAWABLE_PIXMAP) {
143.26724 ++		DBG(("%s: not a window, releasing handle=%d\n",
143.26725 ++		     __FUNCTION__, bo->handle));
143.26726 ++		goto err;
143.26727 ++	}
143.26728 ++
143.26729 ++	if (bo->refcnt > 1 + bo->active_scanout) {
143.26730 ++		DBG(("%s: multiple references [%d], releasing handle\n",
143.26731 ++		     __FUNCTION__, bo->refcnt, bo->handle));
143.26732 ++		goto err;
143.26733 ++	}
143.26734 ++
143.26735 ++	if ((draw->height << 16 | draw->width) != size) {
143.26736 ++		DBG(("%s: wrong size [%dx%d], releasing handle\n",
143.26737 ++		     __FUNCTION__,
143.26738 ++		     size & 0xffff, size >> 16,
143.26739 ++		     bo->handle));
143.26740 ++		goto err;
143.26741 ++	}
143.26742 ++
143.26743 ++	if (bo->scanout && front_pitch(draw) != bo->pitch) {
143.26744 ++		DBG(("%s: scanout with pitch change [%d != %d], releasing handle\n",
143.26745 ++		     __FUNCTION__, bo->pitch, front_pitch(draw), bo->handle));
143.26746 ++		goto err;
143.26747 ++	}
143.26748 ++
143.26749 ++	c = malloc(sizeof(*c));
143.26750 ++	if (!c)
143.26751 ++		goto err;
143.26752 ++
143.26753 ++	DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, bo->handle, name, flags, bo->active_scanout));
143.26754 ++
143.26755 ++	c->bo = bo;
143.26756 ++	c->name = name;
143.26757 ++	c->flags = flags;
143.26758 ++	list_add(&c->link, &dri2_window((WindowPtr)draw)->cache);
143.26759 ++	return;
143.26760 ++
143.26761 ++err:
143.26762 ++	kgem_bo_destroy(&sna->kgem, bo);
143.26763 ++}
143.26764 ++
143.26765 ++static void _sna_dri2_destroy_buffer(struct sna *sna,
143.26766 ++				     DrawablePtr draw,
143.26767 ++				     DRI2Buffer2Ptr buffer)
143.26768 + {
143.26769 + 	struct sna_dri2_private *private = get_private(buffer);
143.26770 + 
143.26771 + 	if (buffer == NULL)
143.26772 + 		return;
143.26773 + 
143.26774 +-	DBG(("%s: %p [handle=%d] -- refcnt=%d, pixmap=%ld\n",
143.26775 ++	DBG(("%s: %p [handle=%d] -- refcnt=%d, draw=%ld, pixmap=%ld, proxy?=%d\n",
143.26776 + 	     __FUNCTION__, buffer, private->bo->handle, private->refcnt,
143.26777 +-	     private->pixmap ? private->pixmap->drawable.serialNumber : 0));
143.26778 ++	     draw ? draw->id : 0,
143.26779 ++	     private->pixmap ? private->pixmap->drawable.serialNumber : 0,
143.26780 ++	     private->proxy != NULL));
143.26781 + 	assert(private->refcnt > 0);
143.26782 + 	if (--private->refcnt)
143.26783 + 		return;
143.26784 +@@ -669,7 +897,10 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
143.26785 + 
143.26786 + 	if (private->proxy) {
143.26787 + 		DBG(("%s: destroying proxy\n", __FUNCTION__));
143.26788 +-		_sna_dri2_destroy_buffer(sna, private->proxy);
143.26789 ++		assert(private->bo->active_scanout > 0);
143.26790 ++		private->bo->active_scanout--;
143.26791 ++
143.26792 ++		_sna_dri2_destroy_buffer(sna, draw, private->proxy);
143.26793 + 		private->pixmap = NULL;
143.26794 + 	}
143.26795 + 
143.26796 +@@ -683,6 +914,11 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
143.26797 + 		assert(priv->pinned & PIN_DRI2);
143.26798 + 		assert(priv->flush);
143.26799 + 
143.26800 ++		DBG(("%s: removing active_scanout=%d from pixmap handle=%d\n",
143.26801 ++		     __FUNCTION__, priv->gpu_bo->active_scanout, priv->gpu_bo->handle));
143.26802 ++		assert(priv->gpu_bo->active_scanout > 0);
143.26803 ++		priv->gpu_bo->active_scanout--;
143.26804 ++
143.26805 + 		/* Undo the DRI markings on this pixmap */
143.26806 + 		DBG(("%s: releasing last DRI pixmap=%ld, scanout?=%d\n",
143.26807 + 		     __FUNCTION__,
143.26808 +@@ -692,28 +928,34 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
143.26809 + 		list_del(&priv->flush_list);
143.26810 + 
143.26811 + 		DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
143.26812 +-		priv->gpu_bo->flush = false;
143.26813 + 		priv->pinned &= ~PIN_DRI2;
143.26814 + 
143.26815 +-		priv->flush = false;
143.26816 +-		sna_accel_watch_flush(sna, -1);
143.26817 ++		if ((priv->pinned & PIN_DRI3) == 0) {
143.26818 ++			priv->gpu_bo->flush = false;
143.26819 ++			priv->flush = false;
143.26820 ++		}
143.26821 ++		sna_watch_flush(sna, -1);
143.26822 + 
143.26823 + 		sna_pixmap_set_buffer(pixmap, NULL);
143.26824 + 		pixmap->drawable.pScreen->DestroyPixmap(pixmap);
143.26825 + 	}
143.26826 +-	assert(private->bo->flush == false);
143.26827 + 
143.26828 +-	kgem_bo_destroy(&sna->kgem, private->bo);
143.26829 ++	sna_dri2_cache_bo(sna, draw,
143.26830 ++			  private->bo,
143.26831 ++			  buffer->name,
143.26832 ++			  private->size,
143.26833 ++			  buffer->flags);
143.26834 + 	free(buffer);
143.26835 + }
143.26836 + 
143.26837 + static void sna_dri2_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer)
143.26838 + {
143.26839 +-	_sna_dri2_destroy_buffer(to_sna_from_drawable(draw), buffer);
143.26840 ++	_sna_dri2_destroy_buffer(to_sna_from_drawable(draw), draw, buffer);
143.26841 + }
143.26842 + 
143.26843 + static DRI2BufferPtr sna_dri2_reference_buffer(DRI2BufferPtr buffer)
143.26844 + {
143.26845 ++	assert(get_private(buffer)->refcnt > 0);
143.26846 + 	get_private(buffer)->refcnt++;
143.26847 + 	return buffer;
143.26848 + }
143.26849 +@@ -746,10 +988,9 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
143.26850 + {
143.26851 + 	struct sna *sna = to_sna_from_pixmap(pixmap);
143.26852 + 	struct sna_pixmap *priv = sna_pixmap(pixmap);
143.26853 +-	RegionRec region;
143.26854 + 
143.26855 +-	DBG(("%s: pixmap=%ld, handle=%d\n",
143.26856 +-	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle));
143.26857 ++	DBG(("%s: pixmap=%ld, handle=%d (old handle=%d)\n",
143.26858 ++	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, priv->gpu_bo->handle));
143.26859 + 
143.26860 + 	assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch);
143.26861 + 	assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo));
143.26862 +@@ -758,21 +999,34 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
143.26863 + 	assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0);
143.26864 + 	assert(priv->flush);
143.26865 + 
143.26866 +-	/* Post damage on the new front buffer so that listeners, such
143.26867 +-	 * as DisplayLink know take a copy and shove it over the USB,
143.26868 +-	 * also for software cursors and the like.
143.26869 +-	 */
143.26870 +-	region.extents.x1 = region.extents.y1 = 0;
143.26871 +-	region.extents.x2 = pixmap->drawable.width;
143.26872 +-	region.extents.y2 = pixmap->drawable.height;
143.26873 +-	region.data = NULL;
143.26874 +-	DamageRegionAppend(&pixmap->drawable, &region);
143.26875 ++	if (APPLY_DAMAGE) {
143.26876 ++		RegionRec region;
143.26877 ++
143.26878 ++		/* Post damage on the new front buffer so that listeners, such
143.26879 ++		 * as DisplayLink know take a copy and shove it over the USB,
143.26880 ++		 * also for software cursors and the like.
143.26881 ++		 */
143.26882 ++		region.extents.x1 = region.extents.y1 = 0;
143.26883 ++		region.extents.x2 = pixmap->drawable.width;
143.26884 ++		region.extents.y2 = pixmap->drawable.height;
143.26885 ++		region.data = NULL;
143.26886 ++
143.26887 ++		/*
143.26888 ++		 * Eeek, beware the sw cursor copying to the old bo
143.26889 ++		 * causing recursion and mayhem.
143.26890 ++		 */
143.26891 ++		DBG(("%s: marking whole pixmap as damaged\n", __FUNCTION__));
143.26892 ++		sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
143.26893 ++		DamageRegionAppend(&pixmap->drawable, &region);
143.26894 ++	}
143.26895 + 
143.26896 + 	damage(pixmap, priv, NULL);
143.26897 + 
143.26898 + 	assert(bo->refcnt);
143.26899 +-	if (priv->move_to_gpu)
143.26900 ++	if (priv->move_to_gpu) {
143.26901 ++		DBG(("%s: applying final/discard move-to-gpu\n", __FUNCTION__));
143.26902 + 		priv->move_to_gpu(sna, priv, 0);
143.26903 ++	}
143.26904 + 	if (priv->gpu_bo != bo) {
143.26905 + 		DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
143.26906 + 		priv->gpu_bo->flush = false;
143.26907 +@@ -792,8 +1046,27 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
143.26908 + 		bo->domain = DOMAIN_NONE;
143.26909 + 	assert(bo->flush);
143.26910 + 
143.26911 +-	DamageRegionProcessPending(&pixmap->drawable);
143.26912 ++	if (APPLY_DAMAGE) {
143.26913 ++		sna->ignore_copy_area = false;
143.26914 ++		DamageRegionProcessPending(&pixmap->drawable);
143.26915 ++	}
143.26916 ++}
143.26917 ++
143.26918 ++#if defined(__GNUC__)
143.26919 ++#define popcount(x) __builtin_popcount(x)
143.26920 ++#else
143.26921 ++static int popcount(unsigned int x)
143.26922 ++{
143.26923 ++	int count = 0;
143.26924 ++
143.26925 ++	while (x) {
143.26926 ++		count += x&1;
143.26927 ++		x >>= 1;
143.26928 ++	}
143.26929 ++
143.26930 ++	return count;
143.26931 + }
143.26932 ++#endif
143.26933 + 
143.26934 + static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync)
143.26935 + {
143.26936 +@@ -823,6 +1096,12 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg
143.26937 + 		return;
143.26938 + 	}
143.26939 + 
143.26940 ++	if (sna->render_state.gt < 2 && sna->kgem.has_semaphores) {
143.26941 ++		DBG(("%s: small GT [%d], not forcing selection\n",
143.26942 ++		     __FUNCTION__, sna->render_state.gt));
143.26943 ++		return;
143.26944 ++	}
143.26945 ++
143.26946 + 	VG_CLEAR(busy);
143.26947 + 	busy.handle = src->handle;
143.26948 + 	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy))
143.26949 +@@ -860,9 +1139,11 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg
143.26950 + 	 * the cost of the query.
143.26951 + 	 */
143.26952 + 	mode = KGEM_RENDER;
143.26953 +-	if (busy.busy & (0xfffe << 16))
143.26954 ++	if ((busy.busy & 0xffff) == I915_EXEC_BLT)
143.26955 + 		mode = KGEM_BLT;
143.26956 +-	kgem_bo_mark_busy(&sna->kgem, busy.handle == src->handle ? src : dst, mode);
143.26957 ++	kgem_bo_mark_busy(&sna->kgem,
143.26958 ++			  busy.handle == src->handle ? src : dst,
143.26959 ++			  mode);
143.26960 + 	_kgem_set_mode(&sna->kgem, mode);
143.26961 + }
143.26962 + 
143.26963 +@@ -871,10 +1152,13 @@ static bool is_front(int attachment)
143.26964 + 	return attachment == DRI2BufferFrontLeft;
143.26965 + }
143.26966 + 
143.26967 ++#define DRI2_SYNC 0x1
143.26968 ++#define DRI2_DAMAGE 0x2
143.26969 ++#define DRI2_BO 0x4
143.26970 + static struct kgem_bo *
143.26971 + __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.26972 + 		      DRI2BufferPtr src, DRI2BufferPtr dst,
143.26973 +-		      bool sync)
143.26974 ++		      unsigned flags)
143.26975 + {
143.26976 + 	PixmapPtr pixmap = get_drawable_pixmap(draw);
143.26977 + 	DrawableRec scratch, *src_draw = &pixmap->drawable, *dst_draw = &pixmap->drawable;
143.26978 +@@ -886,7 +1170,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.26979 + 	struct kgem_bo *dst_bo;
143.26980 + 	const BoxRec *boxes;
143.26981 + 	int16_t dx, dy, sx, sy;
143.26982 +-	unsigned flags;
143.26983 ++	unsigned hint;
143.26984 + 	int n;
143.26985 + 
143.26986 + 	/* To hide a stale DRI2Buffer, one may choose to substitute
143.26987 +@@ -962,8 +1246,9 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.26988 + 			}
143.26989 + 		}
143.26990 + 	} else
143.26991 +-		sync = false;
143.26992 ++		flags &= ~DRI2_SYNC;
143.26993 + 
143.26994 ++	scratch.pScreen = draw->pScreen;
143.26995 + 	scratch.x = scratch.y = 0;
143.26996 + 	scratch.width = scratch.height = 0;
143.26997 + 	scratch.depth = draw->depth;
143.26998 +@@ -971,6 +1256,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.26999 + 
143.27000 + 	src_bo = src_priv->bo;
143.27001 + 	assert(src_bo->refcnt);
143.27002 ++	kgem_bo_unclean(&sna->kgem, src_bo);
143.27003 + 	if (is_front(src->attachment)) {
143.27004 + 		struct sna_pixmap *priv;
143.27005 + 
143.27006 +@@ -987,11 +1273,12 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.27007 + 		scratch.height = src_priv->size >> 16;
143.27008 + 		src_draw = &scratch;
143.27009 + 
143.27010 +-		DBG(("%s: source size %dx%d, region size %dx%d\n",
143.27011 ++		DBG(("%s: source size %dx%d, region size %dx%d, src offset %dx%d\n",
143.27012 + 		     __FUNCTION__,
143.27013 + 		     scratch.width, scratch.height,
143.27014 + 		     clip.extents.x2 - clip.extents.x1,
143.27015 +-		     clip.extents.y2 - clip.extents.y1));
143.27016 ++		     clip.extents.y2 - clip.extents.y1,
143.27017 ++		     -sx, -sy));
143.27018 + 
143.27019 + 		source.extents.x1 = -sx;
143.27020 + 		source.extents.y1 = -sy;
143.27021 +@@ -1002,6 +1289,10 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.27022 + 		assert(region == NULL || region == &clip);
143.27023 + 		pixman_region_intersect(&clip, &clip, &source);
143.27024 + 
143.27025 ++		if (!pixman_region_not_empty(&clip)) {
143.27026 ++			DBG(("%s: region doesn't overlap pixmap\n", __FUNCTION__));
143.27027 ++			return NULL;
143.27028 ++		}
143.27029 + 	}
143.27030 + 
143.27031 + 	dst_bo = dst_priv->bo;
143.27032 +@@ -1013,12 +1304,12 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.27033 + 		/* Preserve the CRTC shadow overrides */
143.27034 + 		sna_shadow_steal_crtcs(sna, &shadow);
143.27035 + 
143.27036 +-		flags = MOVE_WRITE | __MOVE_FORCE;
143.27037 ++		hint = MOVE_WRITE | __MOVE_FORCE;
143.27038 + 		if (clip.data)
143.27039 +-			flags |= MOVE_READ;
143.27040 ++			hint |= MOVE_READ;
143.27041 + 
143.27042 + 		assert(region == NULL || region == &clip);
143.27043 +-		priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, flags);
143.27044 ++		priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, hint);
143.27045 + 		if (priv) {
143.27046 + 			damage(pixmap, priv, region);
143.27047 + 			dst_bo = priv->gpu_bo;
143.27048 +@@ -1050,20 +1341,20 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.27049 + 		assert(region == NULL || region == &clip);
143.27050 + 		pixman_region_intersect(&clip, &clip, &target);
143.27051 + 
143.27052 +-		sync = false;
143.27053 ++		flags &= ~DRI2_SYNC;
143.27054 + 	}
143.27055 + 
143.27056 + 	if (!wedged(sna)) {
143.27057 + 		xf86CrtcPtr crtc;
143.27058 + 
143.27059 + 		crtc = NULL;
143.27060 +-		if (sync && sna_pixmap_is_scanout(sna, pixmap))
143.27061 ++		if (flags & DRI2_SYNC && sna_pixmap_is_scanout(sna, pixmap))
143.27062 + 			crtc = sna_covering_crtc(sna, &clip.extents, NULL);
143.27063 + 		sna_dri2_select_mode(sna, dst_bo, src_bo, crtc != NULL);
143.27064 + 
143.27065 +-		sync = (crtc != NULL&&
143.27066 +-			sna_wait_for_scanline(sna, pixmap, crtc,
143.27067 +-					      &clip.extents));
143.27068 ++		if (crtc == NULL ||
143.27069 ++		    !sna_wait_for_scanline(sna, pixmap, crtc, &clip.extents))
143.27070 ++			flags &= ~DRI2_SYNC;
143.27071 + 	}
143.27072 + 
143.27073 + 	if (region) {
143.27074 +@@ -1075,8 +1366,11 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.27075 + 		boxes = &clip.extents;
143.27076 + 		n = 1;
143.27077 + 	}
143.27078 +-	DamageRegionAppend(&pixmap->drawable, region);
143.27079 +-
143.27080 ++	if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
143.27081 ++		DBG(("%s: marking region as damaged\n", __FUNCTION__));
143.27082 ++		sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
143.27083 ++		DamageRegionAppend(&pixmap->drawable, region);
143.27084 ++	}
143.27085 + 
143.27086 + 	DBG(("%s: copying [(%d, %d), (%d, %d)]x%d src=(%d, %d), dst=(%d, %d)\n",
143.27087 + 	     __FUNCTION__,
143.27088 +@@ -1084,29 +1378,36 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
143.27089 + 	     boxes[0].x2, boxes[0].y2,
143.27090 + 	     n, sx, sy, dx, dy));
143.27091 + 
143.27092 +-	flags = COPY_LAST;
143.27093 +-	if (sync)
143.27094 +-		flags |= COPY_SYNC;
143.27095 ++	hint = COPY_LAST | COPY_DRI;
143.27096 ++	if (flags & DRI2_SYNC)
143.27097 ++		hint |= COPY_SYNC;
143.27098 + 	if (!sna->render.copy_boxes(sna, GXcopy,
143.27099 + 				    src_draw, src_bo, sx, sy,
143.27100 + 				    dst_draw, dst_bo, dx, dy,
143.27101 +-				    boxes, n, flags))
143.27102 ++				    boxes, n, hint))
143.27103 + 		memcpy_copy_boxes(sna, GXcopy,
143.27104 + 				  src_draw, src_bo, sx, sy,
143.27105 + 				  dst_draw, dst_bo, dx, dy,
143.27106 +-				  boxes, n, flags);
143.27107 +-
143.27108 +-	DBG(("%s: flushing? %d\n", __FUNCTION__, sync));
143.27109 +-	if (sync) { /* STAT! */
143.27110 +-		struct kgem_request *rq = sna->kgem.next_request;
143.27111 +-		kgem_submit(&sna->kgem);
143.27112 +-		if (rq->bo) {
143.27113 +-			bo = ref(rq->bo);
143.27114 +-			DBG(("%s: recording sync fence handle=%d\n", __FUNCTION__, bo->handle));
143.27115 ++				  boxes, n, hint);
143.27116 ++
143.27117 ++	sna->needs_dri_flush = true;
143.27118 ++	if (flags & (DRI2_SYNC | DRI2_BO)) { /* STAT! */
143.27119 ++		struct kgem_request *rq = RQ(dst_bo->rq);
143.27120 ++		if (rq && rq != (void *)&sna->kgem) {
143.27121 ++			if (rq->bo == NULL)
143.27122 ++				kgem_submit(&sna->kgem);
143.27123 ++			if (rq->bo) { /* Becareful in case the gpu is wedged */
143.27124 ++				bo = ref(rq->bo);
143.27125 ++				DBG(("%s: recording sync fence handle=%d\n",
143.27126 ++				     __FUNCTION__, bo->handle));
143.27127 ++			}
143.27128 + 		}
143.27129 + 	}
143.27130 + 
143.27131 +-	DamageRegionProcessPending(&pixmap->drawable);
143.27132 ++	if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
143.27133 ++		sna->ignore_copy_area = false;
143.27134 ++		DamageRegionProcessPending(&pixmap->drawable);
143.27135 ++	}
143.27136 + 
143.27137 + 	if (clip.data)
143.27138 + 		pixman_region_fini(&clip);
143.27139 +@@ -1142,6 +1443,8 @@ sna_dri2_copy_region(DrawablePtr draw,
143.27140 + 	assert(get_private(src)->refcnt);
143.27141 + 	assert(get_private(dst)->refcnt);
143.27142 + 
143.27143 ++	assert(get_private(src)->bo != get_private(dst)->bo);
143.27144 ++
143.27145 + 	assert(get_private(src)->bo->refcnt);
143.27146 + 	assert(get_private(dst)->bo->refcnt);
143.27147 + 
143.27148 +@@ -1151,7 +1454,7 @@ sna_dri2_copy_region(DrawablePtr draw,
143.27149 + 	     region->extents.x2, region->extents.y2,
143.27150 + 	     region_num_rects(region)));
143.27151 + 
143.27152 +-	__sna_dri2_copy_region(sna, draw, region, src, dst, false);
143.27153 ++	__sna_dri2_copy_region(sna, draw, region, src, dst, DRI2_DAMAGE);
143.27154 + }
143.27155 + 
143.27156 + inline static uint32_t pipe_select(int pipe)
143.27157 +@@ -1161,6 +1464,7 @@ inline static uint32_t pipe_select(int pipe)
143.27158 + 	 * we can safely ignore the capability check - if we have more
143.27159 + 	 * than two pipes, we can assume that they are fully supported.
143.27160 + 	 */
143.27161 ++	assert(pipe < _DRM_VBLANK_HIGH_CRTC_MASK);
143.27162 + 	if (pipe > 1)
143.27163 + 		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
143.27164 + 	else if (pipe > 0)
143.27165 +@@ -1169,15 +1473,53 @@ inline static uint32_t pipe_select(int pipe)
143.27166 + 		return 0;
143.27167 + }
143.27168 + 
143.27169 +-static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, int pipe)
143.27170 ++static inline bool sna_next_vblank(struct sna_dri2_event *info)
143.27171 + {
143.27172 +-	DBG(("%s(pipe=%d, waiting until seq=%u%s)\n",
143.27173 +-	     __FUNCTION__, pipe, vbl->request.sequence,
143.27174 +-	     vbl->request.type & DRM_VBLANK_RELATIVE ? " [relative]" : ""));
143.27175 +-	assert(pipe != -1);
143.27176 ++	union drm_wait_vblank vbl;
143.27177 + 
143.27178 +-	vbl->request.type |= pipe_select(pipe);
143.27179 +-	return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
143.27180 ++	DBG(("%s(pipe=%d, waiting until next vblank)\n",
143.27181 ++	     __FUNCTION__, info->pipe));
143.27182 ++	assert(info->pipe != -1);
143.27183 ++
143.27184 ++	VG_CLEAR(vbl);
143.27185 ++	vbl.request.type =
143.27186 ++		DRM_VBLANK_RELATIVE |
143.27187 ++		DRM_VBLANK_EVENT |
143.27188 ++		pipe_select(info->pipe);
143.27189 ++	vbl.request.sequence = 1;
143.27190 ++	vbl.request.signal = (uintptr_t)info;
143.27191 ++
143.27192 ++	assert(!info->queued);
143.27193 ++	if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
143.27194 ++		return false;
143.27195 ++
143.27196 ++	info->queued = true;
143.27197 ++	return true;
143.27198 ++}
143.27199 ++
143.27200 ++static inline bool sna_wait_vblank(struct sna_dri2_event *info,
143.27201 ++				   unsigned seq)
143.27202 ++{
143.27203 ++	union drm_wait_vblank vbl;
143.27204 ++
143.27205 ++	DBG(("%s(pipe=%d, waiting until vblank %u)\n",
143.27206 ++	     __FUNCTION__, info->pipe, seq));
143.27207 ++	assert(info->pipe != -1);
143.27208 ++
143.27209 ++	VG_CLEAR(vbl);
143.27210 ++	vbl.request.type =
143.27211 ++		DRM_VBLANK_ABSOLUTE |
143.27212 ++		DRM_VBLANK_EVENT |
143.27213 ++		pipe_select(info->pipe);
143.27214 ++	vbl.request.sequence = seq;
143.27215 ++	vbl.request.signal = (uintptr_t)info;
143.27216 ++
143.27217 ++	assert(!info->queued);
143.27218 ++	if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
143.27219 ++		return false;
143.27220 ++
143.27221 ++	info->queued = true;
143.27222 ++	return true;
143.27223 + }
143.27224 + 
143.27225 + #if DRI2INFOREC_VERSION >= 4
143.27226 +@@ -1195,6 +1537,7 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
143.27227 + {
143.27228 + 	struct dri2_window *priv;
143.27229 + 
143.27230 ++	assert(draw);
143.27231 + 	if (draw->type != DRAWABLE_WINDOW)
143.27232 + 		return msc;
143.27233 + 
143.27234 +@@ -1206,6 +1549,9 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
143.27235 + 			priv->crtc = crtc;
143.27236 + 			priv->msc_delta = 0;
143.27237 + 			priv->chain = NULL;
143.27238 ++			priv->scanout = -1;
143.27239 ++			priv->cache_size = 0;
143.27240 ++			list_init(&priv->cache);
143.27241 + 			dri2_window_attach((WindowPtr)draw, priv);
143.27242 + 		}
143.27243 + 	} else {
143.27244 +@@ -1214,8 +1560,8 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
143.27245 + 			const struct ust_msc *this = sna_crtc_last_swap(crtc);
143.27246 + 			DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n",
143.27247 + 			     __FUNCTION__,
143.27248 +-			     sna_crtc_to_pipe(priv->crtc), (long long)last->msc,
143.27249 +-			     sna_crtc_to_pipe(crtc), (long long)this->msc,
143.27250 ++			     sna_crtc_pipe(priv->crtc), (long long)last->msc,
143.27251 ++			     sna_crtc_pipe(crtc), (long long)this->msc,
143.27252 + 			     (long long)(priv->msc_delta + this->msc - last->msc)));
143.27253 + 			priv->msc_delta += this->msc - last->msc;
143.27254 + 			priv->crtc = crtc;
143.27255 +@@ -1248,57 +1594,119 @@ sna_dri2_get_crtc(DrawablePtr draw)
143.27256 + 				 NULL);
143.27257 + }
143.27258 + 
143.27259 +-static void
143.27260 +-sna_dri2_remove_event(WindowPtr win, struct sna_dri2_event *info)
143.27261 ++static void frame_swap_complete(struct sna_dri2_event *frame, int type)
143.27262 + {
143.27263 +-	struct dri2_window *priv;
143.27264 +-	struct sna_dri2_event *chain;
143.27265 +-
143.27266 +-	assert(win->drawable.type == DRAWABLE_WINDOW);
143.27267 +-	DBG(("%s: remove[%p] from window %ld, active? %d\n",
143.27268 +-	     __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
143.27269 ++	const struct ust_msc *swap;
143.27270 + 
143.27271 +-	priv = dri2_window(win);
143.27272 +-	assert(priv);
143.27273 +-	assert(priv->chain != NULL);
143.27274 ++	assert(frame->signal);
143.27275 ++	frame->signal = false;
143.27276 + 
143.27277 +-	if (priv->chain == info) {
143.27278 +-		priv->chain = info->chain;
143.27279 ++	if (frame->client == NULL) {
143.27280 ++		DBG(("%s: client already gone\n", __FUNCTION__));
143.27281 + 		return;
143.27282 + 	}
143.27283 + 
143.27284 +-	chain = priv->chain;
143.27285 +-	while (chain->chain != info)
143.27286 +-		chain = chain->chain;
143.27287 +-	assert(chain != info);
143.27288 +-	assert(info->chain != chain);
143.27289 +-	chain->chain = info->chain;
143.27290 ++	assert(frame->draw);
143.27291 ++
143.27292 ++	swap = sna_crtc_last_swap(frame->crtc);
143.27293 ++	DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
143.27294 ++	     __FUNCTION__, type, (long)frame->draw->id, frame->pipe,
143.27295 ++	     (long long)swap->msc,
143.27296 ++	     (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
143.27297 ++	     swap->tv_sec, swap->tv_usec));
143.27298 ++
143.27299 ++	DRI2SwapComplete(frame->client, frame->draw,
143.27300 ++			 draw_current_msc(frame->draw, frame->crtc, swap->msc),
143.27301 ++			 swap->tv_sec, swap->tv_usec,
143.27302 ++			 type, frame->event_complete, frame->event_data);
143.27303 + }
143.27304 + 
143.27305 +-static void
143.27306 +-sna_dri2_event_free(struct sna_dri2_event *info)
143.27307 ++static void fake_swap_complete(struct sna *sna, ClientPtr client,
143.27308 ++			       DrawablePtr draw, xf86CrtcPtr crtc,
143.27309 ++			       int type, DRI2SwapEventPtr func, void *data)
143.27310 + {
143.27311 +-	DrawablePtr draw = info->draw;
143.27312 ++	const struct ust_msc *swap;
143.27313 + 
143.27314 +-	DBG(("%s(draw?=%d)\n", __FUNCTION__, draw != NULL));
143.27315 +-	if (draw && draw->type == DRAWABLE_WINDOW)
143.27316 +-		sna_dri2_remove_event((WindowPtr)draw, info);
143.27317 ++	assert(draw);
143.27318 + 
143.27319 +-	_sna_dri2_destroy_buffer(info->sna, info->front);
143.27320 +-	_sna_dri2_destroy_buffer(info->sna, info->back);
143.27321 ++	if (crtc == NULL)
143.27322 ++		crtc = sna_primary_crtc(sna);
143.27323 + 
143.27324 +-	while (!list_is_empty(&info->cache)) {
143.27325 +-		struct dri_bo *c;
143.27326 ++	swap = sna_crtc_last_swap(crtc);
143.27327 ++	DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
143.27328 ++	     __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_pipe(crtc) : -1,
143.27329 ++	     (long long)swap->msc,
143.27330 ++	     (long long)draw_current_msc(draw, crtc, swap->msc),
143.27331 ++	     swap->tv_sec, swap->tv_usec));
143.27332 + 
143.27333 +-		c = list_first_entry(&info->cache, struct dri_bo, link);
143.27334 +-		list_del(&c->link);
143.27335 ++	DRI2SwapComplete(client, draw,
143.27336 ++			 draw_current_msc(draw, crtc, swap->msc),
143.27337 ++			 swap->tv_sec, swap->tv_usec,
143.27338 ++			 type, func, data);
143.27339 ++}
143.27340 + 
143.27341 +-		DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
143.27342 +-		if (c->bo)
143.27343 +-			kgem_bo_destroy(&info->sna->kgem, c->bo);
143.27344 ++static void
143.27345 ++sna_dri2_remove_event(struct sna_dri2_event *info)
143.27346 ++{
143.27347 ++	WindowPtr win = (WindowPtr)info->draw;
143.27348 ++	struct dri2_window *priv;
143.27349 + 
143.27350 +-		free(c);
143.27351 ++	assert(win->drawable.type == DRAWABLE_WINDOW);
143.27352 ++	DBG(("%s: remove[%p] from window %ld, active? %d\n",
143.27353 ++	     __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
143.27354 ++	assert(!info->signal);
143.27355 ++
143.27356 ++	priv = dri2_window(win);
143.27357 ++	assert(priv);
143.27358 ++	assert(priv->chain != NULL);
143.27359 ++	assert(info->chained);
143.27360 ++	info->chained = false;
143.27361 ++
143.27362 ++	if (priv->chain != info) {
143.27363 ++		struct sna_dri2_event *chain = priv->chain;
143.27364 ++		while (chain->chain != info) {
143.27365 ++			assert(chain->chained);
143.27366 ++			chain = chain->chain;
143.27367 ++		}
143.27368 ++		assert(chain != info);
143.27369 ++		assert(info->chain != chain);
143.27370 ++		chain->chain = info->chain;
143.27371 ++		return;
143.27372 ++	}
143.27373 ++
143.27374 ++	priv->chain = info->chain;
143.27375 ++	if (priv->chain == NULL) {
143.27376 ++		struct dri_bo *c, *tmp;
143.27377 ++
143.27378 ++		c = list_entry(priv->cache.next->next, struct dri_bo, link);
143.27379 ++		list_for_each_entry_safe_from(c, tmp, &priv->cache, link) {
143.27380 ++			list_del(&c->link);
143.27381 ++
143.27382 ++			DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
143.27383 ++			assert(c->bo);
143.27384 ++			kgem_bo_destroy(&info->sna->kgem, c->bo);
143.27385 ++			free(c);
143.27386 ++		}
143.27387 + 	}
143.27388 ++}
143.27389 ++
143.27390 ++static void
143.27391 ++sna_dri2_event_free(struct sna_dri2_event *info)
143.27392 ++{
143.27393 ++	DBG(("%s(draw?=%d)\n", __FUNCTION__, info->draw != NULL));
143.27394 ++	assert(!info->queued);
143.27395 ++	assert(!info->signal);
143.27396 ++	assert(info->pending.bo == NULL);
143.27397 ++
143.27398 ++	if (info->sna->dri2.flip_pending == info)
143.27399 ++		info->sna->dri2.flip_pending = NULL;
143.27400 ++	assert(info->sna->dri2.flip_pending != info);
143.27401 ++	if (info->chained)
143.27402 ++		sna_dri2_remove_event(info);
143.27403 ++
143.27404 ++	assert((info->front == NULL && info->back == NULL) || info->front != info->back);
143.27405 ++	_sna_dri2_destroy_buffer(info->sna, info->draw, info->front);
143.27406 ++	_sna_dri2_destroy_buffer(info->sna, info->draw, info->back);
143.27407 + 
143.27408 + 	if (info->bo) {
143.27409 + 		DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
143.27410 +@@ -1331,15 +1739,26 @@ sna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data)
143.27411 + 
143.27412 + 		event = list_first_entry(&priv->events, struct sna_dri2_event, link);
143.27413 + 		assert(event->client == client);
143.27414 ++		list_del(&event->link);
143.27415 ++		event->signal = false;
143.27416 + 
143.27417 +-		if (event->queued) {
143.27418 +-			if (event->draw)
143.27419 +-				sna_dri2_remove_event((WindowPtr)event->draw,
143.27420 +-						      event);
143.27421 +-			event->client = NULL;
143.27422 +-			event->draw = NULL;
143.27423 +-			list_del(&event->link);
143.27424 +-		} else
143.27425 ++		if (event->pending.bo) {
143.27426 ++			assert(event->pending.bo->active_scanout > 0);
143.27427 ++			event->pending.bo->active_scanout--;
143.27428 ++
143.27429 ++			kgem_bo_destroy(&sna->kgem, event->pending.bo);
143.27430 ++			event->pending.bo = NULL;
143.27431 ++		}
143.27432 ++
143.27433 ++		if (event->chained)
143.27434 ++			sna_dri2_remove_event(event);
143.27435 ++
143.27436 ++		event->client = NULL;
143.27437 ++		event->draw = NULL;
143.27438 ++		event->keepalive = 1;
143.27439 ++		assert(!event->signal);
143.27440 ++
143.27441 ++		if (!event->queued)
143.27442 + 			sna_dri2_event_free(event);
143.27443 + 	}
143.27444 + 
143.27445 +@@ -1365,11 +1784,15 @@ static bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, Cl
143.27446 + }
143.27447 + 
143.27448 + static struct sna_dri2_event *
143.27449 +-sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
143.27450 ++sna_dri2_add_event(struct sna *sna,
143.27451 ++		   DrawablePtr draw,
143.27452 ++		   ClientPtr client,
143.27453 ++		   xf86CrtcPtr crtc)
143.27454 + {
143.27455 + 	struct dri2_window *priv;
143.27456 + 	struct sna_dri2_event *info, *chain;
143.27457 + 
143.27458 ++	assert(draw != NULL);
143.27459 + 	assert(draw->type == DRAWABLE_WINDOW);
143.27460 + 	DBG(("%s: adding event to window %ld)\n",
143.27461 + 	     __FUNCTION__, (long)draw->id));
143.27462 +@@ -1382,11 +1805,11 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
143.27463 + 	if (info == NULL)
143.27464 + 		return NULL;
143.27465 + 
143.27466 +-	list_init(&info->cache);
143.27467 + 	info->sna = sna;
143.27468 + 	info->draw = draw;
143.27469 +-	info->crtc = priv->crtc;
143.27470 +-	info->pipe = sna_crtc_to_pipe(priv->crtc);
143.27471 ++	info->crtc = crtc;
143.27472 ++	info->pipe = sna_crtc_pipe(crtc);
143.27473 ++	info->keepalive = 1;
143.27474 + 
143.27475 + 	if (!add_event_to_client(info, sna, client)) {
143.27476 + 		free(info);
143.27477 +@@ -1394,6 +1817,7 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
143.27478 + 	}
143.27479 + 
143.27480 + 	assert(priv->chain != info);
143.27481 ++	info->chained = true;
143.27482 + 
143.27483 + 	if (priv->chain == NULL) {
143.27484 + 		priv->chain = info;
143.27485 +@@ -1409,6 +1833,66 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
143.27486 + 	return info;
143.27487 + }
143.27488 + 
143.27489 ++static void decouple_window(WindowPtr win,
143.27490 ++			    struct dri2_window *priv,
143.27491 ++			    struct sna *sna,
143.27492 ++			    bool signal)
143.27493 ++{
143.27494 ++	if (priv->front) {
143.27495 ++		DBG(("%s: decouple private front\n", __FUNCTION__));
143.27496 ++		assert(priv->crtc);
143.27497 ++		sna_shadow_unset_crtc(sna, priv->crtc);
143.27498 ++
143.27499 ++		_sna_dri2_destroy_buffer(sna, NULL, priv->front);
143.27500 ++		priv->front = NULL;
143.27501 ++	}
143.27502 ++
143.27503 ++	if (priv->chain) {
143.27504 ++		struct sna_dri2_event *info, *chain;
143.27505 ++
143.27506 ++		DBG(("%s: freeing chain\n", __FUNCTION__));
143.27507 ++
143.27508 ++		chain = priv->chain;
143.27509 ++		while ((info = chain)) {
143.27510 ++			DBG(("%s: freeing event, pending signal? %d, pending swap? handle=%d\n",
143.27511 ++			     __FUNCTION__, info->signal,
143.27512 ++			     info->pending.bo ? info->pending.bo->handle : 0));
143.27513 ++			assert(info->draw == &win->drawable);
143.27514 ++
143.27515 ++			if (info->pending.bo) {
143.27516 ++				if (signal) {
143.27517 ++					bool was_signalling = info->signal;
143.27518 ++					info->signal = true;
143.27519 ++					frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
143.27520 ++					info->signal = was_signalling;
143.27521 ++				}
143.27522 ++				assert(info->pending.bo->active_scanout > 0);
143.27523 ++				info->pending.bo->active_scanout--;
143.27524 ++
143.27525 ++				kgem_bo_destroy(&sna->kgem, info->pending.bo);
143.27526 ++				info->pending.bo = NULL;
143.27527 ++			}
143.27528 ++
143.27529 ++			if (info->signal && signal)
143.27530 ++				frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
143.27531 ++			info->signal = false;
143.27532 ++			info->draw = NULL;
143.27533 ++			info->keepalive = 1;
143.27534 ++			assert(!info->signal);
143.27535 ++			list_del(&info->link);
143.27536 ++
143.27537 ++			chain = info->chain;
143.27538 ++			info->chain = NULL;
143.27539 ++			info->chained = false;
143.27540 ++
143.27541 ++			if (!info->queued)
143.27542 ++				sna_dri2_event_free(info);
143.27543 ++		}
143.27544 ++
143.27545 ++		priv->chain = NULL;
143.27546 ++	}
143.27547 ++}
143.27548 ++
143.27549 + void sna_dri2_decouple_window(WindowPtr win)
143.27550 + {
143.27551 + 	struct dri2_window *priv;
143.27552 +@@ -1418,50 +1902,34 @@ void sna_dri2_decouple_window(WindowPtr win)
143.27553 + 		return;
143.27554 + 
143.27555 + 	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
143.27556 ++	decouple_window(win, priv, to_sna_from_drawable(&win->drawable), true);
143.27557 + 
143.27558 +-	if (priv->front) {
143.27559 +-		struct sna *sna = to_sna_from_drawable(&win->drawable);
143.27560 +-		assert(priv->crtc);
143.27561 +-		sna_shadow_unset_crtc(sna, priv->crtc);
143.27562 +-		_sna_dri2_destroy_buffer(sna, priv->front);
143.27563 +-		priv->front = NULL;
143.27564 +-	}
143.27565 ++	priv->scanout = -1;
143.27566 + }
143.27567 + 
143.27568 + void sna_dri2_destroy_window(WindowPtr win)
143.27569 + {
143.27570 + 	struct dri2_window *priv;
143.27571 ++	struct sna *sna;
143.27572 + 
143.27573 + 	priv = dri2_window(win);
143.27574 + 	if (priv == NULL)
143.27575 + 		return;
143.27576 + 
143.27577 + 	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
143.27578 ++	sna = to_sna_from_drawable(&win->drawable);
143.27579 ++	decouple_window(win, priv, sna, false);
143.27580 + 
143.27581 +-	if (priv->front) {
143.27582 +-		struct sna *sna = to_sna_from_drawable(&win->drawable);
143.27583 +-		assert(priv->crtc);
143.27584 +-		sna_shadow_unset_crtc(sna, priv->crtc);
143.27585 +-		_sna_dri2_destroy_buffer(sna, priv->front);
143.27586 +-	}
143.27587 +-
143.27588 +-	if (priv->chain) {
143.27589 +-		struct sna_dri2_event *info, *chain;
143.27590 +-
143.27591 +-		DBG(("%s: freeing chain\n", __FUNCTION__));
143.27592 +-
143.27593 +-		chain = priv->chain;
143.27594 +-		while ((info = chain)) {
143.27595 +-			info->draw = NULL;
143.27596 +-			info->client = NULL;
143.27597 +-			list_del(&info->link);
143.27598 ++	while (!list_is_empty(&priv->cache)) {
143.27599 ++		struct dri_bo *c;
143.27600 + 
143.27601 +-			chain = info->chain;
143.27602 +-			info->chain = NULL;
143.27603 ++		c = list_first_entry(&priv->cache, struct dri_bo, link);
143.27604 ++		list_del(&c->link);
143.27605 + 
143.27606 +-			if (!info->queued)
143.27607 +-				sna_dri2_event_free(info);
143.27608 +-		}
143.27609 ++		DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
143.27610 ++		assert(c->bo);
143.27611 ++		kgem_bo_destroy(&sna->kgem, c->bo);
143.27612 ++		free(c);
143.27613 + 	}
143.27614 + 
143.27615 + 	free(priv);
143.27616 +@@ -1479,19 +1947,30 @@ sna_dri2_flip(struct sna_dri2_event *info)
143.27617 + {
143.27618 + 	struct kgem_bo *bo = get_private(info->back)->bo;
143.27619 + 	struct kgem_bo *tmp_bo;
143.27620 +-	uint32_t tmp_name;
143.27621 ++	uint32_t tmp_name, tmp_flags;
143.27622 + 	int tmp_pitch;
143.27623 + 
143.27624 + 	DBG(("%s(type=%d)\n", __FUNCTION__, info->type));
143.27625 + 
143.27626 + 	assert(sna_pixmap_get_buffer(info->sna->front) == info->front);
143.27627 + 	assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
143.27628 ++	assert(get_private(info->front)->size == get_private(info->back)->size);
143.27629 + 	assert(bo->refcnt);
143.27630 + 
143.27631 ++	if (info->sna->mode.flip_active) {
143.27632 ++		DBG(("%s: %d flips still active, aborting\n",
143.27633 ++		     __FUNCTION__, info->sna->mode.flip_active));
143.27634 ++		return false;
143.27635 ++	}
143.27636 ++
143.27637 ++	assert(!info->queued);
143.27638 + 	if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler,
143.27639 + 			   info->type == FLIP_ASYNC ? NULL : info))
143.27640 + 		return false;
143.27641 + 
143.27642 ++	DBG(("%s: queued flip=%p\n", __FUNCTION__, info->type == FLIP_ASYNC ? NULL : info));
143.27643 ++	assert(info->signal || info->type != FLIP_THROTTLE);
143.27644 ++
143.27645 + 	assert(info->sna->dri2.flip_pending == NULL ||
143.27646 + 	       info->sna->dri2.flip_pending == info);
143.27647 + 	if (info->type != FLIP_ASYNC)
143.27648 +@@ -1505,13 +1984,21 @@ sna_dri2_flip(struct sna_dri2_event *info)
143.27649 + 	tmp_bo = get_private(info->front)->bo;
143.27650 + 	tmp_name = info->front->name;
143.27651 + 	tmp_pitch = info->front->pitch;
143.27652 ++	tmp_flags = info->front->flags;
143.27653 ++
143.27654 ++	assert(tmp_bo->active_scanout > 0);
143.27655 ++	tmp_bo->active_scanout--;
143.27656 + 
143.27657 + 	set_bo(info->sna->front, bo);
143.27658 + 
143.27659 ++	info->front->flags = info->back->flags;
143.27660 + 	info->front->name = info->back->name;
143.27661 + 	info->front->pitch = info->back->pitch;
143.27662 + 	get_private(info->front)->bo = bo;
143.27663 ++	bo->active_scanout++;
143.27664 ++	assert(bo->active_scanout <= bo->refcnt);
143.27665 + 
143.27666 ++	info->back->flags = tmp_flags;
143.27667 + 	info->back->name = tmp_name;
143.27668 + 	info->back->pitch = tmp_pitch;
143.27669 + 	get_private(info->back)->bo = tmp_bo;
143.27670 +@@ -1521,6 +2008,7 @@ sna_dri2_flip(struct sna_dri2_event *info)
143.27671 + 	assert(get_private(info->back)->bo->refcnt);
143.27672 + 	assert(get_private(info->front)->bo != get_private(info->back)->bo);
143.27673 + 
143.27674 ++	info->keepalive = KEEPALIVE;
143.27675 + 	info->queued = true;
143.27676 + 	return true;
143.27677 + }
143.27678 +@@ -1549,15 +2037,16 @@ can_flip(struct sna * sna,
143.27679 + 	}
143.27680 + 
143.27681 + 	assert(sna->scrn->vtSema);
143.27682 ++	assert(!sna->mode.hidden);
143.27683 + 
143.27684 + 	if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) {
143.27685 + 		DBG(("%s: no, pageflips disabled\n", __FUNCTION__));
143.27686 + 		return false;
143.27687 + 	}
143.27688 + 
143.27689 +-	if (front->format != back->format) {
143.27690 ++	if (front->cpp != back->cpp) {
143.27691 + 		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
143.27692 +-		     __FUNCTION__, front->format, back->format));
143.27693 ++		     __FUNCTION__, front->cpp, back->cpp));
143.27694 + 		return false;
143.27695 + 	}
143.27696 + 
143.27697 +@@ -1567,7 +2056,7 @@ can_flip(struct sna * sna,
143.27698 + 	}
143.27699 + 
143.27700 + 	if (!sna_crtc_is_on(crtc)) {
143.27701 +-		DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_to_pipe(crtc)));
143.27702 ++		DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_pipe(crtc)));
143.27703 + 		return false;
143.27704 + 	}
143.27705 + 
143.27706 +@@ -1581,7 +2070,7 @@ can_flip(struct sna * sna,
143.27707 + 	if (sna_pixmap_get_buffer(pixmap) != front) {
143.27708 + 		DBG(("%s: no, DRI2 drawable is no longer attached (old name=%d, new name=%d) to pixmap=%ld\n",
143.27709 + 		     __FUNCTION__, front->name,
143.27710 +-		     sna_pixmap_get_buffer(pixmap) ? ((DRI2BufferPtr)sna_pixmap_get_buffer(pixmap))->name : 0,
143.27711 ++		     sna_pixmap_get_buffer(pixmap) ? sna_pixmap_get_buffer(pixmap)->name : 0,
143.27712 + 		     pixmap->drawable.serialNumber));
143.27713 + 		return false;
143.27714 + 	}
143.27715 +@@ -1661,7 +2150,6 @@ can_flip(struct sna * sna,
143.27716 + 	}
143.27717 + 
143.27718 + 	DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
143.27719 +-	assert(dri2_window(win)->front == NULL);
143.27720 + 	return true;
143.27721 + }
143.27722 + 
143.27723 +@@ -1680,9 +2168,9 @@ can_xchg(struct sna *sna,
143.27724 + 	if (draw->type == DRAWABLE_PIXMAP)
143.27725 + 		return false;
143.27726 + 
143.27727 +-	if (front->format != back->format) {
143.27728 ++	if (front->cpp != back->cpp) {
143.27729 + 		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
143.27730 +-		     __FUNCTION__, front->format, back->format));
143.27731 ++		     __FUNCTION__, front->cpp, back->cpp));
143.27732 + 		return false;
143.27733 + 	}
143.27734 + 
143.27735 +@@ -1714,6 +2202,8 @@ can_xchg(struct sna *sna,
143.27736 + 		return false;
143.27737 + 	}
143.27738 + 
143.27739 ++	DBG(("%s: back size=%x, front size=%x\n",
143.27740 ++	     __FUNCTION__, get_private(back)->size, get_private(front)->size));
143.27741 + 	if (get_private(back)->size != get_private(front)->size) {
143.27742 + 		DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n",
143.27743 + 		     __FUNCTION__,
143.27744 +@@ -1766,9 +2256,9 @@ overlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired)
143.27745 + static bool
143.27746 + can_xchg_crtc(struct sna *sna,
143.27747 + 	      DrawablePtr draw,
143.27748 ++	      xf86CrtcPtr crtc,
143.27749 + 	      DRI2BufferPtr front,
143.27750 +-	      DRI2BufferPtr back,
143.27751 +-	      xf86CrtcPtr crtc)
143.27752 ++	      DRI2BufferPtr back)
143.27753 + {
143.27754 + 	WindowPtr win = (WindowPtr)draw;
143.27755 + 	PixmapPtr pixmap;
143.27756 +@@ -1785,9 +2275,9 @@ can_xchg_crtc(struct sna *sna,
143.27757 + 	if (draw->type == DRAWABLE_PIXMAP)
143.27758 + 		return false;
143.27759 + 
143.27760 +-	if (front->format != back->format) {
143.27761 ++	if (front->cpp != back->cpp) {
143.27762 + 		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
143.27763 +-		     __FUNCTION__, front->format, back->format));
143.27764 ++		     __FUNCTION__, front->cpp, back->cpp));
143.27765 + 		return false;
143.27766 + 	}
143.27767 + 
143.27768 +@@ -1866,20 +2356,21 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
143.27769 + 
143.27770 + 	back_bo = get_private(back)->bo;
143.27771 + 	front_bo = get_private(front)->bo;
143.27772 +-	assert(front_bo != back_bo);
143.27773 + 
143.27774 +-	DBG(("%s: win=%ld, exchange front=%d/%d and back=%d/%d, pixmap=%ld %dx%d\n",
143.27775 ++	DBG(("%s: win=%ld, exchange front=%d/%d,ref=%d and back=%d/%d,ref=%d, pixmap=%ld %dx%d\n",
143.27776 + 	     __FUNCTION__, win->drawable.id,
143.27777 +-	     front_bo->handle, front->name,
143.27778 +-	     back_bo->handle, back->name,
143.27779 ++	     front_bo->handle, front->name, get_private(front)->refcnt,
143.27780 ++	     back_bo->handle, back->name, get_private(back)->refcnt,
143.27781 + 	     pixmap->drawable.serialNumber,
143.27782 + 	     pixmap->drawable.width,
143.27783 + 	     pixmap->drawable.height));
143.27784 + 
143.27785 +-	DBG(("%s: back_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
143.27786 +-	     __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
143.27787 +-	DBG(("%s: front_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
143.27788 +-	     __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
143.27789 ++	DBG(("%s: back_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
143.27790 ++	     __FUNCTION__, back_bo->handle, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
143.27791 ++	DBG(("%s: front_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
143.27792 ++	     __FUNCTION__, front_bo->handle, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
143.27793 ++
143.27794 ++	assert(front_bo != back_bo);
143.27795 + 	assert(front_bo->refcnt);
143.27796 + 	assert(back_bo->refcnt);
143.27797 + 
143.27798 +@@ -1894,6 +2385,11 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
143.27799 + 	get_private(back)->bo = front_bo;
143.27800 + 	mark_stale(back);
143.27801 + 
143.27802 ++	assert(front_bo->active_scanout > 0);
143.27803 ++	front_bo->active_scanout--;
143.27804 ++	back_bo->active_scanout++;
143.27805 ++	assert(back_bo->active_scanout <= back_bo->refcnt);
143.27806 ++
143.27807 + 	tmp = front->name;
143.27808 + 	front->name = back->name;
143.27809 + 	back->name = tmp;
143.27810 +@@ -1902,17 +2398,23 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
143.27811 + 	front->pitch = back->pitch;
143.27812 + 	back->pitch = tmp;
143.27813 + 
143.27814 ++	tmp = front->flags;
143.27815 ++	front->flags = back->flags;
143.27816 ++	back->flags = tmp;
143.27817 ++
143.27818 + 	assert(front_bo->refcnt);
143.27819 + 	assert(back_bo->refcnt);
143.27820 + 
143.27821 ++	assert(front_bo->pitch == get_private(front)->bo->pitch);
143.27822 ++	assert(back_bo->pitch == get_private(back)->bo->pitch);
143.27823 ++
143.27824 + 	assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo);
143.27825 + }
143.27826 + 
143.27827 + static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc, DRI2BufferPtr front, DRI2BufferPtr back)
143.27828 + {
143.27829 + 	WindowPtr win = (WindowPtr)draw;
143.27830 +-	DRI2Buffer2Ptr tmp;
143.27831 +-	struct kgem_bo *bo;
143.27832 ++	struct dri2_window *priv = dri2_window(win);
143.27833 + 
143.27834 + 	DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n",
143.27835 + 	     __FUNCTION__,
143.27836 +@@ -1922,162 +2424,130 @@ static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr cr
143.27837 + 	     get_window_pixmap(win)->drawable.serialNumber,
143.27838 + 	     get_window_pixmap(win)->drawable.width,
143.27839 + 	     get_window_pixmap(win)->drawable.height));
143.27840 ++	assert(can_xchg_crtc(sna, draw, crtc, front, back));
143.27841 + 
143.27842 +-	DamageRegionAppend(&win->drawable, &win->clipList);
143.27843 ++	if (APPLY_DAMAGE) {
143.27844 ++		DBG(("%s: marking drawable as damaged\n", __FUNCTION__));
143.27845 ++		sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
143.27846 ++		DamageRegionAppend(&win->drawable, &win->clipList);
143.27847 ++	}
143.27848 + 	sna_shadow_set_crtc(sna, crtc, get_private(back)->bo);
143.27849 +-	DamageRegionProcessPending(&win->drawable);
143.27850 ++	if (APPLY_DAMAGE) {
143.27851 ++		sna->ignore_copy_area = false;
143.27852 ++		DamageRegionProcessPending(&win->drawable);
143.27853 ++	}
143.27854 + 
143.27855 +-	assert(dri2_window(win)->front == NULL);
143.27856 ++	if (priv->front == NULL) {
143.27857 ++		DRI2Buffer2Ptr tmp;
143.27858 + 
143.27859 +-	tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private));
143.27860 +-	if (tmp == NULL) {
143.27861 +-		back->attachment = -1;
143.27862 +-		if (get_private(back)->proxy == NULL) {
143.27863 +-			get_private(back)->pixmap = get_window_pixmap(win);
143.27864 +-			get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(back)->pixmap));
143.27865 ++		tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private));
143.27866 ++		if (tmp == NULL) {
143.27867 ++			sna_shadow_unset_crtc(sna, crtc);
143.27868 ++			return;
143.27869 + 		}
143.27870 +-		dri2_window(win)->front = sna_dri2_reference_buffer(back);
143.27871 +-		return;
143.27872 +-	}
143.27873 + 
143.27874 +-	*tmp = *back;
143.27875 +-	tmp->attachment = DRI2BufferFrontLeft;
143.27876 +-	tmp->driverPrivate = tmp + 1;
143.27877 +-	get_private(tmp)->refcnt = 1;
143.27878 +-	get_private(tmp)->bo = get_private(back)->bo;
143.27879 +-	get_private(tmp)->size = get_private(back)->size;
143.27880 +-	get_private(tmp)->pixmap = get_window_pixmap(win);
143.27881 +-	get_private(tmp)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(tmp)->pixmap));
143.27882 +-	dri2_window(win)->front = tmp;
143.27883 +-
143.27884 +-	DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
143.27885 +-	back->name = 0;
143.27886 +-	bo = kgem_create_2d(&sna->kgem,
143.27887 +-			    draw->width, draw->height, draw->bitsPerPixel,
143.27888 +-			    get_private(back)->bo->tiling,
143.27889 +-			    CREATE_SCANOUT);
143.27890 +-	if (bo != NULL) {
143.27891 +-		get_private(back)->bo = bo;
143.27892 +-		back->pitch = bo->pitch;
143.27893 +-		back->name = kgem_bo_flink(&sna->kgem, bo);
143.27894 +-	}
143.27895 +-	if (back->name == 0) {
143.27896 +-		if (bo != NULL)
143.27897 +-			kgem_bo_destroy(&sna->kgem, bo);
143.27898 +-		get_private(back)->bo = NULL;
143.27899 +-		back->attachment = -1;
143.27900 ++		tmp->attachment = DRI2BufferFrontLeft;
143.27901 ++		tmp->driverPrivate = tmp + 1;
143.27902 ++		tmp->cpp = back->cpp;
143.27903 ++		tmp->format = back->format;
143.27904 ++
143.27905 ++		get_private(tmp)->refcnt = 1;
143.27906 ++		get_private(tmp)->bo = kgem_create_2d(&sna->kgem,
143.27907 ++						      draw->width, draw->height, draw->bitsPerPixel,
143.27908 ++						      get_private(back)->bo->tiling,
143.27909 ++						      CREATE_SCANOUT | CREATE_EXACT);
143.27910 ++		if (get_private(tmp)->bo != NULL) {
143.27911 ++			tmp->pitch = get_private(tmp)->bo->pitch;
143.27912 ++			tmp->name = kgem_bo_flink(&sna->kgem, get_private(tmp)->bo);
143.27913 ++		}
143.27914 ++		if (tmp->name == 0) {
143.27915 ++			if (get_private(tmp)->bo != NULL)
143.27916 ++				kgem_bo_destroy(&sna->kgem, get_private(tmp)->bo);
143.27917 ++			sna_shadow_unset_crtc(sna, crtc);
143.27918 ++			return;
143.27919 ++		}
143.27920 ++		get_private(tmp)->size = get_private(back)->size;
143.27921 ++		get_private(tmp)->pixmap = get_private(front)->pixmap;
143.27922 ++		get_private(tmp)->proxy = sna_dri2_reference_buffer(front);
143.27923 ++		get_private(tmp)->bo->active_scanout++;
143.27924 ++
143.27925 ++		priv->front = front = tmp;
143.27926 + 	}
143.27927 +-}
143.27928 ++	assert(front == priv->front);
143.27929 + 
143.27930 +-static void frame_swap_complete(struct sna_dri2_event *frame, int type)
143.27931 +-{
143.27932 +-	const struct ust_msc *swap;
143.27933 ++	{
143.27934 ++		struct kgem_bo *front_bo = get_private(front)->bo;
143.27935 ++		struct kgem_bo *back_bo = get_private(back)->bo;
143.27936 ++		unsigned tmp;
143.27937 + 
143.27938 +-	if (frame->draw == NULL)
143.27939 +-		return;
143.27940 ++		assert(front_bo->refcnt);
143.27941 ++		assert(back_bo->refcnt);
143.27942 + 
143.27943 +-	assert(frame->client);
143.27944 ++		get_private(back)->bo = front_bo;
143.27945 ++		get_private(front)->bo = back_bo;
143.27946 ++		mark_stale(back);
143.27947 + 
143.27948 +-	swap = sna_crtc_last_swap(frame->crtc);
143.27949 +-	DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
143.27950 +-	     __FUNCTION__, type, (long)frame->draw, frame->pipe,
143.27951 +-	     (long long)swap->msc,
143.27952 +-	     (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
143.27953 +-	     swap->tv_sec, swap->tv_usec));
143.27954 ++		assert(front_bo->active_scanout > 0);
143.27955 ++		front_bo->active_scanout--;
143.27956 ++		back_bo->active_scanout++;
143.27957 ++		assert(back_bo->active_scanout <= back_bo->refcnt);
143.27958 + 
143.27959 +-	DRI2SwapComplete(frame->client, frame->draw,
143.27960 +-			 draw_current_msc(frame->draw, frame->crtc, swap->msc),
143.27961 +-			 swap->tv_sec, swap->tv_usec,
143.27962 +-			 type, frame->event_complete, frame->event_data);
143.27963 +-}
143.27964 ++		tmp = front->name;
143.27965 ++		front->name = back->name;
143.27966 ++		back->name = tmp;
143.27967 + 
143.27968 +-static void fake_swap_complete(struct sna *sna, ClientPtr client,
143.27969 +-			       DrawablePtr draw, xf86CrtcPtr crtc,
143.27970 +-			       int type, DRI2SwapEventPtr func, void *data)
143.27971 +-{
143.27972 +-	const struct ust_msc *swap;
143.27973 +-
143.27974 +-	swap = sna_crtc_last_swap(crtc);
143.27975 +-	DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
143.27976 +-	     __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1,
143.27977 +-	     (long long)swap->msc,
143.27978 +-	     (long long)draw_current_msc(draw, crtc, swap->msc),
143.27979 +-	     swap->tv_sec, swap->tv_usec));
143.27980 ++		tmp = front->pitch;
143.27981 ++		front->pitch = back->pitch;
143.27982 ++		back->pitch = tmp;
143.27983 + 
143.27984 +-	DRI2SwapComplete(client, draw,
143.27985 +-			 draw_current_msc(draw, crtc, swap->msc),
143.27986 +-			 swap->tv_sec, swap->tv_usec,
143.27987 +-			 type, func, data);
143.27988 ++		tmp = front->flags;
143.27989 ++		front->flags = back->flags;
143.27990 ++		back->flags = tmp;
143.27991 ++	}
143.27992 + }
143.27993 + 
143.27994 + static void chain_swap(struct sna_dri2_event *chain)
143.27995 + {
143.27996 +-	union drm_wait_vblank vbl;
143.27997 ++	DBG(("%s: draw=%ld, queued?=%d, type=%d\n",
143.27998 ++	     __FUNCTION__, (long)chain->draw->id, chain->queued, chain->type));
143.27999 ++
143.28000 ++	if (chain->queued) /* too early! */
143.28001 ++		return;
143.28002 + 
143.28003 + 	if (chain->draw == NULL) {
143.28004 + 		sna_dri2_event_free(chain);
143.28005 + 		return;
143.28006 + 	}
143.28007 + 
143.28008 +-	if (chain->queued) /* too early! */
143.28009 +-		return;
143.28010 +-
143.28011 + 	assert(chain == dri2_chain(chain->draw));
143.28012 +-	DBG(("%s: chaining draw=%ld, type=%d\n",
143.28013 +-	     __FUNCTION__, (long)chain->draw->id, chain->type));
143.28014 +-	chain->queued = true;
143.28015 ++	assert(chain->signal);
143.28016 + 
143.28017 + 	switch (chain->type) {
143.28018 +-	case SWAP_THROTTLE:
143.28019 ++	case SWAP_COMPLETE:
143.28020 + 		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
143.28021 +-		if (chain->sna->mode.shadow &&
143.28022 +-		    !chain->sna->mode.shadow_damage) {
143.28023 +-			/* recursed from wait_for_shadow(), simply requeue */
143.28024 +-			DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
143.28025 +-			VG_CLEAR(vbl);
143.28026 +-			vbl.request.type =
143.28027 +-				DRM_VBLANK_RELATIVE |
143.28028 +-				DRM_VBLANK_EVENT;
143.28029 +-			vbl.request.sequence = 1;
143.28030 +-			vbl.request.signal = (uintptr_t)chain;
143.28031 +-
143.28032 +-			if (!sna_wait_vblank(chain->sna, &vbl, chain->pipe))
143.28033 +-				return;
143.28034 +-
143.28035 +-			DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
143.28036 +-		}
143.28037 +-
143.28038 + 		if (can_xchg(chain->sna, chain->draw, chain->front, chain->back)) {
143.28039 + 			sna_dri2_xchg(chain->draw, chain->front, chain->back);
143.28040 +-		} else if (can_xchg_crtc(chain->sna, chain->draw, chain->front, chain->back, chain->crtc)) {
143.28041 +-			sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc, chain->front, chain->back);
143.28042 ++		} else if (can_xchg_crtc(chain->sna, chain->draw, chain->crtc,
143.28043 ++					 chain->front, chain->back)) {
143.28044 ++			sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc,
143.28045 ++					   chain->front, chain->back);
143.28046 + 		} else {
143.28047 +-			assert(chain->queued);
143.28048 +-			chain->bo = __sna_dri2_copy_region(chain->sna, chain->draw, NULL,
143.28049 +-							   chain->back, chain->front,
143.28050 +-							   true);
143.28051 ++			__sna_dri2_copy_event(chain, chain->sync | DRI2_BO);
143.28052 + 		}
143.28053 ++		assert(get_private(chain->back)->bo != get_private(chain->front)->bo);
143.28054 + 	case SWAP:
143.28055 + 		break;
143.28056 + 	default:
143.28057 + 		return;
143.28058 + 	}
143.28059 + 
143.28060 +-	VG_CLEAR(vbl);
143.28061 +-	vbl.request.type =
143.28062 +-		DRM_VBLANK_RELATIVE |
143.28063 +-		DRM_VBLANK_EVENT;
143.28064 +-	vbl.request.sequence = 1;
143.28065 +-	vbl.request.signal = (uintptr_t)chain;
143.28066 +-	if (sna_wait_vblank(chain->sna, &vbl, chain->pipe)) {
143.28067 ++	if ((chain->type == SWAP_COMPLETE &&
143.28068 ++	     !swap_limit(chain->draw, 2 + !chain->sync) &&
143.28069 ++	     !chain->sync) ||
143.28070 ++	    !sna_next_vblank(chain)) {
143.28071 + 		DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__));
143.28072 + 		frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
143.28073 + 		sna_dri2_event_free(chain);
143.28074 +-	} else {
143.28075 +-		if (chain->type == SWAP_THROTTLE && !swap_limit(chain->draw, 2)) {
143.28076 +-			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
143.28077 +-			frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
143.28078 +-		}
143.28079 + 	}
143.28080 + }
143.28081 + 
143.28082 +@@ -2086,40 +2556,27 @@ static inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo)
143.28083 + 	if (bo == NULL)
143.28084 + 		return false;
143.28085 + 
143.28086 +-	DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
143.28087 +-	     bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL));
143.28088 +-	assert(bo->refcnt);
143.28089 +-
143.28090 +-	if (bo->exec)
143.28091 +-		return true;
143.28092 +-
143.28093 +-	if (bo->rq == NULL)
143.28094 +-		return false;
143.28095 +-
143.28096 +-	return __kgem_busy(kgem, bo->handle);
143.28097 ++	return __kgem_bo_is_busy(kgem, bo);
143.28098 + }
143.28099 + 
143.28100 +-static bool sna_dri2_blit_complete(struct sna *sna,
143.28101 +-				   struct sna_dri2_event *info)
143.28102 ++static bool sna_dri2_blit_complete(struct sna_dri2_event *info)
143.28103 + {
143.28104 +-	if (rq_is_busy(&sna->kgem, info->bo)) {
143.28105 +-		union drm_wait_vblank vbl;
143.28106 ++	if (!info->bo)
143.28107 ++		return true;
143.28108 + 
143.28109 ++	if (__kgem_bo_is_busy(&info->sna->kgem, info->bo)) {
143.28110 + 		DBG(("%s: vsync'ed blit is still busy, postponing\n",
143.28111 + 		     __FUNCTION__));
143.28112 +-
143.28113 +-		VG_CLEAR(vbl);
143.28114 +-		vbl.request.type =
143.28115 +-			DRM_VBLANK_RELATIVE |
143.28116 +-			DRM_VBLANK_EVENT;
143.28117 +-		vbl.request.sequence = 1;
143.28118 +-		vbl.request.signal = (uintptr_t)info;
143.28119 +-		assert(info->queued);
143.28120 +-		if (!sna_wait_vblank(sna, &vbl, info->pipe))
143.28121 ++		if (sna_next_vblank(info))
143.28122 + 			return false;
143.28123 ++
143.28124 ++		kgem_bo_sync__gtt(&info->sna->kgem, info->bo);
143.28125 + 	}
143.28126 + 
143.28127 + 	DBG(("%s: blit finished\n", __FUNCTION__));
143.28128 ++	kgem_bo_destroy(&info->sna->kgem, info->bo);
143.28129 ++	info->bo = NULL;
143.28130 ++
143.28131 + 	return true;
143.28132 + }
143.28133 + 
143.28134 +@@ -2128,11 +2585,12 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
143.28135 + 	struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data;
143.28136 + 	struct sna *sna = info->sna;
143.28137 + 	DrawablePtr draw;
143.28138 +-	union drm_wait_vblank vbl;
143.28139 + 	uint64_t msc;
143.28140 + 
143.28141 +-	DBG(("%s(type=%d, sequence=%d)\n", __FUNCTION__, info->type, event->sequence));
143.28142 ++	DBG(("%s(type=%d, sequence=%d, draw=%ld)\n", __FUNCTION__, info->type, event->sequence, info->draw ? info->draw->serialNumber : 0));
143.28143 + 	assert(info->queued);
143.28144 ++	info->queued = false;
143.28145 ++
143.28146 + 	msc = sna_crtc_record_event(info->crtc, event);
143.28147 + 
143.28148 + 	draw = info->draw;
143.28149 +@@ -2141,68 +2599,120 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
143.28150 + 		goto done;
143.28151 + 	}
143.28152 + 
143.28153 ++	assert((info->front == NULL && info->back == NULL) || info->front != info->back);
143.28154 + 	switch (info->type) {
143.28155 + 	case FLIP:
143.28156 + 		/* If we can still flip... */
143.28157 ++		assert(info->signal);
143.28158 + 		if (can_flip(sna, draw, info->front, info->back, info->crtc) &&
143.28159 + 		    sna_dri2_flip(info))
143.28160 + 			return;
143.28161 + 
143.28162 + 		/* else fall through to blit */
143.28163 + 	case SWAP:
143.28164 +-		assert(info->queued);
143.28165 +-		if (sna->mode.shadow && !sna->mode.shadow_damage) {
143.28166 +-			/* recursed from wait_for_shadow(), simply requeue */
143.28167 +-			DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
143.28168 +-
143.28169 +-		} else if (can_xchg(info->sna, draw, info->front, info->back)) {
143.28170 ++		assert(info->signal);
143.28171 ++		if (can_xchg(info->sna, draw, info->front, info->back)) {
143.28172 + 			sna_dri2_xchg(draw, info->front, info->back);
143.28173 +-			info->type = SWAP_WAIT;
143.28174 +-		} else if (can_xchg_crtc(sna, draw, info->front, info->back, info->crtc)) {
143.28175 +-			sna_dri2_xchg_crtc(sna, draw, info->crtc, info->front, info->back);
143.28176 +-			info->type = SWAP_WAIT;
143.28177 ++			info->type = SWAP_COMPLETE;
143.28178 ++		} else if (can_xchg_crtc(sna, draw, info->crtc,
143.28179 ++					 info->front, info->back)) {
143.28180 ++			sna_dri2_xchg_crtc(sna, draw, info->crtc,
143.28181 ++					   info->front, info->back);
143.28182 ++			info->type = SWAP_COMPLETE;
143.28183 + 		}  else {
143.28184 +-			assert(info->queued);
143.28185 +-			info->bo = __sna_dri2_copy_region(sna, draw, NULL,
143.28186 +-							  info->back, info->front, true);
143.28187 +-			info->type = SWAP_WAIT;
143.28188 ++			__sna_dri2_copy_event(info, DRI2_BO | DRI2_SYNC);
143.28189 ++			info->type = SWAP_COMPLETE;
143.28190 + 		}
143.28191 + 
143.28192 +-		VG_CLEAR(vbl);
143.28193 +-		vbl.request.type =
143.28194 +-			DRM_VBLANK_RELATIVE |
143.28195 +-			DRM_VBLANK_EVENT;
143.28196 +-		vbl.request.sequence = 1;
143.28197 +-		vbl.request.signal = (uintptr_t)info;
143.28198 +-
143.28199 +-		assert(info->queued);
143.28200 +-		if (!sna_wait_vblank(sna, &vbl, info->pipe))
143.28201 ++		if (sna_next_vblank(info))
143.28202 + 			return;
143.28203 + 
143.28204 + 		DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
143.28205 ++		assert(info->pending.bo == NULL);
143.28206 ++		assert(info->keepalive == 1);
143.28207 + 		/* fall through to SwapComplete */
143.28208 +-	case SWAP_WAIT:
143.28209 +-		if (!sna_dri2_blit_complete(sna, info))
143.28210 +-			return;
143.28211 +-
143.28212 +-		DBG(("%s: swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
143.28213 +-		     event->sequence, event->tv_sec, event->tv_usec));
143.28214 +-		frame_swap_complete(info, DRI2_BLIT_COMPLETE);
143.28215 +-		break;
143.28216 +-
143.28217 +-	case SWAP_THROTTLE:
143.28218 ++	case SWAP_COMPLETE:
143.28219 + 		DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
143.28220 + 		     __FUNCTION__, info->type,
143.28221 + 		     event->sequence, event->tv_sec, event->tv_usec));
143.28222 + 
143.28223 +-		if (xorg_can_triple_buffer()) {
143.28224 +-			if (!sna_dri2_blit_complete(sna, info))
143.28225 ++		if (info->signal) {
143.28226 ++			if (!sna_dri2_blit_complete(info))
143.28227 + 				return;
143.28228 + 
143.28229 + 			DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
143.28230 + 			     event->sequence, event->tv_sec, event->tv_usec));
143.28231 + 			frame_swap_complete(info, DRI2_BLIT_COMPLETE);
143.28232 + 		}
143.28233 ++
143.28234 ++		if (info->pending.bo) {
143.28235 ++			struct copy current_back;
143.28236 ++
143.28237 ++			DBG(("%s: swapping back handle=%d [name=%d, active=%d] for pending handle=%d [name=%d, active=%d], front handle=%d [name=%d, active=%d]\n",
143.28238 ++			     __FUNCTION__,
143.28239 ++			     get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout,
143.28240 ++			     info->pending.bo->handle, info->pending.name, info->pending.bo->active_scanout,
143.28241 ++			     get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout));
143.28242 ++
143.28243 ++			assert(info->pending.bo->active_scanout > 0);
143.28244 ++			info->pending.bo->active_scanout--;
143.28245 ++
143.28246 ++			current_back.bo = get_private(info->back)->bo;
143.28247 ++			current_back.size = get_private(info->back)->size;
143.28248 ++			current_back.name = info->back->name;
143.28249 ++			current_back.flags = info->back->flags;
143.28250 ++
143.28251 ++			get_private(info->back)->bo = info->pending.bo;
143.28252 ++			get_private(info->back)->size = info->pending.size;
143.28253 ++			info->back->name = info->pending.name;
143.28254 ++			info->back->pitch = info->pending.bo->pitch;
143.28255 ++			info->back->flags = info->pending.flags;
143.28256 ++			info->pending.bo = NULL;
143.28257 ++
143.28258 ++			assert(get_private(info->back)->bo != get_private(info->front)->bo);
143.28259 ++
143.28260 ++			if (can_xchg(info->sna, info->draw, info->front, info->back))
143.28261 ++				sna_dri2_xchg(info->draw, info->front, info->back);
143.28262 ++			else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
143.28263 ++						 info->front, info->back))
143.28264 ++				sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
143.28265 ++						   info->front, info->back);
143.28266 ++			else
143.28267 ++				__sna_dri2_copy_event(info, info->sync | DRI2_BO);
143.28268 ++
143.28269 ++			sna_dri2_cache_bo(info->sna, info->draw,
143.28270 ++					  get_private(info->back)->bo,
143.28271 ++					  info->back->name,
143.28272 ++					  get_private(info->back)->size,
143.28273 ++					  info->back->flags);
143.28274 ++
143.28275 ++			get_private(info->back)->bo = current_back.bo;
143.28276 ++			get_private(info->back)->size = current_back.size;
143.28277 ++			info->back->name = current_back.name;
143.28278 ++			info->back->pitch = current_back.bo->pitch;
143.28279 ++			info->back->flags = current_back.flags;
143.28280 ++
143.28281 ++			DBG(("%s: restored current back handle=%d [name=%d, active=%d], active=%d], front handle=%d [name=%d, active=%d]\n",
143.28282 ++			     __FUNCTION__,
143.28283 ++			     get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout,
143.28284 ++			     get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout));
143.28285 ++
143.28286 ++			assert(info->draw);
143.28287 ++			assert(!info->signal);
143.28288 ++			info->keepalive++;
143.28289 ++			info->signal = true;
143.28290 ++		}
143.28291 ++
143.28292 ++		if (--info->keepalive) {
143.28293 ++			if (sna_next_vblank(info))
143.28294 ++				return;
143.28295 ++
143.28296 ++			if (info->signal) {
143.28297 ++				DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
143.28298 ++				     event->sequence, event->tv_sec, event->tv_usec));
143.28299 ++				frame_swap_complete(info, DRI2_BLIT_COMPLETE);
143.28300 ++			}
143.28301 ++		}
143.28302 + 		break;
143.28303 + 
143.28304 + 	case WAITMSC:
143.28305 +@@ -2218,11 +2728,11 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
143.28306 + 	}
143.28307 + 
143.28308 + 	if (info->chain) {
143.28309 ++		DBG(("%s: continuing chain\n", __FUNCTION__));
143.28310 + 		assert(info->chain != info);
143.28311 + 		assert(info->draw == draw);
143.28312 +-		sna_dri2_remove_event((WindowPtr)draw, info);
143.28313 ++		sna_dri2_remove_event(info);
143.28314 + 		chain_swap(info->chain);
143.28315 +-		info->draw = NULL;
143.28316 + 	}
143.28317 + 
143.28318 + done:
143.28319 +@@ -2230,101 +2740,148 @@ done:
143.28320 + 	DBG(("%s complete\n", __FUNCTION__));
143.28321 + }
143.28322 + 
143.28323 +-static bool
143.28324 ++static void
143.28325 + sna_dri2_immediate_blit(struct sna *sna,
143.28326 + 			struct sna_dri2_event *info,
143.28327 +-			bool sync, bool event)
143.28328 ++			bool sync)
143.28329 + {
143.28330 +-	DrawablePtr draw = info->draw;
143.28331 +-	bool ret = false;
143.28332 ++	struct sna_dri2_event *chain = dri2_chain(info->draw);
143.28333 + 
143.28334 + 	if (sna->flags & SNA_NO_WAIT)
143.28335 + 		sync = false;
143.28336 + 
143.28337 +-	DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, send-event? %d\n",
143.28338 +-	     __FUNCTION__, sync, dri2_chain(draw) != info,
143.28339 +-	     event));
143.28340 ++	DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, pipe %d\n",
143.28341 ++	     __FUNCTION__, sync, chain != info, info->pipe));
143.28342 ++	assert(chain);
143.28343 + 
143.28344 +-	info->type = SWAP_THROTTLE;
143.28345 +-	if (!sync || dri2_chain(draw) == info) {
143.28346 +-		DBG(("%s: no pending blit, starting chain\n",
143.28347 +-		     __FUNCTION__));
143.28348 ++	info->type = SWAP_COMPLETE;
143.28349 ++	info->sync = sync;
143.28350 ++	info->keepalive = KEEPALIVE;
143.28351 + 
143.28352 +-		info->queued = true;
143.28353 +-		info->bo = __sna_dri2_copy_region(sna, draw, NULL,
143.28354 +-						  info->back,
143.28355 +-						  info->front,
143.28356 +-						  sync);
143.28357 +-		if (event) {
143.28358 +-			if (sync) {
143.28359 +-				union drm_wait_vblank vbl;
143.28360 +-
143.28361 +-				VG_CLEAR(vbl);
143.28362 +-				vbl.request.type =
143.28363 +-					DRM_VBLANK_RELATIVE |
143.28364 +-					DRM_VBLANK_EVENT;
143.28365 +-				vbl.request.sequence = 1;
143.28366 +-				vbl.request.signal = (uintptr_t)info;
143.28367 +-				ret = !sna_wait_vblank(sna, &vbl, info->pipe);
143.28368 +-				if (ret)
143.28369 +-					event = !swap_limit(draw, 2);
143.28370 +-			}
143.28371 +-			if (event) {
143.28372 +-				DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
143.28373 +-				frame_swap_complete(info, DRI2_BLIT_COMPLETE);
143.28374 +-			}
143.28375 ++	if (chain == info) {
143.28376 ++		DBG(("%s: no pending blit, starting chain\n", __FUNCTION__));
143.28377 ++
143.28378 ++		assert(info->front != info->back);
143.28379 ++		if (can_xchg(info->sna, info->draw, info->front, info->back)) {
143.28380 ++			sna_dri2_xchg(info->draw, info->front, info->back);
143.28381 ++		} else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
143.28382 ++					 info->front, info->back)) {
143.28383 ++			sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
143.28384 ++					   info->front, info->back);
143.28385 ++		} else
143.28386 ++			__sna_dri2_copy_event(info, sync | DRI2_BO);
143.28387 ++
143.28388 ++		assert(info->signal);
143.28389 ++
143.28390 ++		if ((!swap_limit(info->draw, 2 + !sync) && !sync) ||
143.28391 ++		    !sna_next_vblank(info)) {
143.28392 ++			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
143.28393 ++			frame_swap_complete(info, DRI2_BLIT_COMPLETE);
143.28394 ++			sna_dri2_event_free(info);
143.28395 ++		}
143.28396 ++		return;
143.28397 ++	}
143.28398 ++
143.28399 ++	DBG(("%s: current event front=%d [name=%d, active?=%d], back=%d [name=%d, active?=%d]\n", __FUNCTION__,
143.28400 ++	     get_private(chain->front)->bo->handle, chain->front->name, get_private(chain->front)->bo->active_scanout,
143.28401 ++	     get_private(chain->back)->bo->handle, chain->back->name, get_private(chain->back)->bo->active_scanout));
143.28402 ++
143.28403 ++	if (chain->type == SWAP_COMPLETE && chain->front == info->front) {
143.28404 ++		assert(chain->draw == info->draw);
143.28405 ++		assert(chain->client == info->client);
143.28406 ++		assert(chain->event_complete == info->event_complete);
143.28407 ++		assert(chain->event_data == info->event_data);
143.28408 ++		assert(chain->queued);
143.28409 ++
143.28410 ++		if ((!sync || !chain->sync) && chain->pending.bo) {
143.28411 ++			bool signal = chain->signal;
143.28412 ++
143.28413 ++			DBG(("%s: swap elision, unblocking client\n", __FUNCTION__));
143.28414 ++			assert(chain->draw);
143.28415 ++			chain->signal = true;
143.28416 ++			frame_swap_complete(chain, DRI2_EXCHANGE_COMPLETE);
143.28417 ++			chain->signal = signal;
143.28418 ++
143.28419 ++			assert(chain->pending.bo->active_scanout > 0);
143.28420 ++			chain->pending.bo->active_scanout--;
143.28421 ++
143.28422 ++			sna_dri2_cache_bo(chain->sna, chain->draw,
143.28423 ++					  chain->pending.bo,
143.28424 ++					  chain->pending.name,
143.28425 ++					  chain->pending.size,
143.28426 ++					  chain->pending.flags);
143.28427 ++			chain->pending.bo = NULL;
143.28428 ++		}
143.28429 ++
143.28430 ++		if (chain->pending.bo == NULL && swap_limit(info->draw, 2 + !sync)) {
143.28431 ++			DBG(("%s: setting handle=%d as pending blit (current event front=%d, back=%d)\n", __FUNCTION__,
143.28432 ++			     get_private(info->back)->bo->handle,
143.28433 ++			     get_private(chain->front)->bo->handle,
143.28434 ++			     get_private(chain->back)->bo->handle));
143.28435 ++			chain->pending.bo = ref(get_private(info->back)->bo);
143.28436 ++			chain->pending.size = get_private(info->back)->size;
143.28437 ++			chain->pending.name = info->back->name;
143.28438 ++			chain->pending.flags = info->back->flags;
143.28439 ++			chain->sync = sync;
143.28440 ++			info->signal = false; /* transfer signal to pending */
143.28441 ++
143.28442 ++			/* Prevent us from handing it back on next GetBuffers */
143.28443 ++			chain->pending.bo->active_scanout++;
143.28444 ++
143.28445 ++			sna_dri2_event_free(info);
143.28446 ++			return;
143.28447 + 		}
143.28448 +-	} else {
143.28449 +-		DBG(("%s: pending blit, chained\n", __FUNCTION__));
143.28450 +-		ret = true;
143.28451 + 	}
143.28452 + 
143.28453 +-	DBG(("%s: continue? %d\n", __FUNCTION__, ret));
143.28454 +-	return ret;
143.28455 ++	DBG(("%s: pending blit, chained\n", __FUNCTION__));
143.28456 + }
143.28457 + 
143.28458 + static bool
143.28459 + sna_dri2_flip_continue(struct sna_dri2_event *info)
143.28460 + {
143.28461 +-	DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
143.28462 ++	struct kgem_bo *bo = get_private(info->front)->bo;
143.28463 + 
143.28464 +-	if (info->mode > 0){
143.28465 +-		struct kgem_bo *bo = get_private(info->front)->bo;
143.28466 ++	DBG(("%s(mode=%d)\n", __FUNCTION__, info->flip_continue));
143.28467 ++	assert(info->flip_continue > 0);
143.28468 ++	info->type = info->flip_continue;
143.28469 ++	info->flip_continue = 0;
143.28470 + 
143.28471 +-		info->type = info->mode;
143.28472 ++	assert(!info->signal);
143.28473 ++	info->signal = info->type == FLIP_THROTTLE && info->draw;
143.28474 + 
143.28475 +-		if (bo != sna_pixmap(info->sna->front)->gpu_bo)
143.28476 +-			return false;
143.28477 ++	if (info->sna->mode.front_active == 0)
143.28478 ++		return false;
143.28479 + 
143.28480 +-		if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
143.28481 +-			return false;
143.28482 ++	if (bo != sna_pixmap(info->sna->front)->gpu_bo)
143.28483 ++		return false;
143.28484 + 
143.28485 +-		assert(info->sna->dri2.flip_pending == NULL ||
143.28486 +-		       info->sna->dri2.flip_pending == info);
143.28487 +-		info->sna->dri2.flip_pending = info;
143.28488 +-		assert(info->queued);
143.28489 +-	} else {
143.28490 +-		info->type = -info->mode;
143.28491 ++	assert(!info->queued);
143.28492 ++	if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
143.28493 ++		return false;
143.28494 + 
143.28495 +-		if (!info->draw)
143.28496 +-			return false;
143.28497 ++	DBG(("%s: queued flip=%p\n", __FUNCTION__, info));
143.28498 ++	assert(info->sna->dri2.flip_pending == NULL ||
143.28499 ++	       info->sna->dri2.flip_pending == info);
143.28500 ++	info->sna->dri2.flip_pending = info;
143.28501 ++	info->queued = true;
143.28502 + 
143.28503 +-		if (!can_flip(info->sna, info->draw, info->front, info->back, info->crtc))
143.28504 +-			return false;
143.28505 ++	return true;
143.28506 ++}
143.28507 + 
143.28508 +-		assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
143.28509 +-		if (!sna_dri2_flip(info))
143.28510 +-			return false;
143.28511 ++static bool
143.28512 ++sna_dri2_flip_keepalive(struct sna_dri2_event *info)
143.28513 ++{
143.28514 ++	DBG(("%s(keepalive?=%d)\n", __FUNCTION__, info->keepalive-1));
143.28515 ++	assert(info->keepalive > 0);
143.28516 ++	if (!--info->keepalive)
143.28517 ++		return false;
143.28518 + 
143.28519 +-		if (!xorg_can_triple_buffer()) {
143.28520 +-			sna_dri2_get_back(info->sna, info->draw, info->back, info);
143.28521 +-			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
143.28522 +-			frame_swap_complete(info, DRI2_FLIP_COMPLETE);
143.28523 +-		}
143.28524 +-	}
143.28525 ++	if (info->draw == NULL)
143.28526 ++		return false;
143.28527 + 
143.28528 +-	info->mode = 0;
143.28529 +-	return true;
143.28530 ++	DBG(("%s: marking next flip as complete\n", __FUNCTION__));
143.28531 ++	info->flip_continue = FLIP_COMPLETE;
143.28532 ++	return sna_dri2_flip_continue(info);
143.28533 + }
143.28534 + 
143.28535 + static void chain_flip(struct sna *sna)
143.28536 +@@ -2332,8 +2889,8 @@ static void chain_flip(struct sna *sna)
143.28537 + 	struct sna_dri2_event *chain = sna->dri2.flip_pending;
143.28538 + 
143.28539 + 	assert(chain->type == FLIP);
143.28540 +-	DBG(("%s: chaining type=%d, cancelled?=%d\n",
143.28541 +-	     __FUNCTION__, chain->type, chain->draw == NULL));
143.28542 ++	DBG(("%s: chaining type=%d, cancelled?=%d window=%ld\n",
143.28543 ++	     __FUNCTION__, chain->type, chain->draw == NULL, chain->draw ? chain->draw->id : 0));
143.28544 + 
143.28545 + 	sna->dri2.flip_pending = NULL;
143.28546 + 	if (chain->draw == NULL) {
143.28547 +@@ -2343,31 +2900,18 @@ static void chain_flip(struct sna *sna)
143.28548 + 
143.28549 + 	assert(chain == dri2_chain(chain->draw));
143.28550 + 	assert(!chain->queued);
143.28551 +-	chain->queued = true;
143.28552 + 
143.28553 + 	if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) &&
143.28554 + 	    sna_dri2_flip(chain)) {
143.28555 + 		DBG(("%s: performing chained flip\n", __FUNCTION__));
143.28556 + 	} else {
143.28557 + 		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
143.28558 +-		chain->bo = __sna_dri2_copy_region(sna, chain->draw, NULL,
143.28559 +-						  chain->back, chain->front,
143.28560 +-						  true);
143.28561 ++		__sna_dri2_copy_event(chain, DRI2_SYNC);
143.28562 + 
143.28563 + 		if (xorg_can_triple_buffer()) {
143.28564 +-			union drm_wait_vblank vbl;
143.28565 +-
143.28566 +-			VG_CLEAR(vbl);
143.28567 +-
143.28568 +-			chain->type = SWAP_WAIT;
143.28569 +-			vbl.request.type =
143.28570 +-				DRM_VBLANK_RELATIVE |
143.28571 +-				DRM_VBLANK_EVENT;
143.28572 +-			vbl.request.sequence = 1;
143.28573 +-			vbl.request.signal = (uintptr_t)chain;
143.28574 +-
143.28575 +-			assert(chain->queued);
143.28576 +-			if (!sna_wait_vblank(sna, &vbl, chain->pipe))
143.28577 ++			chain->type = SWAP_COMPLETE;
143.28578 ++			assert(chain->signal);
143.28579 ++			if (sna_next_vblank(chain))
143.28580 + 				return;
143.28581 + 		}
143.28582 + 
143.28583 +@@ -2381,8 +2925,10 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
143.28584 + {
143.28585 + 	struct sna *sna = flip->sna;
143.28586 + 
143.28587 +-	DBG(("%s(pipe=%d, event=%d)\n", __FUNCTION__, flip->pipe, flip->type));
143.28588 +-	assert(flip->queued);
143.28589 ++	DBG(("%s flip=%p (pipe=%d, event=%d, queued?=%d)\n", __FUNCTION__, flip, flip->pipe, flip->type, flip->queued));
143.28590 ++	if (!flip->queued) /* pageflip died whilst being queued */
143.28591 ++		return;
143.28592 ++	flip->queued = false;
143.28593 + 
143.28594 + 	if (sna->dri2.flip_pending == flip)
143.28595 + 		sna->dri2.flip_pending = NULL;
143.28596 +@@ -2390,8 +2936,10 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
143.28597 + 	/* We assume our flips arrive in order, so we don't check the frame */
143.28598 + 	switch (flip->type) {
143.28599 + 	case FLIP:
143.28600 +-		DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
143.28601 +-		frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
143.28602 ++		if (flip->signal) {
143.28603 ++			DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
143.28604 ++			frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
143.28605 ++		}
143.28606 + 		sna_dri2_event_free(flip);
143.28607 + 
143.28608 + 		if (sna->dri2.flip_pending)
143.28609 +@@ -2399,27 +2947,35 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
143.28610 + 		break;
143.28611 + 
143.28612 + 	case FLIP_THROTTLE:
143.28613 +-		DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
143.28614 +-		frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
143.28615 ++		if (flip->signal) {
143.28616 ++			DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
143.28617 ++			frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
143.28618 ++		}
143.28619 + 	case FLIP_COMPLETE:
143.28620 ++		assert(!flip->signal);
143.28621 + 		if (sna->dri2.flip_pending) {
143.28622 ++			DBG(("%s: pending flip\n", __FUNCTION__));
143.28623 + 			sna_dri2_event_free(flip);
143.28624 + 			chain_flip(sna);
143.28625 +-		} else if (!flip->mode) {
143.28626 ++		} else if (!flip->flip_continue) {
143.28627 + 			DBG(("%s: flip chain complete\n", __FUNCTION__));
143.28628 ++			if (!sna_dri2_flip_keepalive(flip)) {
143.28629 ++				if (flip->chain) {
143.28630 ++					sna_dri2_remove_event(flip);
143.28631 ++					chain_swap(flip->chain);
143.28632 ++				}
143.28633 + 
143.28634 +-			if (flip->chain) {
143.28635 +-				sna_dri2_remove_event((WindowPtr)flip->draw,
143.28636 +-						      flip);
143.28637 +-				chain_swap(flip->chain);
143.28638 +-				flip->draw = NULL;
143.28639 ++				sna_dri2_event_free(flip);
143.28640 + 			}
143.28641 +-
143.28642 +-			sna_dri2_event_free(flip);
143.28643 + 		} else if (!sna_dri2_flip_continue(flip)) {
143.28644 + 			DBG(("%s: no longer able to flip\n", __FUNCTION__));
143.28645 +-			if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0))
143.28646 +-				sna_dri2_event_free(flip);
143.28647 ++			if (flip->draw != NULL)
143.28648 ++				__sna_dri2_copy_event(flip, 0);
143.28649 ++			if (flip->signal) {
143.28650 ++				DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
143.28651 ++				frame_swap_complete(flip, DRI2_BLIT_COMPLETE);
143.28652 ++			}
143.28653 ++			sna_dri2_event_free(flip);
143.28654 + 		}
143.28655 + 		break;
143.28656 + 
143.28657 +@@ -2433,17 +2989,27 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
143.28658 + 	}
143.28659 + }
143.28660 + 
143.28661 ++static int
143.28662 ++sna_query_vblank(struct sna *sna, xf86CrtcPtr crtc, union drm_wait_vblank *vbl)
143.28663 ++{
143.28664 ++	VG_CLEAR(*vbl);
143.28665 ++	vbl->request.type =
143.28666 ++		_DRM_VBLANK_RELATIVE | pipe_select(sna_crtc_pipe(crtc));
143.28667 ++	vbl->request.sequence = 0;
143.28668 ++
143.28669 ++	return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
143.28670 ++}
143.28671 ++
143.28672 + static uint64_t
143.28673 + get_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
143.28674 + {
143.28675 + 	union drm_wait_vblank vbl;
143.28676 +-	uint64_t ret = -1;
143.28677 ++	uint64_t ret;
143.28678 + 
143.28679 +-	VG_CLEAR(vbl);
143.28680 +-	vbl.request.type = _DRM_VBLANK_RELATIVE;
143.28681 +-	vbl.request.sequence = 0;
143.28682 +-	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
143.28683 ++	if (sna_query_vblank(sna, crtc, &vbl) == 0)
143.28684 + 		ret = sna_crtc_record_vblank(crtc, &vbl);
143.28685 ++	else
143.28686 ++		ret = sna_crtc_last_swap(crtc)->msc;
143.28687 + 
143.28688 + 	return draw_current_msc(draw, crtc, ret);
143.28689 + }
143.28690 +@@ -2494,12 +3060,18 @@ static int use_triple_buffer(struct sna *sna, ClientPtr client, bool async)
143.28691 + }
143.28692 + 
143.28693 + static bool immediate_swap(struct sna *sna,
143.28694 +-			   uint64_t target_msc,
143.28695 +-			   uint64_t divisor,
143.28696 + 			   DrawablePtr draw,
143.28697 + 			   xf86CrtcPtr crtc,
143.28698 ++			   uint64_t *target_msc,
143.28699 ++			   uint64_t divisor,
143.28700 ++			   uint64_t remainder,
143.28701 + 			   uint64_t *current_msc)
143.28702 + {
143.28703 ++	/*
143.28704 ++	 * If divisor is zero, or current_msc is smaller than target_msc
143.28705 ++	 * we just need to make sure target_msc passes before initiating
143.28706 ++	 * the swap.
143.28707 ++	 */
143.28708 + 	if (divisor == 0) {
143.28709 + 		*current_msc = -1;
143.28710 + 
143.28711 +@@ -2508,72 +3080,97 @@ static bool immediate_swap(struct sna *sna,
143.28712 + 			return true;
143.28713 + 		}
143.28714 + 
143.28715 +-		if (target_msc)
143.28716 ++		if (*target_msc)
143.28717 + 			*current_msc = get_current_msc(sna, draw, crtc);
143.28718 + 
143.28719 + 		DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n",
143.28720 +-		     __FUNCTION__, (long)*current_msc, (long)target_msc,
143.28721 +-		     (*current_msc >= target_msc - 1) ? "yes" : "no"));
143.28722 +-		return *current_msc >= target_msc - 1;
143.28723 ++		     __FUNCTION__, (long)*current_msc, (long)*target_msc,
143.28724 ++		     (*current_msc >= *target_msc - 1) ? "yes" : "no"));
143.28725 ++		return *current_msc >= *target_msc - 1;
143.28726 + 	}
143.28727 + 
143.28728 + 	DBG(("%s: explicit waits requests, divisor=%ld\n",
143.28729 + 	     __FUNCTION__, (long)divisor));
143.28730 + 	*current_msc = get_current_msc(sna, draw, crtc);
143.28731 +-	return false;
143.28732 ++	if (*current_msc >= *target_msc) {
143.28733 ++		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
143.28734 ++		     __FUNCTION__,
143.28735 ++		     (long long)*current_msc,
143.28736 ++		     (long long)*target_msc,
143.28737 ++		     (long long)divisor,
143.28738 ++		     (long long)remainder));
143.28739 ++
143.28740 ++		*target_msc = *current_msc + remainder - *current_msc % divisor;
143.28741 ++		if (*target_msc <= *current_msc)
143.28742 ++			*target_msc += divisor;
143.28743 ++	}
143.28744 ++
143.28745 ++	DBG(("%s: target_msc=%lld, current_msc=%lld, immediate?=%d\n",
143.28746 ++	     __FUNCTION__, (long long)*target_msc, (long long)*current_msc,
143.28747 ++	     *current_msc >= *target_msc - 1));
143.28748 ++	return *current_msc >= *target_msc - 1;
143.28749 + }
143.28750 + 
143.28751 + static bool
143.28752 + sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
143.28753 + 		       DRI2BufferPtr front, DRI2BufferPtr back,
143.28754 +-		       CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
143.28755 ++		       bool immediate, CARD64 *target_msc, CARD64 current_msc,
143.28756 + 		       DRI2SwapEventPtr func, void *data)
143.28757 + {
143.28758 + 	struct sna *sna = to_sna_from_drawable(draw);
143.28759 + 	struct sna_dri2_event *info;
143.28760 +-	uint64_t current_msc;
143.28761 +-
143.28762 +-	if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
143.28763 +-		int type;
143.28764 + 
143.28765 ++	if (immediate) {
143.28766 ++		bool signal = false;
143.28767 + 		info = sna->dri2.flip_pending;
143.28768 + 		DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n",
143.28769 +-		     __FUNCTION__, sna_crtc_to_pipe(crtc),
143.28770 +-		     info != NULL, info ? info->mode : 0,
143.28771 ++		     __FUNCTION__, sna_crtc_pipe(crtc),
143.28772 ++		     info != NULL, info ? info->flip_continue : 0,
143.28773 + 		     info && info->draw == draw));
143.28774 + 
143.28775 + 		if (info && info->draw == draw) {
143.28776 + 			assert(info->type != FLIP);
143.28777 +-			assert(info->front == front);
143.28778 ++			assert(info->queued);
143.28779 ++			assert(info->front != info->back);
143.28780 ++			if (info->front != front) {
143.28781 ++				assert(info->front != NULL);
143.28782 ++				_sna_dri2_destroy_buffer(sna, draw, info->front);
143.28783 ++				info->front = sna_dri2_reference_buffer(front);
143.28784 ++			}
143.28785 + 			if (info->back != back) {
143.28786 +-				_sna_dri2_destroy_buffer(sna, info->back);
143.28787 ++				assert(info->back != NULL);
143.28788 ++				_sna_dri2_destroy_buffer(sna, draw, info->back);
143.28789 + 				info->back = sna_dri2_reference_buffer(back);
143.28790 + 			}
143.28791 +-			if (info->mode || current_msc >= *target_msc) {
143.28792 +-				DBG(("%s: executing xchg of pending flip\n",
143.28793 +-				     __FUNCTION__));
143.28794 +-				sna_dri2_xchg(draw, front, back);
143.28795 +-				info->mode = type = FLIP_COMPLETE;
143.28796 +-				goto new_back;
143.28797 +-			} else {
143.28798 ++			assert(info->front != info->back);
143.28799 ++			DBG(("%s: executing xchg of pending flip: flip_continue=%d, keepalive=%d, chain?=%d\n", __FUNCTION__, info->flip_continue, info->keepalive, current_msc < *target_msc));
143.28800 ++			sna_dri2_xchg(draw, front, back);
143.28801 ++			info->keepalive = KEEPALIVE;
143.28802 ++			if (xorg_can_triple_buffer() &&
143.28803 ++			    current_msc < *target_msc) {
143.28804 + 				DBG(("%s: chaining flip\n", __FUNCTION__));
143.28805 +-				type = FLIP_THROTTLE;
143.28806 +-				if (xorg_can_triple_buffer())
143.28807 +-					info->mode = -type;
143.28808 +-				else
143.28809 +-					info->mode = -FLIP_COMPLETE;
143.28810 ++				info->flip_continue = FLIP_THROTTLE;
143.28811 + 				goto out;
143.28812 ++			} else {
143.28813 ++				info->flip_continue = FLIP_COMPLETE;
143.28814 ++				signal = info->signal;
143.28815 ++				assert(info->draw);
143.28816 ++				info->signal = true;
143.28817 ++				goto new_back;
143.28818 + 			}
143.28819 + 		}
143.28820 + 
143.28821 +-		info = sna_dri2_add_event(sna, draw, client);
143.28822 ++		info = sna_dri2_add_event(sna, draw, client, crtc);
143.28823 + 		if (info == NULL)
143.28824 + 			return false;
143.28825 + 
143.28826 + 		assert(info->crtc == crtc);
143.28827 + 		info->event_complete = func;
143.28828 + 		info->event_data = data;
143.28829 ++		assert(info->draw);
143.28830 ++		info->signal = true;
143.28831 + 
143.28832 ++		assert(front != back);
143.28833 + 		info->front = sna_dri2_reference_buffer(front);
143.28834 + 		info->back = sna_dri2_reference_buffer(back);
143.28835 + 
143.28836 +@@ -2584,26 +3181,33 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
143.28837 + 			 */
143.28838 + 			DBG(("%s: queueing flip after pending completion\n",
143.28839 + 			     __FUNCTION__));
143.28840 +-			info->type = type = FLIP;
143.28841 ++			info->type = FLIP;
143.28842 + 			sna->dri2.flip_pending = info;
143.28843 +-			assert(info->queued);
143.28844 + 			current_msc++;
143.28845 ++		} else if (sna->mode.flip_active) {
143.28846 ++			DBG(("%s: %d outstanding flips from old client, queueing\n",
143.28847 ++			     __FUNCTION__, sna->mode.flip_active));
143.28848 ++			goto queue;
143.28849 + 		} else {
143.28850 +-			info->type = type = use_triple_buffer(sna, client, *target_msc == 0);
143.28851 ++			info->type = use_triple_buffer(sna, client, *target_msc == 0);
143.28852 + 			if (!sna_dri2_flip(info)) {
143.28853 + 				DBG(("%s: flip failed, falling back\n", __FUNCTION__));
143.28854 ++				info->signal = false;
143.28855 + 				sna_dri2_event_free(info);
143.28856 + 				return false;
143.28857 + 			}
143.28858 ++			assert(get_private(info->front)->bo->active_scanout);
143.28859 + 		}
143.28860 + 
143.28861 +-		swap_limit(draw, 1 + (type == FLIP_THROTTLE));
143.28862 +-		if (type >= FLIP_COMPLETE) {
143.28863 ++		swap_limit(draw, 1 + (info->type == FLIP_THROTTLE));
143.28864 ++		if (info->type >= FLIP_COMPLETE) {
143.28865 + new_back:
143.28866 + 			if (!xorg_can_triple_buffer())
143.28867 +-				sna_dri2_get_back(sna, draw, back, info);
143.28868 ++				sna_dri2_get_back(sna, draw, back);
143.28869 + 			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
143.28870 + 			frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
143.28871 ++			assert(info->draw);
143.28872 ++			info->signal = signal;
143.28873 + 			if (info->type == FLIP_ASYNC)
143.28874 + 				sna_dri2_event_free(info);
143.28875 + 		}
143.28876 +@@ -2613,57 +3217,34 @@ out:
143.28877 + 		return true;
143.28878 + 	}
143.28879 + 
143.28880 +-	info = sna_dri2_add_event(sna, draw, client);
143.28881 ++queue:
143.28882 ++	if (KEEPALIVE > 1 && sna->dri2.flip_pending) {
143.28883 ++		info = sna->dri2.flip_pending;
143.28884 ++		info->keepalive = 1;
143.28885 ++	}
143.28886 ++
143.28887 ++	info = sna_dri2_add_event(sna, draw, client, crtc);
143.28888 + 	if (info == NULL)
143.28889 + 		return false;
143.28890 + 
143.28891 + 	assert(info->crtc == crtc);
143.28892 + 	info->event_complete = func;
143.28893 + 	info->event_data = data;
143.28894 ++	assert(info->draw);
143.28895 ++	info->signal = true;
143.28896 + 	info->type = FLIP;
143.28897 + 
143.28898 ++	assert(front != back);
143.28899 + 	info->front = sna_dri2_reference_buffer(front);
143.28900 + 	info->back = sna_dri2_reference_buffer(back);
143.28901 + 
143.28902 +-	/*
143.28903 +-	 * If divisor is zero, or current_msc is smaller than target_msc
143.28904 +-	 * we just need to make sure target_msc passes before initiating
143.28905 +-	 * the swap.
143.28906 +-	 */
143.28907 +-	if (divisor && current_msc >= *target_msc) {
143.28908 +-		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
143.28909 +-		     __FUNCTION__,
143.28910 +-		     (long long)current_msc,
143.28911 +-		     (long long)*target_msc,
143.28912 +-		     (long long)divisor,
143.28913 +-		     (long long)remainder));
143.28914 +-
143.28915 +-		*target_msc = current_msc + remainder - current_msc % divisor;
143.28916 +-		if (*target_msc <= current_msc)
143.28917 +-			*target_msc += divisor;
143.28918 +-	}
143.28919 +-
143.28920 +-	if (*target_msc <= current_msc + 1) {
143.28921 +-		if (!sna_dri2_flip(info)) {
143.28922 +-			sna_dri2_event_free(info);
143.28923 +-			return false;
143.28924 +-		}
143.28925 ++	if (*target_msc <= current_msc + 1 && sna_dri2_flip(info)) {
143.28926 + 		*target_msc = current_msc + 1;
143.28927 + 	} else {
143.28928 +-		union drm_wait_vblank vbl;
143.28929 +-
143.28930 +-		VG_CLEAR(vbl);
143.28931 +-
143.28932 +-		vbl.request.type =
143.28933 +-			DRM_VBLANK_ABSOLUTE |
143.28934 +-			DRM_VBLANK_EVENT;
143.28935 +-
143.28936 + 		/* Account for 1 frame extra pageflip delay */
143.28937 +-		vbl.reply.sequence = draw_target_seq(draw, *target_msc - 1);
143.28938 +-		vbl.request.signal = (uintptr_t)info;
143.28939 +-
143.28940 +-		info->queued = true;
143.28941 +-		if (sna_wait_vblank(sna, &vbl, info->pipe)) {
143.28942 ++		if (!sna_wait_vblank(info,
143.28943 ++				     draw_target_seq(draw, *target_msc - 1))) {
143.28944 ++			info->signal = false;
143.28945 + 			sna_dri2_event_free(info);
143.28946 + 			return false;
143.28947 + 		}
143.28948 +@@ -2674,128 +3255,6 @@ out:
143.28949 + 	return true;
143.28950 + }
143.28951 + 
143.28952 +-static bool
143.28953 +-sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
143.28954 +-		       DRI2BufferPtr front, DRI2BufferPtr back,
143.28955 +-		       CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
143.28956 +-		       DRI2SwapEventPtr func, void *data)
143.28957 +-{
143.28958 +-	struct sna *sna = to_sna_from_drawable(draw);
143.28959 +-	uint64_t current_msc;
143.28960 +-	bool sync, event;
143.28961 +-
143.28962 +-	if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
143.28963 +-		return false;
143.28964 +-
143.28965 +-	sync = current_msc < *target_msc;
143.28966 +-	event = dri2_chain(draw) == NULL;
143.28967 +-	if (!sync || event) {
143.28968 +-		DBG(("%s: performing immediate xchg on pipe %d\n",
143.28969 +-		     __FUNCTION__, sna_crtc_to_pipe(crtc)));
143.28970 +-		sna_dri2_xchg(draw, front, back);
143.28971 +-	}
143.28972 +-	if (sync) {
143.28973 +-		struct sna_dri2_event *info;
143.28974 +-
143.28975 +-		info = sna_dri2_add_event(sna, draw, client);
143.28976 +-		if (!info)
143.28977 +-			goto complete;
143.28978 +-
143.28979 +-		info->event_complete = func;
143.28980 +-		info->event_data = data;
143.28981 +-
143.28982 +-		info->front = sna_dri2_reference_buffer(front);
143.28983 +-		info->back = sna_dri2_reference_buffer(back);
143.28984 +-		info->type = SWAP_THROTTLE;
143.28985 +-
143.28986 +-		if (event) {
143.28987 +-			union drm_wait_vblank vbl;
143.28988 +-
143.28989 +-			VG_CLEAR(vbl);
143.28990 +-			vbl.request.type =
143.28991 +-				DRM_VBLANK_RELATIVE |
143.28992 +-				DRM_VBLANK_EVENT;
143.28993 +-			vbl.request.sequence = 1;
143.28994 +-			vbl.request.signal = (uintptr_t)info;
143.28995 +-
143.28996 +-			info->queued = true;
143.28997 +-			if (sna_wait_vblank(sna, &vbl, info->pipe)) {
143.28998 +-				sna_dri2_event_free(info);
143.28999 +-				goto complete;
143.29000 +-			}
143.29001 +-
143.29002 +-			swap_limit(draw, 2);
143.29003 +-		}
143.29004 +-	} else {
143.29005 +-complete:
143.29006 +-		fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
143.29007 +-	}
143.29008 +-
143.29009 +-	*target_msc = current_msc + 1;
143.29010 +-	return true;
143.29011 +-}
143.29012 +-
143.29013 +-static bool
143.29014 +-sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
143.29015 +-			    DRI2BufferPtr front, DRI2BufferPtr back,
143.29016 +-			    CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
143.29017 +-			    DRI2SwapEventPtr func, void *data)
143.29018 +-{
143.29019 +-	struct sna *sna = to_sna_from_drawable(draw);
143.29020 +-	uint64_t current_msc;
143.29021 +-	bool sync, event;
143.29022 +-
143.29023 +-	if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
143.29024 +-		return false;
143.29025 +-
143.29026 +-	sync = current_msc < *target_msc;
143.29027 +-	event = dri2_chain(draw) == NULL;
143.29028 +-	if (!sync || event) {
143.29029 +-		DBG(("%s: performing immediate xchg only on pipe %d\n",
143.29030 +-		     __FUNCTION__, sna_crtc_to_pipe(crtc)));
143.29031 +-		sna_dri2_xchg_crtc(sna, draw, crtc, front, back);
143.29032 +-	}
143.29033 +-	if (sync) {
143.29034 +-		struct sna_dri2_event *info;
143.29035 +-
143.29036 +-		info = sna_dri2_add_event(sna, draw, client);
143.29037 +-		if (!info)
143.29038 +-			goto complete;
143.29039 +-
143.29040 +-		info->event_complete = func;
143.29041 +-		info->event_data = data;
143.29042 +-
143.29043 +-		info->front = sna_dri2_reference_buffer(front);
143.29044 +-		info->back = sna_dri2_reference_buffer(back);
143.29045 +-		info->type = SWAP_THROTTLE;
143.29046 +-
143.29047 +-		if (event) {
143.29048 +-			union drm_wait_vblank vbl;
143.29049 +-
143.29050 +-			VG_CLEAR(vbl);
143.29051 +-			vbl.request.type =
143.29052 +-				DRM_VBLANK_RELATIVE |
143.29053 +-				DRM_VBLANK_EVENT;
143.29054 +-			vbl.request.sequence = 1;
143.29055 +-			vbl.request.signal = (uintptr_t)info;
143.29056 +-
143.29057 +-			info->queued = true;
143.29058 +-			if (sna_wait_vblank(sna, &vbl, info->pipe)) {
143.29059 +-				sna_dri2_event_free(info);
143.29060 +-				goto complete;
143.29061 +-			}
143.29062 +-
143.29063 +-			swap_limit(draw, 2);
143.29064 +-		}
143.29065 +-	} else {
143.29066 +-complete:
143.29067 +-		fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
143.29068 +-	}
143.29069 +-
143.29070 +-	*target_msc = current_msc + 1;
143.29071 +-	return true;
143.29072 +-}
143.29073 +-
143.29074 + static bool has_pending_events(struct sna *sna)
143.29075 + {
143.29076 + 	struct pollfd pfd;
143.29077 +@@ -2830,11 +3289,11 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.29078 + 		       CARD64 remainder, DRI2SwapEventPtr func, void *data)
143.29079 + {
143.29080 + 	struct sna *sna = to_sna_from_drawable(draw);
143.29081 +-	union drm_wait_vblank vbl;
143.29082 + 	xf86CrtcPtr crtc = NULL;
143.29083 + 	struct sna_dri2_event *info = NULL;
143.29084 + 	int type = DRI2_EXCHANGE_COMPLETE;
143.29085 + 	CARD64 current_msc;
143.29086 ++	bool immediate;
143.29087 + 
143.29088 + 	DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d) , front=%u (refs=%d/%d, flush=%d)\n",
143.29089 + 	     __FUNCTION__,
143.29090 +@@ -2860,6 +3319,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.29091 + 	assert(get_private(front)->refcnt);
143.29092 + 	assert(get_private(back)->refcnt);
143.29093 + 
143.29094 ++	assert(get_private(back)->bo != get_private(front)->bo);
143.29095 + 	assert(get_private(front)->bo->refcnt);
143.29096 + 	assert(get_private(back)->bo->refcnt);
143.29097 + 
143.29098 +@@ -2876,17 +3336,17 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.29099 + 		goto skip;
143.29100 + 	}
143.29101 + 
143.29102 +-	assert(sna_pixmap_from_drawable(draw)->flush);
143.29103 +-
143.29104 + 	if (draw->type != DRAWABLE_PIXMAP) {
143.29105 + 		WindowPtr win = (WindowPtr)draw;
143.29106 + 		struct dri2_window *priv = dri2_window(win);
143.29107 ++
143.29108 + 		if (priv->front) {
143.29109 +-			assert(front == priv->front);
143.29110 +-			assert(get_private(priv->front)->refcnt > 1);
143.29111 +-			get_private(priv->front)->refcnt--;
143.29112 +-			priv->front = NULL;
143.29113 ++			front = priv->front;
143.29114 ++			assert(front->attachment == DRI2BufferFrontLeft);
143.29115 ++			assert(get_private(front)->refcnt);
143.29116 ++			assert(get_private(front)->pixmap == get_drawable_pixmap(draw));
143.29117 + 		}
143.29118 ++
143.29119 + 		if (win->clipList.extents.x2 <= win->clipList.extents.x1 ||
143.29120 + 		    win->clipList.extents.y2 <= win->clipList.extents.y1) {
143.29121 + 			DBG(("%s: window clipped (%d, %d), (%d, %d)\n",
143.29122 +@@ -2899,6 +3359,10 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.29123 + 		}
143.29124 + 	}
143.29125 + 
143.29126 ++	DBG(("%s: using front handle=%d, active_scanout?=%d, flush?=%d\n", __FUNCTION__, get_private(front)->bo->handle, get_private(front)->bo->active_scanout, sna_pixmap_from_drawable(draw)->flush));
143.29127 ++	assert(get_private(front)->bo->active_scanout);
143.29128 ++	assert(sna_pixmap_from_drawable(draw)->flush);
143.29129 ++
143.29130 + 	/* Drawable not displayed... just complete the swap */
143.29131 + 	if ((sna->flags & SNA_NO_WAIT) == 0)
143.29132 + 		crtc = sna_dri2_get_crtc(draw);
143.29133 +@@ -2914,109 +3378,112 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.29134 + 		sna_mode_wakeup(sna);
143.29135 + 	}
143.29136 + 
143.29137 +-	if (can_xchg(sna, draw, front, back) &&
143.29138 +-	    sna_dri2_schedule_xchg(client, draw, crtc, front, back,
143.29139 ++	immediate = immediate_swap(sna, draw, crtc,
143.29140 + 				   target_msc, divisor, remainder,
143.29141 +-				   func, data))
143.29142 +-		return TRUE;
143.29143 +-
143.29144 +-	if (can_xchg_crtc(sna, draw, front, back, crtc) &&
143.29145 +-	    sna_dri2_schedule_xchg_crtc(client, draw, crtc, front, back,
143.29146 +-					target_msc, divisor, remainder,
143.29147 +-					func, data))
143.29148 +-		return TRUE;
143.29149 ++				   &current_msc);
143.29150 + 
143.29151 + 	if (can_flip(sna, draw, front, back, crtc) &&
143.29152 + 	    sna_dri2_schedule_flip(client, draw, crtc, front, back,
143.29153 +-				  target_msc, divisor, remainder,
143.29154 ++				  immediate, target_msc, current_msc,
143.29155 + 				  func, data))
143.29156 + 		return TRUE;
143.29157 + 
143.29158 +-	VG_CLEAR(vbl);
143.29159 +-
143.29160 +-	info = sna_dri2_add_event(sna, draw, client);
143.29161 ++	info = sna_dri2_add_event(sna, draw, client, crtc);
143.29162 + 	if (!info)
143.29163 + 		goto blit;
143.29164 + 
143.29165 + 	assert(info->crtc == crtc);
143.29166 + 	info->event_complete = func;
143.29167 + 	info->event_data = data;
143.29168 ++	assert(info->draw);
143.29169 ++	info->signal = true;
143.29170 + 
143.29171 ++	assert(front != back);
143.29172 + 	info->front = sna_dri2_reference_buffer(front);
143.29173 + 	info->back = sna_dri2_reference_buffer(back);
143.29174 + 
143.29175 +-	if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
143.29176 ++	if (immediate) {
143.29177 + 		bool sync = current_msc < *target_msc;
143.29178 +-		if (!sna_dri2_immediate_blit(sna, info, sync, true))
143.29179 +-			sna_dri2_event_free(info);
143.29180 ++		sna_dri2_immediate_blit(sna, info, sync);
143.29181 + 		*target_msc = current_msc + sync;
143.29182 ++		DBG(("%s: reported target_msc=%llu\n",
143.29183 ++		     __FUNCTION__, *target_msc));
143.29184 + 		return TRUE;
143.29185 + 	}
143.29186 + 
143.29187 +-	vbl.request.type =
143.29188 +-		DRM_VBLANK_ABSOLUTE |
143.29189 +-		DRM_VBLANK_EVENT;
143.29190 +-	vbl.request.signal = (uintptr_t)info;
143.29191 +-
143.29192 +-	/*
143.29193 +-	 * If divisor is zero, or current_msc is smaller than target_msc
143.29194 +-	 * we just need to make sure target_msc passes before initiating
143.29195 +-	 * the swap.
143.29196 +-	 */
143.29197 + 	info->type = SWAP;
143.29198 +-	info->queued = true;
143.29199 +-	if (divisor && current_msc >= *target_msc) {
143.29200 +-		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
143.29201 +-		     __FUNCTION__,
143.29202 +-		     (long long)current_msc,
143.29203 +-		     (long long)*target_msc,
143.29204 +-		     (long long)divisor,
143.29205 +-		     (long long)remainder));
143.29206 +-
143.29207 +-		*target_msc = current_msc + remainder - current_msc % divisor;
143.29208 +-		if (*target_msc <= current_msc)
143.29209 +-			*target_msc += divisor;
143.29210 +-	}
143.29211 +-	vbl.request.sequence = draw_target_seq(draw, *target_msc - 1);
143.29212 + 	if (*target_msc <= current_msc + 1) {
143.29213 + 		DBG(("%s: performing blit before queueing\n", __FUNCTION__));
143.29214 +-		assert(info->queued);
143.29215 +-		info->bo = __sna_dri2_copy_region(sna, draw, NULL,
143.29216 +-						  back, front,
143.29217 +-						  true);
143.29218 +-		info->type = SWAP_WAIT;
143.29219 +-
143.29220 +-		vbl.request.type =
143.29221 +-			DRM_VBLANK_RELATIVE |
143.29222 +-			DRM_VBLANK_EVENT;
143.29223 +-		vbl.request.sequence = 1;
143.29224 ++		__sna_dri2_copy_event(info, DRI2_SYNC);
143.29225 ++		info->type = SWAP_COMPLETE;
143.29226 ++		if (!sna_next_vblank(info))
143.29227 ++			goto fake;
143.29228 ++
143.29229 ++		DBG(("%s: reported target_msc=%llu\n",
143.29230 ++		     __FUNCTION__, *target_msc));
143.29231 + 		*target_msc = current_msc + 1;
143.29232 +-	}
143.29233 ++		swap_limit(draw, 2);
143.29234 ++	} else {
143.29235 ++		if (!sna_wait_vblank(info,
143.29236 ++				     draw_target_seq(draw, *target_msc - 1)))
143.29237 ++			goto blit;
143.29238 + 
143.29239 +-	assert(info->queued);
143.29240 +-	if (sna_wait_vblank(sna, &vbl, info->pipe))
143.29241 +-		goto blit;
143.29242 ++		DBG(("%s: reported target_msc=%llu (in)\n",
143.29243 ++		     __FUNCTION__, *target_msc));
143.29244 ++		swap_limit(draw, 1);
143.29245 ++	}
143.29246 + 
143.29247 +-	DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
143.29248 +-	swap_limit(draw, 1 + (info->type == SWAP_WAIT));
143.29249 + 	return TRUE;
143.29250 + 
143.29251 + blit:
143.29252 + 	DBG(("%s -- blit\n", __FUNCTION__));
143.29253 +-	if (info)
143.29254 +-		sna_dri2_event_free(info);
143.29255 + 	if (can_xchg(sna, draw, front, back)) {
143.29256 + 		sna_dri2_xchg(draw, front, back);
143.29257 + 	} else {
143.29258 +-		__sna_dri2_copy_region(sna, draw, NULL, back, front, false);
143.29259 ++		__sna_dri2_copy_region(sna, draw, NULL, back, front, 0);
143.29260 ++		front->flags = back->flags;
143.29261 + 		type = DRI2_BLIT_COMPLETE;
143.29262 + 	}
143.29263 ++	if (draw->type == DRAWABLE_PIXMAP)
143.29264 ++		goto fake;
143.29265 + skip:
143.29266 + 	DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__));
143.29267 +-	if (crtc == NULL)
143.29268 +-		crtc = sna_mode_first_crtc(sna);
143.29269 +-	fake_swap_complete(sna, client, draw, crtc, type, func, data);
143.29270 +-	*target_msc = 0; /* offscreen, so zero out target vblank count */
143.29271 ++	if (crtc == NULL && (sna->flags & SNA_NO_WAIT) == 0)
143.29272 ++		crtc = sna_primary_crtc(sna);
143.29273 ++	if (crtc && sna_crtc_is_on(crtc)) {
143.29274 ++		if (info == NULL)
143.29275 ++			info = sna_dri2_add_event(sna, draw, client, crtc);
143.29276 ++		if (info != dri2_chain(draw))
143.29277 ++			goto fake;
143.29278 ++
143.29279 ++		assert(info->crtc == crtc);
143.29280 ++
143.29281 ++		info->type = SWAP_COMPLETE;
143.29282 ++		info->event_complete = func;
143.29283 ++		info->event_data = data;
143.29284 ++		assert(info->draw);
143.29285 ++		info->signal = true;
143.29286 ++
143.29287 ++		if (info->front == NULL)
143.29288 ++			info->front = sna_dri2_reference_buffer(front);
143.29289 ++		if (info->back == NULL)
143.29290 ++			info->back = sna_dri2_reference_buffer(back);
143.29291 ++
143.29292 ++		if (!sna_next_vblank(info))
143.29293 ++			goto fake;
143.29294 ++
143.29295 ++		swap_limit(draw, 1);
143.29296 ++	} else {
143.29297 ++fake:
143.29298 ++		/* XXX Use a Timer to throttle the client? */
143.29299 ++		fake_swap_complete(sna, client, draw, crtc, type, func, data);
143.29300 ++		if (info) {
143.29301 ++			assert(info->draw);
143.29302 ++			info->signal = false;
143.29303 ++			sna_dri2_event_free(info);
143.29304 ++		}
143.29305 ++	}
143.29306 ++	DBG(("%s: reported target_msc=%llu (in)\n", __FUNCTION__, *target_msc));
143.29307 + 	return TRUE;
143.29308 + }
143.29309 + 
143.29310 +@@ -3030,27 +3497,25 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
143.29311 + 	struct sna *sna = to_sna_from_drawable(draw);
143.29312 + 	xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
143.29313 + 	const struct ust_msc *swap;
143.29314 ++	union drm_wait_vblank vbl;
143.29315 + 
143.29316 + 	DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id,
143.29317 +-	     crtc ? sna_crtc_to_pipe(crtc) : -1));
143.29318 ++	     crtc ? sna_crtc_pipe(crtc) : -1));
143.29319 + 
143.29320 +-	if (crtc != NULL) {
143.29321 +-		union drm_wait_vblank vbl;
143.29322 ++	/* Drawable not displayed, make up a *monotonic* value */
143.29323 ++	if (crtc == NULL)
143.29324 ++		crtc = sna_primary_crtc(sna);
143.29325 ++	if (crtc == NULL)
143.29326 ++		return FALSE;
143.29327 + 
143.29328 +-		VG_CLEAR(vbl);
143.29329 +-		vbl.request.type = _DRM_VBLANK_RELATIVE;
143.29330 +-		vbl.request.sequence = 0;
143.29331 +-		if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
143.29332 +-			sna_crtc_record_vblank(crtc, &vbl);
143.29333 +-	} else
143.29334 +-		/* Drawable not displayed, make up a *monotonic* value */
143.29335 +-		crtc = sna_mode_first_crtc(sna);
143.29336 ++	if (sna_query_vblank(sna, crtc, &vbl) == 0)
143.29337 ++		sna_crtc_record_vblank(crtc, &vbl);
143.29338 + 
143.29339 + 	swap = sna_crtc_last_swap(crtc);
143.29340 + 	*msc = draw_current_msc(draw, crtc, swap->msc);
143.29341 + 	*ust = ust64(swap->tv_sec, swap->tv_usec);
143.29342 +-	DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__,
143.29343 +-	     (long long)*msc, (long long)*ust));
143.29344 ++	DBG(("%s: msc=%llu [raw=%llu], ust=%llu\n", __FUNCTION__,
143.29345 ++	     (long long)*msc, swap->msc, (long long)*ust));
143.29346 + 	return TRUE;
143.29347 + }
143.29348 + 
143.29349 +@@ -3068,32 +3533,22 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
143.29350 + 	struct sna_dri2_event *info = NULL;
143.29351 + 	xf86CrtcPtr crtc;
143.29352 + 	CARD64 current_msc;
143.29353 +-	union drm_wait_vblank vbl;
143.29354 + 	const struct ust_msc *swap;
143.29355 +-	int pipe;
143.29356 + 
143.29357 + 	crtc = sna_dri2_get_crtc(draw);
143.29358 + 	DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
143.29359 +-	     __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
143.29360 ++	     __FUNCTION__, crtc ? sna_crtc_pipe(crtc) : -1,
143.29361 + 	     (long long)target_msc,
143.29362 + 	     (long long)divisor,
143.29363 + 	     (long long)remainder));
143.29364 + 
143.29365 + 	/* Drawable not visible, return immediately */
143.29366 + 	if (crtc == NULL)
143.29367 +-		goto out_complete;
143.29368 +-
143.29369 +-	pipe = sna_crtc_to_pipe(crtc);
143.29370 +-
143.29371 +-	VG_CLEAR(vbl);
143.29372 +-
143.29373 +-	/* Get current count */
143.29374 +-	vbl.request.type = _DRM_VBLANK_RELATIVE;
143.29375 +-	vbl.request.sequence = 0;
143.29376 +-	if (sna_wait_vblank(sna, &vbl, pipe))
143.29377 +-		goto out_complete;
143.29378 ++		crtc = sna_primary_crtc(sna);
143.29379 ++	if (crtc == NULL)
143.29380 ++		return FALSE;
143.29381 + 
143.29382 +-	current_msc = draw_current_msc(draw, crtc, sna_crtc_record_vblank(crtc, &vbl));
143.29383 ++	current_msc = get_current_msc(sna, draw, crtc);
143.29384 + 
143.29385 + 	/* If target_msc already reached or passed, set it to
143.29386 + 	 * current_msc to ensure we return a reasonable value back
143.29387 +@@ -3104,15 +3559,13 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
143.29388 + 	if (divisor == 0 && current_msc >= target_msc)
143.29389 + 		goto out_complete;
143.29390 + 
143.29391 +-	info = sna_dri2_add_event(sna, draw, client);
143.29392 ++	info = sna_dri2_add_event(sna, draw, client, crtc);
143.29393 + 	if (!info)
143.29394 + 		goto out_complete;
143.29395 + 
143.29396 + 	assert(info->crtc == crtc);
143.29397 + 	info->type = WAITMSC;
143.29398 + 
143.29399 +-	vbl.request.signal = (uintptr_t)info;
143.29400 +-	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
143.29401 + 	/*
143.29402 + 	 * If divisor is zero, or current_msc is smaller than target_msc,
143.29403 + 	 * we just need to make sure target_msc passes before waking up the
143.29404 +@@ -3129,10 +3582,8 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
143.29405 + 		if (target_msc <= current_msc)
143.29406 + 			target_msc += divisor;
143.29407 + 	}
143.29408 +-	vbl.request.sequence = draw_target_seq(draw, target_msc);
143.29409 + 
143.29410 +-	info->queued = true;
143.29411 +-	if (sna_wait_vblank(sna, &vbl, pipe))
143.29412 ++	if (!sna_wait_vblank(info, draw_target_seq(draw, target_msc)))
143.29413 + 		goto out_free_info;
143.29414 + 
143.29415 + 	DRI2BlockClient(client, draw);
143.29416 +@@ -3141,8 +3592,6 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
143.29417 + out_free_info:
143.29418 + 	sna_dri2_event_free(info);
143.29419 + out_complete:
143.29420 +-	if (crtc == NULL)
143.29421 +-		crtc = sna_mode_first_crtc(sna);
143.29422 + 	swap = sna_crtc_last_swap(crtc);
143.29423 + 	DRI2WaitMSCComplete(client, draw,
143.29424 + 			    draw_current_msc(draw, crtc, swap->msc),
143.29425 +@@ -3231,9 +3680,18 @@ static bool is_level(const char **str)
143.29426 + 	return false;
143.29427 + }
143.29428 + 
143.29429 ++static const char *options_get_dri(struct sna *sna)
143.29430 ++{
143.29431 ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
143.29432 ++	return xf86GetOptValString(sna->Options, OPTION_DRI);
143.29433 ++#else
143.29434 ++	return NULL;
143.29435 ++#endif
143.29436 ++}
143.29437 ++
143.29438 + static const char *dri_driver_name(struct sna *sna)
143.29439 + {
143.29440 +-	const char *s = xf86GetOptValString(sna->Options, OPTION_DRI);
143.29441 ++	const char *s = options_get_dri(sna);
143.29442 + 
143.29443 + 	if (is_level(&s)) {
143.29444 + 		if (sna->kgem.gen < 030)
143.29445 +@@ -3259,7 +3717,7 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
143.29446 + 
143.29447 + 	if (wedged(sna)) {
143.29448 + 		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
143.29449 +-			   "loading DRI2 whilst the GPU is wedged.\n");
143.29450 ++			   "loading DRI2 whilst acceleration is disabled.\n");
143.29451 + 	}
143.29452 + 
143.29453 + 	if (xf86LoaderCheckSymbol("DRI2Version"))
143.29454 +@@ -3274,7 +3732,7 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
143.29455 + 	memset(&info, '\0', sizeof(info));
143.29456 + 	info.fd = sna->kgem.fd;
143.29457 + 	info.driverName = dri_driver_name(sna);
143.29458 +-	info.deviceName = intel_get_client_name(sna->dev);
143.29459 ++	info.deviceName = intel_get_master_name(sna->dev);
143.29460 + 
143.29461 + 	DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n",
143.29462 + 	     __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName));
143.29463 +@@ -3299,11 +3757,12 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
143.29464 + 	info.numDrivers = 2;
143.29465 + 	info.driverNames = driverNames;
143.29466 + 	driverNames[0] = info.driverName;
143.29467 +-	driverNames[1] = info.driverName;
143.29468 ++	driverNames[1] = "va_gl";
143.29469 + #endif
143.29470 + 
143.29471 + #if DRI2INFOREC_VERSION >= 6
143.29472 + 	if (xorg_can_triple_buffer()) {
143.29473 ++		DBG(("%s: enabling Xorg triple buffering\n", __FUNCTION__));
143.29474 + 		info.version = 6;
143.29475 + 		info.SwapLimitValidate = sna_dri2_swap_limit_validate;
143.29476 + 		info.ReuseBufferNotify = sna_dri2_reuse_buffer;
143.29477 +@@ -3311,8 +3770,10 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
143.29478 + #endif
143.29479 + 
143.29480 + #if USE_ASYNC_SWAP
143.29481 ++	DBG(("%s: enabled async swap and buffer age\n", __FUNCTION__));
143.29482 + 	info.version = 10;
143.29483 + 	info.scheduleSwap0 = 1;
143.29484 ++	info.bufferAge = 1;
143.29485 + #endif
143.29486 + 
143.29487 + 	return DRI2ScreenInit(screen, &info);
143.29488 +diff --git a/src/sna/sna_dri3.c b/src/sna/sna_dri3.c
143.29489 +index f586e242..ce4970ae 100644
143.29490 +--- a/src/sna/sna_dri3.c
143.29491 ++++ b/src/sna/sna_dri3.c
143.29492 +@@ -55,11 +55,14 @@ static inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, st
143.29493 + 	if (bo->exec)
143.29494 + 		sna->kgem.flush = 1;
143.29495 + 	if (bo == priv->gpu_bo)
143.29496 +-		priv->flush |= 3;
143.29497 ++		priv->flush |= FLUSH_READ | FLUSH_WRITE;
143.29498 + 	else
143.29499 + 		priv->shm = true;
143.29500 + 
143.29501 +-	sna_accel_watch_flush(sna, 1);
143.29502 ++	sna_watch_flush(sna, 1);
143.29503 ++
143.29504 ++	kgem_bo_submit(&sna->kgem, bo);
143.29505 ++	kgem_bo_unclean(&sna->kgem, bo);
143.29506 + }
143.29507 + 
143.29508 + static void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv)
143.29509 +@@ -270,6 +273,8 @@ static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen,
143.29510 + 		priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
143.29511 + 	} else {
143.29512 + 		assert(priv->gpu_bo == bo);
143.29513 ++		priv->create = kgem_can_create_2d(&sna->kgem,
143.29514 ++						  width, height, depth);
143.29515 + 		priv->pinned |= PIN_DRI3;
143.29516 + 	}
143.29517 + 	list_add(&priv->cow_list, &sna->dri3.pixmaps);
143.29518 +@@ -325,6 +330,15 @@ static int sna_dri3_fd_from_pixmap(ScreenPtr screen,
143.29519 + 		return -1;
143.29520 + 	}
143.29521 + 
143.29522 ++	if (bo->tiling && !sna->kgem.can_fence) {
143.29523 ++		if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
143.29524 ++			DBG(("%s: unable to discard GPU tiling (%d) for DRI3 protocol\n",
143.29525 ++			     __FUNCTION__, bo->tiling));
143.29526 ++			return -1;
143.29527 ++		}
143.29528 ++		bo = priv->gpu_bo;
143.29529 ++	}
143.29530 ++
143.29531 + 	fd = kgem_bo_export_to_prime(&sna->kgem, bo);
143.29532 + 	if (fd == -1) {
143.29533 + 		DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));
143.29534 +diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
143.29535 +index 8a3599c7..1b4015de 100644
143.29536 +--- a/src/sna/sna_driver.c
143.29537 ++++ b/src/sna/sna_driver.c
143.29538 +@@ -57,6 +57,13 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
143.29539 + #include <mi.h>
143.29540 + #include <micmap.h>
143.29541 + 
143.29542 ++#if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H)
143.29543 ++#include <X11/extensions/dpmsconst.h>
143.29544 ++#else
143.29545 ++#define DPMSModeOn 0
143.29546 ++#define DPMSModeOff 3
143.29547 ++#endif
143.29548 ++
143.29549 + #include <sys/ioctl.h>
143.29550 + #include <sys/fcntl.h>
143.29551 + #include <sys/poll.h>
143.29552 +@@ -69,6 +76,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
143.29553 + 
143.29554 + #if HAVE_DOT_GIT
143.29555 + #include "git_version.h"
143.29556 ++#else
143.29557 ++#define git_version "not compiled from git"
143.29558 + #endif
143.29559 + 
143.29560 + #ifdef TEARFREE
143.29561 +@@ -185,12 +194,12 @@ sna_set_fallback_mode(ScrnInfoPtr scrn)
143.29562 + 
143.29563 + 	xf86DisableUnusedFunctions(scrn);
143.29564 + #ifdef RANDR_12_INTERFACE
143.29565 +-	if (get_root_window(scrn->pScreen))
143.29566 +-		xf86RandR12TellChanged(scrn->pScreen);
143.29567 ++	if (get_root_window(xf86ScrnToScreen(scrn)))
143.29568 ++		xf86RandR12TellChanged(xf86ScrnToScreen(scrn));
143.29569 + #endif
143.29570 + }
143.29571 + 
143.29572 +-static Bool sna_set_desired_mode(struct sna *sna)
143.29573 ++static void sna_set_desired_mode(struct sna *sna)
143.29574 + {
143.29575 + 	ScrnInfoPtr scrn = sna->scrn;
143.29576 + 
143.29577 +@@ -203,7 +212,6 @@ static Bool sna_set_desired_mode(struct sna *sna)
143.29578 + 	}
143.29579 + 
143.29580 + 	sna_mode_check(sna);
143.29581 +-	return TRUE;
143.29582 + }
143.29583 + 
143.29584 + /**
143.29585 +@@ -222,7 +230,7 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
143.29586 + 	     screen->width, screen->height, screen->rootDepth));
143.29587 + 
143.29588 + 	assert(sna->scrn == xf86ScreenToScrn(screen));
143.29589 +-	assert(sna->scrn->pScreen == screen);
143.29590 ++	assert(to_screen_from_sna(sna) == screen);
143.29591 + 
143.29592 + 	/* free the data used during miInitScreen */
143.29593 + 	free(screen->devPrivate);
143.29594 +@@ -273,33 +281,89 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
143.29595 + 		if (serverGeneration == 1 && (sna->flags & SNA_IS_HOSTED) == 0)
143.29596 + 			sna_copy_fbcon(sna);
143.29597 + 
143.29598 +-		(void)sna_set_desired_mode(sna);
143.29599 ++		sna_set_desired_mode(sna);
143.29600 + 	}
143.29601 + 
143.29602 + 	return TRUE;
143.29603 + }
143.29604 + 
143.29605 +-static Bool sna_save_screen(ScreenPtr screen, int mode)
143.29606 ++static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
143.29607 + {
143.29608 +-	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
143.29609 ++	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
143.29610 ++	struct sna *sna = to_sna(scrn);
143.29611 ++	bool changed = false;
143.29612 ++	int i;
143.29613 + 
143.29614 +-	DBG(("%s(mode=%d)\n", __FUNCTION__, mode));
143.29615 ++	DBG(("%s(mode=%d, flags=%d), vtSema=%d => off?=%d\n",
143.29616 ++	     __FUNCTION__, mode, flags, scrn->vtSema, mode!=DPMSModeOn));
143.29617 + 	if (!scrn->vtSema)
143.29618 +-		return FALSE;
143.29619 ++		return;
143.29620 + 
143.29621 +-	xf86SaveScreen(screen, mode);
143.29622 +-	sna_crtc_config_notify(screen);
143.29623 +-	return TRUE;
143.29624 ++	/* Opencoded version of xf86DPMSSet().
143.29625 ++	 *
143.29626 ++	 * The principle difference is to skip calling crtc->dpms() when
143.29627 ++	 * turning off the display. This (on recent enough kernels at
143.29628 ++	 * least) should be equivalent in power consumption, but require
143.29629 ++	 * less work (hence quicker and less likely to fail) when switching
143.29630 ++	 * back on.
143.29631 ++	 */
143.29632 ++	if (mode != DPMSModeOn) {
143.29633 ++		if (sna->mode.hidden == 0 && !(sna->flags & SNA_NO_DPMS)) {
143.29634 ++			DBG(("%s: hiding %d outputs\n",
143.29635 ++			     __FUNCTION__, config->num_output));
143.29636 ++			for (i = 0; i < config->num_output; i++) {
143.29637 ++				xf86OutputPtr output = config->output[i];
143.29638 ++				if (output->crtc != NULL)
143.29639 ++					output->funcs->dpms(output, mode);
143.29640 ++			}
143.29641 ++			sna->mode.hidden = sna->mode.front_active + 1;
143.29642 ++			sna->mode.front_active = 0;
143.29643 ++			changed = true;
143.29644 ++		}
143.29645 ++	} else {
143.29646 ++		/* Re-enable CRTC that have been forced off via other means */
143.29647 ++		if (sna->mode.hidden != 0) {
143.29648 ++			DBG(("%s: unhiding %d crtc, %d outputs\n",
143.29649 ++			     __FUNCTION__, config->num_crtc, config->num_output));
143.29650 ++			sna->mode.front_active = sna->mode.hidden - 1;
143.29651 ++			sna->mode.hidden = 0;
143.29652 ++			for (i = 0; i < config->num_crtc; i++) {
143.29653 ++				xf86CrtcPtr crtc = config->crtc[i];
143.29654 ++				if (crtc->enabled)
143.29655 ++					crtc->funcs->dpms(crtc, mode);
143.29656 ++			}
143.29657 ++
143.29658 ++			for (i = 0; i < config->num_output; i++) {
143.29659 ++				xf86OutputPtr output = config->output[i];
143.29660 ++				if (output->crtc != NULL)
143.29661 ++					output->funcs->dpms(output, mode);
143.29662 ++			}
143.29663 ++			changed = true;
143.29664 ++		}
143.29665 ++	}
143.29666 ++
143.29667 ++	DBG(("%s: hiding outputs? %d, front active? %d, changed? %d\n",
143.29668 ++	     __FUNCTION__, sna->mode.hidden, sna->mode.front_active, changed));
143.29669 ++
143.29670 ++	if (changed)
143.29671 ++		sna_crtc_config_notify(xf86ScrnToScreen(scrn));
143.29672 + }
143.29673 + 
143.29674 +-static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
143.29675 ++static Bool sna_save_screen(ScreenPtr screen, int mode)
143.29676 + {
143.29677 +-	DBG(("%s(mode=%d, flags=%d)\n", __FUNCTION__, mode));
143.29678 +-	if (!scrn->vtSema)
143.29679 +-		return;
143.29680 ++	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
143.29681 ++
143.29682 ++	DBG(("%s(mode=%d [unblank=%d])\n",
143.29683 ++	     __FUNCTION__, mode, xf86IsUnblank(mode)));
143.29684 + 
143.29685 +-	xf86DPMSSet(scrn, mode, flags);
143.29686 +-	sna_crtc_config_notify(xf86ScrnToScreen(scrn));
143.29687 ++	/* We have to unroll xf86SaveScreen() here as it is called
143.29688 ++	 * by DPMSSet() nullifying our special handling crtc->dpms()
143.29689 ++	 * in sna_dpms_set().
143.29690 ++	 */
143.29691 ++	sna_dpms_set(scrn,
143.29692 ++		     xf86IsUnblank(mode) ? DPMSModeOn : DPMSModeOff,
143.29693 ++		     0);
143.29694 ++	return TRUE;
143.29695 + }
143.29696 + 
143.29697 + static void sna_selftest(void)
143.29698 +@@ -330,107 +394,6 @@ static void sna_setup_capabilities(ScrnInfoPtr scrn, int fd)
143.29699 + #endif
143.29700 + }
143.29701 + 
143.29702 +-static int
143.29703 +-namecmp(const char *s1, const char *s2)
143.29704 +-{
143.29705 +-	char c1, c2;
143.29706 +-
143.29707 +-	if (!s1 || *s1 == 0) {
143.29708 +-		if (!s2 || *s2 == 0)
143.29709 +-			return 0;
143.29710 +-		else
143.29711 +-			return 1;
143.29712 +-	}
143.29713 +-
143.29714 +-	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
143.29715 +-		s1++;
143.29716 +-
143.29717 +-	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
143.29718 +-		s2++;
143.29719 +-
143.29720 +-	c1 = isupper(*s1) ? tolower(*s1) : *s1;
143.29721 +-	c2 = isupper(*s2) ? tolower(*s2) : *s2;
143.29722 +-	while (c1 == c2) {
143.29723 +-		if (c1 == '\0')
143.29724 +-			return 0;
143.29725 +-
143.29726 +-		s1++;
143.29727 +-		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
143.29728 +-			s1++;
143.29729 +-
143.29730 +-		s2++;
143.29731 +-		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
143.29732 +-			s2++;
143.29733 +-
143.29734 +-		c1 = isupper(*s1) ? tolower(*s1) : *s1;
143.29735 +-		c2 = isupper(*s2) ? tolower(*s2) : *s2;
143.29736 +-	}
143.29737 +-
143.29738 +-	return c1 - c2;
143.29739 +-}
143.29740 +-
143.29741 +-static Bool sna_option_cast_to_bool(struct sna *sna, int id, Bool val)
143.29742 +-{
143.29743 +-	const char *str = xf86GetOptValString(sna->Options, id);
143.29744 +-
143.29745 +-	if (str == NULL)
143.29746 +-		return val;
143.29747 +-
143.29748 +-	if (*str == '\0')
143.29749 +-		return TRUE;
143.29750 +-
143.29751 +-	if (namecmp(str, "1") == 0)
143.29752 +-		return TRUE;
143.29753 +-	if (namecmp(str, "on") == 0)
143.29754 +-		return TRUE;
143.29755 +-	if (namecmp(str, "true") == 0)
143.29756 +-		return TRUE;
143.29757 +-	if (namecmp(str, "yes") == 0)
143.29758 +-		return TRUE;
143.29759 +-
143.29760 +-	if (namecmp(str, "0") == 0)
143.29761 +-		return FALSE;
143.29762 +-	if (namecmp(str, "off") == 0)
143.29763 +-		return FALSE;
143.29764 +-	if (namecmp(str, "false") == 0)
143.29765 +-		return FALSE;
143.29766 +-	if (namecmp(str, "no") == 0)
143.29767 +-		return FALSE;
143.29768 +-
143.29769 +-	return val;
143.29770 +-}
143.29771 +-
143.29772 +-static unsigned sna_option_cast_to_unsigned(struct sna *sna, int id, unsigned val)
143.29773 +-{
143.29774 +-	const char *str = xf86GetOptValString(sna->Options, id);
143.29775 +-	unsigned v;
143.29776 +-
143.29777 +-	if (str == NULL || *str == '\0')
143.29778 +-		return val;
143.29779 +-
143.29780 +-	if (namecmp(str, "on") == 0)
143.29781 +-		return val;
143.29782 +-	if (namecmp(str, "true") == 0)
143.29783 +-		return val;
143.29784 +-	if (namecmp(str, "yes") == 0)
143.29785 +-		return val;
143.29786 +-
143.29787 +-	if (namecmp(str, "0") == 0)
143.29788 +-		return 0;
143.29789 +-	if (namecmp(str, "off") == 0)
143.29790 +-		return 0;
143.29791 +-	if (namecmp(str, "false") == 0)
143.29792 +-		return 0;
143.29793 +-	if (namecmp(str, "no") == 0)
143.29794 +-		return 0;
143.29795 +-
143.29796 +-	v = atoi(str);
143.29797 +-	if (v)
143.29798 +-		return v;
143.29799 +-
143.29800 +-	return val;
143.29801 +-}
143.29802 +-
143.29803 + static Bool fb_supports_depth(int fd, int depth)
143.29804 + {
143.29805 + 	struct drm_i915_gem_create create;
143.29806 +@@ -470,16 +433,24 @@ static void setup_dri(struct sna *sna)
143.29807 + 	unsigned level;
143.29808 + 
143.29809 + 	sna->dri2.available = false;
143.29810 ++	sna->dri2.enable = false;
143.29811 + 	sna->dri3.available = false;
143.29812 ++	sna->dri3.enable = false;
143.29813 ++	sna->dri3.override = false;
143.29814 + 
143.29815 +-	level = sna_option_cast_to_unsigned(sna, OPTION_DRI, ~0);
143.29816 ++	level = intel_option_cast_to_unsigned(sna->Options, OPTION_DRI, DEFAULT_DRI_LEVEL);
143.29817 + #if HAVE_DRI3
143.29818 +-	if (level >= 3)
143.29819 +-		sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3");
143.29820 ++	sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3");
143.29821 ++	sna->dri3.override =
143.29822 ++		!sna->dri3.available ||
143.29823 ++		xf86IsOptionSet(sna->Options, OPTION_DRI);
143.29824 ++	if (level >= 3 && sna->kgem.gen >= 040)
143.29825 ++		sna->dri3.enable = sna->dri3.available;
143.29826 + #endif
143.29827 + #if HAVE_DRI2
143.29828 ++	sna->dri2.available = !!xf86LoadSubModule(sna->scrn, "dri2");
143.29829 + 	if (level >= 2)
143.29830 +-		sna->dri2.available = !!xf86LoadSubModule(sna->scrn, "dri2");
143.29831 ++		sna->dri2.enable = sna->dri2.available;
143.29832 + #endif
143.29833 + }
143.29834 + 
143.29835 +@@ -498,13 +469,13 @@ static bool enable_tear_free(struct sna *sna)
143.29836 + 	return ENABLE_TEAR_FREE;
143.29837 + }
143.29838 + 
143.29839 +-static void setup_tear_free(struct sna *sna)
143.29840 ++static bool setup_tear_free(struct sna *sna)
143.29841 + {
143.29842 + 	MessageType from;
143.29843 + 	Bool enable;
143.29844 + 
143.29845 + 	if (sna->flags & SNA_LINEAR_FB)
143.29846 +-		return;
143.29847 ++		return false;
143.29848 + 
143.29849 + 	if ((sna->flags & SNA_HAS_FLIP) == 0) {
143.29850 + 		from = X_PROBED;
143.29851 +@@ -518,11 +489,12 @@ static void setup_tear_free(struct sna *sna)
143.29852 + 		from = X_CONFIG;
143.29853 + 
143.29854 + 	if (enable)
143.29855 +-		sna->flags |= SNA_TEAR_FREE;
143.29856 ++		sna->flags |= SNA_WANT_TEAR_FREE | SNA_TEAR_FREE;
143.29857 + 
143.29858 + done:
143.29859 + 	xf86DrvMsg(sna->scrn->scrnIndex, from, "TearFree %sabled\n",
143.29860 + 		   sna->flags & SNA_TEAR_FREE ? "en" : "dis");
143.29861 ++	return sna->flags & SNA_TEAR_FREE;
143.29862 + }
143.29863 + 
143.29864 + /**
143.29865 +@@ -612,8 +584,10 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
143.29866 + 	}
143.29867 + 
143.29868 + 	intel_detect_chipset(scrn, sna->dev);
143.29869 +-	xf86DrvMsg(scrn->scrnIndex, X_PROBED, "CPU: %s\n",
143.29870 +-		   sna_cpu_features_to_string(sna->cpu_features, buf));
143.29871 ++	xf86DrvMsg(scrn->scrnIndex, X_PROBED,
143.29872 ++		   "CPU: %s; using a maximum of %d threads\n",
143.29873 ++		   sna_cpu_features_to_string(sna->cpu_features, buf),
143.29874 ++		   sna_use_threads(64*1024, 64*1024, 1));
143.29875 + 
143.29876 + 	if (!xf86SetDepthBpp(scrn, 24, 0, 0,
143.29877 + 			     Support32bppFb |
143.29878 +@@ -651,18 +625,11 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
143.29879 + 	kgem_init(&sna->kgem, fd,
143.29880 + 		  xf86GetPciInfoForEntity(pEnt->index),
143.29881 + 		  sna->info->gen);
143.29882 +-	if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE) ||
143.29883 +-	    !sna_option_cast_to_bool(sna, OPTION_ACCEL_METHOD, TRUE)) {
143.29884 +-		xf86DrvMsg(sna->scrn->scrnIndex, X_CONFIG,
143.29885 +-			   "Disabling hardware acceleration.\n");
143.29886 +-		sna->kgem.wedged = true;
143.29887 +-	}
143.29888 + 
143.29889 + 	if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE))
143.29890 + 		sna->flags |= SNA_LINEAR_FB;
143.29891 +-
143.29892 +-	if (xf86ReturnOptValBool(sna->Options, OPTION_DELETE_DP12, FALSE))
143.29893 +-		sna->flags |= SNA_REMOVE_OUTPUTS;
143.29894 ++	if (!sna->kgem.can_fence)
143.29895 ++		sna->flags |= SNA_LINEAR_FB;
143.29896 + 
143.29897 + 	if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
143.29898 + 		sna->flags |= SNA_NO_WAIT;
143.29899 +@@ -695,7 +662,8 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
143.29900 + 	}
143.29901 + 	scrn->currentMode = scrn->modes;
143.29902 + 
143.29903 +-	setup_tear_free(sna);
143.29904 ++	if (!setup_tear_free(sna) && sna_mode_wants_tear_free(sna))
143.29905 ++		sna->kgem.needs_dirtyfb = sna->kgem.has_dirtyfb;
143.29906 + 
143.29907 + 	xf86SetGamma(scrn, zeros);
143.29908 + 	xf86SetDpi(scrn, 0, 0);
143.29909 +@@ -721,11 +689,13 @@ cleanup:
143.29910 + 	return FALSE;
143.29911 + }
143.29912 + 
143.29913 ++#if !HAVE_NOTIFY_FD
143.29914 + static bool has_shadow(struct sna *sna)
143.29915 + {
143.29916 +-	if (!sna->mode.shadow_damage)
143.29917 ++	if (!sna->mode.shadow_enabled)
143.29918 + 		return false;
143.29919 + 
143.29920 ++	assert(sna->mode.shadow_damage);
143.29921 + 	if (RegionNil(DamageRegion(sna->mode.shadow_damage)))
143.29922 + 		return false;
143.29923 + 
143.29924 +@@ -748,7 +718,7 @@ sna_block_handler(BLOCKHANDLER_ARGS_DECL)
143.29925 + 	sna->BlockHandler(BLOCKHANDLER_ARGS);
143.29926 + 
143.29927 + 	if (*tv == NULL || ((*tv)->tv_usec | (*tv)->tv_sec) || has_shadow(sna))
143.29928 +-		sna_accel_block_handler(sna, tv);
143.29929 ++		sna_accel_block(sna, tv);
143.29930 + }
143.29931 + 
143.29932 + static void
143.29933 +@@ -770,52 +740,102 @@ sna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
143.29934 + 
143.29935 + 	sna->WakeupHandler(WAKEUPHANDLER_ARGS);
143.29936 + 
143.29937 +-	sna_accel_wakeup_handler(sna);
143.29938 +-
143.29939 + 	if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask)) {
143.29940 + 		sna_mode_wakeup(sna);
143.29941 + 		/* Clear the flag so that subsequent ZaphodHeads don't block  */
143.29942 + 		FD_CLR(sna->kgem.fd, (fd_set*)read_mask);
143.29943 + 	}
143.29944 + }
143.29945 ++#else
143.29946 ++static void
143.29947 ++sna_block_handler(void *data, void *_timeout)
143.29948 ++{
143.29949 ++	struct sna *sna = data;
143.29950 ++	int *timeout = _timeout;
143.29951 ++	struct timeval tv, *tvp;
143.29952 ++
143.29953 ++	DBG(("%s (timeout=%d)\n", __FUNCTION__, *timeout));
143.29954 ++	if (*timeout == 0)
143.29955 ++		return;
143.29956 ++
143.29957 ++	if (*timeout < 0) {
143.29958 ++		tvp = NULL;
143.29959 ++	} else {
143.29960 ++		tv.tv_sec = *timeout / 1000;
143.29961 ++		tv.tv_usec = (*timeout % 1000) * 1000;
143.29962 ++		tvp = &tv;
143.29963 ++	}
143.29964 ++
143.29965 ++	sna_accel_block(sna, &tvp);
143.29966 ++	if (tvp)
143.29967 ++		*timeout = tvp->tv_sec * 1000 + tvp->tv_usec / 1000;
143.29968 ++}
143.29969 ++#endif
143.29970 + 
143.29971 + #if HAVE_UDEV
143.29972 ++#include <sys/stat.h>
143.29973 ++
143.29974 + static void
143.29975 + sna_handle_uevents(int fd, void *closure)
143.29976 + {
143.29977 + 	struct sna *sna = closure;
143.29978 +-	struct udev_device *dev;
143.29979 +-	const char *str;
143.29980 + 	struct stat s;
143.29981 +-	dev_t udev_devnum;
143.29982 ++	struct pollfd pfd;
143.29983 ++	bool hotplug = false;
143.29984 + 
143.29985 + 	DBG(("%s\n", __FUNCTION__));
143.29986 + 
143.29987 +-	dev = udev_monitor_receive_device(sna->uevent_monitor);
143.29988 +-	if (!dev)
143.29989 +-		return;
143.29990 ++	pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
143.29991 ++	pfd.events = POLLIN;
143.29992 ++
143.29993 ++	if (fstat(sna->kgem.fd, &s))
143.29994 ++		memset(&s, 0, sizeof(s));
143.29995 ++
143.29996 ++	while (poll(&pfd, 1, 0) > 0) {
143.29997 ++		struct udev_device *dev;
143.29998 ++		dev_t devnum;
143.29999 ++
143.30000 ++		dev = udev_monitor_receive_device(sna->uevent_monitor);
143.30001 ++		if (dev == NULL)
143.30002 ++			break;
143.30003 ++
143.30004 ++		devnum = udev_device_get_devnum(dev);
143.30005 ++		if (memcmp(&s.st_rdev, &devnum, sizeof(dev_t)) == 0) {
143.30006 ++			const char *str;
143.30007 ++
143.30008 ++			str = udev_device_get_property_value(dev, "HOTPLUG");
143.30009 ++			if (str && atoi(str) == 1) {
143.30010 ++				str = udev_device_get_property_value(dev, "CONNECTOR");
143.30011 ++				if (str) {
143.30012 ++					hotplug |= sna_mode_find_hotplug_connector(sna, atoi(str));
143.30013 ++				} else {
143.30014 ++					sna->flags |= SNA_REPROBE;
143.30015 ++					hotplug = true;
143.30016 ++				}
143.30017 ++			}
143.30018 ++		}
143.30019 + 
143.30020 +-	udev_devnum = udev_device_get_devnum(dev);
143.30021 +-	if (fstat(sna->kgem.fd, &s) || memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t))) {
143.30022 + 		udev_device_unref(dev);
143.30023 +-		return;
143.30024 + 	}
143.30025 + 
143.30026 +-	str = udev_device_get_property_value(dev, "HOTPLUG");
143.30027 +-	if (str && atoi(str) == 1) {
143.30028 +-		ScrnInfoPtr scrn = sna->scrn;
143.30029 +-
143.30030 +-		DBG(("%s: hotplug event (vtSema?=%d)\n", __FUNCTION__, scrn->vtSema));
143.30031 ++	if (hotplug) {
143.30032 ++		DBG(("%s: hotplug event (vtSema?=%d)\n",
143.30033 ++		     __FUNCTION__, sna->scrn->vtSema));
143.30034 + 
143.30035 +-		if (scrn->vtSema) {
143.30036 +-			sna_mode_discover(sna);
143.30037 +-			sna_mode_check(sna);
143.30038 +-			RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
143.30039 +-		} else
143.30040 ++		if (sna->scrn->vtSema)
143.30041 ++			sna_mode_discover(sna, true);
143.30042 ++		else
143.30043 + 			sna->flags |= SNA_REPROBE;
143.30044 + 	}
143.30045 ++}
143.30046 + 
143.30047 +-	udev_device_unref(dev);
143.30048 ++static bool has_randr(void)
143.30049 ++{
143.30050 ++#if HAS_DIXREGISTERPRIVATEKEY
143.30051 ++	return dixPrivateKeyRegistered(rrPrivKey);
143.30052 ++#else
143.30053 ++	return *rrPrivKey;
143.30054 ++#endif
143.30055 + }
143.30056 + 
143.30057 + static void
143.30058 +@@ -833,7 +853,7 @@ sna_uevent_init(struct sna *sna)
143.30059 + 	/* RandR will be disabled if Xinerama is active, and so generating
143.30060 + 	 * RR hotplug events is then verboten.
143.30061 + 	 */
143.30062 +-	if (!dixPrivateKeyRegistered(rrPrivKey))
143.30063 ++	if (!has_randr())
143.30064 + 		goto out;
143.30065 + 
143.30066 + 	u = NULL;
143.30067 +@@ -861,7 +881,8 @@ sna_uevent_init(struct sna *sna)
143.30068 + 
143.30069 + 	sna->uevent_monitor = mon;
143.30070 + out:
143.30071 +-	xf86DrvMsg(sna->scrn->scrnIndex, from, "display hotplug detection %s\n",
143.30072 ++	xf86DrvMsg(sna->scrn->scrnIndex, from,
143.30073 ++		   "Display hotplug detection %s\n",
143.30074 + 		   sna->uevent_monitor ? "enabled" : "disabled");
143.30075 + 	return;
143.30076 + 
143.30077 +@@ -874,17 +895,10 @@ err_dev:
143.30078 + 
143.30079 + static bool sna_uevent_poll(struct sna *sna)
143.30080 + {
143.30081 +-	struct pollfd pfd;
143.30082 +-
143.30083 + 	if (sna->uevent_monitor == NULL)
143.30084 + 		return false;
143.30085 + 
143.30086 +-	pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
143.30087 +-	pfd.events = POLLIN;
143.30088 +-
143.30089 +-	while (poll(&pfd, 1, 0) > 0)
143.30090 +-		sna_handle_uevents(pfd.fd, sna);
143.30091 +-
143.30092 ++	sna_handle_uevents(udev_monitor_get_fd(sna->uevent_monitor), sna);
143.30093 + 	return true;
143.30094 + }
143.30095 + 
143.30096 +@@ -918,8 +932,10 @@ sna_randr_getinfo(ScreenPtr screen, Rotation *rotations)
143.30097 + {
143.30098 + 	struct sna *sna = to_sna_from_screen(screen);
143.30099 + 
143.30100 ++	DBG(("%s()\n", __FUNCTION__));
143.30101 ++
143.30102 + 	if (!sna_uevent_poll(sna))
143.30103 +-		sna_mode_discover(sna);
143.30104 ++		sna_mode_discover(sna, false);
143.30105 + 
143.30106 + 	return sna->mode.rrGetInfo(screen, rotations);
143.30107 + }
143.30108 +@@ -931,8 +947,8 @@ static void sna_leave_vt(VT_FUNC_ARGS_DECL)
143.30109 + 
143.30110 + 	DBG(("%s\n", __FUNCTION__));
143.30111 + 
143.30112 +-	sna_accel_leave(sna);
143.30113 + 	sna_mode_reset(sna);
143.30114 ++	sna_accel_leave(sna);
143.30115 + 
143.30116 + 	if (intel_put_master(sna->dev))
143.30117 + 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
143.30118 +@@ -948,6 +964,12 @@ static Bool sna_early_close_screen(CLOSE_SCREEN_ARGS_DECL)
143.30119 + 
143.30120 + 	/* XXX Note that we will leak kernel resources if !vtSema */
143.30121 + 
143.30122 ++#if HAVE_NOTIFY_FD
143.30123 ++	RemoveBlockAndWakeupHandlers(sna_block_handler,
143.30124 ++				     (ServerWakeupHandlerProcPtr)NoopDDA,
143.30125 ++				     sna);
143.30126 ++#endif
143.30127 ++
143.30128 + 	sna_uevent_fini(sna);
143.30129 + 	sna_mode_close(sna);
143.30130 + 
143.30131 +@@ -1047,12 +1069,13 @@ static void sna_dri_init(struct sna *sna, ScreenPtr screen)
143.30132 + {
143.30133 + 	char str[128] = "";
143.30134 + 
143.30135 +-	if (sna->dri2.available)
143.30136 ++	if (sna->dri2.enable)
143.30137 + 		sna->dri2.open = sna_dri2_open(sna, screen);
143.30138 + 	if (sna->dri2.open)
143.30139 + 		strcat(str, "DRI2 ");
143.30140 + 
143.30141 +-	if (sna->dri3.available)
143.30142 ++	/* Load DRI3 in case DRI2 doesn't work, e.g. vgaarb */
143.30143 ++	if (sna->dri3.enable || (!sna->dri2.open && !sna->dri3.override))
143.30144 + 		sna->dri3.open = sna_dri3_open(sna, screen);
143.30145 + 	if (sna->dri3.open)
143.30146 + 		strcat(str, "DRI3 ");
143.30147 +@@ -1098,7 +1121,8 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
143.30148 + 	DBG(("%s\n", __FUNCTION__));
143.30149 + 
143.30150 + 	assert(sna->scrn == scrn);
143.30151 +-	assert(scrn->pScreen == NULL); /* set afterwards */
143.30152 ++	assert(to_screen_from_sna(sna) == NULL || /* set afterwards */
143.30153 ++	       to_screen_from_sna(sna) == screen);
143.30154 + 
143.30155 + 	assert(sna->freed_pixmap == NULL);
143.30156 + 
143.30157 +@@ -1166,11 +1190,17 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
143.30158 + 	 * later memory should be bound when allocating, e.g rotate_mem */
143.30159 + 	scrn->vtSema = TRUE;
143.30160 + 
143.30161 ++#if !HAVE_NOTIFY_FD
143.30162 + 	sna->BlockHandler = screen->BlockHandler;
143.30163 + 	screen->BlockHandler = sna_block_handler;
143.30164 + 
143.30165 + 	sna->WakeupHandler = screen->WakeupHandler;
143.30166 + 	screen->WakeupHandler = sna_wakeup_handler;
143.30167 ++#else
143.30168 ++	RegisterBlockAndWakeupHandlers(sna_block_handler,
143.30169 ++				       (ServerWakeupHandlerProcPtr)NoopDDA,
143.30170 ++				       sna);
143.30171 ++#endif
143.30172 + 
143.30173 + 	screen->SaveScreen = sna_save_screen;
143.30174 + 	screen->CreateScreenResources = sna_create_screen_resources;
143.30175 +@@ -1190,6 +1220,8 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
143.30176 + 				 CMAP_PALETTED_TRUECOLOR))
143.30177 + 		return FALSE;
143.30178 + 
143.30179 ++	if (!xf86CheckBoolOption(scrn->options, "dpms", TRUE))
143.30180 ++		sna->flags |= SNA_NO_DPMS;
143.30181 + 	xf86DPMSInit(screen, sna_dpms_set, 0);
143.30182 + 
143.30183 + 	sna_uevent_init(sna);
143.30184 +@@ -1244,20 +1276,15 @@ static Bool sna_enter_vt(VT_FUNC_ARGS_DECL)
143.30185 + 	if (intel_get_master(sna->dev))
143.30186 + 		return FALSE;
143.30187 + 
143.30188 ++	sna_accel_enter(sna);
143.30189 ++
143.30190 + 	if (sna->flags & SNA_REPROBE) {
143.30191 +-		DBG(("%s: reporting deferred hotplug event\n",
143.30192 +-		     __FUNCTION__));
143.30193 +-		sna_mode_discover(sna);
143.30194 +-		RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
143.30195 +-		sna->flags &= ~SNA_REPROBE;
143.30196 ++		DBG(("%s: reporting deferred hotplug event\n", __FUNCTION__));
143.30197 ++		sna_mode_discover(sna, true);
143.30198 + 	}
143.30199 + 
143.30200 +-	if (!sna_set_desired_mode(sna)) {
143.30201 +-		intel_put_master(sna->dev);
143.30202 +-		return FALSE;
143.30203 +-	}
143.30204 ++	sna_set_desired_mode(sna);
143.30205 + 
143.30206 +-	sna_accel_enter(sna);
143.30207 + 	return TRUE;
143.30208 + }
143.30209 + 
143.30210 +@@ -1379,6 +1406,9 @@ static void describe_sna(ScrnInfoPtr scrn)
143.30211 + 	xf86DrvMsg(scrn->scrnIndex, X_INFO,
143.30212 + 		   "SNA compiled: %s\n", BUILDER_DESCRIPTION);
143.30213 + #endif
143.30214 ++#if HAS_DEBUG_FULL
143.30215 ++	ErrorF("SNA compiled with full debug logging; expect to run slowly\n");
143.30216 ++#endif
143.30217 + #if !NDEBUG
143.30218 + 	xf86DrvMsg(scrn->scrnIndex, X_INFO,
143.30219 + 		   "SNA compiled with assertions enabled\n");
143.30220 +@@ -1400,6 +1430,7 @@ static void describe_sna(ScrnInfoPtr scrn)
143.30221 + 		   "SNA compiled for use with valgrind\n");
143.30222 + 	VALGRIND_PRINTF("SNA compiled for use with valgrind\n");
143.30223 + #endif
143.30224 ++	DBG(("xf86-video-intel version: %s\n", git_version));
143.30225 + 	DBG(("pixman version: %s\n", pixman_version_string()));
143.30226 + }
143.30227 + 
143.30228 +diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
143.30229 +index a5dfb06b..6ee40336 100644
143.30230 +--- a/src/sna/sna_glyphs.c
143.30231 ++++ b/src/sna/sna_glyphs.c
143.30232 +@@ -74,7 +74,7 @@
143.30233 + #define NO_GLYPHS_VIA_MASK 0
143.30234 + #define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */
143.30235 + #define NO_GLYPHS_SLOW 0
143.30236 +-#define NO_DISCARD_MASK 0
143.30237 ++#define DISCARD_MASK 0 /* -1 = never, 1 = always */
143.30238 + 
143.30239 + #define CACHE_PICTURE_SIZE 1024
143.30240 + #define GLYPH_MIN_SIZE 8
143.30241 +@@ -185,7 +185,7 @@ void sna_glyphs_close(struct sna *sna)
143.30242 +  */
143.30243 + bool sna_glyphs_create(struct sna *sna)
143.30244 + {
143.30245 +-	ScreenPtr screen = sna->scrn->pScreen;
143.30246 ++	ScreenPtr screen = to_screen_from_sna(sna);
143.30247 + 	pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
143.30248 + 	unsigned int formats[] = {
143.30249 + 		PIXMAN_a8,
143.30250 +@@ -1094,6 +1094,9 @@ sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
143.30251 + 
143.30252 + static inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth)
143.30253 + {
143.30254 ++	if (depth < 8)
143.30255 ++		return true;
143.30256 ++
143.30257 + 	if (FORCE_SMALL_MASK)
143.30258 + 		return FORCE_SMALL_MASK > 0;
143.30259 + 
143.30260 +@@ -1156,12 +1159,6 @@ glyphs_via_mask(struct sna *sna,
143.30261 + 	src_x += box.x1 - list->xOff;
143.30262 + 	src_y += box.y1 - list->yOff;
143.30263 + 
143.30264 +-	if (format->depth < 8) {
143.30265 +-		format = PictureMatchFormat(screen, 8, PICT_a8);
143.30266 +-		if (!format)
143.30267 +-			return false;
143.30268 +-	}
143.30269 +-
143.30270 + 	component_alpha = NeedsComponent(format->format);
143.30271 + 	if (use_small_mask(sna, width, height, format->depth)) {
143.30272 + 		pixman_image_t *mask_image;
143.30273 +@@ -1179,7 +1176,7 @@ use_small_mask:
143.30274 + 			return false;
143.30275 + 
143.30276 + 		mask_image =
143.30277 +-			pixman_image_create_bits(format->depth << 24 | format->format,
143.30278 ++			pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
143.30279 + 						 width, height,
143.30280 + 						 pixmap->devPrivate.ptr,
143.30281 + 						 pixmap->devKind);
143.30282 +@@ -1386,10 +1383,11 @@ next_image:
143.30283 + 					DBG(("%s: atlas format=%08x, mask format=%08x\n",
143.30284 + 					     __FUNCTION__,
143.30285 + 					     (int)p->atlas->format,
143.30286 +-					     (int)(format->depth << 24 | format->format)));
143.30287 ++					     (int)mask->format));
143.30288 + 
143.30289 + 					memset(&tmp, 0, sizeof(tmp));
143.30290 +-					if (p->atlas->format == (format->depth << 24 | format->format)) {
143.30291 ++					if (p->atlas->format == mask->format ||
143.30292 ++					    alphaless(p->atlas->format) == mask->format) {
143.30293 + 						ok = sna->render.composite(sna, PictOpAdd,
143.30294 + 									   p->atlas, NULL, mask,
143.30295 + 									   0, 0, 0, 0, 0, 0,
143.30296 +@@ -1561,6 +1559,9 @@ skip_glyph:
143.30297 + 		}
143.30298 + 	}
143.30299 + 
143.30300 ++	assert(format);
143.30301 ++	DBG(("%s: format=%08d, depth=%d\n",
143.30302 ++	     __FUNCTION__, format->format, format->depth));
143.30303 + out:
143.30304 + 	if (list_extents != stack_extents)
143.30305 + 		free(list_extents);
143.30306 +@@ -1573,24 +1574,34 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
143.30307 + 	PictFormatPtr g;
143.30308 + 	uint32_t color;
143.30309 + 
143.30310 +-	if (NO_DISCARD_MASK)
143.30311 +-		return false;
143.30312 ++	if (DISCARD_MASK)
143.30313 ++		return DISCARD_MASK > 0;
143.30314 + 
143.30315 + 	DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n",
143.30316 + 	     __FUNCTION__, nlist,
143.30317 + 	     mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0,
143.30318 + 	     op, op_is_bounded(op)));
143.30319 + 
143.30320 +-	if (nlist == 1 && list->len == 1)
143.30321 +-		return true;
143.30322 ++	if (nlist == 1 && list->len == 1) {
143.30323 ++		if (mask == list->format)
143.30324 ++			return true;
143.30325 ++
143.30326 ++		g = list->format;
143.30327 ++		goto skip;
143.30328 ++	}
143.30329 + 
143.30330 +-	if (!op_is_bounded(op))
143.30331 ++	if (!op_is_bounded(op)) {
143.30332 ++		DBG(("%s: unbounded op, not discarding\n", __FUNCTION__));
143.30333 + 		return false;
143.30334 ++	}
143.30335 + 
143.30336 + 	/* No glyphs overlap and we are not performing a mask conversion. */
143.30337 + 	g = glyphs_format(nlist, list, glyphs);
143.30338 +-	if (mask == g)
143.30339 ++	if (mask == g) {
143.30340 ++		DBG(("%s: mask matches glyphs format, no conversion, so discard mask\n",
143.30341 ++		     __FUNCTION__));
143.30342 + 		return true;
143.30343 ++	}
143.30344 + 
143.30345 + 	DBG(("%s: preferred mask format %08x, depth %d\n",
143.30346 + 	     __FUNCTION__, g ? (unsigned)g->format : 0,  g ? g->depth : 0));
143.30347 +@@ -1605,18 +1616,41 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
143.30348 + 
143.30349 + 			list++;
143.30350 + 		}
143.30351 ++
143.30352 ++		if (!sna_picture_is_solid(src, &color))
143.30353 ++			return false;
143.30354 ++
143.30355 ++		return color >> 24 == 0xff;
143.30356 + 	} else {
143.30357 +-		if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format))
143.30358 ++skip:
143.30359 ++		if (mask->format == g->format)
143.30360 + 			return true;
143.30361 + 
143.30362 +-		if (g->depth != 1)
143.30363 +-			return false;
143.30364 +-	}
143.30365 ++		if (mask->format == alphaless(g->format))
143.30366 ++			return true;
143.30367 ++
143.30368 ++		if (PICT_FORMAT_TYPE(g->format) == PICT_TYPE_A &&
143.30369 ++		    PICT_FORMAT_TYPE(mask->format) != PICT_TYPE_A)
143.30370 ++			return true;
143.30371 + 
143.30372 +-	if (!sna_picture_is_solid(src, &color))
143.30373 + 		return false;
143.30374 ++	}
143.30375 ++}
143.30376 + 
143.30377 +-	return color >> 24 == 0xff;
143.30378 ++static uint32_t pixman_format(PictFormatPtr short_format)
143.30379 ++{
143.30380 ++	uint32_t bpp;
143.30381 ++
143.30382 ++	bpp = short_format->depth;
143.30383 ++	if (bpp <= 1)
143.30384 ++		bpp = 1;
143.30385 ++	else if (bpp <= 8)
143.30386 ++		bpp = 8;
143.30387 ++	else if (bpp <= 16)
143.30388 ++		bpp = 16;
143.30389 ++	else
143.30390 ++		bpp = 32;
143.30391 ++	return bpp << 24 | short_format->format;
143.30392 + }
143.30393 + 
143.30394 + static void
143.30395 +@@ -1756,7 +1790,7 @@ next:
143.30396 + 		if (sigtrap_get() == 0) {
143.30397 + 			if (mask_format) {
143.30398 + 				pixman_composite_glyphs(op, src_image, dst_image,
143.30399 +-							mask_format->format | (mask_format->depth << 24),
143.30400 ++							pixman_format(mask_format),
143.30401 + 							src_x + src_dx + region.extents.x1 - dst_x,
143.30402 + 							src_y + src_dy + region.extents.y1 - dst_y,
143.30403 + 							region.extents.x1, region.extents.y1,
143.30404 +@@ -1815,10 +1849,10 @@ out:
143.30405 + 			     x, y,
143.30406 + 			     mask_format->depth,
143.30407 + 			     (long)mask_format->format,
143.30408 +-			     (long)(mask_format->depth << 24 | mask_format->format),
143.30409 ++			     (long)pixman_format(mask_format),
143.30410 + 			     NeedsComponent(mask_format->format)));
143.30411 + 			mask_image =
143.30412 +-				pixman_image_create_bits(mask_format->depth << 24 | mask_format->format,
143.30413 ++				pixman_image_create_bits(pixman_format(mask_format),
143.30414 + 							 region.extents.x2 - region.extents.x1,
143.30415 + 							 region.extents.y2 - region.extents.y1,
143.30416 + 							 NULL, 0);
143.30417 +@@ -2086,12 +2120,6 @@ glyphs_via_image(struct sna *sna,
143.30418 + 	src_x += box.x1 - list->xOff;
143.30419 + 	src_y += box.y1 - list->yOff;
143.30420 + 
143.30421 +-	if (format->depth < 8) {
143.30422 +-		format = PictureMatchFormat(screen, 8, PICT_a8);
143.30423 +-		if (!format)
143.30424 +-			return false;
143.30425 +-	}
143.30426 +-
143.30427 + 	DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
143.30428 + 	     __FUNCTION__, (unsigned long)format->format,
143.30429 + 	     format->depth, (uint32_t)width*height*format->depth));
143.30430 +@@ -2104,7 +2132,7 @@ glyphs_via_image(struct sna *sna,
143.30431 + 		return false;
143.30432 + 
143.30433 + 	mask_image =
143.30434 +-		pixman_image_create_bits(format->depth << 24 | format->format,
143.30435 ++		pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
143.30436 + 					 width, height,
143.30437 + 					 pixmap->devPrivate.ptr,
143.30438 + 					 pixmap->devKind);
143.30439 +diff --git a/src/sna/sna_io.c b/src/sna/sna_io.c
143.30440 +index d6aa1294..d32bd583 100644
143.30441 +--- a/src/sna/sna_io.c
143.30442 ++++ b/src/sna/sna_io.c
143.30443 +@@ -105,8 +105,10 @@ read_boxes_inplace__cpu(struct kgem *kgem,
143.30444 + 	if (!download_inplace__cpu(kgem, dst, bo, box, n))
143.30445 + 		return false;
143.30446 + 
143.30447 ++	if (bo->tiling == I915_TILING_Y)
143.30448 ++		return false;
143.30449 ++
143.30450 + 	assert(kgem_bo_can_map__cpu(kgem, bo, false));
143.30451 +-	assert(bo->tiling != I915_TILING_Y);
143.30452 + 
143.30453 + 	src = kgem_bo_map__cpu(kgem, bo);
143.30454 + 	if (src == NULL)
143.30455 +@@ -281,6 +283,9 @@ fallback:
143.30456 + 		if (box[n].y2 > extents.y2)
143.30457 + 			extents.y2 = box[n].y2;
143.30458 + 	}
143.30459 ++	if (!can_blt && sna->render.max_3d_size == 0)
143.30460 ++		goto fallback;
143.30461 ++
143.30462 + 	if (kgem_bo_can_map(kgem, src_bo)) {
143.30463 + 		/* Is it worth detiling? */
143.30464 + 		if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096)
143.30465 +@@ -477,6 +482,7 @@ fallback:
143.30466 + 			goto fallback;
143.30467 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.30468 + 	}
143.30469 ++	kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
143.30470 + 
143.30471 + 	tmp_nbox = nbox;
143.30472 + 	tmp_box = box;
143.30473 +@@ -539,6 +545,7 @@ fallback:
143.30474 + 				break;
143.30475 + 
143.30476 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.30477 ++			kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
143.30478 + 			tmp_box += nbox_this_time;
143.30479 + 		} while (1);
143.30480 + 	} else {
143.30481 +@@ -597,6 +604,7 @@ fallback:
143.30482 + 				break;
143.30483 + 
143.30484 + 			_kgem_set_mode(kgem, KGEM_BLT);
143.30485 ++			kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
143.30486 + 			tmp_box += nbox_this_time;
143.30487 + 		} while (1);
143.30488 + 	}
143.30489 +@@ -666,8 +674,10 @@ write_boxes_inplace__tiled(struct kgem *kgem,
143.30490 + {
143.30491 + 	uint8_t *dst;
143.30492 + 
143.30493 ++	if (bo->tiling == I915_TILING_Y)
143.30494 ++		return false;
143.30495 ++
143.30496 + 	assert(kgem->has_wc_mmap || kgem_bo_can_map__cpu(kgem, bo, true));
143.30497 +-	assert(bo->tiling != I915_TILING_Y);
143.30498 + 
143.30499 + 	if (kgem_bo_can_map__cpu(kgem, bo, true)) {
143.30500 + 		dst = kgem_bo_map__cpu(kgem, bo);
143.30501 +@@ -778,6 +788,15 @@ static bool __upload_inplace(struct kgem *kgem,
143.30502 + 	if (FORCE_INPLACE)
143.30503 + 		return FORCE_INPLACE > 0;
143.30504 + 
143.30505 ++	if (bo->exec)
143.30506 ++		return false;
143.30507 ++
143.30508 ++	if (bo->flush)
143.30509 ++		return true;
143.30510 ++
143.30511 ++	if (kgem_bo_can_map__cpu(kgem, bo, true))
143.30512 ++		return true;
143.30513 ++
143.30514 + 	/* If we are writing through the GTT, check first if we might be
143.30515 + 	 * able to almagamate a series of small writes into a single
143.30516 + 	 * operation.
143.30517 +@@ -849,6 +868,8 @@ bool sna_write_boxes(struct sna *sna, PixmapPtr dst,
143.30518 + 		if (box[n].y2 > extents.y2)
143.30519 + 			extents.y2 = box[n].y2;
143.30520 + 	}
143.30521 ++	if (!can_blt && sna->render.max_3d_size == 0)
143.30522 ++		goto fallback;
143.30523 + 
143.30524 + 	/* Try to avoid switching rings... */
143.30525 + 	if (!can_blt || kgem->ring == KGEM_RENDER ||
143.30526 +@@ -1038,6 +1059,7 @@ tile:
143.30527 + 			goto fallback;
143.30528 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.30529 + 	}
143.30530 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
143.30531 + 
143.30532 + 	if (kgem->gen >= 0100) {
143.30533 + 		cmd |= 8;
143.30534 +@@ -1129,6 +1151,7 @@ tile:
143.30535 + 			if (nbox) {
143.30536 + 				_kgem_submit(kgem);
143.30537 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.30538 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
143.30539 + 			}
143.30540 + 
143.30541 + 			kgem_bo_destroy(kgem, src_bo);
143.30542 +@@ -1224,6 +1247,7 @@ tile:
143.30543 + 			if (nbox) {
143.30544 + 				_kgem_submit(kgem);
143.30545 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.30546 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
143.30547 + 			}
143.30548 + 
143.30549 + 			kgem_bo_destroy(kgem, src_bo);
143.30550 +@@ -1541,6 +1565,7 @@ tile:
143.30551 + 			goto fallback;
143.30552 + 		_kgem_set_mode(kgem, KGEM_BLT);
143.30553 + 	}
143.30554 ++	kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
143.30555 + 
143.30556 + 	if (sna->kgem.gen >= 0100) {
143.30557 + 		cmd |= 8;
143.30558 +@@ -1636,6 +1661,7 @@ tile:
143.30559 + 			if (nbox) {
143.30560 + 				_kgem_submit(kgem);
143.30561 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.30562 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
143.30563 + 			}
143.30564 + 
143.30565 + 			kgem_bo_destroy(kgem, src_bo);
143.30566 +@@ -1732,6 +1758,7 @@ tile:
143.30567 + 			if (nbox) {
143.30568 + 				_kgem_submit(kgem);
143.30569 + 				_kgem_set_mode(kgem, KGEM_BLT);
143.30570 ++				kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
143.30571 + 			}
143.30572 + 
143.30573 + 			kgem_bo_destroy(kgem, src_bo);
143.30574 +diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
143.30575 +index 6dd6fe88..2796d972 100644
143.30576 +--- a/src/sna/sna_present.c
143.30577 ++++ b/src/sna/sna_present.c
143.30578 +@@ -27,6 +27,7 @@
143.30579 + #include <sys/types.h>
143.30580 + #include <fcntl.h>
143.30581 + #include <unistd.h>
143.30582 ++#include <sys/poll.h>
143.30583 + #include <errno.h>
143.30584 + #include <xf86drm.h>
143.30585 + 
143.30586 +@@ -38,21 +39,73 @@
143.30587 + static present_screen_info_rec present_info;
143.30588 + 
143.30589 + struct sna_present_event {
143.30590 +-	uint64_t event_id;
143.30591 + 	xf86CrtcPtr crtc;
143.30592 ++	struct sna *sna;
143.30593 ++	struct list link;
143.30594 ++	uint64_t *event_id;
143.30595 ++	uint64_t target_msc;
143.30596 ++	int n_event_id;
143.30597 ++	bool queued;
143.30598 + };
143.30599 + 
143.30600 ++static void sna_present_unflip(ScreenPtr screen, uint64_t event_id);
143.30601 ++static bool sna_present_queue(struct sna_present_event *info,
143.30602 ++			      uint64_t last_msc);
143.30603 ++
143.30604 + static inline struct sna_present_event *
143.30605 + to_present_event(uintptr_t  data)
143.30606 + {
143.30607 + 	return (struct sna_present_event *)(data & ~3);
143.30608 + }
143.30609 + 
143.30610 ++static struct sna_present_event *info_alloc(struct sna *sna)
143.30611 ++{
143.30612 ++	struct sna_present_event *info;
143.30613 ++
143.30614 ++	info = sna->present.freed_info;
143.30615 ++	if (info) {
143.30616 ++		sna->present.freed_info = NULL;
143.30617 ++		return info;
143.30618 ++	}
143.30619 ++
143.30620 ++	return malloc(sizeof(struct sna_present_event) + sizeof(uint64_t));
143.30621 ++}
143.30622 ++
143.30623 ++static void info_free(struct sna_present_event *info)
143.30624 ++{
143.30625 ++	struct sna *sna = info->sna;
143.30626 ++
143.30627 ++	if (sna->present.freed_info)
143.30628 ++		free(sna->present.freed_info);
143.30629 ++
143.30630 ++	sna->present.freed_info = info;
143.30631 ++}
143.30632 ++
143.30633 ++static inline bool msc_before(uint64_t msc, uint64_t target)
143.30634 ++{
143.30635 ++	return (int64_t)(msc - target) < 0;
143.30636 ++}
143.30637 ++
143.30638 + #define MARK_PRESENT(x) ((void *)((uintptr_t)(x) | 2))
143.30639 + 
143.30640 +-static int pipe_from_crtc(RRCrtcPtr crtc)
143.30641 ++static inline xf86CrtcPtr unmask_crtc(xf86CrtcPtr crtc)
143.30642 ++{
143.30643 ++	return (xf86CrtcPtr)((uintptr_t)crtc & ~1);
143.30644 ++}
143.30645 ++
143.30646 ++static inline xf86CrtcPtr mark_crtc(xf86CrtcPtr crtc)
143.30647 ++{
143.30648 ++	return (xf86CrtcPtr)((uintptr_t)crtc | 1);
143.30649 ++}
143.30650 ++
143.30651 ++static inline bool has_vblank(xf86CrtcPtr crtc)
143.30652 ++{
143.30653 ++	return (uintptr_t)crtc & 1;
143.30654 ++}
143.30655 ++
143.30656 ++static inline int pipe_from_crtc(RRCrtcPtr crtc)
143.30657 + {
143.30658 +-	return crtc ? sna_crtc_to_pipe(crtc->devPrivate) : -1;
143.30659 ++	return crtc ? sna_crtc_pipe(crtc->devPrivate) : -1;
143.30660 + }
143.30661 + 
143.30662 + static uint32_t pipe_select(int pipe)
143.30663 +@@ -74,6 +127,215 @@ static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, i
143.30664 + 	return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
143.30665 + }
143.30666 + 
143.30667 ++static uint64_t gettime_ust64(void)
143.30668 ++{
143.30669 ++	struct timespec tv;
143.30670 ++
143.30671 ++	if (clock_gettime(CLOCK_MONOTONIC, &tv))
143.30672 ++		return GetTimeInMicros();
143.30673 ++
143.30674 ++	return ust64(tv.tv_sec, tv.tv_nsec / 1000);
143.30675 ++}
143.30676 ++
143.30677 ++static void vblank_complete(struct sna_present_event *info,
143.30678 ++			    uint64_t ust, uint64_t msc)
143.30679 ++{
143.30680 ++	int n;
143.30681 ++
143.30682 ++	if (msc_before(msc, info->target_msc)) {
143.30683 ++		DBG(("%s: event=%d too early, now %lld, expected %lld\n",
143.30684 ++		     __FUNCTION__,
143.30685 ++		     info->event_id[0],
143.30686 ++		     (long long)msc, (long long)info->target_msc));
143.30687 ++		if (sna_present_queue(info, msc))
143.30688 ++			return;
143.30689 ++	}
143.30690 ++
143.30691 ++	DBG(("%s: %d events complete\n", __FUNCTION__, info->n_event_id));
143.30692 ++	for (n = 0; n < info->n_event_id; n++) {
143.30693 ++		DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete%s\n", __FUNCTION__,
143.30694 ++		     sna_crtc_pipe(info->crtc),
143.30695 ++		     (int)(ust / 1000000), (int)(ust % 1000000),
143.30696 ++		     (long long)msc, (long long)info->target_msc,
143.30697 ++		     (long long)info->event_id[n],
143.30698 ++		     info->target_msc && msc == (uint32_t)info->target_msc ? "" : ": MISS"));
143.30699 ++		present_event_notify(info->event_id[n], ust, msc);
143.30700 ++	}
143.30701 ++	if (info->n_event_id > 1)
143.30702 ++		free(info->event_id);
143.30703 ++	list_del(&info->link);
143.30704 ++	info_free(info);
143.30705 ++}
143.30706 ++
143.30707 ++static uint32_t msc_to_delay(xf86CrtcPtr crtc, uint64_t target)
143.30708 ++{
143.30709 ++	const DisplayModeRec *mode = &crtc->desiredMode;
143.30710 ++	const struct ust_msc *swap = sna_crtc_last_swap(crtc);
143.30711 ++	int64_t delay, subframe;
143.30712 ++
143.30713 ++	assert(mode->Clock);
143.30714 ++
143.30715 ++	delay = target - swap->msc;
143.30716 ++	assert(delay >= 0);
143.30717 ++	if (delay > 1) { /* try to use the hw vblank for the last frame */
143.30718 ++		delay--;
143.30719 ++		subframe = 0;
143.30720 ++	} else {
143.30721 ++		subframe = gettime_ust64() - swap_ust(swap);
143.30722 ++		subframe += 500;
143.30723 ++		subframe /= 1000;
143.30724 ++	}
143.30725 ++	delay *= mode->VTotal * mode->HTotal / mode->Clock;
143.30726 ++	if (subframe < delay)
143.30727 ++		delay -= subframe;
143.30728 ++	else
143.30729 ++		delay = 0;
143.30730 ++
143.30731 ++	DBG(("%s: sleep %d frames, %llu ms\n", __FUNCTION__,
143.30732 ++	     (int)(target - swap->msc), (long long)delay));
143.30733 ++	assert(delay >= 0);
143.30734 ++	return MIN(delay, INT32_MAX);
143.30735 ++}
143.30736 ++
143.30737 ++static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data)
143.30738 ++{
143.30739 ++	struct sna_present_event *info = data;
143.30740 ++	union drm_wait_vblank vbl;
143.30741 ++	uint64_t msc, ust;
143.30742 ++
143.30743 ++	DBG(("%s(event=%lldx%d, now=%d)\n", __FUNCTION__, (long long)info->event_id[0], info->n_event_id, now));
143.30744 ++
143.30745 ++	VG_CLEAR(vbl);
143.30746 ++	vbl.request.type = DRM_VBLANK_RELATIVE;
143.30747 ++	vbl.request.sequence = 0;
143.30748 ++	if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
143.30749 ++		ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
143.30750 ++		msc = sna_crtc_record_vblank(info->crtc, &vbl);
143.30751 ++		DBG(("%s: event=%lld, target msc=%lld, now %lld\n",
143.30752 ++		     __FUNCTION__, (long long)info->event_id[0], (long long)info->target_msc, (long long)msc));
143.30753 ++		if (msc_before(msc, info->target_msc)) {
143.30754 ++			int delta = info->target_msc - msc;
143.30755 ++			uint32_t delay;
143.30756 ++
143.30757 ++			DBG(("%s: too early, requeuing delta=%d\n", __FUNCTION__, delta));
143.30758 ++			assert(info->target_msc - msc < 1ull<<31);
143.30759 ++			if (delta <= 2) {
143.30760 ++				vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
143.30761 ++				vbl.request.sequence = info->target_msc;
143.30762 ++				vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
143.30763 ++				if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
143.30764 ++					DBG(("%s: scheduled new vblank event for %lld\n", __FUNCTION__, (long long)info->target_msc));
143.30765 ++					info->queued = true;
143.30766 ++					if (delta == 1) {
143.30767 ++						sna_crtc_set_vblank(info->crtc);
143.30768 ++						info->crtc = mark_crtc(info->crtc);
143.30769 ++					}
143.30770 ++					free(timer);
143.30771 ++					return 0;
143.30772 ++				}
143.30773 ++			}
143.30774 ++
143.30775 ++			delay = msc_to_delay(info->crtc, info->target_msc);
143.30776 ++			if (delay) {
143.30777 ++				DBG(("%s: requeueing timer for %dms delay\n", __FUNCTION__, delay));
143.30778 ++				return delay;
143.30779 ++			}
143.30780 ++
143.30781 ++			/* As a last resort use a blocking wait.
143.30782 ++			 * Less than a millisecond for (hopefully) a rare case.
143.30783 ++			 */
143.30784 ++			DBG(("%s: blocking wait!\n", __FUNCTION__));
143.30785 ++			vbl.request.type = DRM_VBLANK_ABSOLUTE;
143.30786 ++			vbl.request.sequence = info->target_msc;
143.30787 ++			if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
143.30788 ++				ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
143.30789 ++				msc = sna_crtc_record_vblank(info->crtc, &vbl);
143.30790 ++			} else {
143.30791 ++				DBG(("%s: blocking wait failed, fudging\n",
143.30792 ++				     __FUNCTION__));
143.30793 ++				goto fixup;
143.30794 ++			}
143.30795 ++		}
143.30796 ++	} else {
143.30797 ++fixup:
143.30798 ++		ust = gettime_ust64();
143.30799 ++		msc = info->target_msc;
143.30800 ++		DBG(("%s: event=%lld, CRTC OFF, target msc=%lld, was %lld (off)\n",
143.30801 ++		     __FUNCTION__, (long long)info->event_id[0], (long long)info->target_msc, (long long)sna_crtc_last_swap(info->crtc)->msc));
143.30802 ++	}
143.30803 ++
143.30804 ++	vblank_complete(info, ust, msc);
143.30805 ++	free(timer);
143.30806 ++	return 0;
143.30807 ++}
143.30808 ++
143.30809 ++static bool sna_fake_vblank(struct sna_present_event *info)
143.30810 ++{
143.30811 ++	const struct ust_msc *swap = sna_crtc_last_swap(info->crtc);
143.30812 ++	uint32_t delay;
143.30813 ++
143.30814 ++	if (msc_before(swap->msc, info->target_msc))
143.30815 ++		delay = msc_to_delay(info->crtc, info->target_msc);
143.30816 ++	else
143.30817 ++		delay = 0;
143.30818 ++
143.30819 ++	DBG(("%s(event=%lldx%d, target_msc=%lld, msc=%lld, delay=%ums)\n",
143.30820 ++	     __FUNCTION__, (long long)info->event_id[0], info->n_event_id,
143.30821 ++	     (long long)info->target_msc, (long long)swap->msc, delay));
143.30822 ++	if (delay == 0) {
143.30823 ++		uint64_t ust, msc;
143.30824 ++
143.30825 ++		if (msc_before(swap->msc, info->target_msc)) {
143.30826 ++			/* Fixup and pretend it completed immediately */
143.30827 ++			msc = info->target_msc;
143.30828 ++			ust = gettime_ust64();
143.30829 ++		} else {
143.30830 ++			msc = swap->msc;
143.30831 ++			ust = swap_ust(swap);
143.30832 ++		}
143.30833 ++
143.30834 ++		vblank_complete(info, ust, msc);
143.30835 ++		return true;
143.30836 ++	}
143.30837 ++
143.30838 ++	return TimerSet(NULL, 0, delay, sna_fake_vblank_handler, info);
143.30839 ++}
143.30840 ++
143.30841 ++static bool sna_present_queue(struct sna_present_event *info,
143.30842 ++			      uint64_t last_msc)
143.30843 ++{
143.30844 ++	union drm_wait_vblank vbl;
143.30845 ++	int delta = info->target_msc - last_msc;
143.30846 ++
143.30847 ++	DBG(("%s: target msc=%llu, seq=%u (last_msc=%llu), delta=%d\n",
143.30848 ++	     __FUNCTION__,
143.30849 ++	     (long long)info->target_msc,
143.30850 ++	     (unsigned)info->target_msc,
143.30851 ++	     (long long)last_msc,
143.30852 ++	     delta));
143.30853 ++	assert(info->target_msc - last_msc < 1ull<<31);
143.30854 ++	assert(delta >= 0);
143.30855 ++
143.30856 ++	VG_CLEAR(vbl);
143.30857 ++	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
143.30858 ++	vbl.request.sequence = info->target_msc;
143.30859 ++	vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
143.30860 ++	if (delta > 2 ||
143.30861 ++	    sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc))) {
143.30862 ++		DBG(("%s: vblank enqueue failed, faking delta=%d\n", __FUNCTION__, delta));
143.30863 ++		if (!sna_fake_vblank(info))
143.30864 ++			return false;
143.30865 ++	} else {
143.30866 ++		info->queued = true;
143.30867 ++		if (delta == 1) {
143.30868 ++			sna_crtc_set_vblank(info->crtc);
143.30869 ++			info->crtc = mark_crtc(info->crtc);
143.30870 ++		}
143.30871 ++	}
143.30872 ++
143.30873 ++	return true;
143.30874 ++}
143.30875 ++
143.30876 + static RRCrtcPtr
143.30877 + sna_present_get_crtc(WindowPtr window)
143.30878 + {
143.30879 +@@ -81,7 +343,10 @@ sna_present_get_crtc(WindowPtr window)
143.30880 + 	BoxRec box;
143.30881 + 	xf86CrtcPtr crtc;
143.30882 + 
143.30883 +-	DBG(("%s\n", __FUNCTION__));
143.30884 ++	DBG(("%s: window=%ld (pixmap=%ld), box=(%d, %d)x(%d, %d)\n",
143.30885 ++	     __FUNCTION__, window->drawable.id, get_window_pixmap(window)->drawable.serialNumber,
143.30886 ++	     window->drawable.x, window->drawable.y,
143.30887 ++	     window->drawable.width, window->drawable.height));
143.30888 + 
143.30889 + 	box.x1 = window->drawable.x;
143.30890 + 	box.y1 = window->drawable.y;
143.30891 +@@ -99,26 +364,59 @@ static int
143.30892 + sna_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
143.30893 + {
143.30894 + 	struct sna *sna = to_sna_from_screen(crtc->pScreen);
143.30895 +-	int pipe = pipe_from_crtc(crtc);
143.30896 + 	union drm_wait_vblank vbl;
143.30897 + 
143.30898 +-	DBG(("%s(pipe=%d)\n", __FUNCTION__, pipe));
143.30899 ++	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc->devPrivate)));
143.30900 ++	if (sna_crtc_has_vblank(crtc->devPrivate)) {
143.30901 ++		DBG(("%s: vblank active, reusing last swap msc/ust\n",
143.30902 ++		     __FUNCTION__));
143.30903 ++		goto last;
143.30904 ++	}
143.30905 + 
143.30906 + 	VG_CLEAR(vbl);
143.30907 + 	vbl.request.type = DRM_VBLANK_RELATIVE;
143.30908 + 	vbl.request.sequence = 0;
143.30909 +-	if (sna_wait_vblank(sna, &vbl, pipe) == 0) {
143.30910 ++	if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc->devPrivate)) == 0) {
143.30911 ++		struct sna_present_event *info;
143.30912 ++
143.30913 + 		*ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
143.30914 + 		*msc = sna_crtc_record_vblank(crtc->devPrivate, &vbl);
143.30915 ++
143.30916 ++		info = info_alloc(sna);
143.30917 ++		if (info) {
143.30918 ++			info->crtc = crtc->devPrivate;
143.30919 ++			info->sna = sna;
143.30920 ++			info->target_msc = *msc + 1;
143.30921 ++			info->event_id = (uint64_t *)(info + 1);
143.30922 ++			info->n_event_id = 0;
143.30923 ++
143.30924 ++			vbl.request.type =
143.30925 ++				DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
143.30926 ++			vbl.request.sequence = info->target_msc;
143.30927 ++			vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
143.30928 ++
143.30929 ++			if (sna_wait_vblank(info->sna, &vbl,
143.30930 ++					    sna_crtc_pipe(info->crtc)) == 0) {
143.30931 ++				list_add(&info->link,
143.30932 ++					 &sna->present.vblank_queue);
143.30933 ++				info->queued = true;
143.30934 ++				sna_crtc_set_vblank(info->crtc);
143.30935 ++				info->crtc = mark_crtc(info->crtc);
143.30936 ++			} else
143.30937 ++				info_free(info);
143.30938 ++		}
143.30939 + 	} else {
143.30940 +-		const struct ust_msc *swap = sna_crtc_last_swap(crtc->devPrivate);
143.30941 +-		*ust = ust64(swap->tv_sec, swap->tv_usec);
143.30942 ++		const struct ust_msc *swap;
143.30943 ++last:
143.30944 ++		swap = sna_crtc_last_swap(crtc->devPrivate);
143.30945 ++		*ust = swap_ust(swap);
143.30946 + 		*msc = swap->msc;
143.30947 + 	}
143.30948 + 
143.30949 +-	DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__, pipe,
143.30950 ++	DBG(("%s: pipe=%d, tv=%d.%06d seq=%d msc=%lld\n", __FUNCTION__,
143.30951 ++	     sna_crtc_pipe(crtc->devPrivate),
143.30952 + 	     (int)(*ust / 1000000), (int)(*ust % 1000000),
143.30953 +-	     (long long)*msc));
143.30954 ++	     vbl.reply.sequence, (long long)*msc));
143.30955 + 
143.30956 + 	return Success;
143.30957 + }
143.30958 +@@ -127,43 +425,106 @@ void
143.30959 + sna_present_vblank_handler(struct drm_event_vblank *event)
143.30960 + {
143.30961 + 	struct sna_present_event *info = to_present_event(event->user_data);
143.30962 ++	uint64_t msc;
143.30963 + 
143.30964 +-	DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__,
143.30965 +-	     sna_crtc_to_pipe(info->crtc),
143.30966 +-	     event->tv_sec, event->tv_usec, event->sequence,
143.30967 +-	     (long long)info->event_id));
143.30968 +-	present_event_notify(info->event_id,
143.30969 +-			     ust64(event->tv_sec, event->tv_usec),
143.30970 +-			     sna_crtc_record_event(info->crtc, event));
143.30971 +-	free(info);
143.30972 ++	if (!info->queued) {
143.30973 ++		DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__));
143.30974 ++		assert(!has_vblank(info->crtc));
143.30975 ++		return;
143.30976 ++	}
143.30977 ++
143.30978 ++	if (has_vblank(info->crtc)) {
143.30979 ++		DBG(("%s: clearing immediate flag\n", __FUNCTION__));
143.30980 ++		info->crtc = unmask_crtc(info->crtc);
143.30981 ++		sna_crtc_clear_vblank(info->crtc);
143.30982 ++	}
143.30983 ++
143.30984 ++	msc = sna_crtc_record_event(info->crtc, event);
143.30985 ++
143.30986 ++	if (info->sna->mode.shadow_wait) {
143.30987 ++		DBG(("%s: recursed from TearFree\n", __FUNCTION__));
143.30988 ++		if (TimerSet(NULL, 0, 1, sna_fake_vblank_handler, info))
143.30989 ++			return;
143.30990 ++	}
143.30991 ++
143.30992 ++	vblank_complete(info, ust64(event->tv_sec, event->tv_usec), msc);
143.30993 + }
143.30994 + 
143.30995 + static int
143.30996 + sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
143.30997 + {
143.30998 + 	struct sna *sna = to_sna_from_screen(crtc->pScreen);
143.30999 +-	struct sna_present_event *event;
143.31000 +-	union drm_wait_vblank vbl;
143.31001 +-
143.31002 +-	DBG(("%s(pipe=%d, event=%lld, msc=%lld)\n",
143.31003 +-	     __FUNCTION__, pipe_from_crtc(crtc),
143.31004 +-	     (long long)event_id, (long long)msc));
143.31005 ++	struct sna_present_event *info, *tmp;
143.31006 ++	const struct ust_msc *swap;
143.31007 + 
143.31008 +-	event = malloc(sizeof(struct sna_present_event));
143.31009 +-	if (event == NULL)
143.31010 ++	if (!sna_crtc_is_on(crtc->devPrivate))
143.31011 + 		return BadAlloc;
143.31012 + 
143.31013 +-	event->event_id = event_id;
143.31014 +-	event->crtc = crtc->devPrivate;
143.31015 ++	swap = sna_crtc_last_swap(crtc->devPrivate);
143.31016 ++	DBG(("%s(pipe=%d, event=%lld, msc=%lld, last swap=%lld)\n",
143.31017 ++	     __FUNCTION__, sna_crtc_pipe(crtc->devPrivate),
143.31018 ++	     (long long)event_id, (long long)msc, (long long)swap->msc));
143.31019 + 
143.31020 +-	VG_CLEAR(vbl);
143.31021 +-	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
143.31022 +-	vbl.request.sequence = msc;
143.31023 +-	vbl.request.signal = (uintptr_t)MARK_PRESENT(event);
143.31024 +-	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(event->crtc))) {
143.31025 +-		DBG(("%s: vblank enqueue failed\n", __FUNCTION__));
143.31026 +-		free(event);
143.31027 +-		return BadMatch;
143.31028 ++	if (warn_unless((int64_t)(msc - swap->msc) >= 0)) {
143.31029 ++		DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
143.31030 ++		     sna_crtc_pipe(crtc->devPrivate),
143.31031 ++		     swap->tv_sec, swap->tv_usec,
143.31032 ++		     (long long)swap->msc, (long long)msc,
143.31033 ++		     (long long)event_id));
143.31034 ++		present_event_notify(event_id, swap_ust(swap), swap->msc);
143.31035 ++		return Success;
143.31036 ++	}
143.31037 ++	if (warn_unless(msc - swap->msc < 1ull<<31))
143.31038 ++		return BadValue;
143.31039 ++
143.31040 ++	list_for_each_entry(tmp, &sna->present.vblank_queue, link) {
143.31041 ++		if (tmp->target_msc == msc &&
143.31042 ++		    unmask_crtc(tmp->crtc) == crtc->devPrivate) {
143.31043 ++			uint64_t *events = tmp->event_id;
143.31044 ++
143.31045 ++			if (tmp->n_event_id &&
143.31046 ++			    is_power_of_two(tmp->n_event_id)) {
143.31047 ++				events = malloc(2*sizeof(uint64_t)*tmp->n_event_id);
143.31048 ++				if (events == NULL)
143.31049 ++					return BadAlloc;
143.31050 ++
143.31051 ++				memcpy(events,
143.31052 ++				       tmp->event_id,
143.31053 ++				       tmp->n_event_id*sizeof(uint64_t));
143.31054 ++				if (tmp->n_event_id != 1)
143.31055 ++					free(tmp->event_id);
143.31056 ++				tmp->event_id = events;
143.31057 ++			}
143.31058 ++
143.31059 ++			DBG(("%s: appending event=%lld to vblank %lld x %d\n",
143.31060 ++			     __FUNCTION__, (long long)event_id, (long long)msc, tmp->n_event_id+1));
143.31061 ++			events[tmp->n_event_id++] = event_id;
143.31062 ++			return Success;
143.31063 ++		}
143.31064 ++		if ((int64_t)(tmp->target_msc - msc) > 0) {
143.31065 ++			DBG(("%s: previous target_msc=%lld invalid for coalescing\n",
143.31066 ++			     __FUNCTION__, (long long)tmp->target_msc));
143.31067 ++			break;
143.31068 ++		}
143.31069 ++	}
143.31070 ++
143.31071 ++	info = info_alloc(sna);
143.31072 ++	if (info == NULL)
143.31073 ++		return BadAlloc;
143.31074 ++
143.31075 ++	info->crtc = crtc->devPrivate;
143.31076 ++	info->sna = sna;
143.31077 ++	info->target_msc = msc;
143.31078 ++	info->event_id = (uint64_t *)(info + 1);
143.31079 ++	info->event_id[0] = event_id;
143.31080 ++	info->n_event_id = 1;
143.31081 ++	list_add_tail(&info->link, &tmp->link);
143.31082 ++	info->queued = false;
143.31083 ++
143.31084 ++	if (!sna_present_queue(info, swap->msc)) {
143.31085 ++		list_del(&info->link);
143.31086 ++		info_free(info);
143.31087 ++		return BadAlloc;
143.31088 + 	}
143.31089 + 
143.31090 + 	return Success;
143.31091 +@@ -180,14 +541,6 @@ sna_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
143.31092 + static void
143.31093 + sna_present_flush(WindowPtr window)
143.31094 + {
143.31095 +-	PixmapPtr pixmap = get_window_pixmap(window);
143.31096 +-	struct sna_pixmap *priv;
143.31097 +-
143.31098 +-	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
143.31099 +-
143.31100 +-	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE);
143.31101 +-	if (priv && priv->gpu_bo)
143.31102 +-		kgem_scanout_flush(&to_sna_from_pixmap(pixmap)->kgem, priv->gpu_bo);
143.31103 + }
143.31104 + 
143.31105 + static bool
143.31106 +@@ -201,8 +554,13 @@ check_flip__crtc(struct sna *sna,
143.31107 + 
143.31108 + 	assert(sna->scrn->vtSema);
143.31109 + 
143.31110 +-	if (sna->mode.shadow_active) {
143.31111 +-		DBG(("%s: shadow buffer active\n", __FUNCTION__));
143.31112 ++	if (!sna->mode.front_active) {
143.31113 ++		DBG(("%s: DPMS off, no flips\n", __FUNCTION__));
143.31114 ++		return FALSE;
143.31115 ++	}
143.31116 ++
143.31117 ++	if (sna->mode.rr_active) {
143.31118 ++		DBG(("%s: RandR transformation active\n", __FUNCTION__));
143.31119 + 		return false;
143.31120 + 	}
143.31121 + 
143.31122 +@@ -224,6 +582,11 @@ sna_present_check_flip(RRCrtcPtr crtc,
143.31123 + 	     pixmap->drawable.serialNumber,
143.31124 + 	     sync_flip));
143.31125 + 
143.31126 ++	if (!sna->scrn->vtSema) {
143.31127 ++		DBG(("%s: VT switched away, no flips\n", __FUNCTION__));
143.31128 ++		return FALSE;
143.31129 ++	}
143.31130 ++
143.31131 + 	if (sna->flags & SNA_NO_FLIP) {
143.31132 + 		DBG(("%s: flips not suported\n", __FUNCTION__));
143.31133 + 		return FALSE;
143.31134 +@@ -231,7 +594,7 @@ sna_present_check_flip(RRCrtcPtr crtc,
143.31135 + 
143.31136 + 	if (sync_flip) {
143.31137 + 		if ((sna->flags & SNA_HAS_FLIP) == 0) {
143.31138 +-			DBG(("%s: async flips not suported\n", __FUNCTION__));
143.31139 ++			DBG(("%s: sync flips not suported\n", __FUNCTION__));
143.31140 + 			return FALSE;
143.31141 + 		}
143.31142 + 	} else {
143.31143 +@@ -257,24 +620,39 @@ sna_present_check_flip(RRCrtcPtr crtc,
143.31144 + 		return FALSE;
143.31145 + 	}
143.31146 + 
143.31147 +-	return TRUE;
143.31148 +-}
143.31149 +-
143.31150 +-static uint64_t gettime_ust64(void)
143.31151 +-{
143.31152 +-	struct timespec tv;
143.31153 ++	if (flip->pinned) {
143.31154 ++		assert(flip->gpu_bo);
143.31155 ++		if (sna->flags & SNA_LINEAR_FB) {
143.31156 ++			if (flip->gpu_bo->tiling != I915_TILING_NONE) {
143.31157 ++				DBG(("%s: pined bo, tilng=%d needs NONE\n",
143.31158 ++				     __FUNCTION__, flip->gpu_bo->tiling));
143.31159 ++				return FALSE;
143.31160 ++			}
143.31161 ++		} else {
143.31162 ++			if (!sna->kgem.can_scanout_y &&
143.31163 ++			    flip->gpu_bo->tiling == I915_TILING_Y) {
143.31164 ++				DBG(("%s: pined bo, tilng=%d and can't scanout Y\n",
143.31165 ++				     __FUNCTION__, flip->gpu_bo->tiling));
143.31166 ++				return FALSE;
143.31167 ++			}
143.31168 ++		}
143.31169 + 
143.31170 +-	if (clock_gettime(CLOCK_MONOTONIC, &tv))
143.31171 +-		return 0;
143.31172 ++		if (flip->gpu_bo->pitch & 63) {
143.31173 ++			DBG(("%s: pined bo, bad pitch=%d\n",
143.31174 ++			     __FUNCTION__, flip->gpu_bo->pitch));
143.31175 ++			return FALSE;
143.31176 ++		}
143.31177 ++	}
143.31178 + 
143.31179 +-	return ust64(tv.tv_sec, tv.tv_nsec / 1000);
143.31180 ++	return TRUE;
143.31181 + }
143.31182 + 
143.31183 + static Bool
143.31184 +-page_flip__async(RRCrtcPtr crtc,
143.31185 +-		 uint64_t event_id,
143.31186 +-		 uint64_t target_msc,
143.31187 +-		 struct kgem_bo *bo)
143.31188 ++flip__async(struct sna *sna,
143.31189 ++	    RRCrtcPtr crtc,
143.31190 ++	    uint64_t event_id,
143.31191 ++	    uint64_t target_msc,
143.31192 ++	    struct kgem_bo *bo)
143.31193 + {
143.31194 + 	DBG(("%s(pipe=%d, event=%lld, handle=%d)\n",
143.31195 + 	     __FUNCTION__,
143.31196 +@@ -282,17 +660,17 @@ page_flip__async(RRCrtcPtr crtc,
143.31197 + 	     (long long)event_id,
143.31198 + 	     bo->handle));
143.31199 + 
143.31200 +-	if (!sna_page_flip(to_sna_from_screen(crtc->pScreen), bo, NULL, NULL)) {
143.31201 ++	if (!sna_page_flip(sna, bo, NULL, NULL)) {
143.31202 + 		DBG(("%s: async pageflip failed\n", __FUNCTION__));
143.31203 + 		present_info.capabilities &= ~PresentCapabilityAsync;
143.31204 + 		return FALSE;
143.31205 + 	}
143.31206 + 
143.31207 +-	DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__,
143.31208 ++	DBG(("%s: pipe=%d tv=%ld.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
143.31209 + 	     pipe_from_crtc(crtc),
143.31210 +-	     gettime_ust64() / 1000000, gettime_ust64() % 1000000,
143.31211 +-	     sna_crtc_last_swap(crtc->devPrivate)->msc,
143.31212 +-	     (long long)event_id));
143.31213 ++	     (long)(gettime_ust64() / 1000000), (int)(gettime_ust64() % 1000000),
143.31214 ++	     crtc ? (long long)sna_crtc_last_swap(crtc->devPrivate)->msc : 0LL,
143.31215 ++	     (long long)target_msc, (long long)event_id));
143.31216 + 	present_event_notify(event_id, gettime_ust64(), target_msc);
143.31217 + 	return TRUE;
143.31218 + }
143.31219 +@@ -303,7 +681,12 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
143.31220 + 	struct sna_present_event *info = data;
143.31221 + 	struct ust_msc swap;
143.31222 + 
143.31223 +-	DBG(("%s(sequence=%d)\n", __FUNCTION__, event->sequence));
143.31224 ++	DBG(("%s(sequence=%d): event=%lld\n", __FUNCTION__, event->sequence, (long long)info->event_id[0]));
143.31225 ++	assert(info->n_event_id == 1);
143.31226 ++	if (!info->queued) {
143.31227 ++		DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__));
143.31228 ++		return;
143.31229 ++	}
143.31230 + 
143.31231 + 	if (info->crtc == NULL) {
143.31232 + 		swap.tv_sec = event->tv_sec;
143.31233 +@@ -312,22 +695,33 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
143.31234 + 	} else
143.31235 + 		swap = *sna_crtc_last_swap(info->crtc);
143.31236 + 
143.31237 +-	DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
143.31238 +-	     info->crtc ? sna_crtc_to_pipe(info->crtc) : -1,
143.31239 ++	DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld (target %lld), event=%lld complete%s\n", __FUNCTION__,
143.31240 ++	     info->crtc ? sna_crtc_pipe(info->crtc) : -1,
143.31241 + 	     swap.tv_sec, swap.tv_usec, (long long)swap.msc,
143.31242 +-	     (long long)info->event_id));
143.31243 +-	present_event_notify(info->event_id, ust64(swap.tv_sec, swap.tv_usec), swap.msc);
143.31244 +-	free(info);
143.31245 ++	     (long long)info->target_msc,
143.31246 ++	     (long long)info->event_id[0],
143.31247 ++	     info->target_msc && info->target_msc == swap.msc ? "" : ": MISS"));
143.31248 ++	present_event_notify(info->event_id[0], swap_ust(&swap), swap.msc);
143.31249 ++	if (info->crtc)
143.31250 ++		sna_crtc_clear_vblank(info->crtc);
143.31251 ++
143.31252 ++	if (info->sna->present.unflip) {
143.31253 ++		DBG(("%s: executing queued unflip (event=%lld)\n", __FUNCTION__, (long long)info->sna->present.unflip));
143.31254 ++		sna_present_unflip(xf86ScrnToScreen(info->sna->scrn),
143.31255 ++				   info->sna->present.unflip);
143.31256 ++		info->sna->present.unflip = 0;
143.31257 ++	}
143.31258 ++	info_free(info);
143.31259 + }
143.31260 + 
143.31261 + static Bool
143.31262 +-page_flip(ScreenPtr screen,
143.31263 +-	  RRCrtcPtr crtc,
143.31264 +-	  uint64_t event_id,
143.31265 +-	  struct kgem_bo *bo)
143.31266 ++flip(struct sna *sna,
143.31267 ++     RRCrtcPtr crtc,
143.31268 ++     uint64_t event_id,
143.31269 ++     uint64_t target_msc,
143.31270 ++     struct kgem_bo *bo)
143.31271 + {
143.31272 +-	struct sna *sna = to_sna_from_screen(screen);
143.31273 +-	struct sna_present_event *event;
143.31274 ++	struct sna_present_event *info;
143.31275 + 
143.31276 + 	DBG(("%s(pipe=%d, event=%lld, handle=%d)\n",
143.31277 + 	     __FUNCTION__,
143.31278 +@@ -335,18 +729,27 @@ page_flip(ScreenPtr screen,
143.31279 + 	     (long long)event_id,
143.31280 + 	     bo->handle));
143.31281 + 
143.31282 +-	event = malloc(sizeof(struct sna_present_event));
143.31283 +-	if (event == NULL)
143.31284 ++	info = info_alloc(sna);
143.31285 ++	if (info == NULL)
143.31286 + 		return FALSE;
143.31287 + 
143.31288 +-	event->event_id = event_id;
143.31289 +-	event->crtc = crtc ? crtc->devPrivate : NULL;
143.31290 +-	if (!sna_page_flip(sna, bo, present_flip_handler, event)) {
143.31291 ++	info->crtc = crtc ? crtc->devPrivate : NULL;
143.31292 ++	info->sna = sna;
143.31293 ++	info->event_id = (uint64_t *)(info + 1);
143.31294 ++	info->event_id[0] = event_id;
143.31295 ++	info->n_event_id = 1;
143.31296 ++	info->target_msc = target_msc;
143.31297 ++	info->queued = false;
143.31298 ++
143.31299 ++	if (!sna_page_flip(sna, bo, present_flip_handler, info)) {
143.31300 + 		DBG(("%s: pageflip failed\n", __FUNCTION__));
143.31301 +-		free(event);
143.31302 ++		info_free(info);
143.31303 + 		return FALSE;
143.31304 + 	}
143.31305 + 
143.31306 ++	info->queued = true;
143.31307 ++	if (info->crtc)
143.31308 ++		sna_crtc_set_vblank(info->crtc);
143.31309 + 	return TRUE;
143.31310 + }
143.31311 + 
143.31312 +@@ -358,12 +761,48 @@ get_flip_bo(PixmapPtr pixmap)
143.31313 + 
143.31314 + 	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
143.31315 + 
143.31316 +-	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | __MOVE_FORCE);
143.31317 ++	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | __MOVE_SCANOUT | __MOVE_FORCE);
143.31318 + 	if (priv == NULL) {
143.31319 + 		DBG(("%s: cannot force pixmap to the GPU\n", __FUNCTION__));
143.31320 + 		return NULL;
143.31321 + 	}
143.31322 + 
143.31323 ++	if (priv->gpu_bo->scanout)
143.31324 ++		return priv->gpu_bo;
143.31325 ++
143.31326 ++	if (sna->kgem.has_llc && !wedged(sna) && !priv->pinned) {
143.31327 ++		struct kgem_bo *bo;
143.31328 ++		uint32_t tiling;
143.31329 ++
143.31330 ++		tiling = I915_TILING_NONE;
143.31331 ++		if ((sna->flags & SNA_LINEAR_FB) == 0)
143.31332 ++			tiling = I915_TILING_X;
143.31333 ++
143.31334 ++		bo = kgem_create_2d(&sna->kgem,
143.31335 ++				    pixmap->drawable.width,
143.31336 ++				    pixmap->drawable.height,
143.31337 ++				    pixmap->drawable.bitsPerPixel,
143.31338 ++				    tiling, CREATE_SCANOUT | CREATE_CACHED);
143.31339 ++		if (bo) {
143.31340 ++			BoxRec box;
143.31341 ++
143.31342 ++			box.x1 = box.y1 = 0;
143.31343 ++			box.x2 = pixmap->drawable.width;
143.31344 ++			box.y2 = pixmap->drawable.height;
143.31345 ++
143.31346 ++			if (sna->render.copy_boxes(sna, GXcopy,
143.31347 ++						   &pixmap->drawable, priv->gpu_bo, 0, 0,
143.31348 ++						   &pixmap->drawable, bo, 0, 0,
143.31349 ++						   &box, 1, 0)) {
143.31350 ++				sna_pixmap_unmap(pixmap, priv);
143.31351 ++				kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
143.31352 ++
143.31353 ++				priv->gpu_bo = bo;
143.31354 ++			} else
143.31355 ++				kgem_bo_destroy(&sna->kgem, bo);
143.31356 ++		}
143.31357 ++	}
143.31358 ++
143.31359 + 	if (sna->flags & SNA_LINEAR_FB &&
143.31360 + 	    priv->gpu_bo->tiling &&
143.31361 + 	    !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
143.31362 +@@ -372,12 +811,17 @@ get_flip_bo(PixmapPtr pixmap)
143.31363 + 	}
143.31364 + 
143.31365 + 	if (priv->gpu_bo->tiling == I915_TILING_Y &&
143.31366 ++	    !sna->kgem.can_scanout_y &&
143.31367 + 	    !sna_pixmap_change_tiling(pixmap, I915_TILING_X)) {
143.31368 + 		DBG(("%s: invalid Y-tiling, cannot convert\n", __FUNCTION__));
143.31369 + 		return NULL;
143.31370 + 	}
143.31371 + 
143.31372 +-	priv->pinned |= PIN_SCANOUT;
143.31373 ++	if (priv->gpu_bo->pitch & 63) {
143.31374 ++		DBG(("%s: invalid pitch, no conversion\n", __FUNCTION__));
143.31375 ++		return NULL;
143.31376 ++	}
143.31377 ++
143.31378 + 	return priv->gpu_bo;
143.31379 + }
143.31380 + 
143.31381 +@@ -388,6 +832,7 @@ sna_present_flip(RRCrtcPtr crtc,
143.31382 + 		 PixmapPtr pixmap,
143.31383 + 		 Bool sync_flip)
143.31384 + {
143.31385 ++	struct sna *sna = to_sna_from_pixmap(pixmap);
143.31386 + 	struct kgem_bo *bo;
143.31387 + 
143.31388 + 	DBG(("%s(pipe=%d, event=%lld, msc=%lld, pixmap=%ld, sync?=%d)\n",
143.31389 +@@ -397,11 +842,32 @@ sna_present_flip(RRCrtcPtr crtc,
143.31390 + 	     (long long)target_msc,
143.31391 + 	     pixmap->drawable.serialNumber, sync_flip));
143.31392 + 
143.31393 +-	if (!check_flip__crtc(to_sna_from_pixmap(pixmap), crtc)) {
143.31394 ++	if (!check_flip__crtc(sna, crtc)) {
143.31395 + 		DBG(("%s: flip invalid for CRTC\n", __FUNCTION__));
143.31396 + 		return FALSE;
143.31397 + 	}
143.31398 + 
143.31399 ++	assert(sna->present.unflip == 0);
143.31400 ++
143.31401 ++	if (sna->flags & SNA_TEAR_FREE) {
143.31402 ++		DBG(("%s: disabling TearFree (was %s) in favour of Present flips\n",
143.31403 ++		     __FUNCTION__, sna->mode.shadow_enabled ? "enabled" : "disabled"));
143.31404 ++		sna->mode.shadow_enabled = false;
143.31405 ++	}
143.31406 ++	assert(!sna->mode.shadow_enabled);
143.31407 ++
143.31408 ++	if (sna->mode.flip_active) {
143.31409 ++		struct pollfd pfd;
143.31410 ++
143.31411 ++		DBG(("%s: flips still pending, stalling\n", __FUNCTION__));
143.31412 ++		pfd.fd = sna->kgem.fd;
143.31413 ++		pfd.events = POLLIN;
143.31414 ++		while (poll(&pfd, 1, 0) == 1)
143.31415 ++			sna_mode_wakeup(sna);
143.31416 ++		if (sna->mode.flip_active)
143.31417 ++			return FALSE;
143.31418 ++	}
143.31419 ++
143.31420 + 	bo = get_flip_bo(pixmap);
143.31421 + 	if (bo == NULL) {
143.31422 + 		DBG(("%s: flip invalid bo\n", __FUNCTION__));
143.31423 +@@ -409,9 +875,9 @@ sna_present_flip(RRCrtcPtr crtc,
143.31424 + 	}
143.31425 + 
143.31426 + 	if (sync_flip)
143.31427 +-		return page_flip(crtc->pScreen, crtc, event_id, bo);
143.31428 ++		return flip(sna, crtc, event_id, target_msc, bo);
143.31429 + 	else
143.31430 +-		return page_flip__async(crtc, event_id, target_msc, bo);
143.31431 ++		return flip__async(sna, crtc, event_id, target_msc, bo);
143.31432 + }
143.31433 + 
143.31434 + static void
143.31435 +@@ -421,29 +887,70 @@ sna_present_unflip(ScreenPtr screen, uint64_t event_id)
143.31436 + 	struct kgem_bo *bo;
143.31437 + 
143.31438 + 	DBG(("%s(event=%lld)\n", __FUNCTION__, (long long)event_id));
143.31439 +-	if (sna->mode.front_active == 0 || sna->mode.shadow_active) {
143.31440 ++	if (sna->mode.front_active == 0 || sna->mode.rr_active) {
143.31441 + 		const struct ust_msc *swap;
143.31442 + 
143.31443 + 		DBG(("%s: no CRTC active, perform no-op flip\n", __FUNCTION__));
143.31444 + 
143.31445 + notify:
143.31446 +-		swap = sna_crtc_last_swap(sna_mode_first_crtc(sna));
143.31447 +-		DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
143.31448 ++		swap = sna_crtc_last_swap(sna_primary_crtc(sna));
143.31449 ++		DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld, event=%lld complete\n", __FUNCTION__,
143.31450 + 		     -1,
143.31451 + 		     swap->tv_sec, swap->tv_usec, (long long)swap->msc,
143.31452 + 		     (long long)event_id));
143.31453 +-		present_event_notify(event_id,
143.31454 +-				     ust64(swap->tv_sec, swap->tv_usec),
143.31455 +-				     swap->msc);
143.31456 ++		present_event_notify(event_id, swap_ust(swap), swap->msc);
143.31457 ++		return;
143.31458 ++	}
143.31459 ++
143.31460 ++	assert(!sna->mode.shadow_enabled);
143.31461 ++	if (sna->mode.flip_active) {
143.31462 ++		DBG(("%s: %d outstanding flips, queueing unflip\n", __FUNCTION__, sna->mode.flip_active));
143.31463 ++		assert(sna->present.unflip == 0);
143.31464 ++		sna->present.unflip = event_id;
143.31465 + 		return;
143.31466 + 	}
143.31467 + 
143.31468 ++	if (sna->flags & SNA_TEAR_FREE) {
143.31469 ++		DBG(("%s: %s TearFree after Present flips\n",
143.31470 ++		     __FUNCTION__, sna->mode.shadow_damage != NULL ? "enabling" : "disabling"));
143.31471 ++		sna->mode.shadow_enabled = sna->mode.shadow_damage != NULL;
143.31472 ++	}
143.31473 ++
143.31474 + 	bo = get_flip_bo(screen->GetScreenPixmap(screen));
143.31475 +-	if (bo == NULL || !page_flip(screen, NULL, event_id, bo)) {
143.31476 ++	if (bo == NULL) {
143.31477 ++reset_mode:
143.31478 + 		DBG(("%s: failed, trying to restore original mode\n", __FUNCTION__));
143.31479 + 		xf86SetDesiredModes(sna->scrn);
143.31480 + 		goto notify;
143.31481 + 	}
143.31482 ++
143.31483 ++	/* Are we unflipping after a failure that left our ScreenP in place? */
143.31484 ++	if (!sna_needs_page_flip(sna, bo))
143.31485 ++		goto notify;
143.31486 ++
143.31487 ++	assert(sna_pixmap(screen->GetScreenPixmap(screen))->pinned & PIN_SCANOUT);
143.31488 ++
143.31489 ++	if (sna->flags & SNA_HAS_ASYNC_FLIP) {
143.31490 ++		DBG(("%s: trying async flip restore\n", __FUNCTION__));
143.31491 ++		if (flip__async(sna, NULL, event_id, 0, bo))
143.31492 ++			return;
143.31493 ++	}
143.31494 ++
143.31495 ++	if (!flip(sna, NULL, event_id, 0, bo))
143.31496 ++		goto reset_mode;
143.31497 ++}
143.31498 ++
143.31499 ++void sna_present_cancel_flip(struct sna *sna)
143.31500 ++{
143.31501 ++	if (sna->present.unflip) {
143.31502 ++		const struct ust_msc *swap;
143.31503 ++
143.31504 ++		swap = sna_crtc_last_swap(sna_primary_crtc(sna));
143.31505 ++		present_event_notify(sna->present.unflip,
143.31506 ++				     swap_ust(swap), swap->msc);
143.31507 ++
143.31508 ++		sna->present.unflip = 0;
143.31509 ++	}
143.31510 + }
143.31511 + 
143.31512 + static present_screen_info_rec present_info = {
143.31513 +@@ -463,10 +970,13 @@ static present_screen_info_rec present_info = {
143.31514 + 
143.31515 + bool sna_present_open(struct sna *sna, ScreenPtr screen)
143.31516 + {
143.31517 ++	DBG(("%s(num_crtc=%d)\n", __FUNCTION__, sna->mode.num_real_crtc));
143.31518 ++
143.31519 + 	if (sna->mode.num_real_crtc == 0)
143.31520 + 		return false;
143.31521 + 
143.31522 + 	sna_present_update(sna);
143.31523 ++	list_init(&sna->present.vblank_queue);
143.31524 + 
143.31525 + 	return present_screen_init(screen, &present_info);
143.31526 + }
143.31527 +diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
143.31528 +index 3fbb9ecb..3e935d57 100644
143.31529 +--- a/src/sna/sna_render.c
143.31530 ++++ b/src/sna/sna_render.c
143.31531 +@@ -54,7 +54,7 @@ sna_format_for_depth(int depth)
143.31532 + {
143.31533 + 	switch (depth) {
143.31534 + 	case 1: return PICT_a1;
143.31535 +-	case 4: return PICT_a4;
143.31536 ++	case 4: return PICT_x4a4;
143.31537 + 	case 8: return PICT_a8;
143.31538 + 	case 15: return PICT_x1r5g5b5;
143.31539 + 	case 16: return PICT_r5g6b5;
143.31540 +@@ -272,18 +272,6 @@ no_render_context_switch(struct kgem *kgem,
143.31541 + }
143.31542 + 
143.31543 + static void
143.31544 +-no_render_retire(struct kgem *kgem)
143.31545 +-{
143.31546 +-	(void)kgem;
143.31547 +-}
143.31548 +-
143.31549 +-static void
143.31550 +-no_render_expire(struct kgem *kgem)
143.31551 +-{
143.31552 +-	(void)kgem;
143.31553 +-}
143.31554 +-
143.31555 +-static void
143.31556 + no_render_fini(struct sna *sna)
143.31557 + {
143.31558 + 	(void)sna;
143.31559 +@@ -316,8 +304,6 @@ const char *no_render_init(struct sna *sna)
143.31560 + 	render->fini = no_render_fini;
143.31561 + 
143.31562 + 	sna->kgem.context_switch = no_render_context_switch;
143.31563 +-	sna->kgem.retire = no_render_retire;
143.31564 +-	sna->kgem.expire = no_render_expire;
143.31565 + 	if (sna->kgem.has_blt)
143.31566 + 		sna->kgem.ring = KGEM_BLT;
143.31567 + 
143.31568 +@@ -407,10 +393,7 @@ use_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt)
143.31569 + 		}
143.31570 + 	}
143.31571 + 
143.31572 +-	if (priv->shm) {
143.31573 +-		assert(!priv->flush);
143.31574 +-		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.31575 +-	}
143.31576 ++	add_shm_flush(sna, priv);
143.31577 + 
143.31578 + 	DBG(("%s for box=(%d, %d), (%d, %d)\n",
143.31579 + 	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
143.31580 +@@ -567,6 +550,7 @@ static struct kgem_bo *upload(struct sna *sna,
143.31581 + 			assert(priv->gpu_damage == NULL);
143.31582 + 			assert(priv->gpu_bo == NULL);
143.31583 + 			assert(bo->proxy != NULL);
143.31584 ++			sna_damage_all(&priv->cpu_damage, pixmap);
143.31585 + 			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
143.31586 + 		}
143.31587 + 	}
143.31588 +@@ -627,10 +611,7 @@ sna_render_pixmap_bo(struct sna *sna,
143.31589 + 		    !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) {
143.31590 + 			DBG(("%s: CPU all damaged\n", __FUNCTION__));
143.31591 + 			channel->bo = priv->cpu_bo;
143.31592 +-			if (priv->shm) {
143.31593 +-				assert(!priv->flush);
143.31594 +-				sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
143.31595 +-			}
143.31596 ++			add_shm_flush(sna, priv);
143.31597 + 			goto done;
143.31598 + 		}
143.31599 + 	}
143.31600 +@@ -1275,6 +1256,7 @@ sna_render_picture_extract(struct sna *sna,
143.31601 + 			assert(priv->gpu_damage == NULL);
143.31602 + 			assert(priv->gpu_bo == NULL);
143.31603 + 			assert(bo->proxy != NULL);
143.31604 ++			sna_damage_all(&priv->cpu_damage, pixmap);
143.31605 + 			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
143.31606 + 		}
143.31607 + 	}
143.31608 +@@ -1338,6 +1320,8 @@ sna_render_picture_convolve(struct sna *sna,
143.31609 + 	 */
143.31610 + 	DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n",
143.31611 + 	     __FUNCTION__, x_off, y_off, cw, ch, w, h));
143.31612 ++	if (cw*ch > 32) /* too much loss of precision from quantization! */
143.31613 ++		return -1;
143.31614 + 
143.31615 + 	assert(picture->pDrawable);
143.31616 + 	assert(picture->filter == PictFilterConvolution);
143.31617 +@@ -1388,9 +1372,9 @@ sna_render_picture_convolve(struct sna *sna,
143.31618 + 			alpha = CreateSolidPicture(0, &color, &error);
143.31619 + 			if (alpha) {
143.31620 + 				sna_composite(PictOpAdd, picture, alpha, tmp,
143.31621 +-					      x, y,
143.31622 ++					      x-(x_off+i), y-(y_off+j),
143.31623 ++					      0, 0,
143.31624 + 					      0, 0,
143.31625 +-					      x_off+i, y_off+j,
143.31626 + 					      w, h);
143.31627 + 				FreePicture(alpha, 0);
143.31628 + 			}
143.31629 +@@ -2183,11 +2167,11 @@ copy_overlap(struct sna *sna, uint8_t alu,
143.31630 + 	ret = (sna->render.copy_boxes(sna, GXcopy,
143.31631 + 				      draw, bo, src_dx, src_dy,
143.31632 + 				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
143.31633 +-				      box, n , 0) &&
143.31634 ++				      box, n, 0) &&
143.31635 + 	       sna->render.copy_boxes(sna, alu,
143.31636 + 				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
143.31637 + 				      draw, bo, dst_dx, dst_dy,
143.31638 +-				      box, n , 0));
143.31639 ++				      box, n, 0));
143.31640 + 
143.31641 + 	screen->DestroyPixmap(tmp);
143.31642 + 	return ret;
143.31643 +@@ -2308,16 +2292,22 @@ static bool can_copy_cpu(struct sna *sna,
143.31644 + 			 struct kgem_bo *src,
143.31645 + 			 struct kgem_bo *dst)
143.31646 + {
143.31647 +-	if (src->tiling != dst->tiling)
143.31648 +-		return false;
143.31649 ++	DBG(("%s: tiling=%d:%d, pitch=%d:%d, can_map=%d:%d[%d]\n",
143.31650 ++	     __FUNCTION__,
143.31651 ++	     src->tiling, dst->tiling,
143.31652 ++	     src->pitch, dst->pitch,
143.31653 ++	     kgem_bo_can_map__cpu(&sna->kgem, src, false),
143.31654 ++	     kgem_bo_can_map__cpu(&sna->kgem, dst, true),
143.31655 ++	     sna->kgem.has_wc_mmap));
143.31656 + 
143.31657 +-	if (src->pitch != dst->pitch)
143.31658 ++	if (src->tiling != dst->tiling)
143.31659 + 		return false;
143.31660 + 
143.31661 + 	if (!kgem_bo_can_map__cpu(&sna->kgem, src, false))
143.31662 + 		return false;
143.31663 + 
143.31664 +-	if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true))
143.31665 ++	if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true) &&
143.31666 ++	    !sna->kgem.has_wc_mmap)
143.31667 + 		return false;
143.31668 + 
143.31669 + 	DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle));
143.31670 +@@ -2330,31 +2320,62 @@ memcpy_copy_boxes(struct sna *sna, uint8_t op,
143.31671 + 		  const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy,
143.31672 + 		  const BoxRec *box, int n, unsigned flags)
143.31673 + {
143.31674 ++	memcpy_box_func detile = NULL;
143.31675 + 	void *dst, *src;
143.31676 +-	bool clipped;
143.31677 + 
143.31678 + 	if (op != GXcopy)
143.31679 + 		return false;
143.31680 + 
143.31681 +-	clipped = (n > 1 ||
143.31682 +-		   box->x1 + dx > 0 ||
143.31683 +-		   box->y1 + dy > 0 ||
143.31684 +-		   box->x2 + dx < dst_draw->width ||
143.31685 +-		   box->y2 + dy < dst_draw->height);
143.31686 ++	if (src_draw->depth != dst_draw->depth)
143.31687 ++		return false;
143.31688 + 
143.31689 + 	dst = src = NULL;
143.31690 +-	if (!clipped && can_copy_cpu(sna, src_bo, dst_bo)) {
143.31691 +-		dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
143.31692 ++	if (can_copy_cpu(sna, src_bo, dst_bo)) {
143.31693 ++		if (src_bo->pitch != dst_bo->pitch ||
143.31694 ++		    dx != sx || dy != sy || n > 1 ||
143.31695 ++		    box->x1 + dx > 0 ||
143.31696 ++		    box->y1 + dy > 0 ||
143.31697 ++		    box->x2 + dx < dst_draw->width ||
143.31698 ++		    box->y2 + dy < dst_draw->height) {
143.31699 ++			if (dx != sx) /* not implemented in memcpy yet */
143.31700 ++				goto use_gtt;
143.31701 ++
143.31702 ++			switch (dst_bo->tiling) {
143.31703 ++			default:
143.31704 ++			case I915_TILING_Y:
143.31705 ++				goto use_gtt;
143.31706 ++
143.31707 ++			case I915_TILING_X:
143.31708 ++				detile = sna->kgem.memcpy_between_tiled_x;
143.31709 ++				if (detile == NULL)
143.31710 ++					goto use_gtt;
143.31711 ++				break;
143.31712 ++
143.31713 ++			case I915_TILING_NONE:
143.31714 ++				break;
143.31715 ++			}
143.31716 ++		}
143.31717 ++
143.31718 ++		if (kgem_bo_can_map__cpu(&sna->kgem, dst_bo, true))
143.31719 ++			dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
143.31720 ++		else
143.31721 ++			dst = kgem_bo_map__wc(&sna->kgem, dst_bo);
143.31722 + 		src = kgem_bo_map__cpu(&sna->kgem, src_bo);
143.31723 + 	}
143.31724 + 
143.31725 + 	if (dst == NULL || src == NULL) {
143.31726 ++use_gtt:
143.31727 + 		dst = kgem_bo_map__gtt(&sna->kgem, dst_bo);
143.31728 + 		src = kgem_bo_map__gtt(&sna->kgem, src_bo);
143.31729 + 		if (dst == NULL || src == NULL)
143.31730 + 			return false;
143.31731 ++
143.31732 ++		detile = NULL;
143.31733 + 	} else {
143.31734 +-		kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
143.31735 ++		if (dst == dst_bo->map__wc)
143.31736 ++			kgem_bo_sync__gtt(&sna->kgem, dst_bo);
143.31737 ++		else
143.31738 ++			kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
143.31739 + 		kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false);
143.31740 + 	}
143.31741 + 
143.31742 +@@ -2362,7 +2383,16 @@ memcpy_copy_boxes(struct sna *sna, uint8_t op,
143.31743 + 	     __FUNCTION__, sx, sy, dx, dy, n));
143.31744 + 
143.31745 + 	if (sigtrap_get() == 0) {
143.31746 +-		do {
143.31747 ++		if (detile) {
143.31748 ++			do {
143.31749 ++				detile(src, dst, dst_draw->bitsPerPixel,
143.31750 ++				       src_bo->pitch, dst_bo->pitch,
143.31751 ++				       box->x1 + sx, box->y1 + sy,
143.31752 ++				       box->x1 + dx, box->y1 + dy,
143.31753 ++				       box->x2 - box->x1, box->y2 - box->y1);
143.31754 ++				box++;
143.31755 ++			} while (--n);
143.31756 ++		} else do {
143.31757 + 			memcpy_blt(src, dst, dst_draw->bitsPerPixel,
143.31758 + 				   src_bo->pitch, dst_bo->pitch,
143.31759 + 				   box->x1 + sx, box->y1 + sy,
143.31760 +@@ -2380,4 +2410,5 @@ void
143.31761 + sna_render_mark_wedged(struct sna *sna)
143.31762 + {
143.31763 + 	sna->render.copy_boxes = memcpy_copy_boxes;
143.31764 ++	sna->render.prefer_gpu = 0;
143.31765 + }
143.31766 +diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
143.31767 +index 6e1fa480..4ba345a7 100644
143.31768 +--- a/src/sna/sna_render.h
143.31769 ++++ b/src/sna/sna_render.h
143.31770 +@@ -148,6 +148,10 @@ struct sna_composite_op {
143.31771 + 		struct {
143.31772 + 			uint32_t flags;
143.31773 + 		} gen8;
143.31774 ++
143.31775 ++		struct {
143.31776 ++			uint32_t flags;
143.31777 ++		} gen9;
143.31778 + 	} u;
143.31779 + 
143.31780 + 	void *priv;
143.31781 +@@ -238,8 +242,9 @@ struct sna_render {
143.31782 + 			  int16_t w, int16_t h,
143.31783 + 			  unsigned flags,
143.31784 + 			  struct sna_composite_op *tmp);
143.31785 +-#define COMPOSITE_PARTIAL 0x1
143.31786 +-#define COMPOSITE_FALLBACK 0x80000000
143.31787 ++#define COMPOSITE_PARTIAL	0x1
143.31788 ++#define COMPOSITE_UPLOAD	0x40000000
143.31789 ++#define COMPOSITE_FALLBACK	0x80000000
143.31790 + 
143.31791 + 	bool (*check_composite_spans)(struct sna *sna, uint8_t op,
143.31792 + 				      PicturePtr dst, PicturePtr src,
143.31793 +@@ -286,6 +291,8 @@ struct sna_render {
143.31794 + #define COPY_LAST 0x1
143.31795 + #define COPY_SYNC 0x2
143.31796 + #define COPY_NO_OVERLAP 0x4
143.31797 ++#define COPY_SMALL 0x8
143.31798 ++#define COPY_DRI 0x10
143.31799 + 
143.31800 + 	bool (*copy)(struct sna *sna, uint8_t alu,
143.31801 + 		     PixmapPtr src, struct kgem_bo *src_bo,
143.31802 +@@ -481,6 +488,7 @@ enum {
143.31803 + 
143.31804 + 	GEN7_WM_KERNEL_VIDEO_PLANAR,
143.31805 + 	GEN7_WM_KERNEL_VIDEO_PACKED,
143.31806 ++	GEN7_WM_KERNEL_VIDEO_RGB,
143.31807 + 	GEN7_WM_KERNEL_COUNT
143.31808 + };
143.31809 + 
143.31810 +@@ -533,12 +541,13 @@ enum {
143.31811 + 
143.31812 + 	GEN8_WM_KERNEL_VIDEO_PLANAR,
143.31813 + 	GEN8_WM_KERNEL_VIDEO_PACKED,
143.31814 ++	GEN8_WM_KERNEL_VIDEO_RGB,
143.31815 + 	GEN8_WM_KERNEL_COUNT
143.31816 + };
143.31817 + 
143.31818 + struct gen8_render_state {
143.31819 + 	unsigned gt;
143.31820 +-
143.31821 ++	const struct gt_info *info;
143.31822 + 	struct kgem_bo *general_bo;
143.31823 + 
143.31824 + 	uint32_t vs_state;
143.31825 +@@ -565,6 +574,58 @@ struct gen8_render_state {
143.31826 + 	bool emit_flush;
143.31827 + };
143.31828 + 
143.31829 ++enum {
143.31830 ++	GEN9_WM_KERNEL_NOMASK = 0,
143.31831 ++	GEN9_WM_KERNEL_NOMASK_P,
143.31832 ++
143.31833 ++	GEN9_WM_KERNEL_MASK,
143.31834 ++	GEN9_WM_KERNEL_MASK_P,
143.31835 ++
143.31836 ++	GEN9_WM_KERNEL_MASKCA,
143.31837 ++	GEN9_WM_KERNEL_MASKCA_P,
143.31838 ++
143.31839 ++	GEN9_WM_KERNEL_MASKSA,
143.31840 ++	GEN9_WM_KERNEL_MASKSA_P,
143.31841 ++
143.31842 ++	GEN9_WM_KERNEL_OPACITY,
143.31843 ++	GEN9_WM_KERNEL_OPACITY_P,
143.31844 ++
143.31845 ++	GEN9_WM_KERNEL_VIDEO_PLANAR,
143.31846 ++	GEN9_WM_KERNEL_VIDEO_PACKED,
143.31847 ++	GEN9_WM_KERNEL_VIDEO_RGB,
143.31848 ++	GEN9_WM_KERNEL_COUNT
143.31849 ++};
143.31850 ++
143.31851 ++struct gen9_render_state {
143.31852 ++	unsigned gt;
143.31853 ++	const struct gt_info *info;
143.31854 ++	struct kgem_bo *general_bo;
143.31855 ++
143.31856 ++	uint32_t vs_state;
143.31857 ++	uint32_t sf_state;
143.31858 ++	uint32_t sf_mask_state;
143.31859 ++	uint32_t wm_state;
143.31860 ++	uint32_t wm_kernel[GEN9_WM_KERNEL_COUNT][3];
143.31861 ++
143.31862 ++	uint32_t cc_blend;
143.31863 ++
143.31864 ++	uint32_t drawrect_offset;
143.31865 ++	uint32_t drawrect_limit;
143.31866 ++	uint32_t blend;
143.31867 ++	uint32_t samplers;
143.31868 ++	uint32_t kernel;
143.31869 ++
143.31870 ++	uint16_t num_sf_outputs;
143.31871 ++	uint16_t ve_id;
143.31872 ++	uint16_t last_primitive;
143.31873 ++	int16_t floats_per_vertex;
143.31874 ++	uint16_t surface_table;
143.31875 ++
143.31876 ++	bool needs_invariant;
143.31877 ++	bool emit_flush;
143.31878 ++	bool ve_dirty;
143.31879 ++};
143.31880 ++
143.31881 + struct sna_static_stream {
143.31882 + 	uint32_t size, used;
143.31883 + 	uint8_t *data;
143.31884 +@@ -620,6 +681,7 @@ const char *gen5_render_init(struct sna *sna, const char *backend);
143.31885 + const char *gen6_render_init(struct sna *sna, const char *backend);
143.31886 + const char *gen7_render_init(struct sna *sna, const char *backend);
143.31887 + const char *gen8_render_init(struct sna *sna, const char *backend);
143.31888 ++const char *gen9_render_init(struct sna *sna, const char *backend);
143.31889 + 
143.31890 + void sna_render_mark_wedged(struct sna *sna);
143.31891 + 
143.31892 +diff --git a/src/sna/sna_render_inline.h b/src/sna/sna_render_inline.h
143.31893 +index 10fbbfe2..e162e37f 100644
143.31894 +--- a/src/sna/sna_render_inline.h
143.31895 ++++ b/src/sna/sna_render_inline.h
143.31896 +@@ -304,6 +304,12 @@ color_convert(uint32_t pixel,
143.31897 + 	return pixel;
143.31898 + }
143.31899 + 
143.31900 ++inline static uint32_t
143.31901 ++solid_color(uint32_t format, uint32_t pixel)
143.31902 ++{
143.31903 ++	return color_convert(pixel, format, PICT_a8r8g8b8);
143.31904 ++}
143.31905 ++
143.31906 + inline static bool dst_use_gpu(PixmapPtr pixmap)
143.31907 + {
143.31908 + 	struct sna_pixmap *priv = sna_pixmap(pixmap);
143.31909 +diff --git a/src/sna/sna_tiling.c b/src/sna/sna_tiling.c
143.31910 +index 308efc0a..8e2627f7 100644
143.31911 +--- a/src/sna/sna_tiling.c
143.31912 ++++ b/src/sna/sna_tiling.c
143.31913 +@@ -369,8 +369,7 @@ sna_tiling_composite_spans_boxes(struct sna *sna,
143.31914 + 				 const BoxRec *box, int nbox, float opacity)
143.31915 + {
143.31916 + 	while (nbox--)
143.31917 +-		sna_tiling_composite_spans_box(sna, op->base.priv, box++, opacity);
143.31918 +-	(void)sna;
143.31919 ++		sna_tiling_composite_spans_box(sna, op, box++, opacity);
143.31920 + }
143.31921 + 
143.31922 + fastcall static void
143.31923 +@@ -581,6 +580,7 @@ sna_tiling_composite_spans(uint32_t op,
143.31924 + 	tile->rects = tile->rects_embedded;
143.31925 + 	tile->rect_count = 0;
143.31926 + 	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
143.31927 ++	COMPILE_TIME_ASSERT(sizeof(tile->rects_embedded[0]) >= sizeof(struct sna_tile_span));
143.31928 + 
143.31929 + 	tmp->box   = sna_tiling_composite_spans_box;
143.31930 + 	tmp->boxes = sna_tiling_composite_spans_boxes;
143.31931 +diff --git a/src/sna/sna_trapezoids_boxes.c b/src/sna/sna_trapezoids_boxes.c
143.31932 +index 9900e3f0..bbf83759 100644
143.31933 +--- a/src/sna/sna_trapezoids_boxes.c
143.31934 ++++ b/src/sna/sna_trapezoids_boxes.c
143.31935 +@@ -198,7 +198,7 @@ composite_aligned_boxes(struct sna *sna,
143.31936 + 	if (op == PictOpClear && sna->clear)
143.31937 + 		src = sna->clear;
143.31938 + 
143.31939 +-	DBG(("%s: clipped extents (%d, %d), (%d, %d);  now offset by (%d, %d), orgin (%d, %d)\n",
143.31940 ++	DBG(("%s: clipped extents (%d, %d), (%d, %d);  now offset by (%d, %d), origin (%d, %d)\n",
143.31941 + 	     __FUNCTION__,
143.31942 + 	     clip.extents.x1, clip.extents.y1,
143.31943 + 	     clip.extents.x2, clip.extents.y2,
143.31944 +@@ -592,6 +592,8 @@ lerp32_opacity(PixmapPtr scratch,
143.31945 + 	uint32_t *ptr;
143.31946 + 	int stride, i;
143.31947 + 
143.31948 ++	sigtrap_assert_active();
143.31949 ++
143.31950 + 	ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y);
143.31951 + 	ptr += x;
143.31952 + 	stride = scratch->devKind / 4;
143.31953 +diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c
143.31954 +index 37def2f9..8bc7c8a8 100644
143.31955 +--- a/src/sna/sna_trapezoids_imprecise.c
143.31956 ++++ b/src/sna/sna_trapezoids_imprecise.c
143.31957 +@@ -962,6 +962,16 @@ tor_add_trapezoid(struct tor *tor,
143.31958 + 		  const xTrapezoid *t,
143.31959 + 		  int dx, int dy)
143.31960 + {
143.31961 ++	if (!xTrapezoidValid(t)) {
143.31962 ++		__DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
143.31963 ++		       __FUNCTION__,
143.31964 ++		       t->top, t->bottom,
143.31965 ++		       t->left.p1.x, t->left.p1.y,
143.31966 ++		       t->left.p2.x, t->left.p2.y,
143.31967 ++		       t->right.p1.x, t->right.p1.y,
143.31968 ++		       t->right.p2.x, t->right.p2.y));
143.31969 ++		return;
143.31970 ++	}
143.31971 + 	polygon_add_edge(tor->polygon, t, &t->left, 1, dx, dy);
143.31972 + 	polygon_add_edge(tor->polygon, t, &t->right, -1, dx, dy);
143.31973 + }
143.31974 +@@ -1687,31 +1697,27 @@ struct span_thread {
143.31975 + #define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box))
143.31976 + struct span_thread_boxes {
143.31977 + 	const struct sna_composite_spans_op *op;
143.31978 ++	const BoxRec *clip_start, *clip_end;
143.31979 + 	int num_boxes;
143.31980 + 	struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES];
143.31981 + };
143.31982 + 
143.31983 +-static void span_thread_add_boxes(struct sna *sna, void *data,
143.31984 +-				  const BoxRec *box, int count, float alpha)
143.31985 ++static void span_thread_add_box(struct sna *sna, void *data,
143.31986 ++				const BoxRec *box, float alpha)
143.31987 + {
143.31988 + 	struct span_thread_boxes *b = data;
143.31989 + 
143.31990 +-	__DBG(("%s: adding %d boxes with alpha=%f\n",
143.31991 +-	       __FUNCTION__, count, alpha));
143.31992 ++	__DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
143.31993 + 
143.31994 +-	assert(count > 0 && count <= SPAN_THREAD_MAX_BOXES);
143.31995 +-	if (unlikely(b->num_boxes + count > SPAN_THREAD_MAX_BOXES)) {
143.31996 +-		DBG(("%s: flushing %d boxes, adding %d\n", __FUNCTION__, b->num_boxes, count));
143.31997 +-		assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
143.31998 ++	if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
143.31999 ++		DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
143.32000 + 		b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes);
143.32001 + 		b->num_boxes = 0;
143.32002 + 	}
143.32003 + 
143.32004 +-	do {
143.32005 +-		b->boxes[b->num_boxes].box = *box++;
143.32006 +-		b->boxes[b->num_boxes].alpha = alpha;
143.32007 +-		b->num_boxes++;
143.32008 +-	} while (--count);
143.32009 ++	b->boxes[b->num_boxes].box = *box++;
143.32010 ++	b->boxes[b->num_boxes].alpha = alpha;
143.32011 ++	b->num_boxes++;
143.32012 + 	assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
143.32013 + }
143.32014 + 
143.32015 +@@ -1722,8 +1728,22 @@ span_thread_box(struct sna *sna,
143.32016 + 		const BoxRec *box,
143.32017 + 		int coverage)
143.32018 + {
143.32019 ++	struct span_thread_boxes *b = (struct span_thread_boxes *)op;
143.32020 ++
143.32021 + 	__DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
143.32022 +-	span_thread_add_boxes(sna, op, box, 1, AREA_TO_ALPHA(coverage));
143.32023 ++	if (b->num_boxes) {
143.32024 ++		struct sna_opacity_box *bb = &b->boxes[b->num_boxes-1];
143.32025 ++		if (bb->box.x1 == box->x1 &&
143.32026 ++		    bb->box.x2 == box->x2 &&
143.32027 ++		    bb->box.y2 == box->y1 &&
143.32028 ++		    bb->alpha == AREA_TO_ALPHA(coverage)) {
143.32029 ++			bb->box.y2 = box->y2;
143.32030 ++			__DBG(("%s: contracted double row: %d -> %d\n", __func__, bb->box.y1, bb->box.y2));
143.32031 ++			return;
143.32032 ++		}
143.32033 ++	}
143.32034 ++
143.32035 ++	span_thread_add_box(sna, op, box, AREA_TO_ALPHA(coverage));
143.32036 + }
143.32037 + 
143.32038 + static void
143.32039 +@@ -1733,20 +1753,28 @@ span_thread_clipped_box(struct sna *sna,
143.32040 + 			const BoxRec *box,
143.32041 + 			int coverage)
143.32042 + {
143.32043 +-	pixman_region16_t region;
143.32044 ++	struct span_thread_boxes *b = (struct span_thread_boxes *)op;
143.32045 ++	const BoxRec *c;
143.32046 + 
143.32047 + 	__DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2,
143.32048 + 	       AREA_TO_ALPHA(coverage)));
143.32049 + 
143.32050 +-	pixman_region_init_rects(&region, box, 1);
143.32051 +-	RegionIntersect(&region, &region, clip);
143.32052 +-	if (region_num_rects(&region)) {
143.32053 +-		span_thread_add_boxes(sna, op,
143.32054 +-				      region_rects(&region),
143.32055 +-				      region_num_rects(&region),
143.32056 +-				      AREA_TO_ALPHA(coverage));
143.32057 ++	b->clip_start =
143.32058 ++		find_clip_box_for_y(b->clip_start, b->clip_end, box->y1);
143.32059 ++
143.32060 ++	c = b->clip_start;
143.32061 ++	while (c != b->clip_end) {
143.32062 ++		BoxRec clipped;
143.32063 ++
143.32064 ++		if (box->y2 <= c->y1)
143.32065 ++			break;
143.32066 ++
143.32067 ++		clipped = *box;
143.32068 ++		if (!box_intersect(&clipped, c++))
143.32069 ++			continue;
143.32070 ++
143.32071 ++		span_thread_add_box(sna, op, &clipped, AREA_TO_ALPHA(coverage));
143.32072 + 	}
143.32073 +-	pixman_region_fini(&region);
143.32074 + }
143.32075 + 
143.32076 + static span_func_t
143.32077 +@@ -1777,6 +1805,16 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
143.32078 + 	return span;
143.32079 + }
143.32080 + 
143.32081 ++inline static void
143.32082 ++span_thread_boxes_init(struct span_thread_boxes *boxes,
143.32083 ++		       const struct sna_composite_spans_op *op,
143.32084 ++		       const RegionRec *clip)
143.32085 ++{
143.32086 ++	boxes->op = op;
143.32087 ++	region_get_boxes(clip, &boxes->clip_start, &boxes->clip_end);
143.32088 ++	boxes->num_boxes = 0;
143.32089 ++}
143.32090 ++
143.32091 + static void
143.32092 + span_thread(void *arg)
143.32093 + {
143.32094 +@@ -1789,8 +1827,7 @@ span_thread(void *arg)
143.32095 + 	if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
143.32096 + 		return;
143.32097 + 
143.32098 +-	boxes.op = thread->op;
143.32099 +-	boxes.num_boxes = 0;
143.32100 ++	span_thread_boxes_init(&boxes, thread->op, thread->clip);
143.32101 + 
143.32102 + 	y1 = thread->extents.y1 - thread->draw_y;
143.32103 + 	y2 = thread->extents.y2 - thread->draw_y;
143.32104 +@@ -2190,6 +2227,52 @@ static void _tor_blt_src(struct inplace *in, const BoxRec *box, uint8_t v)
143.32105 + 	} while (--h);
143.32106 + }
143.32107 + 
143.32108 ++struct clipped_span {
143.32109 ++	span_func_t span;
143.32110 ++	const BoxRec *clip_start, *clip_end;
143.32111 ++};
143.32112 ++
143.32113 ++static void
143.32114 ++tor_blt_clipped(struct sna *sna,
143.32115 ++		struct sna_composite_spans_op *op,
143.32116 ++		pixman_region16_t *clip,
143.32117 ++		const BoxRec *box,
143.32118 ++		int coverage)
143.32119 ++{
143.32120 ++	struct clipped_span *cs = (struct clipped_span *)clip;
143.32121 ++	const BoxRec *c;
143.32122 ++
143.32123 ++	cs->clip_start =
143.32124 ++		find_clip_box_for_y(cs->clip_start, cs->clip_end, box->y1);
143.32125 ++
143.32126 ++	c = cs->clip_start;
143.32127 ++	while (c != cs->clip_end) {
143.32128 ++		BoxRec clipped;
143.32129 ++
143.32130 ++		if (box->y2 <= c->y1)
143.32131 ++			break;
143.32132 ++
143.32133 ++		clipped = *box;
143.32134 ++		if (!box_intersect(&clipped, c++))
143.32135 ++			continue;
143.32136 ++
143.32137 ++		cs->span(sna, op, NULL, &clipped, coverage);
143.32138 ++	}
143.32139 ++}
143.32140 ++
143.32141 ++inline static span_func_t
143.32142 ++clipped_span(struct clipped_span *cs,
143.32143 ++	     span_func_t span,
143.32144 ++	     const RegionRec *clip)
143.32145 ++{
143.32146 ++	if (clip->data) {
143.32147 ++		cs->span = span;
143.32148 ++		region_get_boxes(clip, &cs->clip_start, &cs->clip_end);
143.32149 ++		span = tor_blt_clipped;
143.32150 ++	}
143.32151 ++	return span;
143.32152 ++}
143.32153 ++
143.32154 + static void
143.32155 + tor_blt_src(struct sna *sna,
143.32156 + 	    struct sna_composite_spans_op *op,
143.32157 +@@ -2203,25 +2286,6 @@ tor_blt_src(struct sna *sna,
143.32158 + }
143.32159 + 
143.32160 + static void
143.32161 +-tor_blt_src_clipped(struct sna *sna,
143.32162 +-		    struct sna_composite_spans_op *op,
143.32163 +-		    pixman_region16_t *clip,
143.32164 +-		    const BoxRec *box,
143.32165 +-		    int coverage)
143.32166 +-{
143.32167 +-	pixman_region16_t region;
143.32168 +-	int n;
143.32169 +-
143.32170 +-	pixman_region_init_rects(&region, box, 1);
143.32171 +-	RegionIntersect(&region, &region, clip);
143.32172 +-	n = region_num_rects(&region);
143.32173 +-	box = region_rects(&region);
143.32174 +-	while (n--)
143.32175 +-		tor_blt_src(sna, op, NULL, box++, coverage);
143.32176 +-	pixman_region_fini(&region);
143.32177 +-}
143.32178 +-
143.32179 +-static void
143.32180 + tor_blt_in(struct sna *sna,
143.32181 + 	   struct sna_composite_spans_op *op,
143.32182 + 	   pixman_region16_t *clip,
143.32183 +@@ -2253,25 +2317,6 @@ tor_blt_in(struct sna *sna,
143.32184 + }
143.32185 + 
143.32186 + static void
143.32187 +-tor_blt_in_clipped(struct sna *sna,
143.32188 +-		   struct sna_composite_spans_op *op,
143.32189 +-		   pixman_region16_t *clip,
143.32190 +-		   const BoxRec *box,
143.32191 +-		   int coverage)
143.32192 +-{
143.32193 +-	pixman_region16_t region;
143.32194 +-	int n;
143.32195 +-
143.32196 +-	pixman_region_init_rects(&region, box, 1);
143.32197 +-	RegionIntersect(&region, &region, clip);
143.32198 +-	n = region_num_rects(&region);
143.32199 +-	box = region_rects(&region);
143.32200 +-	while (n--)
143.32201 +-		tor_blt_in(sna, op, NULL, box++, coverage);
143.32202 +-	pixman_region_fini(&region);
143.32203 +-}
143.32204 +-
143.32205 +-static void
143.32206 + tor_blt_add(struct sna *sna,
143.32207 + 	    struct sna_composite_spans_op *op,
143.32208 + 	    pixman_region16_t *clip,
143.32209 +@@ -2310,25 +2355,6 @@ tor_blt_add(struct sna *sna,
143.32210 + }
143.32211 + 
143.32212 + static void
143.32213 +-tor_blt_add_clipped(struct sna *sna,
143.32214 +-		    struct sna_composite_spans_op *op,
143.32215 +-		    pixman_region16_t *clip,
143.32216 +-		    const BoxRec *box,
143.32217 +-		    int coverage)
143.32218 +-{
143.32219 +-	pixman_region16_t region;
143.32220 +-	int n;
143.32221 +-
143.32222 +-	pixman_region_init_rects(&region, box, 1);
143.32223 +-	RegionIntersect(&region, &region, clip);
143.32224 +-	n = region_num_rects(&region);
143.32225 +-	box = region_rects(&region);
143.32226 +-	while (n--)
143.32227 +-		tor_blt_add(sna, op, NULL, box++, coverage);
143.32228 +-	pixman_region_fini(&region);
143.32229 +-}
143.32230 +-
143.32231 +-static void
143.32232 + tor_blt_lerp32(struct sna *sna,
143.32233 + 	       struct sna_composite_spans_op *op,
143.32234 + 	       pixman_region16_t *clip,
143.32235 +@@ -2343,6 +2369,7 @@ tor_blt_lerp32(struct sna *sna,
143.32236 + 	if (coverage == 0)
143.32237 + 		return;
143.32238 + 
143.32239 ++	sigtrap_assert_active();
143.32240 + 	ptr += box->y1 * stride + box->x1;
143.32241 + 
143.32242 + 	h = box->y2 - box->y1;
143.32243 +@@ -2383,25 +2410,6 @@ tor_blt_lerp32(struct sna *sna,
143.32244 + 	}
143.32245 + }
143.32246 + 
143.32247 +-static void
143.32248 +-tor_blt_lerp32_clipped(struct sna *sna,
143.32249 +-		       struct sna_composite_spans_op *op,
143.32250 +-		       pixman_region16_t *clip,
143.32251 +-		       const BoxRec *box,
143.32252 +-		       int coverage)
143.32253 +-{
143.32254 +-	pixman_region16_t region;
143.32255 +-	int n;
143.32256 +-
143.32257 +-	pixman_region_init_rects(&region, box, 1);
143.32258 +-	RegionIntersect(&region, &region, clip);
143.32259 +-	n = region_num_rects(&region);
143.32260 +-	box = region_rects(&region);
143.32261 +-	while (n--)
143.32262 +-		tor_blt_lerp32(sna, op, NULL, box++, coverage);
143.32263 +-	pixman_region_fini(&region);
143.32264 +-}
143.32265 +-
143.32266 + struct pixman_inplace {
143.32267 + 	pixman_image_t *image, *source, *mask;
143.32268 + 	uint32_t color;
143.32269 +@@ -2431,24 +2439,6 @@ pixmask_span_solid(struct sna *sna,
143.32270 + 			       pi->dx + box->x1, pi->dy + box->y1,
143.32271 + 			       box->x2 - box->x1, box->y2 - box->y1);
143.32272 + }
143.32273 +-static void
143.32274 +-pixmask_span_solid__clipped(struct sna *sna,
143.32275 +-			    struct sna_composite_spans_op *op,
143.32276 +-			    pixman_region16_t *clip,
143.32277 +-			    const BoxRec *box,
143.32278 +-			    int coverage)
143.32279 +-{
143.32280 +-	pixman_region16_t region;
143.32281 +-	int n;
143.32282 +-
143.32283 +-	pixman_region_init_rects(&region, box, 1);
143.32284 +-	RegionIntersect(&region, &region, clip);
143.32285 +-	n = region_num_rects(&region);
143.32286 +-	box = region_rects(&region);
143.32287 +-	while (n--)
143.32288 +-		pixmask_span_solid(sna, op, NULL, box++, coverage);
143.32289 +-	pixman_region_fini(&region);
143.32290 +-}
143.32291 + 
143.32292 + static void
143.32293 + pixmask_span(struct sna *sna,
143.32294 +@@ -2471,24 +2461,6 @@ pixmask_span(struct sna *sna,
143.32295 + 			       pi->dx + box->x1, pi->dy + box->y1,
143.32296 + 			       box->x2 - box->x1, box->y2 - box->y1);
143.32297 + }
143.32298 +-static void
143.32299 +-pixmask_span__clipped(struct sna *sna,
143.32300 +-		      struct sna_composite_spans_op *op,
143.32301 +-		      pixman_region16_t *clip,
143.32302 +-		      const BoxRec *box,
143.32303 +-		      int coverage)
143.32304 +-{
143.32305 +-	pixman_region16_t region;
143.32306 +-	int n;
143.32307 +-
143.32308 +-	pixman_region_init_rects(&region, box, 1);
143.32309 +-	RegionIntersect(&region, &region, clip);
143.32310 +-	n = region_num_rects(&region);
143.32311 +-	box = region_rects(&region);
143.32312 +-	while (n--)
143.32313 +-		pixmask_span(sna, op, NULL, box++, coverage);
143.32314 +-	pixman_region_fini(&region);
143.32315 +-}
143.32316 + 
143.32317 + struct inplace_x8r8g8b8_thread {
143.32318 + 	xTrapezoid *traps;
143.32319 +@@ -2507,6 +2479,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.32320 + 	struct inplace_x8r8g8b8_thread *thread = arg;
143.32321 + 	struct tor tor;
143.32322 + 	span_func_t span;
143.32323 ++	struct clipped_span clipped;
143.32324 + 	RegionPtr clip;
143.32325 + 	int y1, y2, n;
143.32326 + 
143.32327 +@@ -2537,12 +2510,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.32328 + 		inplace.stride = pixmap->devKind;
143.32329 + 		inplace.color = thread->color;
143.32330 + 
143.32331 +-		if (clip->data)
143.32332 +-			span = tor_blt_lerp32_clipped;
143.32333 +-		else
143.32334 +-			span = tor_blt_lerp32;
143.32335 ++		span = clipped_span(&clipped, tor_blt_lerp32, clip);
143.32336 + 
143.32337 +-		tor_render(NULL, &tor, (void*)&inplace, clip, span, false);
143.32338 ++		tor_render(NULL, &tor,
143.32339 ++			   (void*)&inplace, (void*)&clipped,
143.32340 ++			   span, false);
143.32341 + 	} else if (thread->is_solid) {
143.32342 + 		struct pixman_inplace pi;
143.32343 + 
143.32344 +@@ -2555,12 +2527,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.32345 + 						     1, 1, pi.bits, 0);
143.32346 + 		pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
143.32347 + 
143.32348 +-		if (clip->data)
143.32349 +-			span = pixmask_span_solid__clipped;
143.32350 +-		else
143.32351 +-			span = pixmask_span_solid;
143.32352 ++		span = clipped_span(&clipped, pixmask_span_solid, clip);
143.32353 + 
143.32354 +-		tor_render(NULL, &tor, (void*)&pi, clip, span, false);
143.32355 ++		tor_render(NULL, &tor,
143.32356 ++			   (void*)&pi, (void *)&clipped,
143.32357 ++			   span, false);
143.32358 + 
143.32359 + 		pixman_image_unref(pi.source);
143.32360 + 		pixman_image_unref(pi.image);
143.32361 +@@ -2579,12 +2550,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.32362 + 		pi.bits = pixman_image_get_data(pi.mask);
143.32363 + 		pi.op = thread->op;
143.32364 + 
143.32365 +-		if (clip->data)
143.32366 +-			span = pixmask_span__clipped;
143.32367 +-		else
143.32368 +-			span = pixmask_span;
143.32369 ++		span = clipped_span(&clipped, pixmask_span, clip);
143.32370 + 
143.32371 +-		tor_render(NULL, &tor, (void*)&pi, clip, span, false);
143.32372 ++		tor_render(NULL, &tor,
143.32373 ++			   (void*)&pi, (void *)&clipped,
143.32374 ++			   span, false);
143.32375 + 
143.32376 + 		pixman_image_unref(pi.mask);
143.32377 + 		pixman_image_unref(pi.source);
143.32378 +@@ -2698,6 +2668,7 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.32379 + 	if (num_threads == 1) {
143.32380 + 		struct tor tor;
143.32381 + 		span_func_t span;
143.32382 ++		struct clipped_span clipped;
143.32383 + 
143.32384 + 		if (!tor_init(&tor, &region.extents, 2*ntrap))
143.32385 + 			return true;
143.32386 +@@ -2723,17 +2694,15 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.32387 + 			inplace.stride = pixmap->devKind;
143.32388 + 			inplace.color = color;
143.32389 + 
143.32390 +-			if (dst->pCompositeClip->data)
143.32391 +-				span = tor_blt_lerp32_clipped;
143.32392 +-			else
143.32393 +-				span = tor_blt_lerp32;
143.32394 ++			span = clipped_span(&clipped, tor_blt_lerp32, dst->pCompositeClip);
143.32395 + 
143.32396 + 			DBG(("%s: render inplace op=%d, color=%08x\n",
143.32397 + 			     __FUNCTION__, op, color));
143.32398 + 
143.32399 + 			if (sigtrap_get() == 0) {
143.32400 +-				tor_render(NULL, &tor, (void*)&inplace,
143.32401 +-					   dst->pCompositeClip, span, false);
143.32402 ++				tor_render(NULL, &tor,
143.32403 ++					   (void*)&inplace, (void*)&clipped,
143.32404 ++					   span, false);
143.32405 + 				sigtrap_put();
143.32406 + 			}
143.32407 + 		} else if (is_solid) {
143.32408 +@@ -2748,15 +2717,12 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.32409 + 							     1, 1, pi.bits, 0);
143.32410 + 			pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
143.32411 + 
143.32412 +-			if (dst->pCompositeClip->data)
143.32413 +-				span = pixmask_span_solid__clipped;
143.32414 +-			else
143.32415 +-				span = pixmask_span_solid;
143.32416 ++			span = clipped_span(&clipped, pixmask_span_solid, dst->pCompositeClip);
143.32417 + 
143.32418 + 			if (sigtrap_get() == 0) {
143.32419 +-				tor_render(NULL, &tor, (void*)&pi,
143.32420 +-					   dst->pCompositeClip, span,
143.32421 +-					   false);
143.32422 ++				tor_render(NULL, &tor,
143.32423 ++					   (void*)&pi, (void*)&clipped,
143.32424 ++					   span, false);
143.32425 + 				sigtrap_put();
143.32426 + 			}
143.32427 + 
143.32428 +@@ -2777,15 +2743,12 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.32429 + 			pi.bits = pixman_image_get_data(pi.mask);
143.32430 + 			pi.op = op;
143.32431 + 
143.32432 +-			if (dst->pCompositeClip->data)
143.32433 +-				span = pixmask_span__clipped;
143.32434 +-			else
143.32435 +-				span = pixmask_span;
143.32436 ++			span = clipped_span(&clipped, pixmask_span, dst->pCompositeClip);
143.32437 + 
143.32438 + 			if (sigtrap_get() == 0) {
143.32439 +-				tor_render(NULL, &tor, (void*)&pi,
143.32440 +-					   dst->pCompositeClip, span,
143.32441 +-					   false);
143.32442 ++				tor_render(NULL, &tor,
143.32443 ++					   (void*)&pi, (void*)&clipped,
143.32444 ++					   span, false);
143.32445 + 				sigtrap_put();
143.32446 + 			}
143.32447 + 
143.32448 +@@ -2847,9 +2810,9 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.32449 + 
143.32450 + struct inplace_thread {
143.32451 + 	xTrapezoid *traps;
143.32452 +-	RegionPtr clip;
143.32453 + 	span_func_t span;
143.32454 + 	struct inplace inplace;
143.32455 ++	struct clipped_span clipped;
143.32456 + 	BoxRec extents;
143.32457 + 	int dx, dy;
143.32458 + 	int draw_x, draw_y;
143.32459 +@@ -2874,8 +2837,9 @@ static void inplace_thread(void *arg)
143.32460 + 		tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
143.32461 + 	}
143.32462 + 
143.32463 +-	tor_render(NULL, &tor, (void*)&thread->inplace,
143.32464 +-		   thread->clip, thread->span, thread->unbounded);
143.32465 ++	tor_render(NULL, &tor,
143.32466 ++		   (void*)&thread->inplace, (void*)&thread->clipped,
143.32467 ++		   thread->span, thread->unbounded);
143.32468 + 
143.32469 + 	tor_fini(&tor);
143.32470 + }
143.32471 +@@ -2889,6 +2853,7 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
143.32472 + 				 bool fallback)
143.32473 + {
143.32474 + 	struct inplace inplace;
143.32475 ++	struct clipped_span clipped;
143.32476 + 	span_func_t span;
143.32477 + 	PixmapPtr pixmap;
143.32478 + 	struct sna_pixmap *priv;
143.32479 +@@ -3005,21 +2970,12 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
143.32480 + 	     region.extents.x2, region.extents.y2));
143.32481 + 
143.32482 + 	if (op == PictOpSrc) {
143.32483 +-		if (dst->pCompositeClip->data)
143.32484 +-			span = tor_blt_src_clipped;
143.32485 +-		else
143.32486 +-			span = tor_blt_src;
143.32487 ++		span = tor_blt_src;
143.32488 + 	} else if (op == PictOpIn) {
143.32489 +-		if (dst->pCompositeClip->data)
143.32490 +-			span = tor_blt_in_clipped;
143.32491 +-		else
143.32492 +-			span = tor_blt_in;
143.32493 ++		span = tor_blt_in;
143.32494 + 	} else {
143.32495 + 		assert(op == PictOpAdd);
143.32496 +-		if (dst->pCompositeClip->data)
143.32497 +-			span = tor_blt_add_clipped;
143.32498 +-		else
143.32499 +-			span = tor_blt_add;
143.32500 ++		span = tor_blt_add;
143.32501 + 	}
143.32502 + 
143.32503 + 	DBG(("%s: move-to-cpu\n", __FUNCTION__));
143.32504 +@@ -3037,6 +2993,8 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
143.32505 + 	inplace.stride = pixmap->devKind;
143.32506 + 	inplace.opacity = color >> 24;
143.32507 + 
143.32508 ++	span = clipped_span(&clipped, span, dst->pCompositeClip);
143.32509 ++
143.32510 + 	num_threads = 1;
143.32511 + 	if ((flags & COMPOSITE_SPANS_RECTILINEAR) == 0)
143.32512 + 		num_threads = sna_use_threads(region.extents.x2 - region.extents.x1,
143.32513 +@@ -3057,8 +3015,9 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
143.32514 + 		}
143.32515 + 
143.32516 + 		if (sigtrap_get() == 0) {
143.32517 +-			tor_render(NULL, &tor, (void*)&inplace,
143.32518 +-				   dst->pCompositeClip, span, unbounded);
143.32519 ++			tor_render(NULL, &tor,
143.32520 ++				   (void*)&inplace, (void *)&clipped,
143.32521 ++				   span, unbounded);
143.32522 + 			sigtrap_put();
143.32523 + 		}
143.32524 + 
143.32525 +@@ -3075,8 +3034,8 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
143.32526 + 		threads[0].traps = traps;
143.32527 + 		threads[0].ntrap = ntrap;
143.32528 + 		threads[0].inplace = inplace;
143.32529 ++		threads[0].clipped = clipped;
143.32530 + 		threads[0].extents = region.extents;
143.32531 +-		threads[0].clip = dst->pCompositeClip;
143.32532 + 		threads[0].span = span;
143.32533 + 		threads[0].unbounded = unbounded;
143.32534 + 		threads[0].dx = dx;
143.32535 +@@ -3707,8 +3666,7 @@ tristrip_thread(void *arg)
143.32536 + 	if (!tor_init(&tor, &thread->extents, 2*thread->count))
143.32537 + 		return;
143.32538 + 
143.32539 +-	boxes.op = thread->op;
143.32540 +-	boxes.num_boxes = 0;
143.32541 ++	span_thread_boxes_init(&boxes, thread->op, thread->clip);
143.32542 + 
143.32543 + 	cw = 0; ccw = 1;
143.32544 + 	polygon_add_line(tor.polygon,
143.32545 +@@ -3874,7 +3832,7 @@ imprecise_tristrip_span_converter(struct sna *sna,
143.32546 + 				break;
143.32547 + 		} while (1);
143.32548 + 		polygon_add_line(tor.polygon,
143.32549 +-				 &points[cw], &points[2+ccw],
143.32550 ++				 &points[cw], &points[ccw],
143.32551 + 				 dx, dy);
143.32552 + 		assert(tor.polygon->num_edges <= 2*count);
143.32553 + 
143.32554 +diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c
143.32555 +index 808703a9..07a7867d 100644
143.32556 +--- a/src/sna/sna_trapezoids_mono.c
143.32557 ++++ b/src/sna/sna_trapezoids_mono.c
143.32558 +@@ -72,13 +72,14 @@ struct mono {
143.32559 + 	struct sna *sna;
143.32560 + 	struct sna_composite_op op;
143.32561 + 	pixman_region16_t clip;
143.32562 ++	const BoxRec *clip_start, *clip_end;
143.32563 + 
143.32564 + 	fastcall void (*span)(struct mono *, int, int, BoxPtr);
143.32565 + 
143.32566 + 	struct mono_polygon polygon;
143.32567 + };
143.32568 + 
143.32569 +-#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2)
143.32570 ++#define I(x) pixman_fixed_to_int((x) + pixman_fixed_1_minus_e/2)
143.32571 + 
143.32572 + static struct quorem
143.32573 + floored_muldivrem(int32_t x, int32_t a, int32_t b)
143.32574 +@@ -249,22 +250,22 @@ mono_add_line(struct mono *mono,
143.32575 + 
143.32576 + 		e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy);
143.32577 + 
143.32578 +-		e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y,
143.32579 ++		e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1/2 - p1->y,
143.32580 + 					 dx, dy);
143.32581 + 		e->x.quo += p1->x;
143.32582 + 		e->x.rem -= dy;
143.32583 + 
143.32584 + 		e->dy = dy;
143.32585 +-
143.32586 +-		__DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
143.32587 +-		       __FUNCTION__,
143.32588 +-		       I(e->x.quo), e->x.quo, e->x.rem, e->dy,
143.32589 +-		       e->dxdy.quo, e->dxdy.rem, e->dy));
143.32590 + 	}
143.32591 + 	e->x.quo += dst_x*pixman_fixed_1;
143.32592 ++	__DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
143.32593 ++	       __FUNCTION__,
143.32594 ++	       I(e->x.quo), e->x.quo, e->x.rem, e->dy,
143.32595 ++	       e->dxdy.quo, e->dxdy.rem, e->dy));
143.32596 + 
143.32597 + 	{
143.32598 + 		struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1];
143.32599 ++		assert(ytop - mono->clip.extents.y1 < mono->clip.extents.y2 - mono->clip.extents.y1);
143.32600 + 		if (*ptail)
143.32601 + 			(*ptail)->prev = e;
143.32602 + 		e->next = *ptail;
143.32603 +@@ -368,6 +369,10 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
143.32604 + 		    e->x.rem == n->x.rem &&
143.32605 + 		    e->dxdy.quo == n->dxdy.quo &&
143.32606 + 		    e->dxdy.rem == n->dxdy.rem) {
143.32607 ++			assert(e->dy == n->dy);
143.32608 ++			__DBG(("%s: discarding cancellation pair (%d.%d) + (%d.%d)\n",
143.32609 ++			       __FUNCTION__, e->x.quo, e->x.rem, e->dxdy.quo, e->dxdy.rem));
143.32610 ++
143.32611 + 			if (e->prev)
143.32612 + 				e->prev->next = n->next;
143.32613 + 			else
143.32614 +@@ -378,8 +383,11 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
143.32615 + 				break;
143.32616 + 
143.32617 + 			e = n->next;
143.32618 +-		} else
143.32619 ++		} else {
143.32620 ++			__DBG(("%s: adding edge (%d.%d) + (%d.%d)/%d, height=%d\n",
143.32621 ++			       __FUNCTION__, n->x.quo, n->x.rem, n->dxdy.quo, n->dxdy.rem, n->dy, n->height_left));
143.32622 + 			e = n;
143.32623 ++		}
143.32624 + 	}
143.32625 + 
143.32626 + 	return edges;
143.32627 +@@ -474,6 +482,34 @@ mono_span__fast(struct mono *c, int x1, int x2, BoxPtr box)
143.32628 + 	c->op.box(c->sna, &c->op, box);
143.32629 + }
143.32630 + 
143.32631 ++fastcall static void
143.32632 ++mono_span__clipped(struct mono *c, int x1, int x2, BoxPtr box)
143.32633 ++{
143.32634 ++	const BoxRec *b;
143.32635 ++
143.32636 ++	__DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2));
143.32637 ++
143.32638 ++	c->clip_start =
143.32639 ++		find_clip_box_for_y(c->clip_start, c->clip_end, box->y1);
143.32640 ++
143.32641 ++	b = c->clip_start;
143.32642 ++	while (b != c->clip_end) {
143.32643 ++		BoxRec clipped;
143.32644 ++
143.32645 ++		if (box->y2 <= b->y1)
143.32646 ++			break;
143.32647 ++
143.32648 ++		clipped.x1 = x1;
143.32649 ++		clipped.x2 = x2;
143.32650 ++		clipped.y1 = box->y1;
143.32651 ++		clipped.y2 = box->y2;
143.32652 ++		if (!box_intersect(&clipped, b++))
143.32653 ++			continue;
143.32654 ++
143.32655 ++		c->op.box(c->sna, &c->op, &clipped);
143.32656 ++	}
143.32657 ++}
143.32658 ++
143.32659 + struct mono_span_thread_boxes {
143.32660 + 	const struct sna_composite_op *op;
143.32661 + #define MONO_SPAN_MAX_BOXES (8192/sizeof(BoxRec))
143.32662 +@@ -482,40 +518,45 @@ struct mono_span_thread_boxes {
143.32663 + };
143.32664 + 
143.32665 + inline static void
143.32666 +-thread_mono_span_add_boxes(struct mono *c, const BoxRec *box, int count)
143.32667 ++thread_mono_span_add_box(struct mono *c, const BoxRec *box)
143.32668 + {
143.32669 + 	struct mono_span_thread_boxes *b = c->op.priv;
143.32670 + 
143.32671 +-	assert(count > 0 && count <= MONO_SPAN_MAX_BOXES);
143.32672 +-	if (unlikely(b->num_boxes + count > MONO_SPAN_MAX_BOXES)) {
143.32673 ++	if (unlikely(b->num_boxes == MONO_SPAN_MAX_BOXES)) {
143.32674 + 		b->op->thread_boxes(c->sna, b->op, b->boxes, b->num_boxes);
143.32675 + 		b->num_boxes = 0;
143.32676 + 	}
143.32677 + 
143.32678 +-	memcpy(b->boxes + b->num_boxes, box, count*sizeof(BoxRec));
143.32679 +-	b->num_boxes += count;
143.32680 ++	b->boxes[b->num_boxes++] = *box;
143.32681 + 	assert(b->num_boxes <= MONO_SPAN_MAX_BOXES);
143.32682 + }
143.32683 + 
143.32684 + fastcall static void
143.32685 + thread_mono_span_clipped(struct mono *c, int x1, int x2, BoxPtr box)
143.32686 + {
143.32687 +-	pixman_region16_t region;
143.32688 ++	const BoxRec *b;
143.32689 + 
143.32690 + 	__DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2));
143.32691 + 
143.32692 +-	box->x1 = x1;
143.32693 +-	box->x2 = x2;
143.32694 ++	c->clip_start =
143.32695 ++		find_clip_box_for_y(c->clip_start, c->clip_end, box->y1);
143.32696 + 
143.32697 +-	assert(c->clip.data);
143.32698 ++	b = c->clip_start;
143.32699 ++	while (b != c->clip_end) {
143.32700 ++		BoxRec clipped;
143.32701 ++
143.32702 ++		if (box->y2 <= b->y1)
143.32703 ++			break;
143.32704 ++
143.32705 ++		clipped.x1 = x1;
143.32706 ++		clipped.x2 = x2;
143.32707 ++		clipped.y1 = box->y1;
143.32708 ++		clipped.y2 = box->y2;
143.32709 ++		if (!box_intersect(&clipped, b++))
143.32710 ++			continue;
143.32711 + 
143.32712 +-	pixman_region_init_rects(&region, box, 1);
143.32713 +-	RegionIntersect(&region, &region, &c->clip);
143.32714 +-	if (region_num_rects(&region))
143.32715 +-		thread_mono_span_add_boxes(c,
143.32716 +-					   region_rects(&region),
143.32717 +-					   region_num_rects(&region));
143.32718 +-	pixman_region_fini(&region);
143.32719 ++		thread_mono_span_add_box(c, &clipped);
143.32720 ++	}
143.32721 + }
143.32722 + 
143.32723 + fastcall static void
143.32724 +@@ -525,7 +566,7 @@ thread_mono_span(struct mono *c, int x1, int x2, BoxPtr box)
143.32725 + 
143.32726 + 	box->x1 = x1;
143.32727 + 	box->x2 = x2;
143.32728 +-	thread_mono_span_add_boxes(c, box, 1);
143.32729 ++	thread_mono_span_add_box(c, box);
143.32730 + }
143.32731 + 
143.32732 + inline static void
143.32733 +@@ -537,6 +578,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
143.32734 + 	int winding = 0;
143.32735 + 	BoxRec box;
143.32736 + 
143.32737 ++	__DBG(("%s: y=%d, h=%d\n", __FUNCTION__, y, h));
143.32738 ++
143.32739 + 	DBG_MONO_EDGES(edge);
143.32740 + 	VALIDATE_MONO_EDGES(&c->head);
143.32741 + 
143.32742 +@@ -547,6 +590,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
143.32743 + 		struct mono_edge *next = edge->next;
143.32744 + 		int16_t xend = I(edge->x.quo);
143.32745 + 
143.32746 ++		__DBG(("%s: adding edge dir=%d [winding=%d], x=%d [%d]\n",
143.32747 ++		       __FUNCTION__, edge->dir, winding + edge->dir, xend, edge->x.quo));
143.32748 + 		if (--edge->height_left) {
143.32749 + 			if (edge->dy) {
143.32750 + 				edge->x.quo += edge->dxdy.quo;
143.32751 +@@ -555,6 +600,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
143.32752 + 					++edge->x.quo;
143.32753 + 					edge->x.rem -= edge->dy;
143.32754 + 				}
143.32755 ++				__DBG(("%s: stepped edge (%d.%d) + (%d.%d)/%d, height=%d, prev_x=%d\n",
143.32756 ++				       __FUNCTION__, edge->x.quo, edge->x.rem, edge->dxdy.quo, edge->dxdy.rem, edge->dy, edge->height_left, edge->x.quo));
143.32757 + 			}
143.32758 + 
143.32759 + 			if (edge->x.quo < prev_x) {
143.32760 +@@ -578,17 +625,22 @@ mono_row(struct mono *c, int16_t y, int16_t h)
143.32761 + 		winding += edge->dir;
143.32762 + 		if (winding == 0) {
143.32763 + 			assert(I(next->x.quo) >= xend);
143.32764 +-			if (I(next->x.quo) > xend + 1) {
143.32765 ++			if (I(next->x.quo) > xend) {
143.32766 ++				__DBG(("%s: end span: %d\n", __FUNCTION__, xend));
143.32767 + 				if (xstart < c->clip.extents.x1)
143.32768 + 					xstart = c->clip.extents.x1;
143.32769 + 				if (xend > c->clip.extents.x2)
143.32770 + 					xend = c->clip.extents.x2;
143.32771 +-				if (xend > xstart)
143.32772 ++				if (xend > xstart) {
143.32773 ++					__DBG(("%s: emit span [%d, %d]\n", __FUNCTION__, xstart, xend));
143.32774 + 					c->span(c, xstart, xend, &box);
143.32775 ++				}
143.32776 + 				xstart = INT16_MIN;
143.32777 + 			}
143.32778 +-		} else if (xstart == INT16_MIN)
143.32779 ++		} else if (xstart == INT16_MIN) {
143.32780 ++			__DBG(("%s: starting new span: %d\n", __FUNCTION__, xend));
143.32781 + 			xstart = xend;
143.32782 ++		}
143.32783 + 
143.32784 + 		edge = next;
143.32785 + 	}
143.32786 +@@ -650,9 +702,14 @@ mono_render(struct mono *mono)
143.32787 + 	for (i = 0; i < h; i = j) {
143.32788 + 		j = i + 1;
143.32789 + 
143.32790 ++		__DBG(("%s: row=%d, new edges? %d\n", __FUNCTION__,
143.32791 ++		       i, polygon->y_buckets[i] != NULL));
143.32792 ++
143.32793 + 		if (polygon->y_buckets[i])
143.32794 + 			mono_merge_edges(mono, polygon->y_buckets[i]);
143.32795 + 
143.32796 ++		__DBG(("%s: row=%d, vertical? %d\n", __FUNCTION__,
143.32797 ++		       i, mono->is_vertical));
143.32798 + 		if (mono->is_vertical) {
143.32799 + 			struct mono_edge *e = mono->head.next;
143.32800 + 			int min_height = h - i;
143.32801 +@@ -667,6 +724,7 @@ mono_render(struct mono *mono)
143.32802 + 				j++;
143.32803 + 			if (j != i + 1)
143.32804 + 				mono_step_edges(mono, j - (i + 1));
143.32805 ++			__DBG(("%s: %d vertical rows\n", __FUNCTION__, j-i));
143.32806 + 		}
143.32807 + 
143.32808 + 		mono_row(mono, i, j-i);
143.32809 +@@ -717,6 +775,7 @@ mono_span_thread(void *arg)
143.32810 + 		if (RegionNil(&mono.clip))
143.32811 + 			return;
143.32812 + 	}
143.32813 ++	region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
143.32814 + 
143.32815 + 	boxes.op = thread->op;
143.32816 + 	boxes.num_boxes = 0;
143.32817 +@@ -891,9 +950,12 @@ mono_trapezoids_span_converter(struct sna *sna,
143.32818 + 
143.32819 + 	if (mono.clip.data == NULL && mono.op.damage == NULL)
143.32820 + 		mono.span = mono_span__fast;
143.32821 ++	else if (mono.clip.data != NULL && mono.op.damage == NULL)
143.32822 ++		mono.span = mono_span__clipped;
143.32823 + 	else
143.32824 + 		mono.span = mono_span;
143.32825 + 
143.32826 ++	region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
143.32827 + 	mono_render(&mono);
143.32828 + 	mono.op.done(mono.sna, &mono.op);
143.32829 + 	mono_fini(&mono);
143.32830 +@@ -939,6 +1001,7 @@ mono_trapezoids_span_converter(struct sna *sna,
143.32831 + 					       mono.clip.extents.x2 - mono.clip.extents.x1,
143.32832 + 					       mono.clip.extents.y2 - mono.clip.extents.y1,
143.32833 + 					       COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) {
143.32834 ++			region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
143.32835 + 			mono_render(&mono);
143.32836 + 			mono.op.done(mono.sna, &mono.op);
143.32837 + 		}
143.32838 +@@ -974,6 +1037,7 @@ mono_inplace_fill_box(struct sna *sna,
143.32839 + 	     box->x2 - box->x1,
143.32840 + 	     box->y2 - box->y1,
143.32841 + 	     fill->color));
143.32842 ++	sigtrap_assert_active();
143.32843 + 	pixman_fill(fill->data, fill->stride, fill->bpp,
143.32844 + 		    box->x1, box->y1,
143.32845 + 		    box->x2 - box->x1,
143.32846 +@@ -995,6 +1059,7 @@ mono_inplace_fill_boxes(struct sna *sna,
143.32847 + 		     box->x2 - box->x1,
143.32848 + 		     box->y2 - box->y1,
143.32849 + 		     fill->color));
143.32850 ++		sigtrap_assert_active();
143.32851 + 		pixman_fill(fill->data, fill->stride, fill->bpp,
143.32852 + 			    box->x1, box->y1,
143.32853 + 			    box->x2 - box->x1,
143.32854 +@@ -1382,10 +1447,13 @@ mono_triangles_span_converter(struct sna *sna,
143.32855 + 		mono_render(&mono);
143.32856 + 		mono.op.done(mono.sna, &mono.op);
143.32857 + 	}
143.32858 ++	mono_fini(&mono);
143.32859 + 
143.32860 + 	if (!was_clear && !operator_is_bounded(op)) {
143.32861 + 		xPointFixed p1, p2;
143.32862 + 
143.32863 ++		DBG(("%s: performing unbounded clear\n", __FUNCTION__));
143.32864 ++
143.32865 + 		if (!mono_init(&mono, 2+3*count))
143.32866 + 			return false;
143.32867 + 
143.32868 +@@ -1431,7 +1499,6 @@ mono_triangles_span_converter(struct sna *sna,
143.32869 + 		mono_fini(&mono);
143.32870 + 	}
143.32871 + 
143.32872 +-	mono_fini(&mono);
143.32873 + 	REGION_UNINIT(NULL, &mono.clip);
143.32874 + 	return true;
143.32875 + }
143.32876 +diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c
143.32877 +index 9187ab48..242b4acb 100644
143.32878 +--- a/src/sna/sna_trapezoids_precise.c
143.32879 ++++ b/src/sna/sna_trapezoids_precise.c
143.32880 +@@ -1023,6 +1023,16 @@ tor_init(struct tor *converter, const BoxRec *box, int num_edges)
143.32881 + static void
143.32882 + tor_add_trapezoid(struct tor *tor, const xTrapezoid *t, int dx, int dy)
143.32883 + {
143.32884 ++	if (!xTrapezoidValid(t)) {
143.32885 ++		__DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
143.32886 ++		       __FUNCTION__,
143.32887 ++		       t->top, t->bottom,
143.32888 ++		       t->left.p1.x, t->left.p1.y,
143.32889 ++		       t->left.p2.x, t->left.p2.y,
143.32890 ++		       t->right.p1.x, t->right.p1.y,
143.32891 ++		       t->right.p2.x, t->right.p2.y));
143.32892 ++		return;
143.32893 ++	}
143.32894 + 	polygon_add_edge(tor->polygon, t, &t->left, 1, dx, dy);
143.32895 + 	polygon_add_edge(tor->polygon, t, &t->right, -1, dx, dy);
143.32896 + }
143.32897 +@@ -1635,31 +1645,27 @@ struct span_thread {
143.32898 + #define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box))
143.32899 + struct span_thread_boxes {
143.32900 + 	const struct sna_composite_spans_op *op;
143.32901 ++	const BoxRec *clip_start, *clip_end;
143.32902 + 	int num_boxes;
143.32903 + 	struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES];
143.32904 + };
143.32905 + 
143.32906 +-static void span_thread_add_boxes(struct sna *sna, void *data,
143.32907 +-				  const BoxRec *box, int count, float alpha)
143.32908 ++static void span_thread_add_box(struct sna *sna, void *data,
143.32909 ++				const BoxRec *box, float alpha)
143.32910 + {
143.32911 + 	struct span_thread_boxes *b = data;
143.32912 + 
143.32913 +-	__DBG(("%s: adding %d boxes with alpha=%f\n",
143.32914 +-	       __FUNCTION__, count, alpha));
143.32915 ++	__DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
143.32916 + 
143.32917 +-	assert(count > 0 && count <= SPAN_THREAD_MAX_BOXES);
143.32918 +-	if (unlikely(b->num_boxes + count > SPAN_THREAD_MAX_BOXES)) {
143.32919 +-		DBG(("%s: flushing %d boxes, adding %d\n", __FUNCTION__, b->num_boxes, count));
143.32920 +-		assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
143.32921 ++	if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
143.32922 ++		DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
143.32923 + 		b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes);
143.32924 + 		b->num_boxes = 0;
143.32925 + 	}
143.32926 + 
143.32927 +-	do {
143.32928 +-		b->boxes[b->num_boxes].box = *box++;
143.32929 +-		b->boxes[b->num_boxes].alpha = alpha;
143.32930 +-		b->num_boxes++;
143.32931 +-	} while (--count);
143.32932 ++	b->boxes[b->num_boxes].box = *box++;
143.32933 ++	b->boxes[b->num_boxes].alpha = alpha;
143.32934 ++	b->num_boxes++;
143.32935 + 	assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
143.32936 + }
143.32937 + 
143.32938 +@@ -1670,8 +1676,22 @@ span_thread_box(struct sna *sna,
143.32939 + 		const BoxRec *box,
143.32940 + 		int coverage)
143.32941 + {
143.32942 ++	struct span_thread_boxes *b = (struct span_thread_boxes *)op;
143.32943 ++
143.32944 + 	__DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
143.32945 +-	span_thread_add_boxes(sna, op, box, 1, AREA_TO_FLOAT(coverage));
143.32946 ++	if (b->num_boxes) {
143.32947 ++		struct sna_opacity_box *bb = &b->boxes[b->num_boxes-1];
143.32948 ++		if (bb->box.x1 == box->x1 &&
143.32949 ++		    bb->box.x2 == box->x2 &&
143.32950 ++		    bb->box.y2 == box->y1 &&
143.32951 ++		    bb->alpha == AREA_TO_FLOAT(coverage)) {
143.32952 ++			bb->box.y2 = box->y2;
143.32953 ++			__DBG(("%s: contracted double row: %d -> %d\n", __func__, bb->box.y1, bb->box.y2));
143.32954 ++			return;
143.32955 ++		}
143.32956 ++	}
143.32957 ++
143.32958 ++	span_thread_add_box(sna, op, box, AREA_TO_FLOAT(coverage));
143.32959 + }
143.32960 + 
143.32961 + static void
143.32962 +@@ -1681,20 +1701,28 @@ span_thread_clipped_box(struct sna *sna,
143.32963 + 			const BoxRec *box,
143.32964 + 			int coverage)
143.32965 + {
143.32966 +-	pixman_region16_t region;
143.32967 ++	struct span_thread_boxes *b = (struct span_thread_boxes *)op;
143.32968 ++	const BoxRec *c;
143.32969 + 
143.32970 + 	__DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2,
143.32971 + 	       AREA_TO_FLOAT(coverage)));
143.32972 + 
143.32973 +-	pixman_region_init_rects(&region, box, 1);
143.32974 +-	RegionIntersect(&region, &region, clip);
143.32975 +-	if (region_num_rects(&region)) {
143.32976 +-		span_thread_add_boxes(sna, op,
143.32977 +-				      region_rects(&region),
143.32978 +-				      region_num_rects(&region),
143.32979 +-				      AREA_TO_FLOAT(coverage));
143.32980 ++	b->clip_start =
143.32981 ++		find_clip_box_for_y(b->clip_start, b->clip_end, box->y1);
143.32982 ++
143.32983 ++	c = b->clip_start;
143.32984 ++	while (c != b->clip_end) {
143.32985 ++		BoxRec clipped;
143.32986 ++
143.32987 ++		if (box->y2 <= c->y1)
143.32988 ++			break;
143.32989 ++
143.32990 ++		clipped = *box;
143.32991 ++		if (!box_intersect(&clipped, c++))
143.32992 ++			continue;
143.32993 ++
143.32994 ++		span_thread_add_box(sna, op, &clipped, AREA_TO_FLOAT(coverage));
143.32995 + 	}
143.32996 +-	pixman_region_fini(&region);
143.32997 + }
143.32998 + 
143.32999 + static span_func_t
143.33000 +@@ -1712,7 +1740,7 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
143.33001 + 
143.33002 + 	assert(!is_mono(dst, maskFormat));
143.33003 + 	assert(tmp->thread_boxes);
143.33004 +-	DBG(("%s: clipped? %d\n", __FUNCTION__, clip->data != NULL));
143.33005 ++	DBG(("%s: clipped? %d x %d\n", __FUNCTION__, clip->data != NULL, region_num_rects(clip)));
143.33006 + 	if (clip->data)
143.33007 + 		span = span_thread_clipped_box;
143.33008 + 	else
143.33009 +@@ -1721,6 +1749,17 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
143.33010 + 	return span;
143.33011 + }
143.33012 + 
143.33013 ++inline static void
143.33014 ++span_thread_boxes_init(struct span_thread_boxes *boxes,
143.33015 ++		       const struct sna_composite_spans_op *op,
143.33016 ++		       const RegionRec *clip)
143.33017 ++{
143.33018 ++	boxes->op = op;
143.33019 ++	boxes->clip_start = region_rects(clip);
143.33020 ++	boxes->clip_end = boxes->clip_start + region_num_rects(clip);
143.33021 ++	boxes->num_boxes = 0;
143.33022 ++}
143.33023 ++
143.33024 + static void
143.33025 + span_thread(void *arg)
143.33026 + {
143.33027 +@@ -1733,8 +1772,7 @@ span_thread(void *arg)
143.33028 + 	if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
143.33029 + 		return;
143.33030 + 
143.33031 +-	boxes.op = thread->op;
143.33032 +-	boxes.num_boxes = 0;
143.33033 ++	span_thread_boxes_init(&boxes, thread->op, thread->clip);
143.33034 + 
143.33035 + 	y1 = thread->extents.y1 - thread->draw_y;
143.33036 + 	y2 = thread->extents.y2 - thread->draw_y;
143.33037 +@@ -2183,6 +2221,52 @@ static force_inline uint8_t coverage_opacity(int coverage, uint8_t opacity)
143.33038 + 	return opacity == 255 ? coverage : mul_8_8(coverage, opacity);
143.33039 + }
143.33040 + 
143.33041 ++struct clipped_span {
143.33042 ++	span_func_t span;
143.33043 ++	const BoxRec *clip_start, *clip_end;
143.33044 ++};
143.33045 ++
143.33046 ++static void
143.33047 ++tor_blt_clipped(struct sna *sna,
143.33048 ++		struct sna_composite_spans_op *op,
143.33049 ++		pixman_region16_t *clip,
143.33050 ++		const BoxRec *box,
143.33051 ++		int coverage)
143.33052 ++{
143.33053 ++	struct clipped_span *cs = (struct clipped_span *)clip;
143.33054 ++	const BoxRec *c;
143.33055 ++
143.33056 ++	cs->clip_start =
143.33057 ++		find_clip_box_for_y(cs->clip_start, cs->clip_end, box->y1);
143.33058 ++
143.33059 ++	c = cs->clip_start;
143.33060 ++	while (c != cs->clip_end) {
143.33061 ++		BoxRec clipped;
143.33062 ++
143.33063 ++		if (box->y2 <= c->y1)
143.33064 ++			break;
143.33065 ++
143.33066 ++		clipped = *box;
143.33067 ++		if (!box_intersect(&clipped, c++))
143.33068 ++			continue;
143.33069 ++
143.33070 ++		cs->span(sna, op, NULL, &clipped, coverage);
143.33071 ++	}
143.33072 ++}
143.33073 ++
143.33074 ++inline static span_func_t
143.33075 ++clipped_span(struct clipped_span *cs,
143.33076 ++	     span_func_t span,
143.33077 ++	     const RegionRec *clip)
143.33078 ++{
143.33079 ++	if (clip->data) {
143.33080 ++		cs->span = span;
143.33081 ++		region_get_boxes(clip, &cs->clip_start, &cs->clip_end);
143.33082 ++		span = tor_blt_clipped;
143.33083 ++	}
143.33084 ++	return span;
143.33085 ++}
143.33086 ++
143.33087 + static void _tor_blt_src(struct inplace *in, const BoxRec *box, uint8_t v)
143.33088 + {
143.33089 + 	uint8_t *ptr = in->ptr;
143.33090 +@@ -2218,25 +2302,6 @@ tor_blt_src(struct sna *sna,
143.33091 + }
143.33092 + 
143.33093 + static void
143.33094 +-tor_blt_src_clipped(struct sna *sna,
143.33095 +-		    struct sna_composite_spans_op *op,
143.33096 +-		    pixman_region16_t *clip,
143.33097 +-		    const BoxRec *box,
143.33098 +-		    int coverage)
143.33099 +-{
143.33100 +-	pixman_region16_t region;
143.33101 +-	int n;
143.33102 +-
143.33103 +-	pixman_region_init_rects(&region, box, 1);
143.33104 +-	RegionIntersect(&region, &region, clip);
143.33105 +-	n = region_num_rects(&region);
143.33106 +-	box = region_rects(&region);
143.33107 +-	while (n--)
143.33108 +-		tor_blt_src(sna, op, NULL, box++, coverage);
143.33109 +-	pixman_region_fini(&region);
143.33110 +-}
143.33111 +-
143.33112 +-static void
143.33113 + tor_blt_in(struct sna *sna,
143.33114 + 	   struct sna_composite_spans_op *op,
143.33115 + 	   pixman_region16_t *clip,
143.33116 +@@ -2268,25 +2333,6 @@ tor_blt_in(struct sna *sna,
143.33117 + }
143.33118 + 
143.33119 + static void
143.33120 +-tor_blt_in_clipped(struct sna *sna,
143.33121 +-		   struct sna_composite_spans_op *op,
143.33122 +-		   pixman_region16_t *clip,
143.33123 +-		   const BoxRec *box,
143.33124 +-		   int coverage)
143.33125 +-{
143.33126 +-	pixman_region16_t region;
143.33127 +-	int n;
143.33128 +-
143.33129 +-	pixman_region_init_rects(&region, box, 1);
143.33130 +-	RegionIntersect(&region, &region, clip);
143.33131 +-	n = region_num_rects(&region);
143.33132 +-	box = region_rects(&region);
143.33133 +-	while (n--)
143.33134 +-		tor_blt_in(sna, op, NULL, box++, coverage);
143.33135 +-	pixman_region_fini(&region);
143.33136 +-}
143.33137 +-
143.33138 +-static void
143.33139 + tor_blt_add(struct sna *sna,
143.33140 + 	    struct sna_composite_spans_op *op,
143.33141 + 	    pixman_region16_t *clip,
143.33142 +@@ -2325,25 +2371,6 @@ tor_blt_add(struct sna *sna,
143.33143 + }
143.33144 + 
143.33145 + static void
143.33146 +-tor_blt_add_clipped(struct sna *sna,
143.33147 +-		    struct sna_composite_spans_op *op,
143.33148 +-		    pixman_region16_t *clip,
143.33149 +-		    const BoxRec *box,
143.33150 +-		    int coverage)
143.33151 +-{
143.33152 +-	pixman_region16_t region;
143.33153 +-	int n;
143.33154 +-
143.33155 +-	pixman_region_init_rects(&region, box, 1);
143.33156 +-	RegionIntersect(&region, &region, clip);
143.33157 +-	n = region_num_rects(&region);
143.33158 +-	box = region_rects(&region);
143.33159 +-	while (n--)
143.33160 +-		tor_blt_add(sna, op, NULL, box++, coverage);
143.33161 +-	pixman_region_fini(&region);
143.33162 +-}
143.33163 +-
143.33164 +-static void
143.33165 + tor_blt_lerp32(struct sna *sna,
143.33166 + 	       struct sna_composite_spans_op *op,
143.33167 + 	       pixman_region16_t *clip,
143.33168 +@@ -2358,6 +2385,7 @@ tor_blt_lerp32(struct sna *sna,
143.33169 + 	if (coverage == 0)
143.33170 + 		return;
143.33171 + 
143.33172 ++	sigtrap_assert_active();
143.33173 + 	ptr += box->y1 * stride + box->x1;
143.33174 + 
143.33175 + 	h = box->y2 - box->y1;
143.33176 +@@ -2396,25 +2424,6 @@ tor_blt_lerp32(struct sna *sna,
143.33177 + 	}
143.33178 + }
143.33179 + 
143.33180 +-static void
143.33181 +-tor_blt_lerp32_clipped(struct sna *sna,
143.33182 +-		       struct sna_composite_spans_op *op,
143.33183 +-		       pixman_region16_t *clip,
143.33184 +-		       const BoxRec *box,
143.33185 +-		       int coverage)
143.33186 +-{
143.33187 +-	pixman_region16_t region;
143.33188 +-	int n;
143.33189 +-
143.33190 +-	pixman_region_init_rects(&region, box, 1);
143.33191 +-	RegionIntersect(&region, &region, clip);
143.33192 +-	n = region_num_rects(&region);
143.33193 +-	box = region_rects(&region);
143.33194 +-	while (n--)
143.33195 +-		tor_blt_lerp32(sna, op, NULL, box++, coverage);
143.33196 +-	pixman_region_fini(&region);
143.33197 +-}
143.33198 +-
143.33199 + struct pixman_inplace {
143.33200 + 	pixman_image_t *image, *source, *mask;
143.33201 + 	uint32_t color;
143.33202 +@@ -2442,24 +2451,6 @@ pixmask_span_solid(struct sna *sna,
143.33203 + 			       pi->dx + box->x1, pi->dy + box->y1,
143.33204 + 			       box->x2 - box->x1, box->y2 - box->y1);
143.33205 + }
143.33206 +-static void
143.33207 +-pixmask_span_solid__clipped(struct sna *sna,
143.33208 +-			    struct sna_composite_spans_op *op,
143.33209 +-			    pixman_region16_t *clip,
143.33210 +-			    const BoxRec *box,
143.33211 +-			    int coverage)
143.33212 +-{
143.33213 +-	pixman_region16_t region;
143.33214 +-	int n;
143.33215 +-
143.33216 +-	pixman_region_init_rects(&region, box, 1);
143.33217 +-	RegionIntersect(&region, &region, clip);
143.33218 +-	n = region_num_rects(&region);
143.33219 +-	box = region_rects(&region);
143.33220 +-	while (n--)
143.33221 +-		pixmask_span_solid(sna, op, NULL, box++, coverage);
143.33222 +-	pixman_region_fini(&region);
143.33223 +-}
143.33224 + 
143.33225 + static void
143.33226 + pixmask_span(struct sna *sna,
143.33227 +@@ -2480,24 +2471,6 @@ pixmask_span(struct sna *sna,
143.33228 + 			       pi->dx + box->x1, pi->dy + box->y1,
143.33229 + 			       box->x2 - box->x1, box->y2 - box->y1);
143.33230 + }
143.33231 +-static void
143.33232 +-pixmask_span__clipped(struct sna *sna,
143.33233 +-		      struct sna_composite_spans_op *op,
143.33234 +-		      pixman_region16_t *clip,
143.33235 +-		      const BoxRec *box,
143.33236 +-		      int coverage)
143.33237 +-{
143.33238 +-	pixman_region16_t region;
143.33239 +-	int n;
143.33240 +-
143.33241 +-	pixman_region_init_rects(&region, box, 1);
143.33242 +-	RegionIntersect(&region, &region, clip);
143.33243 +-	n = region_num_rects(&region);
143.33244 +-	box = region_rects(&region);
143.33245 +-	while (n--)
143.33246 +-		pixmask_span(sna, op, NULL, box++, coverage);
143.33247 +-	pixman_region_fini(&region);
143.33248 +-}
143.33249 + 
143.33250 + struct inplace_x8r8g8b8_thread {
143.33251 + 	xTrapezoid *traps;
143.33252 +@@ -2516,6 +2489,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.33253 + 	struct inplace_x8r8g8b8_thread *thread = arg;
143.33254 + 	struct tor tor;
143.33255 + 	span_func_t span;
143.33256 ++	struct clipped_span clipped;
143.33257 + 	RegionPtr clip;
143.33258 + 	int y1, y2, n;
143.33259 + 
143.33260 +@@ -2546,12 +2520,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.33261 + 		inplace.stride = pixmap->devKind;
143.33262 + 		inplace.color = thread->color;
143.33263 + 
143.33264 +-		if (clip->data)
143.33265 +-			span = tor_blt_lerp32_clipped;
143.33266 +-		else
143.33267 +-			span = tor_blt_lerp32;
143.33268 ++		span = clipped_span(&clipped, tor_blt_lerp32, clip);
143.33269 + 
143.33270 +-		tor_render(NULL, &tor, (void*)&inplace, clip, span, false);
143.33271 ++		tor_render(NULL, &tor,
143.33272 ++			   (void*)&inplace, (void *)&clipped,
143.33273 ++			   span, false);
143.33274 + 	} else if (thread->is_solid) {
143.33275 + 		struct pixman_inplace pi;
143.33276 + 
143.33277 +@@ -2564,10 +2537,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.33278 + 						     1, 1, pi.bits, 0);
143.33279 + 		pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
143.33280 + 
143.33281 +-		if (clip->data)
143.33282 +-			span = pixmask_span_solid__clipped;
143.33283 +-		else
143.33284 +-			span = pixmask_span_solid;
143.33285 ++		span = clipped_span(&clipped, pixmask_span_solid, clip);
143.33286 + 
143.33287 + 		tor_render(NULL, &tor, (void*)&pi, clip, span, false);
143.33288 + 
143.33289 +@@ -2588,12 +2558,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
143.33290 + 		pi.bits = pixman_image_get_data(pi.mask);
143.33291 + 		pi.op = thread->op;
143.33292 + 
143.33293 +-		if (clip->data)
143.33294 +-			span = pixmask_span__clipped;
143.33295 +-		else
143.33296 +-			span = pixmask_span;
143.33297 ++		span = clipped_span(&clipped, pixmask_span, clip);
143.33298 + 
143.33299 +-		tor_render(NULL, &tor, (void*)&pi, clip, span, false);
143.33300 ++		tor_render(NULL, &tor,
143.33301 ++			   (void*)&pi, (void *)&clipped,
143.33302 ++			   span, false);
143.33303 + 
143.33304 + 		pixman_image_unref(pi.mask);
143.33305 + 		pixman_image_unref(pi.source);
143.33306 +@@ -2712,6 +2681,7 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.33307 + 	if (num_threads == 1) {
143.33308 + 		struct tor tor;
143.33309 + 		span_func_t span;
143.33310 ++		struct clipped_span clipped;
143.33311 + 
143.33312 + 		if (!tor_init(&tor, &region.extents, 2*ntrap))
143.33313 + 			return true;
143.33314 +@@ -2737,17 +2707,14 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.33315 + 			inplace.stride = pixmap->devKind;
143.33316 + 			inplace.color = color;
143.33317 + 
143.33318 +-			if (dst->pCompositeClip->data)
143.33319 +-				span = tor_blt_lerp32_clipped;
143.33320 +-			else
143.33321 +-				span = tor_blt_lerp32;
143.33322 +-
143.33323 ++			span = clipped_span(&clipped, tor_blt_lerp32, dst->pCompositeClip);
143.33324 + 			DBG(("%s: render inplace op=%d, color=%08x\n",
143.33325 + 			     __FUNCTION__, op, color));
143.33326 + 
143.33327 + 			if (sigtrap_get() == 0) {
143.33328 +-				tor_render(NULL, &tor, (void*)&inplace,
143.33329 +-					   dst->pCompositeClip, span, false);
143.33330 ++				tor_render(NULL, &tor,
143.33331 ++					   (void*)&inplace, (void*)&clipped,
143.33332 ++					   span, false);
143.33333 + 				sigtrap_put();
143.33334 + 			}
143.33335 + 		} else if (is_solid) {
143.33336 +@@ -2762,15 +2729,11 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.33337 + 							     1, 1, pi.bits, 0);
143.33338 + 			pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
143.33339 + 
143.33340 +-			if (dst->pCompositeClip->data)
143.33341 +-				span = pixmask_span_solid__clipped;
143.33342 +-			else
143.33343 +-				span = pixmask_span_solid;
143.33344 +-
143.33345 ++			span = clipped_span(&clipped, pixmask_span_solid, dst->pCompositeClip);
143.33346 + 			if (sigtrap_get() == 0) {
143.33347 +-				tor_render(NULL, &tor, (void*)&pi,
143.33348 +-					   dst->pCompositeClip, span,
143.33349 +-					   false);
143.33350 ++				tor_render(NULL, &tor,
143.33351 ++					   (void*)&pi, (void*)&clipped,
143.33352 ++					    span, false);
143.33353 + 				sigtrap_put();
143.33354 + 			}
143.33355 + 
143.33356 +@@ -2791,15 +2754,11 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.33357 + 			pi.bits = pixman_image_get_data(pi.mask);
143.33358 + 			pi.op = op;
143.33359 + 
143.33360 +-			if (dst->pCompositeClip->data)
143.33361 +-				span = pixmask_span__clipped;
143.33362 +-			else
143.33363 +-				span = pixmask_span;
143.33364 +-
143.33365 ++			span = clipped_span(&clipped, pixmask_span, dst->pCompositeClip);
143.33366 + 			if (sigtrap_get() == 0) {
143.33367 +-				tor_render(NULL, &tor, (void*)&pi,
143.33368 +-					   dst->pCompositeClip, span,
143.33369 +-					   false);
143.33370 ++				tor_render(NULL, &tor,
143.33371 ++					   (void*)&pi, (void *)&clipped,
143.33372 ++					   span, false);
143.33373 + 				sigtrap_put();
143.33374 + 			}
143.33375 + 
143.33376 +@@ -2861,9 +2820,9 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
143.33377 + 
143.33378 + struct inplace_thread {
143.33379 + 	xTrapezoid *traps;
143.33380 +-	RegionPtr clip;
143.33381 + 	span_func_t span;
143.33382 + 	struct inplace inplace;
143.33383 ++	struct clipped_span clipped;
143.33384 + 	BoxRec extents;
143.33385 + 	int dx, dy;
143.33386 + 	int draw_x, draw_y;
143.33387 +@@ -2888,8 +2847,9 @@ static void inplace_thread(void *arg)
143.33388 + 		tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
143.33389 + 	}
143.33390 + 
143.33391 +-	tor_render(NULL, &tor, (void*)&thread->inplace,
143.33392 +-		   thread->clip, thread->span, thread->unbounded);
143.33393 ++	tor_render(NULL, &tor, 
143.33394 ++		   (void*)&thread->inplace, (void*)&thread->clipped,
143.33395 ++		   thread->span, thread->unbounded);
143.33396 + 
143.33397 + 	tor_fini(&tor);
143.33398 + }
143.33399 +@@ -2903,6 +2863,7 @@ precise_trapezoid_span_inplace(struct sna *sna,
143.33400 + 			       bool fallback)
143.33401 + {
143.33402 + 	struct inplace inplace;
143.33403 ++	struct clipped_span clipped;
143.33404 + 	span_func_t span;
143.33405 + 	PixmapPtr pixmap;
143.33406 + 	struct sna_pixmap *priv;
143.33407 +@@ -3020,21 +2981,12 @@ precise_trapezoid_span_inplace(struct sna *sna,
143.33408 + 	     dst->pCompositeClip->data != NULL));
143.33409 + 
143.33410 + 	if (op == PictOpSrc) {
143.33411 +-		if (dst->pCompositeClip->data)
143.33412 +-			span = tor_blt_src_clipped;
143.33413 +-		else
143.33414 +-			span = tor_blt_src;
143.33415 ++		span = tor_blt_src;
143.33416 + 	} else if (op == PictOpIn) {
143.33417 +-		if (dst->pCompositeClip->data)
143.33418 +-			span = tor_blt_in_clipped;
143.33419 +-		else
143.33420 +-			span = tor_blt_in;
143.33421 ++		span = tor_blt_in;
143.33422 + 	} else {
143.33423 + 		assert(op == PictOpAdd);
143.33424 +-		if (dst->pCompositeClip->data)
143.33425 +-			span = tor_blt_add_clipped;
143.33426 +-		else
143.33427 +-			span = tor_blt_add;
143.33428 ++		span = tor_blt_add;
143.33429 + 	}
143.33430 + 
143.33431 + 	DBG(("%s: move-to-cpu(dst)\n", __FUNCTION__));
143.33432 +@@ -3052,6 +3004,8 @@ precise_trapezoid_span_inplace(struct sna *sna,
143.33433 + 	inplace.stride = pixmap->devKind;
143.33434 + 	inplace.opacity = color >> 24;
143.33435 + 
143.33436 ++	span = clipped_span(&clipped, span, dst->pCompositeClip);
143.33437 ++
143.33438 + 	num_threads = 1;
143.33439 + 	if (!NO_GPU_THREADS &&
143.33440 + 	    (flags & COMPOSITE_SPANS_RECTILINEAR) == 0)
143.33441 +@@ -3074,8 +3028,9 @@ precise_trapezoid_span_inplace(struct sna *sna,
143.33442 + 		}
143.33443 + 
143.33444 + 		if (sigtrap_get() == 0) {
143.33445 +-			tor_render(NULL, &tor, (void*)&inplace,
143.33446 +-				   dst->pCompositeClip, span, unbounded);
143.33447 ++			tor_render(NULL, &tor,
143.33448 ++				   (void*)&inplace, (void *)&clipped,
143.33449 ++				   span, unbounded);
143.33450 + 			sigtrap_put();
143.33451 + 		}
143.33452 + 
143.33453 +@@ -3093,7 +3048,7 @@ precise_trapezoid_span_inplace(struct sna *sna,
143.33454 + 		threads[0].ntrap = ntrap;
143.33455 + 		threads[0].inplace = inplace;
143.33456 + 		threads[0].extents = region.extents;
143.33457 +-		threads[0].clip = dst->pCompositeClip;
143.33458 ++		threads[0].clipped = clipped;
143.33459 + 		threads[0].span = span;
143.33460 + 		threads[0].unbounded = unbounded;
143.33461 + 		threads[0].dx = dx;
143.33462 +@@ -3316,8 +3271,7 @@ tristrip_thread(void *arg)
143.33463 + 	if (!tor_init(&tor, &thread->extents, 2*thread->count))
143.33464 + 		return;
143.33465 + 
143.33466 +-	boxes.op = thread->op;
143.33467 +-	boxes.num_boxes = 0;
143.33468 ++	span_thread_boxes_init(&boxes, thread->op, thread->clip);
143.33469 + 
143.33470 + 	cw = 0; ccw = 1;
143.33471 + 	polygon_add_line(tor.polygon,
143.33472 +diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
143.33473 +index ed0e7b31..e2b11c31 100644
143.33474 +--- a/src/sna/sna_video.c
143.33475 ++++ b/src/sna/sna_video.c
143.33476 +@@ -591,6 +591,72 @@ use_gtt: /* copy data, must use GTT so that we keep the overlay uncached */
143.33477 + 	return true;
143.33478 + }
143.33479 + 
143.33480 ++void sna_video_fill_colorkey(struct sna_video *video,
143.33481 ++			     const RegionRec *clip)
143.33482 ++{
143.33483 ++	struct sna *sna = video->sna;
143.33484 ++	PixmapPtr front = sna->front;
143.33485 ++	struct kgem_bo *bo = __sna_pixmap_get_bo(front);
143.33486 ++	uint8_t *dst, *tmp;
143.33487 ++	int w, width;
143.33488 ++
143.33489 ++	if (video->AlwaysOnTop || RegionEqual(&video->clip, (RegionPtr)clip))
143.33490 ++		return;
143.33491 ++
143.33492 ++	assert(bo);
143.33493 ++	if (!wedged(sna) &&
143.33494 ++	    sna_blt_fill_boxes(sna, GXcopy, bo,
143.33495 ++			       front->drawable.bitsPerPixel,
143.33496 ++			       video->color_key,
143.33497 ++			       region_rects(clip),
143.33498 ++			       region_num_rects(clip))) {
143.33499 ++		RegionCopy(&video->clip, (RegionPtr)clip);
143.33500 ++		return;
143.33501 ++	}
143.33502 ++
143.33503 ++	dst = kgem_bo_map__gtt(&sna->kgem, bo);
143.33504 ++	if (dst == NULL)
143.33505 ++		return;
143.33506 ++
143.33507 ++	w = front->drawable.bitsPerPixel/8;
143.33508 ++	width = (clip->extents.x2 - clip->extents.x1) * w;
143.33509 ++	tmp = malloc(width);
143.33510 ++	if (tmp == NULL)
143.33511 ++		return;
143.33512 ++
143.33513 ++	memcpy(tmp, &video->color_key, w);
143.33514 ++	while (2 * w < width) {
143.33515 ++		memcpy(tmp + w, tmp, w);
143.33516 ++		w *= 2;
143.33517 ++	}
143.33518 ++	if (w < width)
143.33519 ++		memcpy(tmp + w, tmp, width - w);
143.33520 ++
143.33521 ++	if (sigtrap_get() == 0) {
143.33522 ++		const BoxRec *box = region_rects(clip);
143.33523 ++		int n = region_num_rects(clip);
143.33524 ++
143.33525 ++		w = front->drawable.bitsPerPixel/8;
143.33526 ++		do {
143.33527 ++			int y = box->y1;
143.33528 ++			uint8_t *row = dst + y*bo->pitch + w*box->x1;
143.33529 ++
143.33530 ++			width = (box->x2 - box->x1) * w;
143.33531 ++			while (y < box->y2) {
143.33532 ++				memcpy(row, tmp, width);
143.33533 ++				row += bo->pitch;
143.33534 ++				y++;
143.33535 ++			}
143.33536 ++			box++;
143.33537 ++		} while (--n);
143.33538 ++		sigtrap_put();
143.33539 ++
143.33540 ++		RegionCopy(&video->clip, (RegionPtr)clip);
143.33541 ++	}
143.33542 ++
143.33543 ++	free(tmp);
143.33544 ++}
143.33545 ++
143.33546 + XvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
143.33547 + {
143.33548 + 	XvAdaptorPtr new_adaptors;
143.33549 +diff --git a/src/sna/sna_video.h b/src/sna/sna_video.h
143.33550 +index f21605fc..39cb725f 100644
143.33551 +--- a/src/sna/sna_video.h
143.33552 ++++ b/src/sna/sna_video.h
143.33553 +@@ -72,6 +72,8 @@ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
143.33554 + struct sna_video {
143.33555 + 	struct sna *sna;
143.33556 + 
143.33557 ++	int idx; /* XXX expose struct plane instead? */
143.33558 ++
143.33559 + 	int brightness;
143.33560 + 	int contrast;
143.33561 + 	int saturation;
143.33562 +@@ -193,6 +195,9 @@ bool
143.33563 + sna_video_copy_data(struct sna_video *video,
143.33564 + 		    struct sna_video_frame *frame,
143.33565 + 		    const uint8_t *buf);
143.33566 ++void
143.33567 ++sna_video_fill_colorkey(struct sna_video *video,
143.33568 ++			const RegionRec *clip);
143.33569 + 
143.33570 + void sna_video_buffer_fini(struct sna_video *video);
143.33571 + 
143.33572 +@@ -210,4 +215,26 @@ sna_window_set_port(WindowPtr window, XvPortPtr port)
143.33573 + 	((void **)__get_private(window, sna_window_key))[2] = port;
143.33574 + }
143.33575 + 
143.33576 ++static inline int offset_and_clip(int x, int dx)
143.33577 ++{
143.33578 ++	x += dx;
143.33579 ++	if (x <= 0)
143.33580 ++		return 0;
143.33581 ++	if (x >= MAXSHORT)
143.33582 ++		return MAXSHORT;
143.33583 ++	return x;
143.33584 ++}
143.33585 ++
143.33586 ++static inline void init_video_region(RegionRec *region,
143.33587 ++				     DrawablePtr draw,
143.33588 ++				     int drw_x, int drw_y,
143.33589 ++				     int drw_w, int drw_h)
143.33590 ++{
143.33591 ++	region->extents.x1 = offset_and_clip(draw->x, drw_x);
143.33592 ++	region->extents.y1 = offset_and_clip(draw->y, drw_y);
143.33593 ++	region->extents.x2 = offset_and_clip(draw->x, drw_x + drw_w);
143.33594 ++	region->extents.y2 = offset_and_clip(draw->y, drw_y + drw_h);
143.33595 ++	region->data = NULL;
143.33596 ++}
143.33597 ++
143.33598 + #endif /* SNA_VIDEO_H */
143.33599 +diff --git a/src/sna/sna_video_overlay.c b/src/sna/sna_video_overlay.c
143.33600 +index ac81f1a0..9bc5ce40 100644
143.33601 +--- a/src/sna/sna_video_overlay.c
143.33602 ++++ b/src/sna/sna_video_overlay.c
143.33603 +@@ -130,7 +130,7 @@ static int sna_video_overlay_stop(ddStopVideo_ARGS)
143.33604 + 
143.33605 + 	DBG(("%s()\n", __FUNCTION__));
143.33606 + 
143.33607 +-	REGION_EMPTY(scrn->pScreen, &video->clip);
143.33608 ++	REGION_EMPTY(to_screen_from_sna(sna), &video->clip);
143.33609 + 
143.33610 + 	request.flags = 0;
143.33611 + 	(void)drmIoctl(sna->kgem.fd,
143.33612 +@@ -474,15 +474,13 @@ sna_video_overlay_put_image(ddPutImage_ARGS)
143.33613 + 	if (src_h >= (drw_h * 8))
143.33614 + 		drw_h = src_h / 7;
143.33615 + 
143.33616 +-	clip.extents.x1 = draw->x + drw_x;
143.33617 +-	clip.extents.y1 = draw->y + drw_y;
143.33618 +-	clip.extents.x2 = clip.extents.x1 + drw_w;
143.33619 +-	clip.extents.y2 = clip.extents.y1 + drw_h;
143.33620 +-	clip.data = NULL;
143.33621 ++	init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h);
143.33622 + 
143.33623 + 	DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop));
143.33624 +-	if (!video->AlwaysOnTop)
143.33625 ++	if (!video->AlwaysOnTop) {
143.33626 ++		ValidateGC(draw, gc);
143.33627 + 		RegionIntersect(&clip, &clip, gc->pCompositeClip);
143.33628 ++	}
143.33629 + 	if (box_empty(&clip.extents))
143.33630 + 		goto invisible;
143.33631 + 
143.33632 +@@ -551,15 +549,7 @@ sna_video_overlay_put_image(ddPutImage_ARGS)
143.33633 + 	ret = Success;
143.33634 + 	if (sna_video_overlay_show
143.33635 + 	    (sna, video, &frame, crtc, &dstBox, src_w, src_h, drw_w, drw_h)) {
143.33636 +-		//xf86XVFillKeyHelperDrawable(draw, video->color_key, &clip);
143.33637 +-		if (!video->AlwaysOnTop && !RegionEqual(&video->clip, &clip) &&
143.33638 +-		    sna_blt_fill_boxes(sna, GXcopy,
143.33639 +-				       __sna_pixmap_get_bo(sna->front),
143.33640 +-				       sna->front->drawable.bitsPerPixel,
143.33641 +-				       video->color_key,
143.33642 +-				       region_rects(&clip),
143.33643 +-				       region_num_rects(&clip)))
143.33644 +-			RegionCopy(&video->clip, &clip);
143.33645 ++		sna_video_fill_colorkey(video, &clip);
143.33646 + 		sna_window_set_port((WindowPtr)draw, port);
143.33647 + 	} else {
143.33648 + 		DBG(("%s: failed to show video frame\n", __FUNCTION__));
143.33649 +diff --git a/src/sna/sna_video_sprite.c b/src/sna/sna_video_sprite.c
143.33650 +index 92230f97..69bfdfd2 100644
143.33651 +--- a/src/sna/sna_video_sprite.c
143.33652 ++++ b/src/sna/sna_video_sprite.c
143.33653 +@@ -47,6 +47,8 @@
143.33654 + #define DRM_FORMAT_YUYV         fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */
143.33655 + #define DRM_FORMAT_UYVY         fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */
143.33656 + 
143.33657 ++#define has_hw_scaling(sna) ((sna)->kgem.gen < 071)
143.33658 ++
143.33659 + #define LOCAL_IOCTL_MODE_SETPLANE	DRM_IOWR(0xB7, struct local_mode_set_plane)
143.33660 + struct local_mode_set_plane {
143.33661 + 	uint32_t plane_id;
143.33662 +@@ -81,19 +83,17 @@ static int sna_video_sprite_stop(ddStopVideo_ARGS)
143.33663 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn);
143.33664 + 	int i;
143.33665 + 
143.33666 +-	for (i = 0; i < config->num_crtc; i++) {
143.33667 ++	for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
143.33668 + 		xf86CrtcPtr crtc = config->crtc[i];
143.33669 + 		int pipe;
143.33670 + 
143.33671 +-		if (sna_crtc_id(crtc) == 0)
143.33672 +-			break;
143.33673 +-
143.33674 +-		pipe = sna_crtc_to_pipe(crtc);
143.33675 ++		pipe = sna_crtc_pipe(crtc);
143.33676 ++		assert(pipe < ARRAY_SIZE(video->bo));
143.33677 + 		if (video->bo[pipe] == NULL)
143.33678 + 			continue;
143.33679 + 
143.33680 + 		memset(&s, 0, sizeof(s));
143.33681 +-		s.plane_id = sna_crtc_to_sprite(crtc);
143.33682 ++		s.plane_id = sna_crtc_to_sprite(crtc, video->idx);
143.33683 + 		if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
143.33684 + 			xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR,
143.33685 + 				   "failed to disable plane\n");
143.33686 +@@ -153,7 +153,7 @@ static int sna_video_sprite_best_size(ddQueryBestSize_ARGS)
143.33687 + 	struct sna_video *video = port->devPriv.ptr;
143.33688 + 	struct sna *sna = video->sna;
143.33689 + 
143.33690 +-	if (sna->kgem.gen >= 075) {
143.33691 ++	if (!has_hw_scaling(sna) && !sna->render.video) {
143.33692 + 		*p_w = vid_w;
143.33693 + 		*p_h = vid_h;
143.33694 + 	} else {
143.33695 +@@ -221,12 +221,12 @@ sna_video_sprite_show(struct sna *sna,
143.33696 + 		      BoxPtr dstBox)
143.33697 + {
143.33698 + 	struct local_mode_set_plane s;
143.33699 +-	int pipe = sna_crtc_to_pipe(crtc);
143.33700 ++	int pipe = sna_crtc_pipe(crtc);
143.33701 + 
143.33702 + 	/* XXX handle video spanning multiple CRTC */
143.33703 + 
143.33704 + 	VG_CLEAR(s);
143.33705 +-	s.plane_id = sna_crtc_to_sprite(crtc);
143.33706 ++	s.plane_id = sna_crtc_to_sprite(crtc, video->idx);
143.33707 + 
143.33708 + #define DRM_I915_SET_SPRITE_COLORKEY 0x2b
143.33709 + #define LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct local_intel_sprite_colorkey)
143.33710 +@@ -263,9 +263,6 @@ sna_video_sprite_show(struct sna *sna,
143.33711 + 		video->color_key_changed &= ~(1 << pipe);
143.33712 + 	}
143.33713 + 
143.33714 +-	if (video->bo[pipe] == frame->bo)
143.33715 +-		return true;
143.33716 +-
143.33717 + 	update_dst_box_to_crtc_coords(sna, crtc, dstBox);
143.33718 + 	if (frame->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
143.33719 + 		int tmp = frame->width;
143.33720 +@@ -283,15 +280,30 @@ sna_video_sprite_show(struct sna *sna,
143.33721 + 			uint32_t handles[4];
143.33722 + 			uint32_t pitches[4]; /* pitch for each plane */
143.33723 + 			uint32_t offsets[4]; /* offset of each plane */
143.33724 ++			uint64_t modifiers[4];
143.33725 + 		} f;
143.33726 + 		bool purged = true;
143.33727 + 
143.33728 + 		memset(&f, 0, sizeof(f));
143.33729 + 		f.width = frame->width;
143.33730 + 		f.height = frame->height;
143.33731 ++		f.flags = 1 << 1; /* +modifiers */
143.33732 + 		f.handles[0] = frame->bo->handle;
143.33733 + 		f.pitches[0] = frame->pitch[0];
143.33734 + 
143.33735 ++		switch (frame->bo->tiling) {
143.33736 ++		case I915_TILING_NONE:
143.33737 ++			break;
143.33738 ++		case I915_TILING_X:
143.33739 ++			/* I915_FORMAT_MOD_X_TILED */
143.33740 ++			f.modifiers[0] = (uint64_t)1 << 56 | 1;
143.33741 ++			break;
143.33742 ++		case I915_TILING_Y:
143.33743 ++			/* I915_FORMAT_MOD_X_TILED */
143.33744 ++			f.modifiers[0] = (uint64_t)1 << 56 | 2;
143.33745 ++			break;
143.33746 ++		}
143.33747 ++
143.33748 + 		switch (frame->id) {
143.33749 + 		case FOURCC_RGB565:
143.33750 + 			f.pixel_format = DRM_FORMAT_RGB565;
143.33751 +@@ -360,7 +372,7 @@ sna_video_sprite_show(struct sna *sna,
143.33752 + 		return false;
143.33753 + 	}
143.33754 + 
143.33755 +-	frame->bo->domain = DOMAIN_NONE;
143.33756 ++	__kgem_bo_clear_dirty(frame->bo);
143.33757 + 
143.33758 + 	if (video->bo[pipe])
143.33759 + 		kgem_bo_destroy(&sna->kgem, video->bo[pipe]);
143.33760 +@@ -374,17 +386,17 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
143.33761 + 	struct sna *sna = video->sna;
143.33762 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.33763 + 	RegionRec clip;
143.33764 ++	BoxRec draw_extents;
143.33765 + 	int ret, i;
143.33766 + 
143.33767 +-	clip.extents.x1 = draw->x + drw_x;
143.33768 +-	clip.extents.y1 = draw->y + drw_y;
143.33769 +-	clip.extents.x2 = clip.extents.x1 + drw_w;
143.33770 +-	clip.extents.y2 = clip.extents.y1 + drw_h;
143.33771 +-	clip.data = NULL;
143.33772 ++	init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h);
143.33773 ++	draw_extents = clip.extents;
143.33774 + 
143.33775 + 	DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop));
143.33776 +-	if (!video->AlwaysOnTop)
143.33777 ++	if (!video->AlwaysOnTop) {
143.33778 ++		ValidateGC(draw, gc);
143.33779 + 		RegionIntersect(&clip, &clip, gc->pCompositeClip);
143.33780 ++	}
143.33781 + 
143.33782 + 	DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n",
143.33783 + 	     __FUNCTION__,
143.33784 +@@ -402,19 +414,17 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
143.33785 + 		goto err;
143.33786 + 	}
143.33787 + 
143.33788 +-	for (i = 0; i < config->num_crtc; i++) {
143.33789 ++	for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
143.33790 + 		xf86CrtcPtr crtc = config->crtc[i];
143.33791 + 		struct sna_video_frame frame;
143.33792 ++		BoxRec dst = draw_extents;
143.33793 + 		int pipe;
143.33794 + 		INT32 x1, x2, y1, y2;
143.33795 +-		BoxRec dst;
143.33796 + 		RegionRec reg;
143.33797 + 		Rotation rotation;
143.33798 ++		bool cache_bo;
143.33799 + 
143.33800 +-		if (sna_crtc_id(crtc) == 0)
143.33801 +-			break;
143.33802 +-
143.33803 +-		pipe = sna_crtc_to_pipe(crtc);
143.33804 ++		pipe = sna_crtc_pipe(crtc);
143.33805 + 
143.33806 + 		sna_video_frame_init(video, format->id, width, height, &frame);
143.33807 + 
143.33808 +@@ -423,10 +433,11 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
143.33809 + 		RegionIntersect(&reg, &reg, &clip);
143.33810 + 		if (RegionNil(&reg)) {
143.33811 + off:
143.33812 ++			assert(pipe < ARRAY_SIZE(video->bo));
143.33813 + 			if (video->bo[pipe]) {
143.33814 + 				struct local_mode_set_plane s;
143.33815 + 				memset(&s, 0, sizeof(s));
143.33816 +-				s.plane_id = sna_crtc_to_sprite(crtc);
143.33817 ++				s.plane_id = sna_crtc_to_sprite(crtc, video->idx);
143.33818 + 				if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
143.33819 + 					xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR,
143.33820 + 						   "failed to disable plane\n");
143.33821 +@@ -440,8 +451,6 @@ off:
143.33822 + 		y1 = src_y;
143.33823 + 		y2 = src_y + src_h;
143.33824 + 
143.33825 +-		dst = clip.extents;
143.33826 +-
143.33827 + 		ret = xf86XVClipVideoHelper(&dst, &x1, &x2, &y1, &y2,
143.33828 + 					    &reg, frame.width, frame.height);
143.33829 + 		RegionUninit(&reg);
143.33830 +@@ -465,8 +474,8 @@ off:
143.33831 + 
143.33832 + 		/* if sprite can't handle rotation natively, store it for the copy func */
143.33833 + 		rotation = RR_Rotate_0;
143.33834 +-		if (!sna_crtc_set_sprite_rotation(crtc, crtc->rotation)) {
143.33835 +-			sna_crtc_set_sprite_rotation(crtc, RR_Rotate_0);
143.33836 ++		if (!sna_crtc_set_sprite_rotation(crtc, video->idx, crtc->rotation)) {
143.33837 ++			sna_crtc_set_sprite_rotation(crtc, video->idx, RR_Rotate_0);
143.33838 + 			rotation = crtc->rotation;
143.33839 + 		}
143.33840 + 		sna_video_frame_set_rotation(video, &frame, rotation);
143.33841 +@@ -496,6 +505,8 @@ off:
143.33842 + 			frame.image.y1 = 0;
143.33843 + 			frame.image.x2 = frame.width;
143.33844 + 			frame.image.y2 = frame.height;
143.33845 ++
143.33846 ++			cache_bo = false;
143.33847 + 		} else {
143.33848 + 			frame.bo = sna_video_buffer(video, &frame);
143.33849 + 			if (frame.bo == NULL) {
143.33850 +@@ -509,6 +520,60 @@ off:
143.33851 + 				ret = BadAlloc;
143.33852 + 				goto err;
143.33853 + 			}
143.33854 ++
143.33855 ++			cache_bo = true;
143.33856 ++		}
143.33857 ++
143.33858 ++		if (!has_hw_scaling(sna) && sna->render.video &&
143.33859 ++		    !((frame.src.x2 - frame.src.x1) == (dst.x2 - dst.x1) &&
143.33860 ++		      (frame.src.y2 - frame.src.y1) == (dst.y2 - dst.y1))) {
143.33861 ++			ScreenPtr screen = to_screen_from_sna(sna);
143.33862 ++			PixmapPtr scaled;
143.33863 ++			RegionRec r;
143.33864 ++
143.33865 ++			r.extents.x1 = r.extents.y1 = 0;
143.33866 ++			r.extents.x2 = dst.x2 - dst.x1;
143.33867 ++			r.extents.y2 = dst.y2 - dst.y1;
143.33868 ++			r.data = NULL;
143.33869 ++
143.33870 ++			DBG(("%s: scaling from (%d, %d) to (%d, %d)\n",
143.33871 ++			     __FUNCTION__,
143.33872 ++			     frame.src.x2 - frame.src.x1,
143.33873 ++			     frame.src.y2 - frame.src.y1,
143.33874 ++			     r.extents.x2, r.extents.y2));
143.33875 ++
143.33876 ++			scaled = screen->CreatePixmap(screen,
143.33877 ++						      r.extents.x2,
143.33878 ++						      r.extents.y2,
143.33879 ++						      24,
143.33880 ++						      CREATE_PIXMAP_USAGE_SCRATCH);
143.33881 ++			if (scaled == NULL) {
143.33882 ++				ret = BadAlloc;
143.33883 ++				goto err;
143.33884 ++			}
143.33885 ++
143.33886 ++			if (!sna->render.video(sna, video, &frame, &r, scaled)) {
143.33887 ++				screen->DestroyPixmap(scaled);
143.33888 ++				ret = BadAlloc;
143.33889 ++				goto err;
143.33890 ++			}
143.33891 ++
143.33892 ++			if (cache_bo)
143.33893 ++				sna_video_buffer_fini(video);
143.33894 ++			else
143.33895 ++				kgem_bo_destroy(&sna->kgem, frame.bo);
143.33896 ++
143.33897 ++			frame.bo = kgem_bo_reference(__sna_pixmap_get_bo(scaled));
143.33898 ++			kgem_bo_submit(&sna->kgem, frame.bo);
143.33899 ++
143.33900 ++			frame.id = FOURCC_RGB888;
143.33901 ++			frame.src = frame.image = r.extents;
143.33902 ++			frame.width = frame.image.x2;
143.33903 ++			frame.height = frame.image.y2;
143.33904 ++			frame.pitch[0] = frame.bo->pitch;
143.33905 ++
143.33906 ++			screen->DestroyPixmap(scaled);
143.33907 ++			cache_bo = false;
143.33908 + 		}
143.33909 + 
143.33910 + 		ret = Success;
143.33911 +@@ -517,24 +582,16 @@ off:
143.33912 + 			ret = BadAlloc;
143.33913 + 		}
143.33914 + 
143.33915 +-		frame.bo->domain = DOMAIN_NONE;
143.33916 +-		if (xvmc_passthrough(format->id))
143.33917 +-			kgem_bo_destroy(&sna->kgem, frame.bo);
143.33918 +-		else
143.33919 ++		if (cache_bo)
143.33920 + 			sna_video_buffer_fini(video);
143.33921 ++		else
143.33922 ++			kgem_bo_destroy(&sna->kgem, frame.bo);
143.33923 + 
143.33924 + 		if (ret != Success)
143.33925 + 			goto err;
143.33926 + 	}
143.33927 + 
143.33928 +-	if (!video->AlwaysOnTop && !RegionEqual(&video->clip, &clip) &&
143.33929 +-	    sna_blt_fill_boxes(sna, GXcopy,
143.33930 +-			       __sna_pixmap_get_bo(sna->front),
143.33931 +-			       sna->front->drawable.bitsPerPixel,
143.33932 +-			       video->color_key,
143.33933 +-			       region_rects(&clip),
143.33934 +-			       region_num_rects(&clip)))
143.33935 +-		RegionCopy(&video->clip, &clip);
143.33936 ++	sna_video_fill_colorkey(video, &clip);
143.33937 + 	sna_window_set_port((WindowPtr)draw, port);
143.33938 + 
143.33939 + 	return Success;
143.33940 +@@ -606,25 +663,28 @@ static int sna_video_sprite_color_key(struct sna *sna)
143.33941 + 	return color_key & ((1 << scrn->depth) - 1);
143.33942 + }
143.33943 + 
143.33944 +-static bool sna_video_has_sprites(struct sna *sna)
143.33945 ++static int sna_video_has_sprites(struct sna *sna)
143.33946 + {
143.33947 + 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
143.33948 ++	unsigned min;
143.33949 + 	int i;
143.33950 + 
143.33951 + 	DBG(("%s: num_crtc=%d\n", __FUNCTION__, sna->mode.num_real_crtc));
143.33952 + 
143.33953 + 	if (sna->mode.num_real_crtc == 0)
143.33954 +-		return false;
143.33955 ++		return 0;
143.33956 + 
143.33957 ++	min = -1;
143.33958 + 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
143.33959 +-		if (!sna_crtc_to_sprite(config->crtc[i])) {
143.33960 +-			DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_to_pipe(config->crtc[i])));
143.33961 +-			return false;
143.33962 +-		}
143.33963 ++		unsigned count =  sna_crtc_count_sprites(config->crtc[i]);
143.33964 ++		DBG(("%s: %d sprites found on pipe %d\n", __FUNCTION__,
143.33965 ++		     count, sna_crtc_pipe(config->crtc[i])));
143.33966 ++		if (count < min)
143.33967 ++			min = count;
143.33968 + 	}
143.33969 + 
143.33970 +-	DBG(("%s: yes\n", __FUNCTION__));
143.33971 +-	return true;
143.33972 ++	DBG(("%s: min=%d\n", __FUNCTION__, min));
143.33973 ++	return min;
143.33974 + }
143.33975 + 
143.33976 + void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
143.33977 +@@ -632,16 +692,18 @@ void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
143.33978 + 	XvAdaptorPtr adaptor;
143.33979 + 	struct sna_video *video;
143.33980 + 	XvPortPtr port;
143.33981 ++	int count, i;
143.33982 + 
143.33983 +-	if (!sna_video_has_sprites(sna))
143.33984 ++	count = sna_video_has_sprites(sna);
143.33985 ++	if (!count)
143.33986 + 		return;
143.33987 + 
143.33988 + 	adaptor = sna_xv_adaptor_alloc(sna);
143.33989 + 	if (!adaptor)
143.33990 + 		return;
143.33991 + 
143.33992 +-	video = calloc(1, sizeof(*video));
143.33993 +-	port = calloc(1, sizeof(*port));
143.33994 ++	video = calloc(count, sizeof(*video));
143.33995 ++	port = calloc(count, sizeof(*port));
143.33996 + 	if (video == NULL || port == NULL) {
143.33997 + 		free(video);
143.33998 + 		free(port);
143.33999 +@@ -686,36 +748,43 @@ void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
143.34000 + 	adaptor->ddPutImage = sna_video_sprite_put_image;
143.34001 + 	adaptor->ddQueryImageAttributes = sna_video_sprite_query;
143.34002 + 
143.34003 +-	adaptor->nPorts = 1;
143.34004 ++	adaptor->nPorts = count;
143.34005 + 	adaptor->pPorts = port;
143.34006 + 
143.34007 +-	adaptor->base_id = port->id = FakeClientID(0);
143.34008 +-	AddResource(port->id, XvGetRTPort(), port);
143.34009 +-	port->pAdaptor = adaptor;
143.34010 +-	port->pNotify =  NULL;
143.34011 +-	port->pDraw =  NULL;
143.34012 +-	port->client =  NULL;
143.34013 +-	port->grab.client =  NULL;
143.34014 +-	port->time = currentTime;
143.34015 +-	port->devPriv.ptr = video;
143.34016 +-
143.34017 +-	video->sna = sna;
143.34018 +-	video->alignment = 64;
143.34019 +-	video->color_key = sna_video_sprite_color_key(sna);
143.34020 +-	video->color_key_changed = ~0;
143.34021 +-	video->has_color_key = true;
143.34022 +-	video->brightness = -19;	/* (255/219) * -16 */
143.34023 +-	video->contrast = 75;	/* 255/219 * 64 */
143.34024 +-	video->saturation = 146;	/* 128/112 * 128 */
143.34025 +-	video->desired_crtc = NULL;
143.34026 +-	video->gamma5 = 0xc0c0c0;
143.34027 +-	video->gamma4 = 0x808080;
143.34028 +-	video->gamma3 = 0x404040;
143.34029 +-	video->gamma2 = 0x202020;
143.34030 +-	video->gamma1 = 0x101010;
143.34031 +-	video->gamma0 = 0x080808;
143.34032 +-	RegionNull(&video->clip);
143.34033 +-	video->SyncToVblank = 1;
143.34034 ++	for (i = 0; i < count; i++) {
143.34035 ++		port->id = FakeClientID(0);
143.34036 ++		AddResource(port->id, XvGetRTPort(), port);
143.34037 ++		port->pAdaptor = adaptor;
143.34038 ++		port->pNotify =  NULL;
143.34039 ++		port->pDraw =  NULL;
143.34040 ++		port->client =  NULL;
143.34041 ++		port->grab.client =  NULL;
143.34042 ++		port->time = currentTime;
143.34043 ++		port->devPriv.ptr = video;
143.34044 ++
143.34045 ++		video->sna = sna;
143.34046 ++		video->idx = i;
143.34047 ++		video->alignment = 64;
143.34048 ++		video->color_key = sna_video_sprite_color_key(sna);
143.34049 ++		video->color_key_changed = ~0;
143.34050 ++		video->has_color_key = true;
143.34051 ++		video->brightness = -19;	/* (255/219) * -16 */
143.34052 ++		video->contrast = 75;	/* 255/219 * 64 */
143.34053 ++		video->saturation = 146;	/* 128/112 * 128 */
143.34054 ++		video->desired_crtc = NULL;
143.34055 ++		video->gamma5 = 0xc0c0c0;
143.34056 ++		video->gamma4 = 0x808080;
143.34057 ++		video->gamma3 = 0x404040;
143.34058 ++		video->gamma2 = 0x202020;
143.34059 ++		video->gamma1 = 0x101010;
143.34060 ++		video->gamma0 = 0x080808;
143.34061 ++		RegionNull(&video->clip);
143.34062 ++		video->SyncToVblank = 1;
143.34063 ++
143.34064 ++		port++;
143.34065 ++		video++;
143.34066 ++	}
143.34067 ++	adaptor->base_id = adaptor->pPorts[0].id;
143.34068 + 
143.34069 + 	xvColorKey = MAKE_ATOM("XV_COLORKEY");
143.34070 + 	xvAlwaysOnTop = MAKE_ATOM("XV_ALWAYS_ON_TOP");
143.34071 +diff --git a/src/sna/sna_video_textured.c b/src/sna/sna_video_textured.c
143.34072 +index 95011939..3cce5cf1 100644
143.34073 +--- a/src/sna/sna_video_textured.c
143.34074 ++++ b/src/sna/sna_video_textured.c
143.34075 +@@ -48,7 +48,12 @@ static const XvAttributeRec Attributes[] = {
143.34076 + 	//{XvSettable | XvGettable, 0, 255, (char *)"XV_CONTRAST"},
143.34077 + };
143.34078 + 
143.34079 +-static const XvImageRec Images[] = {
143.34080 ++static const XvImageRec gen2_Images[] = {
143.34081 ++	XVIMAGE_YUY2,
143.34082 ++	XVIMAGE_UYVY,
143.34083 ++};
143.34084 ++
143.34085 ++static const XvImageRec gen3_Images[] = {
143.34086 + 	XVIMAGE_YUY2,
143.34087 + 	XVIMAGE_YV12,
143.34088 + 	XVIMAGE_I420,
143.34089 +@@ -149,15 +154,16 @@ sna_video_textured_put_image(ddPutImage_ARGS)
143.34090 + 	BoxRec dstBox;
143.34091 + 	RegionRec clip;
143.34092 + 	xf86CrtcPtr crtc;
143.34093 ++	int16_t dx, dy;
143.34094 + 	bool flush = false;
143.34095 + 	bool ret;
143.34096 + 
143.34097 +-	clip.extents.x1 = draw->x + drw_x;
143.34098 +-	clip.extents.y1 = draw->y + drw_y;
143.34099 +-	clip.extents.x2 = clip.extents.x1 + drw_w;
143.34100 +-	clip.extents.y2 = clip.extents.y1 + drw_h;
143.34101 +-	clip.data = NULL;
143.34102 ++	if (wedged(sna))
143.34103 ++		return BadAlloc;
143.34104 + 
143.34105 ++	init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h);
143.34106 ++
143.34107 ++	ValidateGC(draw, gc);
143.34108 + 	RegionIntersect(&clip, &clip, gc->pCompositeClip);
143.34109 + 	if (!RegionNotEmpty(&clip))
143.34110 + 		return Success;
143.34111 +@@ -181,6 +187,9 @@ sna_video_textured_put_image(ddPutImage_ARGS)
143.34112 + 				   &clip))
143.34113 + 		return Success;
143.34114 + 
143.34115 ++	if (get_drawable_deltas(draw, pixmap, &dx, &dy))
143.34116 ++		RegionTranslate(&clip, dx, dy);
143.34117 ++
143.34118 + 	flags = MOVE_WRITE | __MOVE_FORCE;
143.34119 + 	if (clip.data)
143.34120 + 		flags |= MOVE_READ;
143.34121 +@@ -234,7 +243,7 @@ sna_video_textured_put_image(ddPutImage_ARGS)
143.34122 + 		DBG(("%s: failed to render video\n", __FUNCTION__));
143.34123 + 		ret = BadAlloc;
143.34124 + 	} else
143.34125 +-		DamageDamageRegion(draw, &clip);
143.34126 ++		DamageDamageRegion(&pixmap->drawable, &clip);
143.34127 + 
143.34128 + 	kgem_bo_destroy(&sna->kgem, frame.bo);
143.34129 + 
143.34130 +@@ -316,7 +325,7 @@ void sna_video_textured_setup(struct sna *sna, ScreenPtr screen)
143.34131 + 
143.34132 + 	if (!sna->render.video) {
143.34133 + 		xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
143.34134 +-			   "Textured video not supported on this hardware\n");
143.34135 ++			   "Textured video not supported on this hardware or backend\n");
143.34136 + 		return;
143.34137 + 	}
143.34138 + 
143.34139 +@@ -362,8 +371,13 @@ void sna_video_textured_setup(struct sna *sna, ScreenPtr screen)
143.34140 + 						 ARRAY_SIZE(Formats));
143.34141 + 	adaptor->nAttributes = ARRAY_SIZE(Attributes);
143.34142 + 	adaptor->pAttributes = (XvAttributeRec *)Attributes;
143.34143 +-	adaptor->nImages = ARRAY_SIZE(Images);
143.34144 +-	adaptor->pImages = (XvImageRec *)Images;
143.34145 ++	if (sna->kgem.gen < 030) {
143.34146 ++		adaptor->nImages = ARRAY_SIZE(gen2_Images);
143.34147 ++		adaptor->pImages = (XvImageRec *)gen2_Images;
143.34148 ++	} else {
143.34149 ++		adaptor->nImages = ARRAY_SIZE(gen3_Images);
143.34150 ++		adaptor->pImages = (XvImageRec *)gen3_Images;
143.34151 ++	}
143.34152 + #if XORG_XV_VERSION < 2
143.34153 + 	adaptor->ddAllocatePort = sna_xv_alloc_port;
143.34154 + 	adaptor->ddFreePort = sna_xv_free_port;
143.34155 +diff --git a/src/sna/xassert.h b/src/sna/xassert.h
143.34156 +index 1bcfd080..e648e4bc 100644
143.34157 +--- a/src/sna/xassert.h
143.34158 ++++ b/src/sna/xassert.h
143.34159 +@@ -43,6 +43,28 @@
143.34160 + 	xorg_backtrace(); \
143.34161 + 	FatalError("%s:%d assertion '%s' failed\n", __func__, __LINE__, #E); \
143.34162 + } while (0)
143.34163 ++
143.34164 ++#define warn_unless(E) \
143.34165 ++({ \
143.34166 ++	bool fail = !(E); \
143.34167 ++	if (unlikely(fail)) { \
143.34168 ++		static int __warn_once__; \
143.34169 ++		if (!__warn_once__) { \
143.34170 ++			xorg_backtrace(); \
143.34171 ++			ErrorF("%s:%d assertion '%s' failed\n", __func__, __LINE__, #E); \
143.34172 ++			__warn_once__ = 1; \
143.34173 ++		} \
143.34174 ++	} \
143.34175 ++	unlikely(fail); \
143.34176 ++})
143.34177 ++
143.34178 ++#define dbg(EXPR) EXPR
143.34179 ++
143.34180 ++#else
143.34181 ++
143.34182 ++#define warn_unless(E) ({ bool fail = !(E); unlikely(fail); })
143.34183 ++#define dbg(EXPR)
143.34184 ++
143.34185 + #endif
143.34186 + 
143.34187 + #endif /* __XASSERT_H__ */
143.34188 +diff --git a/src/uxa/i830_reg.h b/src/uxa/i830_reg.h
143.34189 +index d8306bcd..ba39d82c 100644
143.34190 +--- a/src/uxa/i830_reg.h
143.34191 ++++ b/src/uxa/i830_reg.h
143.34192 +@@ -65,6 +65,12 @@
143.34193 + #define MI_LOAD_SCAN_LINES_DISPLAY_PIPEA	(0)
143.34194 + #define MI_LOAD_SCAN_LINES_DISPLAY_PIPEB	(0x1<<20)
143.34195 + 
143.34196 ++#define MI_LOAD_REGISTER_IMM		(0x22<<23 | (3-2))
143.34197 ++
143.34198 ++#define BCS_SWCTRL                      0x22200
143.34199 ++# define BCS_SWCTRL_SRC_Y               (1 << 0)
143.34200 ++# define BCS_SWCTRL_DST_Y               (1 << 1)
143.34201 ++
143.34202 + /* BLT commands */
143.34203 + #define COLOR_BLT_CMD		((2<<29)|(0x40<<22)|(0x3))
143.34204 + #define COLOR_BLT_WRITE_ALPHA	(1<<21)
143.34205 +diff --git a/src/uxa/i965_video.c b/src/uxa/i965_video.c
143.34206 +index 68e6fd38..438ab909 100644
143.34207 +--- a/src/uxa/i965_video.c
143.34208 ++++ b/src/uxa/i965_video.c
143.34209 +@@ -37,7 +37,6 @@
143.34210 + #include "fourcc.h"
143.34211 + 
143.34212 + #include "intel.h"
143.34213 +-#include "intel_xvmc.h"
143.34214 + #include "intel_uxa.h"
143.34215 + #include "i830_reg.h"
143.34216 + #include "i965_reg.h"
143.34217 +diff --git a/src/uxa/intel.h b/src/uxa/intel.h
143.34218 +index 1b7e5339..a5e77af4 100644
143.34219 +--- a/src/uxa/intel.h
143.34220 ++++ b/src/uxa/intel.h
143.34221 +@@ -121,7 +121,6 @@ typedef struct intel_screen_private {
143.34222 + 
143.34223 + 	void *modes;
143.34224 + 	drm_intel_bo *front_buffer, *back_buffer;
143.34225 +-	unsigned int back_name;
143.34226 + 	long front_pitch, front_tiling;
143.34227 + 
143.34228 + 	dri_bufmgr *bufmgr;
143.34229 +@@ -169,6 +168,7 @@ typedef struct intel_screen_private {
143.34230 + 	const struct intel_device_info *info;
143.34231 + 
143.34232 + 	unsigned int BR[20];
143.34233 ++	unsigned int BR_tiling[2];
143.34234 + 
143.34235 + 	CloseScreenProcPtr CloseScreen;
143.34236 + 
143.34237 +@@ -196,7 +196,9 @@ typedef struct intel_screen_private {
143.34238 + 
143.34239 + 	int colorKey;
143.34240 + 	XF86VideoAdaptorPtr adaptor;
143.34241 ++#if !HAVE_NOTIFY_FD
143.34242 + 	ScreenBlockHandlerProcPtr BlockHandler;
143.34243 ++#endif
143.34244 + 	Bool overlayOn;
143.34245 + 
143.34246 + 	struct {
143.34247 +@@ -285,8 +287,6 @@ typedef struct intel_screen_private {
143.34248 + 	Bool has_kernel_flush;
143.34249 + 	Bool needs_flush;
143.34250 + 
143.34251 +-	struct _DRI2FrameEvent *pending_flip[MAX_PIPES];
143.34252 +-
143.34253 + 	/* Broken-out options. */
143.34254 + 	OptionInfoPtr Options;
143.34255 + 
143.34256 +@@ -368,6 +368,7 @@ typedef void (*intel_drm_abort_proc)(ScrnInfoPtr scrn,
143.34257 + 
143.34258 + extern uint32_t intel_drm_queue_alloc(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data, intel_drm_handler_proc handler, intel_drm_abort_proc abort);
143.34259 + extern void intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data);
143.34260 ++extern void intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq);
143.34261 + 
143.34262 + extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
143.34263 + extern int intel_crtc_id(xf86CrtcPtr crtc);
143.34264 +@@ -408,7 +409,6 @@ typedef struct _DRI2FrameEvent {
143.34265 + 	ClientPtr client;
143.34266 + 	enum DRI2FrameEventType type;
143.34267 + 	int frame;
143.34268 +-	int pipe;
143.34269 + 
143.34270 + 	struct list drawable_resource, client_resource;
143.34271 + 
143.34272 +@@ -418,7 +418,12 @@ typedef struct _DRI2FrameEvent {
143.34273 + 	DRI2BufferPtr front;
143.34274 + 	DRI2BufferPtr back;
143.34275 + 
143.34276 +-	struct _DRI2FrameEvent *chain;
143.34277 ++	/* current scanout for triple buffer */
143.34278 ++	int old_width;
143.34279 ++	int old_height;
143.34280 ++	int old_pitch;
143.34281 ++	int old_tiling;
143.34282 ++	dri_bo *old_buffer;
143.34283 + } DRI2FrameEventRec, *DRI2FrameEventPtr;
143.34284 + 
143.34285 + extern Bool intel_do_pageflip(intel_screen_private *intel,
143.34286 +@@ -456,10 +461,6 @@ extern xf86CrtcPtr intel_covering_crtc(ScrnInfoPtr scrn, BoxPtr box,
143.34287 + 
143.34288 + Bool I830DRI2ScreenInit(ScreenPtr pScreen);
143.34289 + void I830DRI2CloseScreen(ScreenPtr pScreen);
143.34290 +-void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
143.34291 +-			       unsigned int tv_usec, DRI2FrameEventPtr flip_info);
143.34292 +-void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
143.34293 +-			      unsigned int tv_usec, DRI2FrameEventPtr flip_info);
143.34294 + 
143.34295 + /* intel_dri3.c */
143.34296 + Bool intel_dri3_screen_init(ScreenPtr screen);
143.34297 +diff --git a/src/uxa/intel_batchbuffer.c b/src/uxa/intel_batchbuffer.c
143.34298 +index a29e4434..114c6026 100644
143.34299 +--- a/src/uxa/intel_batchbuffer.c
143.34300 ++++ b/src/uxa/intel_batchbuffer.c
143.34301 +@@ -245,6 +245,17 @@ void intel_batch_submit(ScrnInfoPtr scrn)
143.34302 + 	if (intel->batch_used == 0)
143.34303 + 		return;
143.34304 + 
143.34305 ++	if (intel->current_batch == I915_EXEC_BLT &&
143.34306 ++	    INTEL_INFO(intel)->gen >= 060) {
143.34307 ++		OUT_BATCH(MI_FLUSH_DW);
143.34308 ++		OUT_BATCH(0);
143.34309 ++		OUT_BATCH(0);
143.34310 ++		OUT_BATCH(0);
143.34311 ++		OUT_BATCH(MI_LOAD_REGISTER_IMM);
143.34312 ++		OUT_BATCH(BCS_SWCTRL);
143.34313 ++		OUT_BATCH((BCS_SWCTRL_DST_Y | BCS_SWCTRL_SRC_Y) << 16);
143.34314 ++	}
143.34315 ++
143.34316 + 	/* Mark the end of the batchbuffer. */
143.34317 + 	OUT_BATCH(MI_BATCH_BUFFER_END);
143.34318 + 	/* Emit a padding dword if we aren't going to be quad-word aligned. */
143.34319 +diff --git a/src/uxa/intel_batchbuffer.h b/src/uxa/intel_batchbuffer.h
143.34320 +index e5fb8d08..e71ffd19 100644
143.34321 +--- a/src/uxa/intel_batchbuffer.h
143.34322 ++++ b/src/uxa/intel_batchbuffer.h
143.34323 +@@ -30,7 +30,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
143.34324 + #ifndef _INTEL_BATCHBUFFER_H
143.34325 + #define _INTEL_BATCHBUFFER_H
143.34326 + 
143.34327 +-#define BATCH_RESERVED		16
143.34328 ++#define BATCH_RESERVED		64
143.34329 + 
143.34330 + 
143.34331 + void intel_batch_init(ScrnInfoPtr scrn);
143.34332 +@@ -202,6 +202,23 @@ do {									\
143.34333 + 
143.34334 + #define BEGIN_BATCH(n)	__BEGIN_BATCH(n,RENDER_BATCH)
143.34335 + #define BEGIN_BATCH_BLT(n)	__BEGIN_BATCH(n,BLT_BATCH)
143.34336 ++#define BEGIN_BATCH_BLT_TILED(n) \
143.34337 ++do { \
143.34338 ++	if (INTEL_INFO(intel)->gen < 060) { \
143.34339 ++		__BEGIN_BATCH(n, BLT_BATCH); \
143.34340 ++	} else { \
143.34341 ++		__BEGIN_BATCH(n+7, BLT_BATCH); \
143.34342 ++		OUT_BATCH(MI_FLUSH_DW); \
143.34343 ++		OUT_BATCH(0); \
143.34344 ++		OUT_BATCH(0); \
143.34345 ++		OUT_BATCH(0); \
143.34346 ++		OUT_BATCH(MI_LOAD_REGISTER_IMM); \
143.34347 ++		OUT_BATCH(BCS_SWCTRL); \
143.34348 ++		OUT_BATCH((BCS_SWCTRL_DST_Y | BCS_SWCTRL_SRC_Y) << 16 | \
143.34349 ++			  ((intel->BR_tiling[0] == I915_TILING_Y) ? BCS_SWCTRL_DST_Y : 0) | \
143.34350 ++			  ((intel->BR_tiling[1] == I915_TILING_Y) ? BCS_SWCTRL_SRC_Y : 0)); \
143.34351 ++	} \
143.34352 ++} while (0)
143.34353 + 
143.34354 + #define ADVANCE_BATCH() do {						\
143.34355 + 	if (intel->batch_emitting == 0)					\
143.34356 +diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c
143.34357 +index 7b4d4e0c..809cda1d 100644
143.34358 +--- a/src/uxa/intel_display.c
143.34359 ++++ b/src/uxa/intel_display.c
143.34360 +@@ -89,11 +89,11 @@ struct intel_mode {
143.34361 + 	struct list outputs;
143.34362 + 	struct list crtcs;
143.34363 + 
143.34364 +-	void *pageflip_data;
143.34365 +-	intel_pageflip_handler_proc pageflip_handler;
143.34366 +-	intel_pageflip_abort_proc pageflip_abort;
143.34367 +-
143.34368 +-	Bool delete_dp_12_displays;
143.34369 ++	struct {
143.34370 ++		intel_pageflip_handler_proc handler;
143.34371 ++		intel_pageflip_abort_proc abort;
143.34372 ++		void *data;
143.34373 ++	} pageflip;
143.34374 + };
143.34375 + 
143.34376 + struct intel_pageflip {
143.34377 +@@ -114,7 +114,6 @@ struct intel_crtc {
143.34378 + 	struct list link;
143.34379 + 	PixmapPtr scanout_pixmap;
143.34380 + 	uint32_t scanout_fb_id;
143.34381 +-	int32_t vblank_offset;
143.34382 + 	uint32_t msc_prev;
143.34383 + 	uint64_t msc_high;
143.34384 + };
143.34385 +@@ -193,7 +192,7 @@ intel_output_backlight_init(xf86OutputPtr output)
143.34386 + 
143.34387 + 	str = xf86GetOptValString(intel->Options, OPTION_BACKLIGHT);
143.34388 + 	if (str != NULL) {
143.34389 +-		if (backlight_exists(str) != BL_NONE) {
143.34390 ++		if (backlight_exists(str)) {
143.34391 + 			intel_output->backlight_active_level =
143.34392 + 				backlight_open(&intel_output->backlight,
143.34393 + 					       strdup(str));
143.34394 +@@ -689,9 +688,11 @@ intel_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
143.34395 + 	}
143.34396 + 
143.34397 + 	bo = intel_get_pixmap_bo(ppix);
143.34398 +-	if (intel->front_buffer) {
143.34399 +-		ErrorF("have front buffer\n");
143.34400 +-	}
143.34401 ++	if (!bo)
143.34402 ++		return FALSE;
143.34403 ++
143.34404 ++	if (intel->front_buffer)
143.34405 ++		return FALSE;
143.34406 + 
143.34407 + 	drm_intel_bo_disable_reuse(bo);
143.34408 + 
143.34409 +@@ -867,6 +868,48 @@ intel_output_attach_edid(xf86OutputPtr output)
143.34410 + 	xf86OutputSetEDID(output, mon);
143.34411 + }
143.34412 + 
143.34413 ++static void
143.34414 ++intel_output_attach_tile(xf86OutputPtr output)
143.34415 ++{
143.34416 ++#if XF86_OUTPUT_VERSION >= 3
143.34417 ++	struct intel_output *intel_output = output->driver_private;
143.34418 ++	drmModeConnectorPtr koutput = intel_output->mode_output;
143.34419 ++	struct intel_mode *mode = intel_output->mode;
143.34420 ++	drmModePropertyBlobPtr blob = NULL;
143.34421 ++	struct xf86CrtcTileInfo tile_info, *set = NULL;
143.34422 ++	int i;
143.34423 ++
143.34424 ++	for (i = 0; koutput && i < koutput->count_props; i++) {
143.34425 ++		drmModePropertyPtr props;
143.34426 ++
143.34427 ++		props = drmModeGetProperty(mode->fd, koutput->props[i]);
143.34428 ++		if (!props)
143.34429 ++			continue;
143.34430 ++
143.34431 ++		if (!(props->flags & DRM_MODE_PROP_BLOB)) {
143.34432 ++			drmModeFreeProperty(props);
143.34433 ++			continue;
143.34434 ++		}
143.34435 ++
143.34436 ++		if (!strcmp(props->name, "TILE")) {
143.34437 ++			blob = drmModeGetPropertyBlob(mode->fd,
143.34438 ++						      koutput->prop_values[i]);
143.34439 ++		}
143.34440 ++		drmModeFreeProperty(props);
143.34441 ++	}
143.34442 ++
143.34443 ++	if (blob) {
143.34444 ++		if (xf86OutputParseKMSTile(blob->data,
143.34445 ++					   blob->length,
143.34446 ++					   &tile_info))
143.34447 ++			set = &tile_info;
143.34448 ++		drmModeFreePropertyBlob(blob);
143.34449 ++	}
143.34450 ++
143.34451 ++	xf86OutputSetTile(output, set);
143.34452 ++#endif
143.34453 ++}
143.34454 ++
143.34455 + static DisplayModePtr
143.34456 + intel_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
143.34457 + {
143.34458 +@@ -922,6 +965,7 @@ intel_output_get_modes(xf86OutputPtr output)
143.34459 + 	int i;
143.34460 + 
143.34461 + 	intel_output_attach_edid(output);
143.34462 ++	intel_output_attach_tile(output);
143.34463 + 
143.34464 + 	if (!koutput)
143.34465 + 		return Modes;
143.34466 +@@ -1492,6 +1536,7 @@ intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_
143.34467 + 			intel_output = output->driver_private;
143.34468 + 			intel_output->output_id = mode_res->connectors[num];
143.34469 + 			intel_output->mode_output = koutput;
143.34470 ++			RROutputChanged(output->randr_output, TRUE);
143.34471 + 			return;
143.34472 + 		}
143.34473 + 	}
143.34474 +@@ -1650,9 +1695,6 @@ intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data);
143.34475 + static void
143.34476 + intel_pageflip_complete(struct intel_mode *mode);
143.34477 + 
143.34478 +-static void
143.34479 +-intel_drm_abort_seq (ScrnInfoPtr scrn, uint32_t seq);
143.34480 +-
143.34481 + Bool
143.34482 + intel_do_pageflip(intel_screen_private *intel,
143.34483 + 		  dri_bo *new_front,
143.34484 +@@ -1671,23 +1713,30 @@ intel_do_pageflip(intel_screen_private *intel,
143.34485 + 	uint32_t new_fb_id;
143.34486 + 	uint32_t flags;
143.34487 + 	uint32_t seq;
143.34488 ++	int err = 0;
143.34489 + 	int i;
143.34490 + 
143.34491 + 	/*
143.34492 ++	 * We only have a single length queue in the kernel, so any
143.34493 ++	 * attempts to schedule a second flip before processing the first
143.34494 ++	 * is a bug. Punt it back to the caller.
143.34495 ++	 */
143.34496 ++	if (mode->flip_count)
143.34497 ++		return FALSE;
143.34498 ++
143.34499 ++	/*
143.34500 + 	 * Create a new handle for the back buffer
143.34501 + 	 */
143.34502 + 	if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
143.34503 + 			 scrn->depth, scrn->bitsPerPixel, pitch,
143.34504 +-			 new_front->handle, &new_fb_id))
143.34505 ++			 new_front->handle, &new_fb_id)) {
143.34506 ++		err = errno;
143.34507 + 		goto error_out;
143.34508 ++	}
143.34509 + 
143.34510 + 	drm_intel_bo_disable_reuse(new_front);
143.34511 +         intel_flush(intel);
143.34512 + 
143.34513 +-	mode->pageflip_data = pageflip_data;
143.34514 +-	mode->pageflip_handler = pageflip_handler;
143.34515 +-	mode->pageflip_abort = pageflip_abort;
143.34516 +-
143.34517 + 	/*
143.34518 + 	 * Queue flips on all enabled CRTCs
143.34519 + 	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
143.34520 +@@ -1699,6 +1748,7 @@ intel_do_pageflip(intel_screen_private *intel,
143.34521 + 	 */
143.34522 + 	mode->fe_msc = 0;
143.34523 + 	mode->fe_usec = 0;
143.34524 ++	memset(&mode->pageflip, 0, sizeof(mode->pageflip));
143.34525 + 
143.34526 + 	flags = DRM_MODE_PAGE_FLIP_EVENT;
143.34527 + 	if (async)
143.34528 +@@ -1711,8 +1761,7 @@ intel_do_pageflip(intel_screen_private *intel,
143.34529 + 
143.34530 + 		flip = calloc(1, sizeof(struct intel_pageflip));
143.34531 + 		if (flip == NULL) {
143.34532 +-			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
143.34533 +-				   "flip queue: carrier alloc failed.\n");
143.34534 ++			err = errno;
143.34535 + 			goto error_undo;
143.34536 + 		}
143.34537 + 
143.34538 +@@ -1724,33 +1773,30 @@ intel_do_pageflip(intel_screen_private *intel,
143.34539 + 
143.34540 + 		seq = intel_drm_queue_alloc(scrn, config->crtc[i], flip, intel_pageflip_handler, intel_pageflip_abort);
143.34541 + 		if (!seq) {
143.34542 ++			err = errno;
143.34543 + 			free(flip);
143.34544 + 			goto error_undo;
143.34545 + 		}
143.34546 + 
143.34547 +-again:
143.34548 ++		mode->flip_count++;
143.34549 ++
143.34550 + 		if (drmModePageFlip(mode->fd,
143.34551 + 				    crtc_id(crtc),
143.34552 + 				    new_fb_id,
143.34553 + 				    flags, (void *)(uintptr_t)seq)) {
143.34554 +-			if (intel_mode_read_drm_events(intel)) {
143.34555 +-				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
143.34556 +-					   "flip queue retry\n");
143.34557 +-				goto again;
143.34558 +-			}
143.34559 +-			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
143.34560 +-				   "flip queue failed: %s\n", strerror(errno));
143.34561 +-			if (seq)
143.34562 +-				intel_drm_abort_seq(scrn, seq);
143.34563 +-			free(flip);
143.34564 ++			err = errno;
143.34565 ++			intel_drm_abort_seq(scrn, seq);
143.34566 + 			goto error_undo;
143.34567 + 		}
143.34568 +-		mode->flip_count++;
143.34569 + 	}
143.34570 + 
143.34571 + 	mode->old_fb_id = mode->fb_id;
143.34572 + 	mode->fb_id = new_fb_id;
143.34573 + 
143.34574 ++	mode->pageflip.data = pageflip_data;
143.34575 ++	mode->pageflip.handler = pageflip_handler;
143.34576 ++	mode->pageflip.abort = pageflip_abort;
143.34577 ++
143.34578 + 	if (!mode->flip_count)
143.34579 + 		intel_pageflip_complete(mode);
143.34580 + 
143.34581 +@@ -1765,7 +1811,7 @@ error_undo:
143.34582 + 
143.34583 + error_out:
143.34584 + 	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
143.34585 +-		   strerror(errno));
143.34586 ++		   strerror(err));
143.34587 + 
143.34588 + 	mode->flip_count = 0;
143.34589 + 	return FALSE;
143.34590 +@@ -1839,7 +1885,7 @@ intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), v
143.34591 + /*
143.34592 +  * Abort by drm queue sequence number
143.34593 +  */
143.34594 +-static void
143.34595 ++void
143.34596 + intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq)
143.34597 + {
143.34598 + 	struct intel_drm_queue *q;
143.34599 +@@ -1911,7 +1957,6 @@ intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence)
143.34600 + {
143.34601 + 	struct intel_crtc *intel_crtc = crtc->driver_private;
143.34602 + 
143.34603 +-        sequence += intel_crtc->vblank_offset;
143.34604 +         if ((int32_t) (sequence - intel_crtc->msc_prev) < -0x40000000)
143.34605 +                 intel_crtc->msc_high += 0x100000000L;
143.34606 +         intel_crtc->msc_prev = sequence;
143.34607 +@@ -1935,37 +1980,10 @@ intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64
143.34608 +         return 0;
143.34609 + }
143.34610 + 
143.34611 +-/*
143.34612 +- * Convert a 64-bit adjusted MSC value into a 32-bit kernel sequence number,
143.34613 +- * removing the high 32 bits and subtracting out the vblank_offset term.
143.34614 +- *
143.34615 +- * This also updates the vblank_offset when it notices that the value should
143.34616 +- * change.
143.34617 +- */
143.34618 +-
143.34619 +-#define MAX_VBLANK_OFFSET       1000
143.34620 +-
143.34621 + uint32_t
143.34622 + intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect)
143.34623 + {
143.34624 +-	struct intel_crtc *intel_crtc = crtc->driver_private;
143.34625 +-        uint64_t msc, ust;
143.34626 +-
143.34627 +-	if (intel_get_crtc_msc_ust(scrn, crtc, &msc, &ust) == 0) {
143.34628 +-		int64_t diff = expect - msc;
143.34629 +-
143.34630 +-		/* We're way off here, assume that the kernel has lost its mind
143.34631 +-		 * and smack the vblank back to something sensible
143.34632 +-		 */
143.34633 +-		if (diff < -MAX_VBLANK_OFFSET || diff > MAX_VBLANK_OFFSET) {
143.34634 +-			intel_crtc->vblank_offset += (int32_t) diff;
143.34635 +-			if (intel_crtc->vblank_offset > -MAX_VBLANK_OFFSET &&
143.34636 +-			    intel_crtc->vblank_offset < MAX_VBLANK_OFFSET)
143.34637 +-				intel_crtc->vblank_offset = 0;
143.34638 +-		}
143.34639 +-	}
143.34640 +-
143.34641 +-        return (uint32_t) (expect - intel_crtc->vblank_offset);
143.34642 ++        return (uint32_t)expect;
143.34643 + }
143.34644 + 
143.34645 + /*
143.34646 +@@ -1998,14 +2016,13 @@ intel_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, void *use
143.34647 + static void
143.34648 + intel_pageflip_complete(struct intel_mode *mode)
143.34649 + {
143.34650 +-	/* Release framebuffer */
143.34651 +-	drmModeRmFB(mode->fd, mode->old_fb_id);
143.34652 +-
143.34653 +-	if (!mode->pageflip_handler)
143.34654 ++	if (!mode->pageflip.handler)
143.34655 + 		return;
143.34656 + 
143.34657 +-	mode->pageflip_handler(mode->fe_msc, mode->fe_usec,
143.34658 +-			       mode->pageflip_data);
143.34659 ++	/* Release framebuffer */
143.34660 ++	drmModeRmFB(mode->fd, mode->old_fb_id);
143.34661 ++	mode->pageflip.handler(mode->fe_msc, mode->fe_usec,
143.34662 ++			       mode->pageflip.data);
143.34663 + }
143.34664 + 
143.34665 + /*
143.34666 +@@ -2045,6 +2062,7 @@ intel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
143.34667 + 
143.34668 + 	if (!mode)
143.34669 + 		return;
143.34670 ++
143.34671 + 	intel_pageflip_complete(mode);
143.34672 + }
143.34673 + 
143.34674 +@@ -2060,18 +2078,18 @@ intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data)
143.34675 + 	if (!mode)
143.34676 + 		return;
143.34677 + 
143.34678 +-	/* Release framebuffer */
143.34679 +-	drmModeRmFB(mode->fd, mode->old_fb_id);
143.34680 +-
143.34681 +-	if (!mode->pageflip_abort)
143.34682 ++	if (!mode->pageflip.abort)
143.34683 + 		return;
143.34684 + 
143.34685 +-	mode->pageflip_abort(mode->pageflip_data);
143.34686 ++	/* Release framebuffer */
143.34687 ++	drmModeRmFB(mode->fd, mode->old_fb_id);
143.34688 ++	mode->pageflip.abort(mode->pageflip.data);
143.34689 + }
143.34690 + 
143.34691 + /*
143.34692 +  * Check for pending DRM events and process them.
143.34693 +  */
143.34694 ++#if !HAVE_NOTIFY_FD
143.34695 + static void
143.34696 + drm_wakeup_handler(pointer data, int err, pointer p)
143.34697 + {
143.34698 +@@ -2086,6 +2104,14 @@ drm_wakeup_handler(pointer data, int err, pointer p)
143.34699 + 	if (FD_ISSET(mode->fd, read_mask))
143.34700 + 		drmHandleEvent(mode->fd, &mode->event_context);
143.34701 + }
143.34702 ++#else
143.34703 ++static void
143.34704 ++drm_notify_fd(int fd, int ready, void *data)
143.34705 ++{
143.34706 ++	struct intel_mode *mode = data;
143.34707 ++	drmHandleEvent(mode->fd, &mode->event_context);
143.34708 ++}
143.34709 ++#endif
143.34710 + 
143.34711 + /*
143.34712 +  * If there are any available, read drm_events
143.34713 +@@ -2231,10 +2257,6 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
143.34714 + 		intel->use_pageflipping = TRUE;
143.34715 + 	}
143.34716 + 
143.34717 +-	if (xf86ReturnOptValBool(intel->Options, OPTION_DELETE_DP12, FALSE)) {
143.34718 +-		mode->delete_dp_12_displays = TRUE;
143.34719 +-	}
143.34720 +-
143.34721 + 	intel->modes = mode;
143.34722 + 	drmModeFreeResources(mode_res);
143.34723 + 	return TRUE;
143.34724 +@@ -2250,9 +2272,11 @@ intel_mode_init(struct intel_screen_private *intel)
143.34725 + 	 * registration within ScreenInit and not PreInit.
143.34726 + 	 */
143.34727 + 	mode->flip_count = 0;
143.34728 +-	AddGeneralSocket(mode->fd);
143.34729 ++	SetNotifyFd(mode->fd, drm_notify_fd, X_NOTIFY_READ, mode);
143.34730 ++#if !HAVE_NOTIFY_FD
143.34731 + 	RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
143.34732 + 				       drm_wakeup_handler, mode);
143.34733 ++#endif
143.34734 + }
143.34735 + 
143.34736 + void
143.34737 +@@ -2276,9 +2300,11 @@ intel_mode_close(intel_screen_private *intel)
143.34738 + 
143.34739 +         intel_drm_abort_scrn(intel->scrn);
143.34740 + 
143.34741 ++#if !HAVE_NOTIFY_FD
143.34742 + 	RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
143.34743 + 				     drm_wakeup_handler, mode);
143.34744 +-	RemoveGeneralSocket(mode->fd);
143.34745 ++#endif
143.34746 ++	RemoveNotifyFd(mode->fd);
143.34747 + }
143.34748 + 
143.34749 + void
143.34750 +@@ -2498,12 +2524,11 @@ intel_mode_hotplug(struct intel_screen_private *intel)
143.34751 + 	int i, j;
143.34752 + 	Bool found;
143.34753 + 	Bool changed = FALSE;
143.34754 +-	struct intel_mode *mode = intel->modes;
143.34755 ++
143.34756 + 	mode_res = drmModeGetResources(intel->drmSubFD);
143.34757 + 	if (!mode_res)
143.34758 + 		goto out;
143.34759 + 
143.34760 +-restart_destroy:
143.34761 + 	for (i = 0; i < config->num_output; i++) {
143.34762 + 		xf86OutputPtr output = config->output[i];
143.34763 + 		struct intel_output *intel_output;
143.34764 +@@ -2522,13 +2547,9 @@ restart_destroy:
143.34765 + 		drmModeFreeConnector(intel_output->mode_output);
143.34766 + 		intel_output->mode_output = NULL;
143.34767 + 		intel_output->output_id = -1;
143.34768 ++		RROutputChanged(output->randr_output, TRUE);
143.34769 + 
143.34770 + 		changed = TRUE;
143.34771 +-		if (mode->delete_dp_12_displays) {
143.34772 +-			RROutputDestroy(output->randr_output);
143.34773 +-			xf86OutputDestroy(output);
143.34774 +-			goto restart_destroy;
143.34775 +-		}
143.34776 + 	}
143.34777 + 
143.34778 + 	/* find new output ids we don't have outputs for */
143.34779 +@@ -2552,10 +2573,8 @@ restart_destroy:
143.34780 + 		intel_output_init(scrn, intel->modes, mode_res, i, 1);
143.34781 + 	}
143.34782 + 
143.34783 +-	if (changed) {
143.34784 +-		RRSetChanged(xf86ScrnToScreen(scrn));
143.34785 ++	if (changed)
143.34786 + 		RRTellChanged(xf86ScrnToScreen(scrn));
143.34787 +-	}
143.34788 + 
143.34789 + 	drmModeFreeResources(mode_res);
143.34790 + out:
143.34791 +diff --git a/src/uxa/intel_dri.c b/src/uxa/intel_dri.c
143.34792 +index f61c6210..524826d2 100644
143.34793 +--- a/src/uxa/intel_dri.c
143.34794 ++++ b/src/uxa/intel_dri.c
143.34795 +@@ -81,6 +81,47 @@ static DevPrivateKeyRec i830_client_key;
143.34796 + static int i830_client_key;
143.34797 + #endif
143.34798 + 
143.34799 ++static void I830DRI2FlipEventHandler(unsigned int frame,
143.34800 ++				     unsigned int tv_sec,
143.34801 ++				     unsigned int tv_usec,
143.34802 ++				     DRI2FrameEventPtr flip_info);
143.34803 ++
143.34804 ++static void I830DRI2FrameEventHandler(unsigned int frame,
143.34805 ++				      unsigned int tv_sec,
143.34806 ++				      unsigned int tv_usec,
143.34807 ++				      DRI2FrameEventPtr swap_info);
143.34808 ++
143.34809 ++static void
143.34810 ++i830_dri2_del_frame_event(DRI2FrameEventPtr info);
143.34811 ++
143.34812 ++static uint32_t pipe_select(int pipe)
143.34813 ++{
143.34814 ++	if (pipe > 1)
143.34815 ++		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
143.34816 ++	else if (pipe > 0)
143.34817 ++		return DRM_VBLANK_SECONDARY;
143.34818 ++	else
143.34819 ++		return 0;
143.34820 ++}
143.34821 ++
143.34822 ++static void
143.34823 ++intel_dri2_vblank_handler(ScrnInfoPtr scrn,
143.34824 ++                          xf86CrtcPtr crtc,
143.34825 ++                          uint64_t msc,
143.34826 ++                          uint64_t usec,
143.34827 ++                          void *data)
143.34828 ++{
143.34829 ++        I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, data);
143.34830 ++}
143.34831 ++
143.34832 ++static void
143.34833 ++intel_dri2_vblank_abort(ScrnInfoPtr scrn,
143.34834 ++                        xf86CrtcPtr crtc,
143.34835 ++                        void *data)
143.34836 ++{
143.34837 ++        i830_dri2_del_frame_event(data);
143.34838 ++}
143.34839 ++
143.34840 + static uint32_t pixmap_flink(PixmapPtr pixmap)
143.34841 + {
143.34842 + 	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
143.34843 +@@ -135,9 +176,6 @@ I830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
143.34844 + 		pixmap = NULL;
143.34845 + 		if (attachments[i] == DRI2BufferFrontLeft) {
143.34846 + 			pixmap = get_front_buffer(drawable);
143.34847 +-
143.34848 +-			if (pixmap == NULL)
143.34849 +-				drawable = &(get_drawable_pixmap(drawable)->drawable);
143.34850 + 		} else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
143.34851 + 			pixmap = pDepthPixmap;
143.34852 + 			pixmap->refcnt++;
143.34853 +@@ -246,11 +284,8 @@ I830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
143.34854 + 	}
143.34855 + 
143.34856 + 	pixmap = NULL;
143.34857 +-	if (attachment == DRI2BufferFrontLeft) {
143.34858 ++	if (attachment == DRI2BufferFrontLeft)
143.34859 + 		pixmap = get_front_buffer(drawable);
143.34860 +-		if (pixmap == NULL)
143.34861 +-			drawable = &(get_drawable_pixmap(drawable)->drawable);
143.34862 +-	}
143.34863 + 
143.34864 + 	if (pixmap == NULL) {
143.34865 + 		unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
143.34866 +@@ -673,6 +708,20 @@ i830_dri2_del_frame_event(DRI2FrameEventPtr info)
143.34867 + 	if (info->back)
143.34868 + 		I830DRI2DestroyBuffer(NULL, info->back);
143.34869 + 
143.34870 ++	if (info->old_buffer) {
143.34871 ++		/* Check that the old buffer still matches the front buffer
143.34872 ++		 * in case a mode change occurred before we woke up.
143.34873 ++		 */
143.34874 ++		if (info->intel->back_buffer == NULL &&
143.34875 ++		    info->old_width  == info->intel->scrn->virtualX &&
143.34876 ++		    info->old_height == info->intel->scrn->virtualY &&
143.34877 ++		    info->old_pitch  == info->intel->front_pitch &&
143.34878 ++		    info->old_tiling == info->intel->front_tiling)
143.34879 ++			info->intel->back_buffer = info->old_buffer;
143.34880 ++		else
143.34881 ++			dri_bo_unreference(info->old_buffer);
143.34882 ++	}
143.34883 ++
143.34884 + 	free(info);
143.34885 + }
143.34886 + 
143.34887 +@@ -708,16 +757,14 @@ static void
143.34888 + I830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
143.34889 + {
143.34890 + 	I830DRI2BufferPrivatePtr front_priv, back_priv;
143.34891 +-	int tmp;
143.34892 + 	struct intel_uxa_pixmap *new_front;
143.34893 + 
143.34894 + 	front_priv = front->driverPrivate;
143.34895 + 	back_priv = back->driverPrivate;
143.34896 + 
143.34897 + 	/* Swap BO names so DRI works */
143.34898 +-	tmp = front->name;
143.34899 + 	front->name = back->name;
143.34900 +-	back->name = tmp;
143.34901 ++	back->name = pixmap_flink(front_priv->pixmap);
143.34902 + 
143.34903 + 	/* Swap pixmap bos */
143.34904 + 	new_front = intel_exchange_pixmap_buffers(intel,
143.34905 +@@ -753,87 +800,30 @@ I830DRI2FlipAbort(void *pageflip_data)
143.34906 +         i830_dri2_del_frame_event(info);
143.34907 + }
143.34908 + 
143.34909 +-/*
143.34910 +- * Our internal swap routine takes care of actually exchanging, blitting, or
143.34911 +- * flipping buffers as necessary.
143.34912 +- */
143.34913 + static Bool
143.34914 +-I830DRI2ScheduleFlip(struct intel_screen_private *intel,
143.34915 +-		     DrawablePtr draw,
143.34916 +-		     DRI2FrameEventPtr info)
143.34917 ++allocate_back_buffer(struct intel_screen_private *intel)
143.34918 + {
143.34919 +-	I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
143.34920 +-	drm_intel_bo *new_back, *old_back;
143.34921 +-	int tmp_name;
143.34922 +-
143.34923 +-	if (!intel->use_triple_buffer) {
143.34924 +-		info->type = DRI2_SWAP;
143.34925 +-		if (!intel_do_pageflip(intel,
143.34926 +-				       get_pixmap_bo(priv),
143.34927 +-				       info->pipe, FALSE, info,
143.34928 +-                                       I830DRI2FlipComplete,
143.34929 +-                                       I830DRI2FlipAbort))
143.34930 +-			return FALSE;
143.34931 +-
143.34932 +-		I830DRI2ExchangeBuffers(intel, info->front, info->back);
143.34933 +-		return TRUE;
143.34934 +-	}
143.34935 ++	drm_intel_bo *bo;
143.34936 ++	int pitch;
143.34937 ++	uint32_t tiling;
143.34938 + 
143.34939 +-	if (intel->pending_flip[info->pipe]) {
143.34940 +-		assert(intel->pending_flip[info->pipe]->chain == NULL);
143.34941 +-		intel->pending_flip[info->pipe]->chain = info;
143.34942 ++	if (intel->back_buffer)
143.34943 + 		return TRUE;
143.34944 +-	}
143.34945 + 
143.34946 +-	if (intel->back_buffer == NULL) {
143.34947 +-		new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer",
143.34948 +-					      intel->front_buffer->size, 0);
143.34949 +-		if (new_back == NULL)
143.34950 +-			return FALSE;
143.34951 +-
143.34952 +-		if (intel->front_tiling != I915_TILING_NONE) {
143.34953 +-			uint32_t tiling = intel->front_tiling;
143.34954 +-			drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch);
143.34955 +-			if (tiling != intel->front_tiling) {
143.34956 +-				drm_intel_bo_unreference(new_back);
143.34957 +-				return FALSE;
143.34958 +-			}
143.34959 +-		}
143.34960 +-
143.34961 +-		drm_intel_bo_disable_reuse(new_back);
143.34962 +-		dri_bo_flink(new_back, &intel->back_name);
143.34963 +-	} else {
143.34964 +-		new_back = intel->back_buffer;
143.34965 +-		intel->back_buffer = NULL;
143.34966 +-	}
143.34967 ++	bo = intel_allocate_framebuffer(intel->scrn,
143.34968 ++					intel->scrn->virtualX,
143.34969 ++					intel->scrn->virtualY,
143.34970 ++					intel->cpp,
143.34971 ++					&pitch, &tiling);
143.34972 ++	if (bo == NULL)
143.34973 ++		return FALSE;
143.34974 + 
143.34975 +-	old_back = get_pixmap_bo(priv);
143.34976 +-	if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) {
143.34977 +-		intel->back_buffer = new_back;
143.34978 ++	if (pitch != intel->front_pitch || tiling != intel->front_tiling) {
143.34979 ++		drm_intel_bo_unreference(bo);
143.34980 + 		return FALSE;
143.34981 + 	}
143.34982 +-	info->type = DRI2_SWAP_CHAIN;
143.34983 +-	intel->pending_flip[info->pipe] = info;
143.34984 +-
143.34985 +-	priv = info->front->driverPrivate;
143.34986 +-
143.34987 +-	/* Exchange the current front-buffer with the fresh bo */
143.34988 +-
143.34989 +-	intel->back_buffer = intel->front_buffer;
143.34990 +-	drm_intel_bo_reference(intel->back_buffer);
143.34991 +-	intel_set_pixmap_bo(priv->pixmap, new_back);
143.34992 +-	drm_intel_bo_unreference(new_back);
143.34993 +-
143.34994 +-	tmp_name = info->front->name;
143.34995 +-	info->front->name = intel->back_name;
143.34996 +-	intel->back_name = tmp_name;
143.34997 + 
143.34998 +-	/* Then flip DRI2 pointers and update the screen pixmap */
143.34999 +-	I830DRI2ExchangeBuffers(intel, info->front, info->back);
143.35000 +-	DRI2SwapComplete(info->client, draw, 0, 0, 0,
143.35001 +-			 DRI2_EXCHANGE_COMPLETE,
143.35002 +-			 info->event_complete,
143.35003 +-			 info->event_data);
143.35004 ++	intel->back_buffer = bo;
143.35005 + 	return TRUE;
143.35006 + }
143.35007 + 
143.35008 +@@ -889,8 +879,88 @@ can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
143.35009 + 	return TRUE;
143.35010 + }
143.35011 + 
143.35012 +-void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
143.35013 +-			       unsigned int tv_usec, DRI2FrameEventPtr swap_info)
143.35014 ++static Bool
143.35015 ++queue_flip(struct intel_screen_private *intel,
143.35016 ++	   DrawablePtr draw,
143.35017 ++	   DRI2FrameEventPtr info)
143.35018 ++{
143.35019 ++	xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
143.35020 ++	I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
143.35021 ++	drm_intel_bo *old_back = get_pixmap_bo(priv);
143.35022 ++
143.35023 ++	if (crtc == NULL)
143.35024 ++		return FALSE;
143.35025 ++
143.35026 ++	if (!can_exchange(draw, info->front, info->back))
143.35027 ++		return FALSE;
143.35028 ++
143.35029 ++	if (!intel_do_pageflip(intel, old_back,
143.35030 ++			       intel_crtc_to_pipe(crtc),
143.35031 ++			       FALSE, info,
143.35032 ++			       I830DRI2FlipComplete, I830DRI2FlipAbort))
143.35033 ++		return FALSE;
143.35034 ++
143.35035 ++#if DRI2INFOREC_VERSION >= 6
143.35036 ++	if (intel->use_triple_buffer && allocate_back_buffer(intel)) {
143.35037 ++		info->old_width  = intel->scrn->virtualX;
143.35038 ++		info->old_height = intel->scrn->virtualY;
143.35039 ++		info->old_pitch  = intel->front_pitch;
143.35040 ++		info->old_tiling = intel->front_tiling;
143.35041 ++		info->old_buffer = intel->front_buffer;
143.35042 ++		dri_bo_reference(info->old_buffer);
143.35043 ++
143.35044 ++		priv = info->front->driverPrivate;
143.35045 ++		intel_set_pixmap_bo(priv->pixmap, intel->back_buffer);
143.35046 ++
143.35047 ++		dri_bo_unreference(intel->back_buffer);
143.35048 ++		intel->back_buffer = NULL;
143.35049 ++
143.35050 ++		DRI2SwapLimit(draw, 2);
143.35051 ++	} else
143.35052 ++		DRI2SwapLimit(draw, 1);
143.35053 ++#endif
143.35054 ++
143.35055 ++	/* Then flip DRI2 pointers and update the screen pixmap */
143.35056 ++	I830DRI2ExchangeBuffers(intel, info->front, info->back);
143.35057 ++	return TRUE;
143.35058 ++}
143.35059 ++
143.35060 ++static Bool
143.35061 ++queue_swap(struct intel_screen_private *intel,
143.35062 ++	   DrawablePtr draw,
143.35063 ++	   DRI2FrameEventPtr info)
143.35064 ++{
143.35065 ++	xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
143.35066 ++	drmVBlank vbl;
143.35067 ++
143.35068 ++	if (crtc == NULL)
143.35069 ++		return FALSE;
143.35070 ++
143.35071 ++	vbl.request.type =
143.35072 ++		DRM_VBLANK_RELATIVE |
143.35073 ++		DRM_VBLANK_EVENT |
143.35074 ++		pipe_select(intel_crtc_to_pipe(crtc));
143.35075 ++	vbl.request.sequence = 1;
143.35076 ++	vbl.request.signal =
143.35077 ++		intel_drm_queue_alloc(intel->scrn, crtc, info,
143.35078 ++				      intel_dri2_vblank_handler,
143.35079 ++				      intel_dri2_vblank_abort);
143.35080 ++	if (vbl.request.signal == 0)
143.35081 ++		return FALSE;
143.35082 ++
143.35083 ++	info->type = DRI2_SWAP;
143.35084 ++	if (drmWaitVBlank(intel->drmSubFD, &vbl)) {
143.35085 ++		intel_drm_abort_seq(intel->scrn, vbl.request.signal);
143.35086 ++		return FALSE;
143.35087 ++	}
143.35088 ++
143.35089 ++	return TRUE;
143.35090 ++}
143.35091 ++
143.35092 ++static void I830DRI2FrameEventHandler(unsigned int frame,
143.35093 ++				      unsigned int tv_sec,
143.35094 ++				      unsigned int tv_usec,
143.35095 ++				      DRI2FrameEventPtr swap_info)
143.35096 + {
143.35097 + 	intel_screen_private *intel = swap_info->intel;
143.35098 + 	DrawablePtr drawable;
143.35099 +@@ -906,24 +976,22 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
143.35100 + 		return;
143.35101 + 	}
143.35102 + 
143.35103 +-
143.35104 + 	switch (swap_info->type) {
143.35105 + 	case DRI2_FLIP:
143.35106 + 		/* If we can still flip... */
143.35107 +-		if (can_exchange(drawable, swap_info->front, swap_info->back) &&
143.35108 +-		    I830DRI2ScheduleFlip(intel, drawable, swap_info))
143.35109 +-			return;
143.35110 +-
143.35111 +-		/* else fall through to exchange/blit */
143.35112 +-	case DRI2_SWAP: {
143.35113 +-		I830DRI2FallbackBlitSwap(drawable,
143.35114 +-					 swap_info->front, swap_info->back);
143.35115 +-		DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
143.35116 +-				 DRI2_BLIT_COMPLETE,
143.35117 +-				 swap_info->client ? swap_info->event_complete : NULL,
143.35118 +-				 swap_info->event_data);
143.35119 +-		break;
143.35120 +-	}
143.35121 ++		if (!queue_flip(intel, drawable, swap_info) &&
143.35122 ++		    !queue_swap(intel, drawable, swap_info)) {
143.35123 ++		case DRI2_SWAP:
143.35124 ++			I830DRI2FallbackBlitSwap(drawable,
143.35125 ++						 swap_info->front, swap_info->back);
143.35126 ++			DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
143.35127 ++					 DRI2_BLIT_COMPLETE,
143.35128 ++					 swap_info->client ? swap_info->event_complete : NULL,
143.35129 ++					 swap_info->event_data);
143.35130 ++			break;
143.35131 ++		}
143.35132 ++		return;
143.35133 ++
143.35134 + 	case DRI2_WAITMSC:
143.35135 + 		if (swap_info->client)
143.35136 + 			DRI2WaitMSCComplete(swap_info->client, drawable,
143.35137 +@@ -939,12 +1007,13 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
143.35138 + 	i830_dri2_del_frame_event(swap_info);
143.35139 + }
143.35140 + 
143.35141 +-void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
143.35142 +-			      unsigned int tv_usec, DRI2FrameEventPtr flip_info)
143.35143 ++static void I830DRI2FlipEventHandler(unsigned int frame,
143.35144 ++				     unsigned int tv_sec,
143.35145 ++				     unsigned int tv_usec,
143.35146 ++				     DRI2FrameEventPtr flip_info)
143.35147 + {
143.35148 + 	struct intel_screen_private *intel = flip_info->intel;
143.35149 + 	DrawablePtr drawable;
143.35150 +-	DRI2FrameEventPtr chain;
143.35151 + 
143.35152 + 	drawable = NULL;
143.35153 + 	if (flip_info->drawable_id)
143.35154 +@@ -954,6 +1023,7 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
143.35155 + 
143.35156 + 	/* We assume our flips arrive in order, so we don't check the frame */
143.35157 + 	switch (flip_info->type) {
143.35158 ++	case DRI2_FLIP:
143.35159 + 	case DRI2_SWAP:
143.35160 + 		if (!drawable)
143.35161 + 			break;
143.35162 +@@ -984,35 +1054,6 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
143.35163 + 				 flip_info->event_data);
143.35164 + 		break;
143.35165 + 
143.35166 +-	case DRI2_SWAP_CHAIN:
143.35167 +-		assert(intel->pending_flip[flip_info->pipe] == flip_info);
143.35168 +-		intel->pending_flip[flip_info->pipe] = NULL;
143.35169 +-
143.35170 +-		chain = flip_info->chain;
143.35171 +-		if (chain) {
143.35172 +-			DrawablePtr chain_drawable = NULL;
143.35173 +-			if (chain->drawable_id)
143.35174 +-				 dixLookupDrawable(&chain_drawable,
143.35175 +-						   chain->drawable_id,
143.35176 +-						   serverClient,
143.35177 +-						   M_ANY, DixWriteAccess);
143.35178 +-			if (chain_drawable == NULL) {
143.35179 +-				i830_dri2_del_frame_event(chain);
143.35180 +-			} else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
143.35181 +-				   !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
143.35182 +-				I830DRI2FallbackBlitSwap(chain_drawable,
143.35183 +-							 chain->front,
143.35184 +-							 chain->back);
143.35185 +-
143.35186 +-				DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec,
143.35187 +-						 DRI2_BLIT_COMPLETE,
143.35188 +-						 chain->client ? chain->event_complete : NULL,
143.35189 +-						 chain->event_data);
143.35190 +-				i830_dri2_del_frame_event(chain);
143.35191 +-			}
143.35192 +-		}
143.35193 +-		break;
143.35194 +-
143.35195 + 	default:
143.35196 + 		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
143.35197 + 			   "%s: unknown vblank event received\n", __func__);
143.35198 +@@ -1023,38 +1064,6 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
143.35199 + 	i830_dri2_del_frame_event(flip_info);
143.35200 + }
143.35201 + 
143.35202 +-static uint32_t pipe_select(int pipe)
143.35203 +-{
143.35204 +-	if (pipe > 1)
143.35205 +-		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
143.35206 +-	else if (pipe > 0)
143.35207 +-		return DRM_VBLANK_SECONDARY;
143.35208 +-	else
143.35209 +-		return 0;
143.35210 +-}
143.35211 +-
143.35212 +-static void
143.35213 +-intel_dri2_vblank_handler(ScrnInfoPtr scrn,
143.35214 +-                          xf86CrtcPtr crtc,
143.35215 +-                          uint64_t msc,
143.35216 +-                          uint64_t usec,
143.35217 +-                          void *data)
143.35218 +-{
143.35219 +-        DRI2FrameEventPtr swap_info = data;
143.35220 +-
143.35221 +-        I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info);
143.35222 +-}
143.35223 +-
143.35224 +-static void
143.35225 +-intel_dri2_vblank_abort(ScrnInfoPtr scrn,
143.35226 +-                        xf86CrtcPtr crtc,
143.35227 +-                        void *data)
143.35228 +-{
143.35229 +-        DRI2FrameEventPtr swap_info = data;
143.35230 +-
143.35231 +-        i830_dri2_del_frame_event(swap_info);
143.35232 +-}
143.35233 +-
143.35234 + /*
143.35235 +  * ScheduleSwap is responsible for requesting a DRM vblank event for the
143.35236 +  * appropriate frame.
143.35237 +@@ -1089,7 +1098,6 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.35238 +         int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
143.35239 +         int flip = 0;
143.35240 + 	DRI2FrameEventPtr swap_info = NULL;
143.35241 +-	enum DRI2FrameEventType swap_type = DRI2_SWAP;
143.35242 + 	uint64_t current_msc, current_ust;
143.35243 +         uint64_t request_msc;
143.35244 +         uint32_t seq;
143.35245 +@@ -1109,7 +1117,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.35246 + 	swap_info->event_data = data;
143.35247 + 	swap_info->front = front;
143.35248 + 	swap_info->back = back;
143.35249 +-	swap_info->pipe = pipe;
143.35250 ++	swap_info->type = DRI2_SWAP;
143.35251 + 
143.35252 + 	if (!i830_dri2_add_frame_event(swap_info)) {
143.35253 + 	    free(swap_info);
143.35254 +@@ -1124,20 +1132,27 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.35255 + 	if (ret)
143.35256 + 	    goto blit_fallback;
143.35257 + 
143.35258 +-	/* Flips need to be submitted one frame before */
143.35259 ++	/*
143.35260 ++	 * If we can, schedule the flip directly from here rather
143.35261 ++	 * than waiting for an event from the kernel for the current
143.35262 ++	 * (or a past) MSC.
143.35263 ++	 */
143.35264 ++	if (divisor == 0 &&
143.35265 ++	    current_msc >= *target_msc &&
143.35266 ++	    queue_flip(intel, draw, swap_info))
143.35267 ++		return TRUE;
143.35268 ++
143.35269 + 	if (can_exchange(draw, front, back)) {
143.35270 +-	    swap_type = DRI2_FLIP;
143.35271 +-	    flip = 1;
143.35272 ++		swap_info->type = DRI2_FLIP;
143.35273 ++		/* Flips need to be submitted one frame before */
143.35274 ++		if (*target_msc > 0)
143.35275 ++			--*target_msc;
143.35276 ++		flip = 1;
143.35277 + 	}
143.35278 + 
143.35279 +-	swap_info->type = swap_type;
143.35280 +-
143.35281 +-	/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
143.35282 +-	 * Do it early, so handling of different timing constraints
143.35283 +-	 * for divisor, remainder and msc vs. target_msc works.
143.35284 +-	 */
143.35285 +-	if (*target_msc > 0)
143.35286 +-		*target_msc -= flip;
143.35287 ++#if DRI2INFOREC_VERSION >= 6
143.35288 ++	DRI2SwapLimit(draw, 1);
143.35289 ++#endif
143.35290 + 
143.35291 + 	/*
143.35292 + 	 * If divisor is zero, or current_msc is smaller than target_msc
143.35293 +@@ -1145,15 +1160,6 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.35294 + 	 * the swap.
143.35295 + 	 */
143.35296 + 	if (divisor == 0 || current_msc < *target_msc) {
143.35297 +-		/*
143.35298 +-		 * If we can, schedule the flip directly from here rather
143.35299 +-		 * than waiting for an event from the kernel for the current
143.35300 +-		 * (or a past) MSC.
143.35301 +-		 */
143.35302 +-		if (flip && divisor == 0 && current_msc >= *target_msc &&
143.35303 +-		    I830DRI2ScheduleFlip(intel, draw, swap_info))
143.35304 +-			return TRUE;
143.35305 +-
143.35306 + 		vbl.request.type =
143.35307 + 			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
143.35308 + 
143.35309 +@@ -1168,7 +1174,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.35310 + 		 * current_msc to ensure we return a reasonable value back
143.35311 + 		 * to the caller. This makes swap_interval logic more robust.
143.35312 + 		 */
143.35313 +-		if (current_msc >= *target_msc)
143.35314 ++		if (current_msc > *target_msc)
143.35315 + 			*target_msc = current_msc;
143.35316 + 
143.35317 +                 seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
143.35318 +@@ -1183,6 +1189,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
143.35319 + 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
143.35320 + 				   "divisor 0 get vblank counter failed: %s\n",
143.35321 + 				   strerror(errno));
143.35322 ++			intel_drm_abort_seq(intel->scrn, seq);
143.35323 ++			swap_info = NULL;
143.35324 + 			goto blit_fallback;
143.35325 + 		}
143.35326 + 
143.35327 +@@ -1332,7 +1340,6 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
143.35328 + 
143.35329 + 	if (!i830_dri2_add_frame_event(wait_info)) {
143.35330 + 	    free(wait_info);
143.35331 +-	    wait_info = NULL;
143.35332 + 	    goto out_complete;
143.35333 + 	}
143.35334 + 
143.35335 +@@ -1374,7 +1381,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
143.35336 + 					   strerror(errno));
143.35337 + 				limit--;
143.35338 + 			}
143.35339 +-			goto out_free;
143.35340 ++			intel_drm_abort_seq(intel->scrn, seq);
143.35341 ++			goto out_complete;
143.35342 + 		}
143.35343 + 
143.35344 + 		wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
143.35345 +@@ -1417,7 +1425,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
143.35346 + 				   strerror(errno));
143.35347 + 			limit--;
143.35348 + 		}
143.35349 +-		goto out_free;
143.35350 ++		intel_drm_abort_seq(intel->scrn, seq);
143.35351 ++		goto out_complete;
143.35352 + 	}
143.35353 + 
143.35354 + 	wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
143.35355 +@@ -1440,13 +1449,92 @@ static int has_i830_dri(void)
143.35356 + 	return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
143.35357 + }
143.35358 + 
143.35359 +-static const char *dri_driver_name(intel_screen_private *intel)
143.35360 ++static int
143.35361 ++namecmp(const char *s1, const char *s2)
143.35362 ++{
143.35363 ++	char c1, c2;
143.35364 ++
143.35365 ++	if (!s1 || *s1 == 0) {
143.35366 ++		if (!s2 || *s2 == 0)
143.35367 ++			return 0;
143.35368 ++		else
143.35369 ++			return 1;
143.35370 ++	}
143.35371 ++
143.35372 ++	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
143.35373 ++		s1++;
143.35374 ++
143.35375 ++	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
143.35376 ++		s2++;
143.35377 ++
143.35378 ++	c1 = isupper(*s1) ? tolower(*s1) : *s1;
143.35379 ++	c2 = isupper(*s2) ? tolower(*s2) : *s2;
143.35380 ++	while (c1 == c2) {
143.35381 ++		if (c1 == '\0')
143.35382 ++			return 0;
143.35383 ++
143.35384 ++		s1++;
143.35385 ++		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
143.35386 ++			s1++;
143.35387 ++
143.35388 ++		s2++;
143.35389 ++		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
143.35390 ++			s2++;
143.35391 ++
143.35392 ++		c1 = isupper(*s1) ? tolower(*s1) : *s1;
143.35393 ++		c2 = isupper(*s2) ? tolower(*s2) : *s2;
143.35394 ++	}
143.35395 ++
143.35396 ++	return c1 - c2;
143.35397 ++}
143.35398 ++
143.35399 ++static Bool is_level(const char **str)
143.35400 ++{
143.35401 ++	const char *s = *str;
143.35402 ++	char *end;
143.35403 ++	unsigned val;
143.35404 ++
143.35405 ++	if (s == NULL || *s == '\0')
143.35406 ++		return TRUE;
143.35407 ++
143.35408 ++	if (namecmp(s, "on") == 0)
143.35409 ++		return TRUE;
143.35410 ++	if (namecmp(s, "true") == 0)
143.35411 ++		return TRUE;
143.35412 ++	if (namecmp(s, "yes") == 0)
143.35413 ++		return TRUE;
143.35414 ++
143.35415 ++	if (namecmp(s, "0") == 0)
143.35416 ++		return TRUE;
143.35417 ++	if (namecmp(s, "off") == 0)
143.35418 ++		return TRUE;
143.35419 ++	if (namecmp(s, "false") == 0)
143.35420 ++		return TRUE;
143.35421 ++	if (namecmp(s, "no") == 0)
143.35422 ++		return TRUE;
143.35423 ++
143.35424 ++	val = strtoul(s, &end, 0);
143.35425 ++	if (val && *end == '\0')
143.35426 ++		return TRUE;
143.35427 ++	if (val && *end == ':')
143.35428 ++		*str = end + 1;
143.35429 ++	return FALSE;
143.35430 ++}
143.35431 ++
143.35432 ++static const char *options_get_dri(intel_screen_private *intel)
143.35433 + {
143.35434 + #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
143.35435 +-	const char *s = xf86GetOptValString(intel->Options, OPTION_DRI);
143.35436 +-	Bool dummy;
143.35437 ++	return xf86GetOptValString(intel->Options, OPTION_DRI);
143.35438 ++#else
143.35439 ++	return NULL;
143.35440 ++#endif
143.35441 ++}
143.35442 + 
143.35443 +-	if (s == NULL || xf86getBoolValue(&dummy, s)) {
143.35444 ++static const char *dri_driver_name(intel_screen_private *intel)
143.35445 ++{
143.35446 ++	const char *s = options_get_dri(intel);
143.35447 ++
143.35448 ++	if (is_level(&s)) {
143.35449 + 		if (INTEL_INFO(intel)->gen < 030)
143.35450 + 			return has_i830_dri() ? "i830" : "i915";
143.35451 + 		else if (INTEL_INFO(intel)->gen < 040)
143.35452 +@@ -1456,14 +1544,6 @@ static const char *dri_driver_name(intel_screen_private *intel)
143.35453 + 	}
143.35454 + 
143.35455 + 	return s;
143.35456 +-#else
143.35457 +-	if (INTEL_INFO(intel)->gen < 030)
143.35458 +-		return has_i830_dri() ? "i830" : "i915";
143.35459 +-	else if (INTEL_INFO(intel)->gen < 040)
143.35460 +-		return "i915";
143.35461 +-	else
143.35462 +-		return "i965";
143.35463 +-#endif
143.35464 + }
143.35465 + 
143.35466 + Bool I830DRI2ScreenInit(ScreenPtr screen)
143.35467 +@@ -1544,7 +1624,7 @@ Bool I830DRI2ScreenInit(ScreenPtr screen)
143.35468 + 	info.numDrivers = 2;
143.35469 + 	info.driverNames = driverNames;
143.35470 + 	driverNames[0] = info.driverName;
143.35471 +-	driverNames[1] = info.driverName;
143.35472 ++	driverNames[1] = "va_gl";
143.35473 + #endif
143.35474 + 
143.35475 + 	return DRI2ScreenInit(screen, &info);
143.35476 +diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c
143.35477 +index 2793da5d..3703c412 100644
143.35478 +--- a/src/uxa/intel_driver.c
143.35479 ++++ b/src/uxa/intel_driver.c
143.35480 +@@ -237,24 +237,17 @@ static Bool I830GetEarlyOptions(ScrnInfoPtr scrn)
143.35481 + 	return TRUE;
143.35482 + }
143.35483 + 
143.35484 +-static Bool intel_option_cast_string_to_bool(intel_screen_private *intel,
143.35485 +-					     int id, Bool val)
143.35486 +-{
143.35487 +-#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
143.35488 +-	xf86getBoolValue(&val, xf86GetOptValString(intel->Options, id));
143.35489 +-	return val;
143.35490 +-#else
143.35491 +-	return val;
143.35492 +-#endif
143.35493 +-}
143.35494 +-
143.35495 + static void intel_check_dri_option(ScrnInfoPtr scrn)
143.35496 + {
143.35497 + 	intel_screen_private *intel = intel_get_screen_private(scrn);
143.35498 ++	unsigned level;
143.35499 + 
143.35500 + 	intel->dri2 = intel->dri3 = DRI_NONE;
143.35501 +-	if (!intel_option_cast_string_to_bool(intel, OPTION_DRI, TRUE))
143.35502 +-		intel->dri2 = intel->dri3 = DRI_DISABLED;
143.35503 ++	level = intel_option_cast_to_unsigned(intel->Options, OPTION_DRI, DEFAULT_DRI_LEVEL);
143.35504 ++	if (level < 3 || INTEL_INFO(intel)->gen < 040)
143.35505 ++		intel->dri3 = DRI_DISABLED;
143.35506 ++	if (level < 2)
143.35507 ++		intel->dri2 = DRI_DISABLED;
143.35508 + 
143.35509 + 	if (scrn->depth != 16 && scrn->depth != 24 && scrn->depth != 30) {
143.35510 + 		xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
143.35511 +@@ -371,8 +364,8 @@ static Bool can_accelerate_blt(struct intel_screen_private *intel)
143.35512 + 	if (INTEL_INFO(intel)->gen == -1)
143.35513 + 		return FALSE;
143.35514 + 
143.35515 +-	if (xf86ReturnOptValBool(intel->Options, OPTION_ACCEL_DISABLE, FALSE) ||
143.35516 +-	    !intel_option_cast_string_to_bool(intel, OPTION_ACCEL_METHOD, TRUE)) {
143.35517 ++	if (!xf86ReturnOptValBool(intel->Options, OPTION_ACCEL_ENABLE, TRUE) ||
143.35518 ++	    !intel_option_cast_to_bool(intel->Options, OPTION_ACCEL_METHOD, TRUE)) {
143.35519 + 		xf86DrvMsg(intel->scrn->scrnIndex, X_CONFIG,
143.35520 + 			   "Disabling hardware acceleration.\n");
143.35521 + 		return FALSE;
143.35522 +@@ -659,8 +652,9 @@ redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty)
143.35523 + }
143.35524 + 
143.35525 + static void
143.35526 +-intel_dirty_update(ScreenPtr screen)
143.35527 ++intel_dirty_update(intel_screen_private *intel)
143.35528 + {
143.35529 ++	ScreenPtr screen = xf86ScrnToScreen(intel->scrn);
143.35530 + 	RegionPtr region;
143.35531 + 	PixmapDirtyUpdatePtr ent;
143.35532 + 
143.35533 +@@ -677,6 +671,7 @@ intel_dirty_update(ScreenPtr screen)
143.35534 + }
143.35535 + #endif
143.35536 + 
143.35537 ++#if !HAVE_NOTIFY_FD
143.35538 + static void
143.35539 + I830BlockHandler(BLOCKHANDLER_ARGS_DECL)
143.35540 + {
143.35541 +@@ -694,9 +689,22 @@ I830BlockHandler(BLOCKHANDLER_ARGS_DECL)
143.35542 + 	intel_uxa_block_handler(intel);
143.35543 + 	intel_video_block_handler(intel);
143.35544 + #ifdef INTEL_PIXMAP_SHARING
143.35545 +-	intel_dirty_update(screen);
143.35546 ++	intel_dirty_update(intel);
143.35547 + #endif
143.35548 + }
143.35549 ++#else
143.35550 ++static void
143.35551 ++I830BlockHandler(void *data, void *timeout)
143.35552 ++{
143.35553 ++	intel_screen_private *intel = data;
143.35554 ++
143.35555 ++	intel_uxa_block_handler(intel);
143.35556 ++	intel_video_block_handler(intel);
143.35557 ++#ifdef INTEL_PIXMAP_SHARING
143.35558 ++	intel_dirty_update(intel);
143.35559 ++#endif
143.35560 ++}
143.35561 ++#endif
143.35562 + 
143.35563 + static Bool
143.35564 + intel_init_initial_framebuffer(ScrnInfoPtr scrn)
143.35565 +@@ -735,6 +743,8 @@ intel_flush_callback(CallbackListPtr *list,
143.35566 + }
143.35567 + 
143.35568 + #if HAVE_UDEV
143.35569 ++#include <sys/stat.h>
143.35570 ++
143.35571 + static void
143.35572 + I830HandleUEvents(int fd, void *closure)
143.35573 + {
143.35574 +@@ -771,6 +781,15 @@ I830HandleUEvents(int fd, void *closure)
143.35575 + 	udev_device_unref(dev);
143.35576 + }
143.35577 + 
143.35578 ++static int has_randr(void)
143.35579 ++{
143.35580 ++#if HAS_DIXREGISTERPRIVATEKEY
143.35581 ++	return dixPrivateKeyRegistered(rrPrivKey);
143.35582 ++#else
143.35583 ++	return *rrPrivKey;
143.35584 ++#endif
143.35585 ++}
143.35586 ++
143.35587 + static void
143.35588 + I830UeventInit(ScrnInfoPtr scrn)
143.35589 + {
143.35590 +@@ -780,6 +799,10 @@ I830UeventInit(ScrnInfoPtr scrn)
143.35591 + 	Bool hotplug;
143.35592 + 	MessageType from = X_CONFIG;
143.35593 + 
143.35594 ++	/* Without RR, nothing we can do here */
143.35595 ++	if (!has_randr())
143.35596 ++		return;
143.35597 ++
143.35598 + 	if (!xf86GetOptValBool(intel->Options, OPTION_HOTPLUG, &hotplug)) {
143.35599 + 		from = X_DEFAULT;
143.35600 + 		hotplug = TRUE;
143.35601 +@@ -939,8 +962,14 @@ I830ScreenInit(SCREEN_INIT_ARGS_DECL)
143.35602 + 			   "Hardware cursor initialization failed\n");
143.35603 + 	}
143.35604 + 
143.35605 ++#if !HAVE_NOTIFY_FD
143.35606 + 	intel->BlockHandler = screen->BlockHandler;
143.35607 + 	screen->BlockHandler = I830BlockHandler;
143.35608 ++#else
143.35609 ++	RegisterBlockAndWakeupHandlers(I830BlockHandler,
143.35610 ++				       (ServerWakeupHandlerProcPtr)NoopDDA,
143.35611 ++				       intel);
143.35612 ++#endif
143.35613 + 
143.35614 + #ifdef INTEL_PIXMAP_SHARING
143.35615 + 	screen->StartPixmapTracking = PixmapStartDirtyTracking;
143.35616 +@@ -1164,8 +1193,6 @@ static Bool I830CloseScreen(CLOSE_SCREEN_ARGS_DECL)
143.35617 + 
143.35618 + 	intel_sync_close(screen);
143.35619 + 
143.35620 +-	xf86GARTCloseScreen(scrn->scrnIndex);
143.35621 +-
143.35622 + 	scrn->vtSema = FALSE;
143.35623 + 	return TRUE;
143.35624 + }
143.35625 +diff --git a/src/uxa/intel_hwmc.c b/src/uxa/intel_hwmc.c
143.35626 +index 829cb8e0..78540600 100644
143.35627 +--- a/src/uxa/intel_hwmc.c
143.35628 ++++ b/src/uxa/intel_hwmc.c
143.35629 +@@ -193,7 +193,7 @@ Bool intel_xvmc_adaptor_init(ScreenPtr pScreen)
143.35630 + 	intel_screen_private *intel = intel_get_screen_private(scrn);
143.35631 + 	struct pci_device *pci;
143.35632 + 	static XF86MCAdaptorRec *pAdapt;
143.35633 +-	char *name;
143.35634 ++	const char *name;
143.35635 + 	char buf[64];
143.35636 + 
143.35637 + 	if (!intel->XvMCEnabled)
143.35638 +diff --git a/src/uxa/intel_memory.c b/src/uxa/intel_memory.c
143.35639 +index 0c6cf30c..b2d7a367 100644
143.35640 +--- a/src/uxa/intel_memory.c
143.35641 ++++ b/src/uxa/intel_memory.c
143.35642 +@@ -42,7 +42,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
143.35643 +  * This is the video memory allocator.  Our memory allocation is different from
143.35644 +  * other graphics chips, where you have a fixed amount of graphics memory
143.35645 +  * available that you want to put to the best use.  Instead, we have almost no
143.35646 +- * memory pre-allocated, and we have to choose an appropriate amount of sytem
143.35647 ++ * memory pre-allocated, and we have to choose an appropriate amount of system
143.35648 +  * memory to use.
143.35649 +  *
143.35650 +  * The allocations we might do:
143.35651 +diff --git a/src/uxa/intel_present.c b/src/uxa/intel_present.c
143.35652 +index d20043f3..ac028edd 100644
143.35653 +--- a/src/uxa/intel_present.c
143.35654 ++++ b/src/uxa/intel_present.c
143.35655 +@@ -244,6 +244,7 @@ intel_present_check_flip(RRCrtcPtr              crtc,
143.35656 + 	ScrnInfoPtr             scrn = xf86ScreenToScrn(screen);
143.35657 + 	intel_screen_private    *intel = intel_get_screen_private(scrn);
143.35658 +         dri_bo                  *bo;
143.35659 ++	uint32_t		tiling, swizzle;
143.35660 + 
143.35661 + 	if (!scrn->vtSema)
143.35662 + 		return FALSE;
143.35663 +@@ -266,6 +267,12 @@ intel_present_check_flip(RRCrtcPtr              crtc,
143.35664 +         if (!bo)
143.35665 +                 return FALSE;
143.35666 + 
143.35667 ++	if (drm_intel_bo_get_tiling(bo, &tiling, &swizzle))
143.35668 ++		return FALSE;
143.35669 ++
143.35670 ++	if (tiling == I915_TILING_Y)
143.35671 ++		return FALSE;
143.35672 ++
143.35673 + 	return TRUE;
143.35674 + }
143.35675 + 
143.35676 +@@ -343,29 +350,33 @@ intel_present_unflip(ScreenPtr screen, uint64_t event_id)
143.35677 + {
143.35678 + 	ScrnInfoPtr                             scrn = xf86ScreenToScrn(screen);
143.35679 + 	intel_screen_private                    *intel = intel_get_screen_private(scrn);
143.35680 +-	struct intel_present_vblank_event       *event;
143.35681 + 	PixmapPtr                               pixmap = screen->GetScreenPixmap(screen);
143.35682 ++	struct intel_present_vblank_event       *event = NULL;
143.35683 + 	dri_bo                                  *bo;
143.35684 +-	Bool                                    ret;
143.35685 + 
143.35686 + 	if (!intel_present_check_flip(NULL, screen->root, pixmap, true))
143.35687 +-		return;
143.35688 ++		goto fail;
143.35689 + 
143.35690 + 	bo = intel_get_pixmap_bo(pixmap);
143.35691 + 	if (!bo)
143.35692 +-		return;
143.35693 ++		goto fail;
143.35694 + 
143.35695 + 	event = calloc(1, sizeof(struct intel_present_vblank_event));
143.35696 + 	if (!event)
143.35697 +-		return;
143.35698 ++		goto fail;
143.35699 + 
143.35700 + 	event->event_id = event_id;
143.35701 + 
143.35702 +-	ret = intel_do_pageflip(intel, bo, -1, FALSE, event, intel_present_flip_event, intel_present_flip_abort);
143.35703 +-	if (!ret) {
143.35704 +-		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
143.35705 +-			   "present unflip failed\n");
143.35706 +-	}
143.35707 ++	if (!intel_do_pageflip(intel, bo, -1, FALSE, event,
143.35708 ++			       intel_present_flip_event,
143.35709 ++			       intel_present_flip_abort))
143.35710 ++		goto fail;
143.35711 ++
143.35712 ++	return;
143.35713 ++fail:
143.35714 ++	xf86SetDesiredModes(scrn);
143.35715 ++	present_event_notify(event_id, 0, 0);
143.35716 ++	free(event);
143.35717 + }
143.35718 + 
143.35719 + static present_screen_info_rec intel_present_screen_info = {
143.35720 +diff --git a/src/uxa/intel_uxa.c b/src/uxa/intel_uxa.c
143.35721 +index 590ff5d1..ec32a723 100644
143.35722 +--- a/src/uxa/intel_uxa.c
143.35723 ++++ b/src/uxa/intel_uxa.c
143.35724 +@@ -176,6 +176,24 @@ intel_uxa_check_solid(DrawablePtr drawable, int alu, Pixel planemask)
143.35725 + 	return TRUE;
143.35726 + }
143.35727 + 
143.35728 ++static Bool
143.35729 ++intel_uxa_check_bo_tiling(intel_screen_private *intel,
143.35730 ++			  PixmapPtr pixmap,
143.35731 ++			  unsigned *tiling_out)
143.35732 ++{
143.35733 ++	struct intel_uxa_pixmap *priv;
143.35734 ++
143.35735 ++	priv = intel_uxa_get_pixmap_private(pixmap);
143.35736 ++	if (!priv)
143.35737 ++		return FALSE;
143.35738 ++
143.35739 ++	if (priv->tiling == I915_TILING_Y && INTEL_INFO(intel)->gen < 060)
143.35740 ++		return FALSE;
143.35741 ++
143.35742 ++	*tiling_out = priv->tiling;
143.35743 ++	return TRUE;
143.35744 ++}
143.35745 ++
143.35746 + /**
143.35747 +  * Sets up hardware state for a series of solid fills.
143.35748 +  */
143.35749 +@@ -189,6 +207,9 @@ intel_uxa_prepare_solid(PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
143.35750 + 		intel_uxa_get_pixmap_bo(pixmap),
143.35751 + 	};
143.35752 + 
143.35753 ++	if (!intel_uxa_check_bo_tiling(intel, pixmap, &intel->BR_tiling[0]))
143.35754 ++		return FALSE;
143.35755 ++
143.35756 + 	if (!intel_uxa_check_pitch_2d(pixmap))
143.35757 + 		return FALSE;
143.35758 + 
143.35759 +@@ -236,7 +257,7 @@ static void intel_uxa_solid(PixmapPtr pixmap, int x1, int y1, int x2, int y2)
143.35760 + 
143.35761 + 	{
143.35762 + 		int len = INTEL_INFO(intel)->gen >= 0100 ? 7 : 6;
143.35763 +-		BEGIN_BATCH_BLT(len);
143.35764 ++		BEGIN_BATCH_BLT_TILED(len);
143.35765 + 
143.35766 + 		cmd = XY_COLOR_BLT_CMD | (len - 2);
143.35767 + 
143.35768 +@@ -310,6 +331,10 @@ intel_uxa_prepare_copy(PixmapPtr source, PixmapPtr dest, int xdir,
143.35769 + 		intel_uxa_get_pixmap_bo(dest),
143.35770 + 	};
143.35771 + 
143.35772 ++	if (!intel_uxa_check_bo_tiling(intel, dest, &intel->BR_tiling[0]) ||
143.35773 ++	    !intel_uxa_check_bo_tiling(intel, source, &intel->BR_tiling[1]))
143.35774 ++		return FALSE;
143.35775 ++
143.35776 + 	if (!intel_uxa_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
143.35777 + 		return FALSE;
143.35778 + 
143.35779 +@@ -375,7 +400,7 @@ intel_uxa_copy(PixmapPtr dest, int src_x1, int src_y1, int dst_x1,
143.35780 + 
143.35781 + 	{
143.35782 + 		int len = INTEL_INFO(intel)->gen >= 0100 ? 10 : 8;
143.35783 +-		BEGIN_BATCH_BLT(len);
143.35784 ++		BEGIN_BATCH_BLT_TILED(len);
143.35785 + 
143.35786 + 		cmd = XY_SRC_COPY_BLT_CMD | (len - 2);
143.35787 + 
143.35788 +@@ -1068,7 +1093,7 @@ Bool intel_uxa_create_screen_resources(ScreenPtr screen)
143.35789 + 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
143.35790 + 	PixmapPtr pixmap;
143.35791 + 	intel_screen_private *intel = intel_get_screen_private(scrn);
143.35792 +-	dri_bo *bo = intel->front_buffer;
143.35793 ++	dri_bo *bo = intel->front_buffer, *old_bo;
143.35794 + 	int old_width, old_height, old_pitch;
143.35795 + 
143.35796 + 	if (!uxa_resources_init(screen))
143.35797 +@@ -1081,6 +1106,7 @@ Bool intel_uxa_create_screen_resources(ScreenPtr screen)
143.35798 + 	old_width = pixmap->drawable.width;
143.35799 + 	old_height = pixmap->drawable.height;
143.35800 + 	old_pitch = pixmap->devKind;
143.35801 ++	old_bo = intel_uxa_get_pixmap_bo(pixmap);
143.35802 + 
143.35803 + 	if (!screen->ModifyPixmapHeader(pixmap,
143.35804 + 					scrn->virtualX,
143.35805 +@@ -1102,6 +1128,9 @@ Bool intel_uxa_create_screen_resources(ScreenPtr screen)
143.35806 + err:
143.35807 + 	screen->ModifyPixmapHeader(pixmap,
143.35808 + 				   old_width, old_height, -1, -1, old_pitch, NULL);
143.35809 ++	if (old_bo)
143.35810 ++		intel_uxa_set_pixmap_bo(pixmap, old_bo);
143.35811 ++
143.35812 + 	return FALSE;
143.35813 + }
143.35814 + 
143.35815 +diff --git a/test/Makefile.am b/test/Makefile.am
143.35816 +index 66ed8ebb..12b5d5d8 100644
143.35817 +--- a/test/Makefile.am
143.35818 ++++ b/test/Makefile.am
143.35819 +@@ -5,6 +5,7 @@ stress_TESTS = \
143.35820 + 	basic-rectangle \
143.35821 + 	basic-string \
143.35822 + 	basic-copyarea \
143.35823 ++	basic-copyplane \
143.35824 + 	basic-copyarea-size \
143.35825 + 	basic-putimage \
143.35826 + 	basic-lines \
143.35827 +@@ -12,8 +13,10 @@ stress_TESTS = \
143.35828 + 	DrawSegments \
143.35829 + 	cursor-test \
143.35830 + 	render-fill \
143.35831 ++	render-glyphs \
143.35832 + 	render-trapezoid \
143.35833 + 	render-trapezoid-image \
143.35834 ++	render-triangle \
143.35835 + 	render-fill-copy \
143.35836 + 	render-composite-solid \
143.35837 + 	render-composite-solid-mask \
143.35838 +@@ -25,9 +28,16 @@ stress_TESTS = \
143.35839 + 	shm-test \
143.35840 + 	$(NULL)
143.35841 + 
143.35842 ++if X11_VM
143.35843 ++stress_TESTS += \
143.35844 ++	xvidmode \
143.35845 ++	$(NULL)
143.35846 ++endif
143.35847 ++
143.35848 + if DRI2
143.35849 + stress_TESTS += \
143.35850 + 	dri2-race \
143.35851 ++	dri2-speed \
143.35852 + 	dri2-swap \
143.35853 + 	dri2-test \
143.35854 + 	$(NULL)
143.35855 +@@ -36,8 +46,11 @@ endif
143.35856 + if X11_DRI3
143.35857 + stress_TESTS += \
143.35858 + 	dri3-test \
143.35859 ++	present-race \
143.35860 ++	present-speed \
143.35861 + 	present-test \
143.35862 + 	$(NULL)
143.35863 ++present_speed_CFLAGS = ${AM_CFLAGS} -pthread
143.35864 + endif
143.35865 + check_PROGRAMS = $(stress_TESTS)
143.35866 + 
143.35867 +diff --git a/test/basic-copyplane.c b/test/basic-copyplane.c
143.35868 +new file mode 100644
143.35869 +index 00000000..f049b82b
143.35870 +--- /dev/null
143.35871 ++++ b/test/basic-copyplane.c
143.35872 +@@ -0,0 +1,99 @@
143.35873 ++#include <stdint.h>
143.35874 ++#include <stdio.h>
143.35875 ++#include <stdlib.h>
143.35876 ++
143.35877 ++#include <X11/Xutil.h> /* for XDestroyImage */
143.35878 ++#include <pixman.h> /* for pixman blt functions */
143.35879 ++
143.35880 ++#include "test.h"
143.35881 ++
143.35882 ++static uint8_t clock_bits[] = {0x3C, 0x5E, 0xEF, 0xF7, 0x87, 0xFF, 0x7E, 0x3C};
143.35883 ++
143.35884 ++/* https://bugs.freedesktop.org/show_bug.cgi?id=91499 */
143.35885 ++static void draw_clock(struct test_display *t, Drawable d,
143.35886 ++		       uint8_t alu, int x, int y, uint32_t fg, uint32_t bg)
143.35887 ++{
143.35888 ++	Pixmap pixmap;
143.35889 ++	XGCValues val;
143.35890 ++	GC gc;
143.35891 ++
143.35892 ++	val.graphics_exposures = 0;
143.35893 ++	val.function = alu;
143.35894 ++	val.foreground = fg;
143.35895 ++	val.background = fg;
143.35896 ++
143.35897 ++	gc = XCreateGC(t->dpy, d,
143.35898 ++		       GCGraphicsExposures | GCForeground | GCBackground | GCFunction,
143.35899 ++		       &val);
143.35900 ++	pixmap = XCreateBitmapFromData(t->dpy, d, (char *)clock_bits, 8, 8);
143.35901 ++
143.35902 ++	XCopyPlane(t->dpy, pixmap, d, gc, 0, 0, 8, 8, x, y, 1);
143.35903 ++
143.35904 ++	XFreePixmap(t->dpy, pixmap);
143.35905 ++	XFreeGC(t->dpy, gc);
143.35906 ++}
143.35907 ++
143.35908 ++static void clear(struct test_display *dpy, struct test_target *tt)
143.35909 ++{
143.35910 ++	XRenderColor render_color = {0};
143.35911 ++	XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
143.35912 ++			     0, 0, tt->width, tt->height);
143.35913 ++}
143.35914 ++
143.35915 ++static void clock_tests(struct test *t, int reps, int sets, enum target target)
143.35916 ++{
143.35917 ++	struct test_target out, ref;
143.35918 ++	int r, s;
143.35919 ++
143.35920 ++	printf("Testing clock (%s): ", test_target_name(target));
143.35921 ++	fflush(stdout);
143.35922 ++
143.35923 ++	test_target_create_render(&t->out, target, &out);
143.35924 ++	clear(&t->out, &out);
143.35925 ++
143.35926 ++	test_target_create_render(&t->ref, target, &ref);
143.35927 ++	clear(&t->ref, &ref);
143.35928 ++
143.35929 ++	for (s = 0; s < sets; s++) {
143.35930 ++		for (r = 0; r < reps; r++) {
143.35931 ++			int x = rand() % (out.width - 8);
143.35932 ++			int y = rand() % (out.height - 8);
143.35933 ++			uint8_t alu = rand() % (GXset + 1);
143.35934 ++			uint32_t bg = rand();
143.35935 ++			uint32_t fg = rand();
143.35936 ++
143.35937 ++			draw_clock(&t->out, out.draw, alu, x, y, fg, bg);
143.35938 ++			draw_clock(&t->ref, ref.draw, alu, x, y, fg, bg);
143.35939 ++		}
143.35940 ++
143.35941 ++		test_compare(t,
143.35942 ++			     out.draw, out.format,
143.35943 ++			     ref.draw, ref.format,
143.35944 ++			     0, 0, out.width, out.height,
143.35945 ++			     "");
143.35946 ++	}
143.35947 ++
143.35948 ++	printf("passed [%d iterations x %d]\n", reps, sets);
143.35949 ++
143.35950 ++	test_target_destroy_render(&t->out, &out);
143.35951 ++	test_target_destroy_render(&t->ref, &ref);
143.35952 ++}
143.35953 ++
143.35954 ++int main(int argc, char **argv)
143.35955 ++{
143.35956 ++	struct test test;
143.35957 ++	int i;
143.35958 ++
143.35959 ++	test_init(&test, argc, argv);
143.35960 ++
143.35961 ++	for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
143.35962 ++		int reps = REPS(i), sets = SETS(i);
143.35963 ++		enum target t;
143.35964 ++
143.35965 ++		for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
143.35966 ++			clock_tests(&test, reps, sets, t);
143.35967 ++		}
143.35968 ++	}
143.35969 ++
143.35970 ++	return 0;
143.35971 ++}
143.35972 +diff --git a/test/dri2-race.c b/test/dri2-race.c
143.35973 +index 8862c84c..ece624f6 100644
143.35974 +--- a/test/dri2-race.c
143.35975 ++++ b/test/dri2-race.c
143.35976 +@@ -5,6 +5,11 @@
143.35977 + #include <X11/Xlib.h>
143.35978 + #include <X11/Xutil.h>
143.35979 + #include <X11/extensions/Xfixes.h>
143.35980 ++#include <X11/extensions/Xcomposite.h>
143.35981 ++#include <X11/Xlib-xcb.h>
143.35982 ++#include <xcb/xcb.h>
143.35983 ++#include <xcb/xcbext.h>
143.35984 ++#include <xcb/dri2.h>
143.35985 + #include <unistd.h>
143.35986 + #include <fcntl.h>
143.35987 + #include <string.h>
143.35988 +@@ -12,11 +17,49 @@
143.35989 + 
143.35990 + #include <xf86drm.h>
143.35991 + #include <drm.h>
143.35992 ++#include <setjmp.h>
143.35993 + 
143.35994 + #include "dri2.h"
143.35995 + 
143.35996 + #define COUNT 60
143.35997 + 
143.35998 ++#define N_DIVISORS 3
143.35999 ++static const int divisors[N_DIVISORS] = { 0, 1, 16 };
143.36000 ++
143.36001 ++static jmp_buf error_handler[4];
143.36002 ++static int have_error_handler;
143.36003 ++
143.36004 ++#define error_get() \
143.36005 ++	setjmp(error_handler[have_error_handler++])
143.36006 ++
143.36007 ++#define error_put() \
143.36008 ++	have_error_handler--
143.36009 ++
143.36010 ++static int (*saved_io_error)(Display *dpy);
143.36011 ++
143.36012 ++static int io_error(Display *dpy)
143.36013 ++{
143.36014 ++	if (have_error_handler)
143.36015 ++		longjmp(error_handler[--have_error_handler], 0);
143.36016 ++
143.36017 ++	return saved_io_error(dpy);
143.36018 ++}
143.36019 ++
143.36020 ++static int x_error(Display *dpy, XErrorEvent *e)
143.36021 ++{
143.36022 ++	return Success;
143.36023 ++}
143.36024 ++
143.36025 ++static uint32_t upper_32_bits(uint64_t val)
143.36026 ++{
143.36027 ++	return val >> 32;
143.36028 ++}
143.36029 ++
143.36030 ++static uint32_t lower_32_bits(uint64_t val)
143.36031 ++{
143.36032 ++	return val & 0xffffffff;
143.36033 ++}
143.36034 ++
143.36035 + static int dri2_open(Display *dpy)
143.36036 + {
143.36037 + 	drm_auth_t auth;
143.36038 +@@ -41,45 +84,701 @@ static int dri2_open(Display *dpy)
143.36039 + 	return fd;
143.36040 + }
143.36041 + 
143.36042 +-static void run(Display *dpy, int width, int height,
143.36043 +-		unsigned int *attachments, int nattachments,
143.36044 +-		const char *name)
143.36045 ++static void swap_buffers(Display *dpy, Window win, int divisor,
143.36046 ++			 unsigned int *attachments, int nattachments)
143.36047 ++{
143.36048 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.36049 ++	unsigned int seq[2];
143.36050 ++
143.36051 ++	seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
143.36052 ++						 0, 0, 0, divisor, 0, 0).sequence;
143.36053 ++
143.36054 ++
143.36055 ++	seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
143.36056 ++						nattachments, nattachments,
143.36057 ++						attachments).sequence;
143.36058 ++
143.36059 ++	xcb_flush(c);
143.36060 ++	xcb_discard_reply(c, seq[0]);
143.36061 ++	xcb_discard_reply(c, seq[1]);
143.36062 ++}
143.36063 ++
143.36064 ++#define COMPOSITE 1
143.36065 ++
143.36066 ++static int has_composite(Display *dpy)
143.36067 ++{
143.36068 ++	Display *dummy = NULL;
143.36069 ++	int event, error;
143.36070 ++	int major = -1, minor = -1;
143.36071 ++
143.36072 ++	if (dpy == NULL)
143.36073 ++		dummy = dpy = XOpenDisplay(NULL);
143.36074 ++
143.36075 ++	if (XCompositeQueryExtension(dpy, &event, &error))
143.36076 ++		XCompositeQueryVersion(dpy, &major, &minor);
143.36077 ++
143.36078 ++	if (dummy)
143.36079 ++		XCloseDisplay(dummy);
143.36080 ++
143.36081 ++	return major > 0 || minor >= 4;
143.36082 ++}
143.36083 ++
143.36084 ++static void race_window(Display *dpy, int width, int height,
143.36085 ++			unsigned int *attachments, int nattachments,
143.36086 ++			unsigned flags, const char *name)
143.36087 + {
143.36088 + 	Window win;
143.36089 + 	XSetWindowAttributes attr;
143.36090 +-	int count, loop;
143.36091 ++	int count, loop, n;
143.36092 + 	DRI2Buffer *buffers;
143.36093 + 
143.36094 ++	if (flags & COMPOSITE && !has_composite(dpy))
143.36095 ++		return;
143.36096 ++
143.36097 ++	printf("%s(%s)\n", __func__, name);
143.36098 ++
143.36099 + 	/* Be nasty and install a fullscreen window on top so that we
143.36100 + 	 * can guarantee we do not get clipped by children.
143.36101 + 	 */
143.36102 + 	attr.override_redirect = 1;
143.36103 +-	loop = 100;
143.36104 +-	do {
143.36105 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36106 ++		loop = 256 >> ffs(divisors[n]);
143.36107 ++		printf("DRI2SwapBuffers(divisor=%d), loop=%d", divisors[n], loop);
143.36108 ++		fflush(stdout);
143.36109 ++		do {
143.36110 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36111 ++					0, 0, width, height, 0,
143.36112 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36113 ++					InputOutput,
143.36114 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36115 ++					CWOverrideRedirect, &attr);
143.36116 ++			if (flags & COMPOSITE)
143.36117 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36118 ++			XMapWindow(dpy, win);
143.36119 ++
143.36120 ++			DRI2CreateDrawable(dpy, win);
143.36121 ++
143.36122 ++			buffers = DRI2GetBuffers(dpy, win, &width, &height,
143.36123 ++					attachments, nattachments, &count);
143.36124 ++			if (count != nattachments)
143.36125 ++				return;
143.36126 ++
143.36127 ++			free(buffers);
143.36128 ++			for (count = 0; count < loop; count++)
143.36129 ++				DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
143.36130 ++			XDestroyWindow(dpy, win);
143.36131 ++			printf("."); fflush(stdout);
143.36132 ++		} while (--loop);
143.36133 ++		printf("*\n");
143.36134 ++	}
143.36135 ++
143.36136 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36137 ++		loop = 256 >> ffs(divisors[n]);
143.36138 ++		printf("xcb_dri2_swap_buffers(divisor=%d), loops=%d", divisors[n], loop);
143.36139 ++		fflush(stdout);
143.36140 ++		do {
143.36141 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36142 ++					0, 0, width, height, 0,
143.36143 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36144 ++					InputOutput,
143.36145 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36146 ++					CWOverrideRedirect, &attr);
143.36147 ++			if (flags & COMPOSITE)
143.36148 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36149 ++			XMapWindow(dpy, win);
143.36150 ++
143.36151 ++			DRI2CreateDrawable(dpy, win);
143.36152 ++
143.36153 ++			buffers = DRI2GetBuffers(dpy, win, &width, &height,
143.36154 ++					attachments, nattachments, &count);
143.36155 ++			if (count != nattachments)
143.36156 ++				return;
143.36157 ++
143.36158 ++			free(buffers);
143.36159 ++			for (count = 0; count < loop; count++)
143.36160 ++				swap_buffers(dpy, win, divisors[n], attachments, nattachments);
143.36161 ++			XDestroyWindow(dpy, win);
143.36162 ++			printf("."); fflush(stdout);
143.36163 ++		} while (--loop);
143.36164 ++		printf("*\n");
143.36165 ++	}
143.36166 ++
143.36167 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36168 ++		loop = 256 >> ffs(divisors[n]);
143.36169 ++		printf("DRI2WaitMsc(divisor=%d), loop=%d", divisors[n], loop);
143.36170 ++		fflush(stdout);
143.36171 ++		do {
143.36172 ++			uint64_t ignore, msc;
143.36173 ++			xcb_connection_t *c = XGetXCBConnection(dpy);
143.36174 ++
143.36175 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36176 ++					0, 0, width, height, 0,
143.36177 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36178 ++					InputOutput,
143.36179 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36180 ++					CWOverrideRedirect, &attr);
143.36181 ++			if (flags & COMPOSITE)
143.36182 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36183 ++			XMapWindow(dpy, win);
143.36184 ++
143.36185 ++			DRI2CreateDrawable(dpy, win);
143.36186 ++			DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
143.36187 ++			msc++;
143.36188 ++			for (count = 0; count < loop; count++) {
143.36189 ++				xcb_discard_reply(c,
143.36190 ++						xcb_dri2_wait_msc(c, win,
143.36191 ++							upper_32_bits(msc),
143.36192 ++							lower_32_bits(msc),
143.36193 ++							0, 0, 0, 0).sequence);
143.36194 ++				msc += divisors[n];
143.36195 ++			}
143.36196 ++			XFlush(dpy);
143.36197 ++			XDestroyWindow(dpy, win);
143.36198 ++			printf("."); fflush(stdout);
143.36199 ++		} while (--loop);
143.36200 ++		printf("*\n");
143.36201 ++	}
143.36202 ++
143.36203 ++	XSync(dpy, 1);
143.36204 ++	sleep(2);
143.36205 ++	XSync(dpy, 1);
143.36206 ++}
143.36207 ++
143.36208 ++static int rand_size(int max)
143.36209 ++{
143.36210 ++	return 1 + (rand() % (max - 1));
143.36211 ++}
143.36212 ++
143.36213 ++static void race_resize(Display *dpy, int width, int height,
143.36214 ++			unsigned int *attachments, int nattachments,
143.36215 ++			unsigned flags, const char *name)
143.36216 ++{
143.36217 ++	Window win;
143.36218 ++	XSetWindowAttributes attr;
143.36219 ++	int count, loop, n;
143.36220 ++	DRI2Buffer *buffers;
143.36221 ++
143.36222 ++	if (flags & COMPOSITE && !has_composite(dpy))
143.36223 ++		return;
143.36224 ++
143.36225 ++	printf("%s(%s)\n", __func__, name);
143.36226 ++
143.36227 ++	attr.override_redirect = 1;
143.36228 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36229 ++		win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36230 ++				    0, 0, width, height, 0,
143.36231 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
143.36232 ++				    InputOutput,
143.36233 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
143.36234 ++				    CWOverrideRedirect, &attr);
143.36235 ++		if (flags & COMPOSITE)
143.36236 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36237 ++		XMapWindow(dpy, win);
143.36238 ++
143.36239 ++		DRI2CreateDrawable(dpy, win);
143.36240 ++
143.36241 ++		loop = 256 >> ffs(divisors[n]);
143.36242 ++		printf("DRI2SwapBuffers(divisor=%d), loop=%d", divisors[n], loop);
143.36243 ++		fflush(stdout);
143.36244 ++		do {
143.36245 ++			int w, h;
143.36246 ++
143.36247 ++			buffers = DRI2GetBuffers(dpy, win, &w, &h,
143.36248 ++					attachments, nattachments, &count);
143.36249 ++			if (count != nattachments)
143.36250 ++				return;
143.36251 ++
143.36252 ++			free(buffers);
143.36253 ++			for (count = 0; count < loop; count++)
143.36254 ++				DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
143.36255 ++			XResizeWindow(dpy, win, rand_size(width), rand_size(height));
143.36256 ++			printf("."); fflush(stdout);
143.36257 ++		} while (--loop);
143.36258 ++		XDestroyWindow(dpy, win);
143.36259 ++		XSync(dpy, True);
143.36260 ++		printf("*\n");
143.36261 ++	}
143.36262 ++
143.36263 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36264 + 		win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36265 + 				    0, 0, width, height, 0,
143.36266 + 				    DefaultDepth(dpy, DefaultScreen(dpy)),
143.36267 + 				    InputOutput,
143.36268 + 				    DefaultVisual(dpy, DefaultScreen(dpy)),
143.36269 + 				    CWOverrideRedirect, &attr);
143.36270 ++		if (flags & COMPOSITE)
143.36271 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36272 + 		XMapWindow(dpy, win);
143.36273 + 
143.36274 + 		DRI2CreateDrawable(dpy, win);
143.36275 + 
143.36276 +-		buffers = DRI2GetBuffers(dpy, win, &width, &height,
143.36277 +-					 attachments, nattachments, &count);
143.36278 +-		if (count != nattachments)
143.36279 +-			return;
143.36280 ++		loop = 256 >> ffs(divisors[n]);
143.36281 ++		printf("xcb_dri2_swap_buffers(divisor=%d), loops=%d", divisors[n], loop);
143.36282 ++		fflush(stdout);
143.36283 ++		do {
143.36284 ++			int w, h;
143.36285 ++
143.36286 ++			buffers = DRI2GetBuffers(dpy, win, &w, &h,
143.36287 ++					attachments, nattachments, &count);
143.36288 ++			if (count != nattachments)
143.36289 ++				return;
143.36290 + 
143.36291 +-		free(buffers);
143.36292 +-		for (count = 0; count < loop; count++)
143.36293 +-			DRI2SwapBuffers(dpy, win, 0, 0, 0);
143.36294 ++			free(buffers);
143.36295 ++			for (count = 0; count < loop; count++)
143.36296 ++				swap_buffers(dpy, win, divisors[n], attachments, nattachments);
143.36297 ++			XResizeWindow(dpy, win, rand_size(width), rand_size(height));
143.36298 ++			printf("."); fflush(stdout);
143.36299 ++		} while (--loop);
143.36300 + 		XDestroyWindow(dpy, win);
143.36301 +-	} while (--loop);
143.36302 ++		XSync(dpy, True);
143.36303 ++		printf("*\n");
143.36304 ++	}
143.36305 ++
143.36306 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36307 ++		win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36308 ++				    0, 0, width, height, 0,
143.36309 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
143.36310 ++				    InputOutput,
143.36311 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
143.36312 ++				    CWOverrideRedirect, &attr);
143.36313 ++		if (flags & COMPOSITE)
143.36314 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36315 ++		XMapWindow(dpy, win);
143.36316 ++
143.36317 ++		DRI2CreateDrawable(dpy, win);
143.36318 ++
143.36319 ++		loop = 256 >> ffs(divisors[n]);
143.36320 ++		printf("DRI2WaitMsc(divisor=%d), loop=%d", divisors[n], loop);
143.36321 ++		fflush(stdout);
143.36322 ++		do {
143.36323 ++			uint64_t ignore, msc;
143.36324 ++			xcb_connection_t *c = XGetXCBConnection(dpy);
143.36325 ++
143.36326 ++			DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
143.36327 ++			msc++;
143.36328 ++			for (count = 0; count < loop; count++) {
143.36329 ++				xcb_discard_reply(c,
143.36330 ++						xcb_dri2_wait_msc(c, win,
143.36331 ++							upper_32_bits(msc),
143.36332 ++							lower_32_bits(msc),
143.36333 ++							0, 0, 0, 0).sequence);
143.36334 ++				msc += divisors[n];
143.36335 ++			}
143.36336 ++			XFlush(dpy);
143.36337 ++			XResizeWindow(dpy, win, rand_size(width), rand_size(height));
143.36338 ++			printf("."); fflush(stdout);
143.36339 ++		} while (--loop);
143.36340 ++		XDestroyWindow(dpy, win);
143.36341 ++		XSync(dpy, True);
143.36342 ++		printf("*\n");
143.36343 ++	}
143.36344 ++
143.36345 ++	XSync(dpy, 1);
143.36346 ++	sleep(2);
143.36347 ++	XSync(dpy, 1);
143.36348 ++}
143.36349 ++
143.36350 ++static void race_manager(Display *dpy, int width, int height,
143.36351 ++			 unsigned int *attachments, int nattachments,
143.36352 ++			 unsigned flags, const char *name)
143.36353 ++{
143.36354 ++	Display *mgr = XOpenDisplay(NULL);
143.36355 ++	Window win;
143.36356 ++	XSetWindowAttributes attr;
143.36357 ++	int count, loop, n;
143.36358 ++	DRI2Buffer *buffers;
143.36359 ++
143.36360 ++	if (flags & COMPOSITE && !has_composite(dpy))
143.36361 ++		return;
143.36362 ++
143.36363 ++	printf("%s(%s)\n", __func__, name);
143.36364 ++
143.36365 ++	/* Be nasty and install a fullscreen window on top so that we
143.36366 ++	 * can guarantee we do not get clipped by children.
143.36367 ++	 */
143.36368 ++	attr.override_redirect = 1;
143.36369 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36370 ++		printf("DRI2SwapBuffers(divisor=%d)", divisors[n]);
143.36371 ++		fflush(stdout);
143.36372 ++		loop = 256 >> ffs(divisors[n]);
143.36373 ++		do {
143.36374 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36375 ++					0, 0, width, height, 0,
143.36376 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36377 ++					InputOutput,
143.36378 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36379 ++					CWOverrideRedirect, &attr);
143.36380 ++			if (flags & COMPOSITE)
143.36381 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36382 ++			XMapWindow(dpy, win);
143.36383 ++
143.36384 ++			DRI2CreateDrawable(dpy, win);
143.36385 ++
143.36386 ++			buffers = DRI2GetBuffers(dpy, win, &width, &height,
143.36387 ++					attachments, nattachments, &count);
143.36388 ++			if (count != nattachments)
143.36389 ++				return;
143.36390 ++
143.36391 ++			free(buffers);
143.36392 ++			for (count = 0; count < loop; count++)
143.36393 ++				DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
143.36394 ++			XFlush(dpy);
143.36395 ++			XDestroyWindow(mgr, win);
143.36396 ++			XFlush(mgr);
143.36397 ++			printf("."); fflush(stdout);
143.36398 ++		} while (--loop);
143.36399 ++		printf("*\n");
143.36400 ++	}
143.36401 ++
143.36402 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36403 ++		printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]);
143.36404 ++		fflush(stdout);
143.36405 ++		loop = 256 >> ffs(divisors[n]);
143.36406 ++		do {
143.36407 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36408 ++					0, 0, width, height, 0,
143.36409 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36410 ++					InputOutput,
143.36411 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36412 ++					CWOverrideRedirect, &attr);
143.36413 ++			if (flags & COMPOSITE)
143.36414 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36415 ++			XMapWindow(dpy, win);
143.36416 ++
143.36417 ++			DRI2CreateDrawable(dpy, win);
143.36418 ++
143.36419 ++			buffers = DRI2GetBuffers(dpy, win, &width, &height,
143.36420 ++					attachments, nattachments, &count);
143.36421 ++			if (count != nattachments)
143.36422 ++				return;
143.36423 ++
143.36424 ++			free(buffers);
143.36425 ++			for (count = 0; count < loop; count++)
143.36426 ++				swap_buffers(dpy, win, divisors[n], attachments, nattachments);
143.36427 ++			XFlush(dpy);
143.36428 ++			XDestroyWindow(mgr, win);
143.36429 ++			XFlush(mgr);
143.36430 ++			printf("."); fflush(stdout);
143.36431 ++		} while (--loop);
143.36432 ++		printf("*\n");
143.36433 ++	}
143.36434 ++
143.36435 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36436 ++		printf("DRI2WaitMsc(divisor=%d)", divisors[n]);
143.36437 ++		fflush(stdout);
143.36438 ++		loop = 256 >> ffs(divisors[n]);
143.36439 ++		do {
143.36440 ++			uint64_t ignore, msc;
143.36441 ++			xcb_connection_t *c = XGetXCBConnection(dpy);
143.36442 ++
143.36443 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36444 ++					0, 0, width, height, 0,
143.36445 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36446 ++					InputOutput,
143.36447 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36448 ++					CWOverrideRedirect, &attr);
143.36449 ++			if (flags & COMPOSITE)
143.36450 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36451 ++			XMapWindow(dpy, win);
143.36452 ++
143.36453 ++			DRI2CreateDrawable(dpy, win);
143.36454 ++			DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
143.36455 ++			msc++;
143.36456 ++			for (count = 0; count < loop; count++) {
143.36457 ++				xcb_discard_reply(c,
143.36458 ++						xcb_dri2_wait_msc(c, win,
143.36459 ++							upper_32_bits(msc),
143.36460 ++							lower_32_bits(msc),
143.36461 ++							0, 0, 0, 0).sequence);
143.36462 ++				msc += divisors[n];
143.36463 ++			}
143.36464 ++			XFlush(dpy);
143.36465 ++			XDestroyWindow(mgr, win);
143.36466 ++			XFlush(mgr);
143.36467 ++			printf("."); fflush(stdout);
143.36468 ++		} while (--loop);
143.36469 ++		printf("*\n");
143.36470 ++	}
143.36471 + 
143.36472 + 	XSync(dpy, 1);
143.36473 ++	XSync(mgr, 1);
143.36474 + 	sleep(2);
143.36475 + 	XSync(dpy, 1);
143.36476 ++	XSync(mgr, 1);
143.36477 ++
143.36478 ++	XCloseDisplay(mgr);
143.36479 ++}
143.36480 ++
143.36481 ++static void race_close(int width, int height,
143.36482 ++		       unsigned int *attachments, int nattachments,
143.36483 ++		       unsigned flags, const char *name)
143.36484 ++{
143.36485 ++	XSetWindowAttributes attr;
143.36486 ++	int count, loop, n;
143.36487 ++
143.36488 ++	if (flags & COMPOSITE && !has_composite(NULL))
143.36489 ++		return;
143.36490 ++
143.36491 ++	printf("%s(%s)\n", __func__, name);
143.36492 ++
143.36493 ++	/* Be nasty and install a fullscreen window on top so that we
143.36494 ++	 * can guarantee we do not get clipped by children.
143.36495 ++	 */
143.36496 ++	attr.override_redirect = 1;
143.36497 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36498 ++		printf("DRI2SwapBuffers(divisor=%d)", divisors[n]);
143.36499 ++		fflush(stdout);
143.36500 ++		loop = 256 >> ffs(divisors[n]);
143.36501 ++		do {
143.36502 ++			Display *dpy = XOpenDisplay(NULL);
143.36503 ++			Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36504 ++					0, 0, width, height, 0,
143.36505 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36506 ++					InputOutput,
143.36507 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36508 ++					CWOverrideRedirect, &attr);
143.36509 ++			if (flags & COMPOSITE)
143.36510 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36511 ++			XMapWindow(dpy, win);
143.36512 ++
143.36513 ++			DRI2CreateDrawable(dpy, win);
143.36514 ++			free(DRI2GetBuffers(dpy, win, &width, &height,
143.36515 ++						attachments, nattachments, &count));
143.36516 ++			if (count != nattachments)
143.36517 ++				return;
143.36518 ++
143.36519 ++			for (count = 0; count < loop; count++)
143.36520 ++				DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
143.36521 ++			XCloseDisplay(dpy);
143.36522 ++			printf("."); fflush(stdout);
143.36523 ++		} while (--loop);
143.36524 ++		printf("*\n");
143.36525 ++	}
143.36526 ++
143.36527 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36528 ++		printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]);
143.36529 ++		fflush(stdout);
143.36530 ++		loop = 256 >> ffs(divisors[n]);
143.36531 ++		do {
143.36532 ++			Display *dpy = XOpenDisplay(NULL);
143.36533 ++			Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36534 ++					0, 0, width, height, 0,
143.36535 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36536 ++					InputOutput,
143.36537 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36538 ++					CWOverrideRedirect, &attr);
143.36539 ++			if (flags & COMPOSITE)
143.36540 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36541 ++			XMapWindow(dpy, win);
143.36542 ++
143.36543 ++			DRI2CreateDrawable(dpy, win);
143.36544 ++			free(DRI2GetBuffers(dpy, win, &width, &height,
143.36545 ++						attachments, nattachments, &count));
143.36546 ++			if (count != nattachments)
143.36547 ++				return;
143.36548 ++
143.36549 ++			for (count = 0; count < loop; count++)
143.36550 ++				swap_buffers(dpy, win, divisors[n], attachments, nattachments);
143.36551 ++			XCloseDisplay(dpy);
143.36552 ++			printf("."); fflush(stdout);
143.36553 ++		} while (--loop);
143.36554 ++		printf("*\n");
143.36555 ++	}
143.36556 ++
143.36557 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36558 ++		printf("DRI2WaitMsc(divisor=%d)", divisors[n]);
143.36559 ++		fflush(stdout);
143.36560 ++		loop = 256 >> ffs(divisors[n]);
143.36561 ++		do {
143.36562 ++			uint64_t ignore, msc;
143.36563 ++			Display *dpy = XOpenDisplay(NULL);
143.36564 ++			xcb_connection_t *c = XGetXCBConnection(dpy);
143.36565 ++			Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36566 ++					0, 0, width, height, 0,
143.36567 ++					DefaultDepth(dpy, DefaultScreen(dpy)),
143.36568 ++					InputOutput,
143.36569 ++					DefaultVisual(dpy, DefaultScreen(dpy)),
143.36570 ++					CWOverrideRedirect, &attr);
143.36571 ++			if (flags & COMPOSITE)
143.36572 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36573 ++			XMapWindow(dpy, win);
143.36574 ++
143.36575 ++			DRI2CreateDrawable(dpy, win);
143.36576 ++			DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
143.36577 ++			msc++;
143.36578 ++			for (count = 0; count < loop; count++) {
143.36579 ++				xcb_discard_reply(c,
143.36580 ++						xcb_dri2_wait_msc(c, win,
143.36581 ++							upper_32_bits(msc),
143.36582 ++							lower_32_bits(msc),
143.36583 ++							0, 0, 0, 0).sequence);
143.36584 ++				msc += divisors[n];
143.36585 ++			}
143.36586 ++			XFlush(dpy);
143.36587 ++			XCloseDisplay(dpy);
143.36588 ++			printf("."); fflush(stdout);
143.36589 ++		} while (--loop);
143.36590 ++		printf("*\n");
143.36591 ++	}
143.36592 ++}
143.36593 ++
143.36594 ++static void race_client(int width, int height,
143.36595 ++			unsigned int *attachments, int nattachments,
143.36596 ++			unsigned flags, const char *name)
143.36597 ++{
143.36598 ++	Display *mgr = XOpenDisplay(NULL);
143.36599 ++	XSetWindowAttributes attr;
143.36600 ++	int count, loop, n;
143.36601 ++
143.36602 ++	if (flags & COMPOSITE && !has_composite(NULL))
143.36603 ++		return;
143.36604 ++
143.36605 ++	printf("%s(%s)\n", __func__, name);
143.36606 ++
143.36607 ++	/* Be nasty and install a fullscreen window on top so that we
143.36608 ++	 * can guarantee we do not get clipped by children.
143.36609 ++	 */
143.36610 ++	attr.override_redirect = 1;
143.36611 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36612 ++		printf("DRI2SwapBuffers(divisor=%d)", divisors[n]);
143.36613 ++		fflush(stdout);
143.36614 ++		loop = 256 >> ffs(divisors[n]);
143.36615 ++		do {
143.36616 ++			Display *dpy = XOpenDisplay(NULL);
143.36617 ++			Window win;
143.36618 ++
143.36619 ++			if (error_get()) {
143.36620 ++				XCloseDisplay(dpy);
143.36621 ++				printf("+"); fflush(stdout);
143.36622 ++				continue;
143.36623 ++			}
143.36624 ++
143.36625 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36626 ++					    0, 0, width, height, 0,
143.36627 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.36628 ++					    InputOutput,
143.36629 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.36630 ++					    CWOverrideRedirect, &attr);
143.36631 ++			if (flags & COMPOSITE)
143.36632 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36633 ++			XMapWindow(dpy, win);
143.36634 ++
143.36635 ++			DRI2CreateDrawable(dpy, win);
143.36636 ++			free(DRI2GetBuffers(dpy, win, &width, &height,
143.36637 ++					    attachments, nattachments, &count));
143.36638 ++			if (count == nattachments) {
143.36639 ++				for (count = 0; count < loop; count++)
143.36640 ++					DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
143.36641 ++			}
143.36642 ++
143.36643 ++			XFlush(dpy);
143.36644 ++			XKillClient(mgr, win);
143.36645 ++			XFlush(mgr);
143.36646 ++
143.36647 ++			XCloseDisplay(dpy);
143.36648 ++			printf("."); fflush(stdout);
143.36649 ++
143.36650 ++			error_put();
143.36651 ++		} while (--loop);
143.36652 ++		printf("*\n");
143.36653 ++	}
143.36654 ++
143.36655 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36656 ++		printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]);
143.36657 ++		fflush(stdout);
143.36658 ++		loop = 256 >> ffs(divisors[n]);
143.36659 ++		do {
143.36660 ++			Display *dpy = XOpenDisplay(NULL);
143.36661 ++			Window win;
143.36662 ++
143.36663 ++			if (error_get()) {
143.36664 ++				XCloseDisplay(dpy);
143.36665 ++				printf("+"); fflush(stdout);
143.36666 ++				continue;
143.36667 ++			}
143.36668 ++
143.36669 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36670 ++					    0, 0, width, height, 0,
143.36671 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.36672 ++					    InputOutput,
143.36673 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.36674 ++					    CWOverrideRedirect, &attr);
143.36675 ++			if (flags & COMPOSITE)
143.36676 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36677 ++			XMapWindow(dpy, win);
143.36678 ++
143.36679 ++			DRI2CreateDrawable(dpy, win);
143.36680 ++			free(DRI2GetBuffers(dpy, win, &width, &height,
143.36681 ++					    attachments, nattachments, &count));
143.36682 ++			if (count == nattachments) {
143.36683 ++				for (count = 0; count < loop; count++)
143.36684 ++					swap_buffers(dpy, win, divisors[n], attachments, nattachments);
143.36685 ++			}
143.36686 ++
143.36687 ++			XFlush(dpy);
143.36688 ++			XKillClient(mgr, win);
143.36689 ++			XFlush(mgr);
143.36690 ++
143.36691 ++			XCloseDisplay(dpy);
143.36692 ++			printf("."); fflush(stdout);
143.36693 ++
143.36694 ++			error_put();
143.36695 ++		} while (--loop);
143.36696 ++		printf("*\n");
143.36697 ++	}
143.36698 ++
143.36699 ++	for (n = 0; n < N_DIVISORS; n++) {
143.36700 ++		printf("DRI2WaitMsc(divisor=%d)", divisors[n]);
143.36701 ++		fflush(stdout);
143.36702 ++		loop = 256 >> ffs(divisors[n]);
143.36703 ++		do {
143.36704 ++			Display *dpy = XOpenDisplay(NULL);
143.36705 ++			uint64_t ignore, msc;
143.36706 ++			xcb_connection_t *c;
143.36707 ++			Window win;
143.36708 ++
143.36709 ++			if (error_get()) {
143.36710 ++				XCloseDisplay(dpy);
143.36711 ++				printf("+"); fflush(stdout);
143.36712 ++				continue;
143.36713 ++			}
143.36714 ++
143.36715 ++			win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.36716 ++					    0, 0, width, height, 0,
143.36717 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.36718 ++					    InputOutput,
143.36719 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.36720 ++					    CWOverrideRedirect, &attr);
143.36721 ++			if (flags & COMPOSITE)
143.36722 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.36723 ++			XMapWindow(dpy, win);
143.36724 ++
143.36725 ++			DRI2CreateDrawable(dpy, win);
143.36726 ++			DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
143.36727 ++			c = XGetXCBConnection(dpy);
143.36728 ++			msc++;
143.36729 ++			for (count = 0; count < loop; count++) {
143.36730 ++				xcb_discard_reply(c,
143.36731 ++						  xcb_dri2_wait_msc(c, win,
143.36732 ++								    upper_32_bits(msc),
143.36733 ++								    lower_32_bits(msc),
143.36734 ++								    0, 0, 0, 0).sequence);
143.36735 ++				msc += divisors[n];
143.36736 ++			}
143.36737 ++
143.36738 ++			XFlush(dpy);
143.36739 ++			XKillClient(mgr, win);
143.36740 ++			XFlush(mgr);
143.36741 ++
143.36742 ++			XCloseDisplay(dpy);
143.36743 ++			printf("."); fflush(stdout);
143.36744 ++
143.36745 ++			error_put();
143.36746 ++		} while (--loop);
143.36747 ++		printf("*\n");
143.36748 ++	}
143.36749 ++
143.36750 ++	XCloseDisplay(mgr);
143.36751 + }
143.36752 + 
143.36753 + int main(void)
143.36754 +@@ -91,7 +790,10 @@ int main(void)
143.36755 + 		DRI2BufferFrontLeft,
143.36756 + 	};
143.36757 + 
143.36758 +-	dpy = XOpenDisplay (NULL);
143.36759 ++	saved_io_error = XSetIOErrorHandler(io_error);
143.36760 ++	XSetErrorHandler(x_error);
143.36761 ++
143.36762 ++	dpy = XOpenDisplay(NULL);
143.36763 + 	if (dpy == NULL)
143.36764 + 		return 77;
143.36765 + 
143.36766 +@@ -101,13 +803,52 @@ int main(void)
143.36767 + 
143.36768 + 	width = WidthOfScreen(DefaultScreenOfDisplay(dpy));
143.36769 + 	height = HeightOfScreen(DefaultScreenOfDisplay(dpy));
143.36770 +-	run(dpy, width, height, attachments, 1, "fullscreen");
143.36771 +-	run(dpy, width, height, attachments, 2, "fullscreen (with front)");
143.36772 ++	race_window(dpy, width, height, attachments, 1, 0, "fullscreen");
143.36773 ++	race_window(dpy, width, height, attachments, 1, COMPOSITE, "composite fullscreen");
143.36774 ++	race_window(dpy, width, height, attachments, 2, 0, "fullscreen (with front)");
143.36775 ++	race_window(dpy, width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
143.36776 ++
143.36777 ++	race_resize(dpy, width, height, attachments, 1, 0, "");
143.36778 ++	race_resize(dpy, width, height, attachments, 1, COMPOSITE, "composite");
143.36779 ++	race_resize(dpy, width, height, attachments, 2, 0, "with front");
143.36780 ++	race_resize(dpy, width, height, attachments, 2, COMPOSITE, "composite with front");
143.36781 ++
143.36782 ++	race_manager(dpy, width, height, attachments, 1, 0, "fullscreen");
143.36783 ++	race_manager(dpy, width, height, attachments, 1, COMPOSITE, "composite fullscreen");
143.36784 ++	race_manager(dpy, width, height, attachments, 2, 0, "fullscreen (with front)");
143.36785 ++	race_manager(dpy, width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
143.36786 ++
143.36787 ++	race_close(width, height, attachments, 1, 0, "fullscreen");
143.36788 ++	race_close(width, height, attachments, 1, COMPOSITE, "composite fullscreen");
143.36789 ++	race_close(width, height, attachments, 2, 0, "fullscreen (with front)");
143.36790 ++	race_close(width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
143.36791 ++
143.36792 ++	race_client(width, height, attachments, 1, 0, "fullscreen");
143.36793 ++	race_client(width, height, attachments, 1, COMPOSITE, "composite fullscreen");
143.36794 ++	race_client(width, height, attachments, 2, 0, "fullscreen (with front)");
143.36795 ++	race_client(width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
143.36796 + 
143.36797 + 	width /= 2;
143.36798 + 	height /= 2;
143.36799 +-	run(dpy, width, height, attachments, 1, "windowed");
143.36800 +-	run(dpy, width, height, attachments, 2, "windowed (with front)");
143.36801 ++	race_window(dpy, width, height, attachments, 1, 0, "windowed");
143.36802 ++	race_window(dpy, width, height, attachments, 1, COMPOSITE, "composite windowed");
143.36803 ++	race_window(dpy, width, height, attachments, 2, 0, "windowed (with front)");
143.36804 ++	race_window(dpy, width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
143.36805 ++
143.36806 ++	race_manager(dpy, width, height, attachments, 1, 0, "windowed");
143.36807 ++	race_manager(dpy, width, height, attachments, 1, COMPOSITE, "composite windowed");
143.36808 ++	race_manager(dpy, width, height, attachments, 2, 0, "windowed (with front)");
143.36809 ++	race_manager(dpy, width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
143.36810 ++
143.36811 ++	race_close(width, height, attachments, 1, 0, "windowed");
143.36812 ++	race_close(width, height, attachments, 1, COMPOSITE, "composite windowed");
143.36813 ++	race_close(width, height, attachments, 2, 0, "windowed (with front)");
143.36814 ++	race_close(width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
143.36815 ++
143.36816 ++	race_client(width, height, attachments, 1, 0, "windowed");
143.36817 ++	race_client(width, height, attachments, 1, COMPOSITE, "composite windowed");
143.36818 ++	race_client(width, height, attachments, 2, 0, "windowed (with front)");
143.36819 ++	race_client(width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
143.36820 + 
143.36821 + 	return 0;
143.36822 + }
143.36823 +diff --git a/test/dri2-speed.c b/test/dri2-speed.c
143.36824 +new file mode 100644
143.36825 +index 00000000..87b9d0b6
143.36826 +--- /dev/null
143.36827 ++++ b/test/dri2-speed.c
143.36828 +@@ -0,0 +1,342 @@
143.36829 ++/*
143.36830 ++ * Copyright (c) 2015 Intel Corporation
143.36831 ++ *
143.36832 ++ * Permission is hereby granted, free of charge, to any person obtaining a
143.36833 ++ * copy of this software and associated documentation files (the "Software"),
143.36834 ++ * to deal in the Software without restriction, including without limitation
143.36835 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
143.36836 ++ * and/or sell copies of the Software, and to permit persons to whom the
143.36837 ++ * Software is furnished to do so, subject to the following conditions:
143.36838 ++ *
143.36839 ++ * The above copyright notice and this permission notice (including the next
143.36840 ++ * paragraph) shall be included in all copies or substantial portions of the
143.36841 ++ * Software.
143.36842 ++ *
143.36843 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
143.36844 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
143.36845 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
143.36846 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143.36847 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
143.36848 ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
143.36849 ++ * SOFTWARE.
143.36850 ++ *
143.36851 ++ */
143.36852 ++
143.36853 ++#ifdef HAVE_CONFIG_H
143.36854 ++#include "config.h"
143.36855 ++#endif
143.36856 ++
143.36857 ++#include <X11/Xlib.h>
143.36858 ++#include <X11/Xatom.h>
143.36859 ++#include <X11/Xlib-xcb.h>
143.36860 ++#include <X11/Xutil.h>
143.36861 ++#include <X11/Xlibint.h>
143.36862 ++#include <X11/extensions/dpms.h>
143.36863 ++#include <X11/extensions/randr.h>
143.36864 ++#include <X11/extensions/Xcomposite.h>
143.36865 ++#include <X11/extensions/Xdamage.h>
143.36866 ++#include <X11/extensions/Xrandr.h>
143.36867 ++#include <xcb/xcb.h>
143.36868 ++#include <xcb/dri2.h>
143.36869 ++#include <xf86drm.h>
143.36870 ++
143.36871 ++#include <stdio.h>
143.36872 ++#include <string.h>
143.36873 ++#include <fcntl.h>
143.36874 ++#include <unistd.h>
143.36875 ++#include <assert.h>
143.36876 ++#include <errno.h>
143.36877 ++#include <setjmp.h>
143.36878 ++#include <signal.h>
143.36879 ++
143.36880 ++#include "dri2.h"
143.36881 ++
143.36882 ++static int _x_error_occurred;
143.36883 ++
143.36884 ++static int
143.36885 ++_check_error_handler(Display     *display,
143.36886 ++		     XErrorEvent *event)
143.36887 ++{
143.36888 ++	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
143.36889 ++	       DisplayString(display),
143.36890 ++	       event->serial,
143.36891 ++	       event->error_code,
143.36892 ++	       event->request_code,
143.36893 ++	       event->minor_code);
143.36894 ++	_x_error_occurred++;
143.36895 ++	return False; /* ignored */
143.36896 ++}
143.36897 ++
143.36898 ++static double elapsed(const struct timespec *start,
143.36899 ++		      const struct timespec *end)
143.36900 ++{
143.36901 ++	return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
143.36902 ++}
143.36903 ++
143.36904 ++static void run(Display *dpy, Window win, const char *name)
143.36905 ++{
143.36906 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.36907 ++	struct timespec start, end;
143.36908 ++	int n, completed = 0;
143.36909 ++
143.36910 ++	_x_error_occurred = 0;
143.36911 ++
143.36912 ++	clock_gettime(CLOCK_MONOTONIC, &start);
143.36913 ++	do {
143.36914 ++		for (n = 0; n < 1000; n++) {
143.36915 ++			unsigned int attachments[] = { DRI2BufferBackLeft };
143.36916 ++			unsigned int seq[2];
143.36917 ++
143.36918 ++			seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
143.36919 ++								 0, 0, 0, 0, 0, 0).sequence;
143.36920 ++
143.36921 ++
143.36922 ++			seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
143.36923 ++								1, 1, attachments).sequence;
143.36924 ++
143.36925 ++			xcb_flush(c);
143.36926 ++			xcb_discard_reply(c, seq[0]);
143.36927 ++			xcb_discard_reply(c, seq[1]);
143.36928 ++			completed++;
143.36929 ++		}
143.36930 ++		clock_gettime(CLOCK_MONOTONIC, &end);
143.36931 ++	} while (end.tv_sec < start.tv_sec + 10);
143.36932 ++
143.36933 ++	XSync(dpy, True);
143.36934 ++	if (_x_error_occurred)
143.36935 ++		abort();
143.36936 ++
143.36937 ++	printf("%s: Completed %d swaps in %.1fs, %.3fus each (%.1f FPS)\n",
143.36938 ++	       name, completed, elapsed(&start, &end) / 1000000,
143.36939 ++	       elapsed(&start, &end) / completed,
143.36940 ++	       completed / (elapsed(&start, &end) / 1000000));
143.36941 ++}
143.36942 ++
143.36943 ++static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
143.36944 ++{
143.36945 ++	XRRScreenResources *res;
143.36946 ++
143.36947 ++	res = XRRGetScreenResourcesCurrent(dpy, window);
143.36948 ++	if (res == NULL)
143.36949 ++		res = XRRGetScreenResources(dpy, window);
143.36950 ++
143.36951 ++	return res;
143.36952 ++}
143.36953 ++
143.36954 ++static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
143.36955 ++{
143.36956 ++	int i;
143.36957 ++
143.36958 ++	for (i = 0; i < res->nmode; i++) {
143.36959 ++		if (res->modes[i].id == id)
143.36960 ++			return &res->modes[i];
143.36961 ++	}
143.36962 ++
143.36963 ++	return NULL;
143.36964 ++}
143.36965 ++
143.36966 ++static int dri2_open(Display *dpy)
143.36967 ++{
143.36968 ++	drm_auth_t auth;
143.36969 ++	char *driver, *device;
143.36970 ++	int fd;
143.36971 ++
143.36972 ++	if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
143.36973 ++		return -1;
143.36974 ++
143.36975 ++	printf ("Connecting to %s driver on %s\n", driver, device);
143.36976 ++
143.36977 ++	fd = open(device, O_RDWR);
143.36978 ++	if (fd < 0)
143.36979 ++		return -1;
143.36980 ++
143.36981 ++	if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
143.36982 ++		return -1;
143.36983 ++
143.36984 ++	if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
143.36985 ++		return -1;
143.36986 ++
143.36987 ++	return fd;
143.36988 ++}
143.36989 ++
143.36990 ++static void fullscreen(Display *dpy, Window win)
143.36991 ++{
143.36992 ++	Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
143.36993 ++	XChangeProperty(dpy, win,
143.36994 ++			XInternAtom(dpy, "_NET_WM_STATE", False),
143.36995 ++			XA_ATOM, 32, PropModeReplace,
143.36996 ++			(unsigned char *)&atom, 1);
143.36997 ++}
143.36998 ++
143.36999 ++static int has_composite(Display *dpy)
143.37000 ++{
143.37001 ++	int event, error;
143.37002 ++	int major, minor;
143.37003 ++
143.37004 ++	if (!XDamageQueryExtension (dpy, &event, &error))
143.37005 ++		return 0;
143.37006 ++
143.37007 ++	if (!XCompositeQueryExtension(dpy, &event, &error))
143.37008 ++		return 0;
143.37009 ++
143.37010 ++	XCompositeQueryVersion(dpy, &major, &minor);
143.37011 ++
143.37012 ++	return major > 0 || minor >= 4;
143.37013 ++}
143.37014 ++
143.37015 ++int main(void)
143.37016 ++{
143.37017 ++	Display *dpy;
143.37018 ++	Window root, win;
143.37019 ++	XRRScreenResources *res;
143.37020 ++	XRRCrtcInfo **original_crtc;
143.37021 ++	XSetWindowAttributes attr;
143.37022 ++	int i, j, fd;
143.37023 ++
143.37024 ++	attr.override_redirect = 1;
143.37025 ++
143.37026 ++	dpy = XOpenDisplay(NULL);
143.37027 ++	if (dpy == NULL)
143.37028 ++		return 77;
143.37029 ++
143.37030 ++	fd = dri2_open(dpy);
143.37031 ++	if (fd < 0)
143.37032 ++		return 77;
143.37033 ++
143.37034 ++	if (DPMSQueryExtension(dpy, &i, &i))
143.37035 ++		DPMSDisable(dpy);
143.37036 ++
143.37037 ++	root = DefaultRootWindow(dpy);
143.37038 ++
143.37039 ++	signal(SIGALRM, SIG_IGN);
143.37040 ++	XSetErrorHandler(_check_error_handler);
143.37041 ++
143.37042 ++	res = NULL;
143.37043 ++	if (XRRQueryVersion(dpy, &i, &i))
143.37044 ++		res = _XRRGetScreenResourcesCurrent(dpy, root);
143.37045 ++	if (res == NULL)
143.37046 ++		return 77;
143.37047 ++
143.37048 ++	original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
143.37049 ++	for (i = 0; i < res->ncrtc; i++)
143.37050 ++		original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
143.37051 ++
143.37052 ++	printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
143.37053 ++	for (i = 0; i < res->ncrtc; i++)
143.37054 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
143.37055 ++				 0, 0, None, RR_Rotate_0, NULL, 0);
143.37056 ++
143.37057 ++	DRI2CreateDrawable(dpy, root);
143.37058 ++	DRI2SwapInterval(dpy, root, 0);
143.37059 ++	run(dpy, root, "off");
143.37060 ++	XSync(dpy, True);
143.37061 ++
143.37062 ++	for (i = 0; i < res->noutput; i++) {
143.37063 ++		XRROutputInfo *output;
143.37064 ++		XRRModeInfo *mode;
143.37065 ++
143.37066 ++		output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
143.37067 ++		if (output == NULL)
143.37068 ++			continue;
143.37069 ++
143.37070 ++		mode = NULL;
143.37071 ++		if (res->nmode)
143.37072 ++			mode = lookup_mode(res, output->modes[0]);
143.37073 ++
143.37074 ++		for (j = 0; mode && j < 2*output->ncrtc; j++) {
143.37075 ++			int c = j;
143.37076 ++			if (c >= output->ncrtc)
143.37077 ++				c = 2*output->ncrtc - j - 1;
143.37078 ++
143.37079 ++			printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld: %dx%d\n",
143.37080 ++			       i, c, (long)res->outputs[i], (long)output->crtcs[c],
143.37081 ++			       mode->width, mode->height);
143.37082 ++			XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
143.37083 ++					 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
143.37084 ++
143.37085 ++			run(dpy, root, "root");
143.37086 ++			XSync(dpy, True);
143.37087 ++
143.37088 ++			win = XCreateWindow(dpy, root,
143.37089 ++					    0, 0, mode->width, mode->height, 0,
143.37090 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.37091 ++					    InputOutput,
143.37092 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.37093 ++					    CWOverrideRedirect, &attr);
143.37094 ++			DRI2CreateDrawable(dpy, win);
143.37095 ++			DRI2SwapInterval(dpy, win, 0);
143.37096 ++			fullscreen(dpy, win);
143.37097 ++			XMapWindow(dpy, win);
143.37098 ++			run(dpy, win, "fullscreen");
143.37099 ++			XDestroyWindow(dpy, win);
143.37100 ++			XSync(dpy, True);
143.37101 ++
143.37102 ++			win = XCreateWindow(dpy, root,
143.37103 ++					    0, 0, mode->width, mode->height, 0,
143.37104 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.37105 ++					    InputOutput,
143.37106 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.37107 ++					    CWOverrideRedirect, &attr);
143.37108 ++			DRI2CreateDrawable(dpy, win);
143.37109 ++			DRI2SwapInterval(dpy, win, 0);
143.37110 ++			XMapWindow(dpy, win);
143.37111 ++			run(dpy, win, "windowed");
143.37112 ++			XDestroyWindow(dpy, win);
143.37113 ++			XSync(dpy, True);
143.37114 ++
143.37115 ++			if (has_composite(dpy)) {
143.37116 ++				Damage damage;
143.37117 ++
143.37118 ++				_x_error_occurred = 0;
143.37119 ++				win = XCreateWindow(dpy, root,
143.37120 ++						    0, 0, mode->width, mode->height, 0,
143.37121 ++						    DefaultDepth(dpy, DefaultScreen(dpy)),
143.37122 ++						    InputOutput,
143.37123 ++						    DefaultVisual(dpy, DefaultScreen(dpy)),
143.37124 ++						    CWOverrideRedirect, &attr);
143.37125 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.37126 ++				damage = XDamageCreate(dpy, win, XDamageReportRawRectangles);
143.37127 ++				DRI2CreateDrawable(dpy, win);
143.37128 ++				DRI2SwapInterval(dpy, win, 0);
143.37129 ++				XMapWindow(dpy, win);
143.37130 ++				XSync(dpy, True);
143.37131 ++				if (!_x_error_occurred)
143.37132 ++					run(dpy, win, "composited");
143.37133 ++				XDamageDestroy(dpy, damage);
143.37134 ++				XDestroyWindow(dpy, win);
143.37135 ++				XSync(dpy, True);
143.37136 ++			}
143.37137 ++
143.37138 ++			win = XCreateWindow(dpy, root,
143.37139 ++					    0, 0, mode->width/2, mode->height/2, 0,
143.37140 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.37141 ++					    InputOutput,
143.37142 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.37143 ++					    CWOverrideRedirect, &attr);
143.37144 ++			DRI2CreateDrawable(dpy, win);
143.37145 ++			DRI2SwapInterval(dpy, win, 0);
143.37146 ++			XMapWindow(dpy, win);
143.37147 ++			run(dpy, win, "half");
143.37148 ++			XDestroyWindow(dpy, win);
143.37149 ++			XSync(dpy, True);
143.37150 ++
143.37151 ++			XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
143.37152 ++					 0, 0, None, RR_Rotate_0, NULL, 0);
143.37153 ++		}
143.37154 ++
143.37155 ++		XRRFreeOutputInfo(output);
143.37156 ++	}
143.37157 ++
143.37158 ++	for (i = 0; i < res->ncrtc; i++)
143.37159 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
143.37160 ++				 original_crtc[i]->x,
143.37161 ++				 original_crtc[i]->y,
143.37162 ++				 original_crtc[i]->mode,
143.37163 ++				 original_crtc[i]->rotation,
143.37164 ++				 original_crtc[i]->outputs,
143.37165 ++				 original_crtc[i]->noutput);
143.37166 ++
143.37167 ++	if (DPMSQueryExtension(dpy, &i, &i))
143.37168 ++		DPMSEnable(dpy);
143.37169 ++	return 0;
143.37170 ++}
143.37171 +diff --git a/test/dri2-test.c b/test/dri2-test.c
143.37172 +index dd4179f3..bdf01f38 100644
143.37173 +--- a/test/dri2-test.c
143.37174 ++++ b/test/dri2-test.c
143.37175 +@@ -6,6 +6,10 @@
143.37176 + #include <X11/Xutil.h>
143.37177 + #include <X11/extensions/Xfixes.h>
143.37178 + #include <X11/extensions/Xrandr.h>
143.37179 ++#include <X11/Xlib-xcb.h>
143.37180 ++#include <xcb/xcb.h>
143.37181 ++#include <xcb/xcbext.h>
143.37182 ++#include <xcb/dri2.h>
143.37183 + #include <unistd.h>
143.37184 + #include <fcntl.h>
143.37185 + #include <string.h>
143.37186 +@@ -18,6 +22,8 @@
143.37187 + 
143.37188 + #define COUNT 60
143.37189 + 
143.37190 ++static int prime[] = { 0, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47, 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131 };
143.37191 ++
143.37192 + static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
143.37193 + {
143.37194 + 	XRRScreenResources *res;
143.37195 +@@ -101,16 +107,41 @@ static uint64_t check_msc(Display *dpy, Window win, uint64_t last_msc)
143.37196 + 	return current_msc;
143.37197 + }
143.37198 + 
143.37199 ++static void wait_next_vblank(Display *dpy, Window win)
143.37200 ++{
143.37201 ++	uint64_t msc, ust, sbc;
143.37202 ++	DRI2WaitMSC(dpy, win, 0, 1, 0, &ust, &msc, &sbc);
143.37203 ++}
143.37204 ++
143.37205 ++static void swap_buffers(xcb_connection_t *c, Window win,
143.37206 ++		unsigned int *attachments, int nattachments)
143.37207 ++{
143.37208 ++	unsigned int seq[2];
143.37209 ++
143.37210 ++	seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
143.37211 ++						 0, 0, 0, 0, 0, 0).sequence;
143.37212 ++
143.37213 ++
143.37214 ++	seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
143.37215 ++						nattachments, nattachments,
143.37216 ++						attachments).sequence;
143.37217 ++
143.37218 ++	xcb_flush(c);
143.37219 ++	xcb_discard_reply(c, seq[0]);
143.37220 ++	xcb_discard_reply(c, seq[1]);
143.37221 ++}
143.37222 ++
143.37223 + static void run(Display *dpy, int width, int height,
143.37224 + 		unsigned int *attachments, int nattachments,
143.37225 + 		const char *name)
143.37226 + {
143.37227 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.37228 + 	Window win;
143.37229 + 	XSetWindowAttributes attr;
143.37230 +-	int count;
143.37231 + 	DRI2Buffer *buffers;
143.37232 + 	struct timespec start, end;
143.37233 +-	uint64_t msc;
143.37234 ++	uint64_t start_msc, end_msc;
143.37235 ++	int modulus, remainder, count;
143.37236 + 
143.37237 + 	/* Be nasty and install a fullscreen window on top so that we
143.37238 + 	 * can guarantee we do not get clipped by children.
143.37239 +@@ -125,42 +156,99 @@ static void run(Display *dpy, int width, int height,
143.37240 + 	XMapWindow(dpy, win);
143.37241 + 
143.37242 + 	DRI2CreateDrawable(dpy, win);
143.37243 +-	msc = check_msc(dpy, win, 0);
143.37244 ++	DRI2SwapInterval(dpy, win, 1);
143.37245 ++	start_msc = check_msc(dpy, win, 0);
143.37246 + 
143.37247 + 	buffers = DRI2GetBuffers(dpy, win, &width, &height,
143.37248 + 				 attachments, nattachments, &count);
143.37249 + 	if (count != nattachments)
143.37250 + 		return;
143.37251 + 
143.37252 +-	msc = check_msc(dpy, win, msc);
143.37253 ++	swap_buffers(c, win, attachments, nattachments);
143.37254 ++	start_msc = check_msc(dpy, win, start_msc);
143.37255 + 	clock_gettime(CLOCK_MONOTONIC, &start);
143.37256 + 	for (count = 0; count < COUNT; count++)
143.37257 +-		DRI2SwapBuffers(dpy, win, 0, 0, 0);
143.37258 +-	msc = check_msc(dpy, win, msc);
143.37259 ++		swap_buffers(c, win, attachments, nattachments);
143.37260 ++	end_msc = check_msc(dpy, win, start_msc);
143.37261 + 	clock_gettime(CLOCK_MONOTONIC, &end);
143.37262 +-	printf("%d %s (%dx%d) swaps in %fs.\n",
143.37263 +-	       count, name, width, height, elapsed(&start, &end));
143.37264 ++	printf("%d [%ld] %s (%dx%d) swaps in %fs.\n",
143.37265 ++	       count, (long)(end_msc - start_msc),
143.37266 ++	       name, width, height, elapsed(&start, &end));
143.37267 + 
143.37268 +-	msc = check_msc(dpy, win, msc);
143.37269 ++	swap_buffers(c, win, attachments, nattachments);
143.37270 ++	start_msc = check_msc(dpy, win, end_msc);
143.37271 + 	clock_gettime(CLOCK_MONOTONIC, &start);
143.37272 + 	for (count = 0; count < COUNT; count++)
143.37273 + 		dri2_copy_swap(dpy, win, width, height, nattachments == 2);
143.37274 +-	msc = check_msc(dpy, win, msc);
143.37275 ++	end_msc = check_msc(dpy, win, start_msc);
143.37276 + 	clock_gettime(CLOCK_MONOTONIC, &end);
143.37277 + 
143.37278 +-	printf("%d %s (%dx%d) blits in %fs.\n",
143.37279 +-	       count, name, width, height, elapsed(&start, &end));
143.37280 ++	printf("%d [%ld] %s (%dx%d) blits in %fs.\n",
143.37281 ++	       count, (long)(end_msc - start_msc),
143.37282 ++	       name, width, height, elapsed(&start, &end));
143.37283 + 
143.37284 + 	DRI2SwapInterval(dpy, win, 0);
143.37285 ++	wait_next_vblank(dpy, win);
143.37286 ++
143.37287 ++	swap_buffers(c, win, attachments, nattachments);
143.37288 ++	start_msc = check_msc(dpy, win, end_msc);
143.37289 ++	clock_gettime(CLOCK_MONOTONIC, &start);
143.37290 ++	for (count = 0; count < COUNT; count++)
143.37291 ++		swap_buffers(c, win, attachments, nattachments);
143.37292 ++	end_msc = check_msc(dpy, win, start_msc);
143.37293 ++	clock_gettime(CLOCK_MONOTONIC, &end);
143.37294 ++	printf("%d [%ld] %s (%dx%d) vblank=0 swaps in %fs.\n",
143.37295 ++	       count, (long)(end_msc - start_msc),
143.37296 ++	       name, width, height, elapsed(&start, &end));
143.37297 + 
143.37298 +-	msc = check_msc(dpy, win, msc);
143.37299 ++	start_msc = check_msc(dpy, win, end_msc);
143.37300 + 	clock_gettime(CLOCK_MONOTONIC, &start);
143.37301 + 	for (count = 0; count < COUNT; count++)
143.37302 +-		DRI2SwapBuffers(dpy, win, 0, 0, 0);
143.37303 +-	msc = check_msc(dpy, win, msc);
143.37304 ++		wait_next_vblank(dpy, win);
143.37305 ++	end_msc = check_msc(dpy, win, start_msc);
143.37306 + 	clock_gettime(CLOCK_MONOTONIC, &end);
143.37307 +-	printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n",
143.37308 +-	       count, name, width, height, elapsed(&start, &end));
143.37309 ++	printf("%d [%ld] %s waits in %fs.\n",
143.37310 ++	       count, (long)(end_msc - start_msc),
143.37311 ++	       name, elapsed(&start, &end));
143.37312 ++
143.37313 ++	printf("Testing past & future waits\n");
143.37314 ++	for (modulus = 1; modulus <= 128; modulus <<= 1) {
143.37315 ++		for (count = 0;  prime[count] < modulus; count++) {
143.37316 ++			uint64_t msc, ust, sbc;
143.37317 ++			uint64_t target;
143.37318 ++
143.37319 ++			remainder = prime[count];
143.37320 ++
143.37321 ++			DRI2WaitMSC(dpy, win, 0, 1, 0, &ust, &msc, &sbc);
143.37322 ++
143.37323 ++			target = msc + modulus + 1;
143.37324 ++			target &= -modulus;
143.37325 ++			target += remainder;
143.37326 ++
143.37327 ++			DRI2WaitMSC(dpy, win, target, modulus, remainder,
143.37328 ++				    &ust, &msc, &sbc);
143.37329 ++			if (msc != target) {
143.37330 ++				printf("Missed future MSC (%d, %d): expected=%lld, found=%lld\n",
143.37331 ++				       modulus, remainder,
143.37332 ++				       (long long)target, (long long)msc);
143.37333 ++			}
143.37334 ++
143.37335 ++			target = msc;
143.37336 ++			target &= -modulus;
143.37337 ++			target += remainder;
143.37338 ++			if (target <= msc)
143.37339 ++				target += modulus;
143.37340 ++
143.37341 ++			DRI2WaitMSC(dpy, win, msc, modulus, remainder,
143.37342 ++				    &ust, &msc, &sbc);
143.37343 ++
143.37344 ++			if (msc != target) {
143.37345 ++				printf("Missed past MSC (%d, %d): expected=%lld, found=%lld\n",
143.37346 ++				       modulus, remainder,
143.37347 ++				       (long long)target, (long long)msc);
143.37348 ++			}
143.37349 ++		}
143.37350 ++	}
143.37351 + 
143.37352 + 	XDestroyWindow(dpy, win);
143.37353 + 	free(buffers);
143.37354 +diff --git a/test/dri3-test.c b/test/dri3-test.c
143.37355 +index c66da313..78e105a8 100644
143.37356 +--- a/test/dri3-test.c
143.37357 ++++ b/test/dri3-test.c
143.37358 +@@ -93,14 +93,9 @@ static const struct pci_id_match ids[] = {
143.37359 + 	INTEL_IVB_D_IDS(070),
143.37360 + 	INTEL_IVB_M_IDS(070),
143.37361 + 
143.37362 +-	INTEL_HSW_D_IDS(075),
143.37363 +-	INTEL_HSW_M_IDS(075),
143.37364 +-
143.37365 +-	INTEL_VLV_D_IDS(071),
143.37366 +-	INTEL_VLV_M_IDS(071),
143.37367 +-
143.37368 +-	INTEL_BDW_D_IDS(0100),
143.37369 +-	INTEL_BDW_M_IDS(0100),
143.37370 ++	INTEL_HSW_IDS(075),
143.37371 ++	INTEL_VLV_IDS(071),
143.37372 ++	INTEL_BDW_IDS(0100),
143.37373 + };
143.37374 + 
143.37375 + static int i915_gen(int device)
143.37376 +@@ -1020,6 +1015,67 @@ fail:
143.37377 + 	return 1;
143.37378 + }
143.37379 + 
143.37380 ++static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
143.37381 ++{
143.37382 ++	struct drm_i915_gem_set_tiling set_tiling;
143.37383 ++
143.37384 ++	set_tiling.handle = handle;
143.37385 ++	set_tiling.tiling_mode = tiling;
143.37386 ++	set_tiling.stride = stride;
143.37387 ++
143.37388 ++	return drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0;
143.37389 ++}
143.37390 ++
143.37391 ++static int test_tiling(Display *dpy, int device)
143.37392 ++{
143.37393 ++	Window root = RootWindow(dpy, DefaultScreen(dpy));
143.37394 ++	const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
143.37395 ++	int line = -1;
143.37396 ++	int t;
143.37397 ++
143.37398 ++	_x_error_occurred = 0;
143.37399 ++
143.37400 ++	for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
143.37401 ++		uint32_t src;
143.37402 ++		int src_fd;
143.37403 ++		Pixmap src_pix;
143.37404 ++
143.37405 ++		src = gem_create(device, 4*4096);
143.37406 ++		if (!src) {
143.37407 ++			line = __LINE__;
143.37408 ++			goto fail;
143.37409 ++		}
143.37410 ++
143.37411 ++		gem_set_tiling(device, src, tiling[t], 512);
143.37412 ++
143.37413 ++		src_fd = gem_export(device, src);
143.37414 ++		if (src_fd < 0) {
143.37415 ++			line = __LINE__;
143.37416 ++			goto fail;
143.37417 ++		}
143.37418 ++
143.37419 ++		src_pix = dri3_create_pixmap(dpy, root,
143.37420 ++					     128, 32, 32,
143.37421 ++					     src_fd, 32, 512, 4*4096);
143.37422 ++		XSync(dpy, True);
143.37423 ++		if (_x_error_occurred) {
143.37424 ++			line = __LINE__;
143.37425 ++			goto fail;
143.37426 ++		}
143.37427 ++		XFreePixmap(dpy, src_pix);
143.37428 ++		_x_error_occurred = 0;
143.37429 ++
143.37430 ++		close(src_fd);
143.37431 ++		gem_close(device, src);
143.37432 ++	}
143.37433 ++
143.37434 ++	return 0;
143.37435 ++
143.37436 ++fail:
143.37437 ++	printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
143.37438 ++	return 1;
143.37439 ++}
143.37440 ++
143.37441 + static int
143.37442 + _check_error_handler(Display     *display,
143.37443 + 		     XErrorEvent *event)
143.37444 +@@ -1060,6 +1116,7 @@ int main(void)
143.37445 + 
143.37446 + 	error += test_bad_size(dpy, device);
143.37447 + 	error += test_bad_pitch(dpy, device);
143.37448 ++	error += test_tiling(dpy, device);
143.37449 + 
143.37450 + 	error += test_shm(dpy, device, 400, 300);
143.37451 + 	error += test_shm(dpy, device, 300, 400);
143.37452 +diff --git a/test/dri3.c b/test/dri3.c
143.37453 +index 45f3285c..e5644629 100644
143.37454 +--- a/test/dri3.c
143.37455 ++++ b/test/dri3.c
143.37456 +@@ -29,6 +29,7 @@
143.37457 + #include <xcb/dri3.h>
143.37458 + #include <xcb/sync.h>
143.37459 + #include <unistd.h>
143.37460 ++#include <stdlib.h>
143.37461 + 
143.37462 + #include "dri3.h"
143.37463 + 
143.37464 +@@ -109,12 +110,45 @@ void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
143.37465 + 	xcb_sync_destroy_fence(c, fence->xid);
143.37466 + }
143.37467 + 
143.37468 ++static void dri3_query_version(xcb_connection_t *c, int *major, int *minor)
143.37469 ++{
143.37470 ++	xcb_dri3_query_version_reply_t *reply;
143.37471 ++
143.37472 ++	reply = xcb_dri3_query_version_reply(c,
143.37473 ++					     xcb_dri3_query_version(c,
143.37474 ++								    XCB_DRI3_MAJOR_VERSION,
143.37475 ++								    XCB_DRI3_MINOR_VERSION),
143.37476 ++					     NULL);
143.37477 ++	if (reply != NULL) {
143.37478 ++		*major = reply->major_version;
143.37479 ++		*minor = reply->minor_version;
143.37480 ++		free(reply);
143.37481 ++	}
143.37482 ++}
143.37483 ++
143.37484 ++static int dri3_exists(xcb_connection_t *c)
143.37485 ++{
143.37486 ++	const xcb_query_extension_reply_t *ext;
143.37487 ++	int major, minor;
143.37488 ++
143.37489 ++	major = minor = -1;
143.37490 ++
143.37491 ++	ext = xcb_get_extension_data(c, &xcb_dri3_id);
143.37492 ++	if (ext != NULL && ext->present)
143.37493 ++		dri3_query_version(c, &major, &minor);
143.37494 ++
143.37495 ++	return major >= 0;
143.37496 ++}
143.37497 ++
143.37498 + int dri3_open__full(Display *dpy, Window root, unsigned provider)
143.37499 + {
143.37500 + 	xcb_connection_t *c = XGetXCBConnection(dpy);
143.37501 + 	xcb_dri3_open_cookie_t cookie;
143.37502 + 	xcb_dri3_open_reply_t *reply;
143.37503 + 
143.37504 ++	if (!dri3_exists(c))
143.37505 ++		return -1;
143.37506 ++
143.37507 + 	cookie = xcb_dri3_open(c, root, provider);
143.37508 + 	reply = xcb_dri3_open_reply(c, cookie, NULL);
143.37509 + 
143.37510 +diff --git a/test/present-race.c b/test/present-race.c
143.37511 +new file mode 100644
143.37512 +index 00000000..b2b6aa2b
143.37513 +--- /dev/null
143.37514 ++++ b/test/present-race.c
143.37515 +@@ -0,0 +1,484 @@
143.37516 ++/*
143.37517 ++ * Copyright (c) 2014 Intel Corporation
143.37518 ++ *
143.37519 ++ * Permission is hereby granted, free of charge, to any person obtaining a
143.37520 ++ * copy of this software and associated documentation files (the "Software"),
143.37521 ++ * to deal in the Software without restriction, including without limitation
143.37522 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
143.37523 ++ * and/or sell copies of the Software, and to permit persons to whom the
143.37524 ++ * Software is furnished to do so, subject to the following conditions:
143.37525 ++ *
143.37526 ++ * The above copyright notice and this permission notice (including the next
143.37527 ++ * paragraph) shall be included in all copies or substantial portions of the
143.37528 ++ * Software.
143.37529 ++ *
143.37530 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
143.37531 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
143.37532 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
143.37533 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143.37534 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
143.37535 ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
143.37536 ++ * SOFTWARE.
143.37537 ++ *
143.37538 ++ */
143.37539 ++
143.37540 ++#ifdef HAVE_CONFIG_H
143.37541 ++#include "config.h"
143.37542 ++#endif
143.37543 ++
143.37544 ++#include <X11/Xlib.h>
143.37545 ++#include <X11/Xlib-xcb.h>
143.37546 ++#include <X11/xshmfence.h>
143.37547 ++#include <X11/Xutil.h>
143.37548 ++#include <X11/Xlibint.h>
143.37549 ++#include <X11/extensions/dpms.h>
143.37550 ++#include <X11/extensions/randr.h>
143.37551 ++#include <X11/extensions/Xcomposite.h>
143.37552 ++#include <X11/extensions/Xrandr.h>
143.37553 ++#include <X11/extensions/Xrender.h>
143.37554 ++#include <X11/extensions/XShm.h>
143.37555 ++#if HAVE_X11_EXTENSIONS_SHMPROTO_H
143.37556 ++#include <X11/extensions/shmproto.h>
143.37557 ++#elif HAVE_X11_EXTENSIONS_SHMSTR_H
143.37558 ++#include <X11/extensions/shmstr.h>
143.37559 ++#else
143.37560 ++#error Failed to find the right header for X11 MIT-SHM protocol definitions
143.37561 ++#endif
143.37562 ++#include <xcb/xcb.h>
143.37563 ++#include <xcb/present.h>
143.37564 ++#include <xcb/xfixes.h>
143.37565 ++#include <xcb/dri3.h>
143.37566 ++#include <xf86drm.h>
143.37567 ++#include <i915_drm.h>
143.37568 ++
143.37569 ++#include <stdio.h>
143.37570 ++#include <string.h>
143.37571 ++#include <fcntl.h>
143.37572 ++#include <unistd.h>
143.37573 ++#include <assert.h>
143.37574 ++#include <errno.h>
143.37575 ++#include <setjmp.h>
143.37576 ++#include <signal.h>
143.37577 ++
143.37578 ++#include <sys/mman.h>
143.37579 ++#include <sys/ipc.h>
143.37580 ++#include <sys/shm.h>
143.37581 ++#include <pciaccess.h>
143.37582 ++
143.37583 ++#include "dri3.h"
143.37584 ++
143.37585 ++static int _x_error_occurred;
143.37586 ++static uint32_t stamp;
143.37587 ++
143.37588 ++static int
143.37589 ++_check_error_handler(Display     *display,
143.37590 ++		     XErrorEvent *event)
143.37591 ++{
143.37592 ++	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
143.37593 ++	       DisplayString(display),
143.37594 ++	       event->serial,
143.37595 ++	       event->error_code,
143.37596 ++	       event->request_code,
143.37597 ++	       event->minor_code);
143.37598 ++	_x_error_occurred++;
143.37599 ++	return False; /* ignored */
143.37600 ++}
143.37601 ++
143.37602 ++static int has_composite(Display *dpy)
143.37603 ++{
143.37604 ++	int event, error;
143.37605 ++	int major, minor;
143.37606 ++
143.37607 ++	if (!XCompositeQueryExtension(dpy, &event, &error))
143.37608 ++		return 0;
143.37609 ++
143.37610 ++	XCompositeQueryVersion(dpy, &major, &minor);
143.37611 ++
143.37612 ++	return major > 0 || minor >= 4;
143.37613 ++}
143.37614 ++
143.37615 ++static void *setup_msc(Display *dpy, Window win)
143.37616 ++{
143.37617 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.37618 ++	xcb_void_cookie_t cookie;
143.37619 ++	uint32_t id = xcb_generate_id(c);
143.37620 ++	xcb_generic_error_t *error;
143.37621 ++	void *q;
143.37622 ++
143.37623 ++	cookie = xcb_present_select_input_checked(c, id, win, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
143.37624 ++	q = xcb_register_for_special_xge(c, &xcb_present_id, id, &stamp);
143.37625 ++
143.37626 ++	error = xcb_request_check(c, cookie);
143.37627 ++	assert(error == NULL);
143.37628 ++
143.37629 ++	return q;
143.37630 ++}
143.37631 ++
143.37632 ++static void teardown_msc(Display *dpy, void *q)
143.37633 ++{
143.37634 ++	xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
143.37635 ++}
143.37636 ++
143.37637 ++static uint64_t wait_vblank(Display *dpy, Window win)
143.37638 ++{
143.37639 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.37640 ++	static uint32_t serial = 1;
143.37641 ++	uint64_t msc = 0;
143.37642 ++	int complete = 0;
143.37643 ++	void *q;
143.37644 ++
143.37645 ++	if (win == 0)
143.37646 ++		win = DefaultRootWindow(dpy);
143.37647 ++
143.37648 ++	q = setup_msc(dpy, win);
143.37649 ++
143.37650 ++	xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0);
143.37651 ++	xcb_flush(c);
143.37652 ++
143.37653 ++	do {
143.37654 ++		xcb_present_complete_notify_event_t *ce;
143.37655 ++		xcb_generic_event_t *ev;
143.37656 ++
143.37657 ++		ev = xcb_wait_for_special_event(c, q);
143.37658 ++		if (ev == NULL)
143.37659 ++			break;
143.37660 ++
143.37661 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.37662 ++		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
143.37663 ++		    ce->serial == (serial ^ 0xdeadbeef)) {
143.37664 ++			msc = ce->msc;
143.37665 ++			complete = 1;
143.37666 ++		}
143.37667 ++		free(ev);
143.37668 ++	} while (!complete);
143.37669 ++
143.37670 ++	if (++serial == 0)
143.37671 ++		serial = 1;
143.37672 ++
143.37673 ++	teardown_msc(dpy, q);
143.37674 ++
143.37675 ++	return msc;
143.37676 ++}
143.37677 ++
143.37678 ++static int test_basic(Display *dpy, int dummy)
143.37679 ++{
143.37680 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.37681 ++	XSetWindowAttributes attr;
143.37682 ++	Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
143.37683 ++	Pixmap pixmap;
143.37684 ++	struct dri3_fence fence;
143.37685 ++	Window root, win;
143.37686 ++	unsigned int width, height;
143.37687 ++	unsigned border, depth;
143.37688 ++	int x, y, ret = 1;
143.37689 ++	const char *phase;
143.37690 ++	uint64_t msc;
143.37691 ++
143.37692 ++	root = DefaultRootWindow(dpy);
143.37693 ++	XGetGeometry(dpy, root,
143.37694 ++		     &win, &x, &y,
143.37695 ++		     &width, &height, &border, &depth);
143.37696 ++
143.37697 ++	_x_error_occurred = 0;
143.37698 ++	attr.override_redirect = 1;
143.37699 ++	switch (dummy) {
143.37700 ++	case 0:
143.37701 ++		win = root;
143.37702 ++		phase = "root";
143.37703 ++		break;
143.37704 ++	case 1:
143.37705 ++		win = XCreateWindow(dpy, root,
143.37706 ++				    0, 0, width, height, 0, depth,
143.37707 ++				    InputOutput, visual,
143.37708 ++				    CWOverrideRedirect, &attr);
143.37709 ++		phase = "fullscreen";
143.37710 ++		break;
143.37711 ++	case 2:
143.37712 ++		width /= 2;
143.37713 ++		height /= 2;
143.37714 ++		win = XCreateWindow(dpy, root,
143.37715 ++				    0, 0, width, height, 0, depth,
143.37716 ++				    InputOutput, visual,
143.37717 ++				    CWOverrideRedirect, &attr);
143.37718 ++		phase = "window";
143.37719 ++		break;
143.37720 ++	case 3:
143.37721 ++		if (!has_composite(dpy))
143.37722 ++			return 0;
143.37723 ++
143.37724 ++		win = XCreateWindow(dpy, root,
143.37725 ++				    0, 0, width, height, 0,
143.37726 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
143.37727 ++				    InputOutput,
143.37728 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
143.37729 ++				    CWOverrideRedirect, &attr);
143.37730 ++		XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.37731 ++		phase = "composite";
143.37732 ++		break;
143.37733 ++
143.37734 ++	default:
143.37735 ++		phase = "broken";
143.37736 ++		win = root;
143.37737 ++		abort();
143.37738 ++		break;
143.37739 ++	}
143.37740 ++
143.37741 ++	XMapWindow(dpy, win);
143.37742 ++	XSync(dpy, True);
143.37743 ++	if (_x_error_occurred)
143.37744 ++		return 1;
143.37745 ++
143.37746 ++	if (dri3_create_fence(dpy, win, &fence))
143.37747 ++		return 0;
143.37748 ++
143.37749 ++	printf("%s: Testing basic flip: %dx%d\n", phase, width, height);
143.37750 ++	fflush(stdout);
143.37751 ++	_x_error_occurred = 0;
143.37752 ++
143.37753 ++	xshmfence_reset(fence.addr);
143.37754 ++	msc = wait_vblank(dpy, win);
143.37755 ++
143.37756 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.37757 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.37758 ++			   0, /* valid */
143.37759 ++			   0, /* update */
143.37760 ++			   0, /* x_off */
143.37761 ++			   0, /* y_off */
143.37762 ++			   None,
143.37763 ++			   None, /* wait fence */
143.37764 ++			   fence.xid,
143.37765 ++			   XCB_PRESENT_OPTION_NONE,
143.37766 ++			   (msc + 64) & -64, /* target msc */
143.37767 ++			   64, /* divisor */
143.37768 ++			   32, /* remainder */
143.37769 ++			   0, NULL);
143.37770 ++	XFreePixmap(dpy, pixmap);
143.37771 ++
143.37772 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.37773 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.37774 ++			   0, /* valid */
143.37775 ++			   0, /* update */
143.37776 ++			   0, /* x_off */
143.37777 ++			   0, /* y_off */
143.37778 ++			   None,
143.37779 ++			   None, /* wait fence */
143.37780 ++			   None, /* sync fence */
143.37781 ++			   XCB_PRESENT_OPTION_NONE,
143.37782 ++			   (msc + 64) & -64, /* target msc */
143.37783 ++			   64, /* divisor */
143.37784 ++			   48, /* remainder */
143.37785 ++			   0, NULL);
143.37786 ++	XFreePixmap(dpy, pixmap);
143.37787 ++	XDestroyWindow(dpy, win);
143.37788 ++	XFlush(dpy);
143.37789 ++
143.37790 ++	ret = !!xshmfence_await(fence.addr);
143.37791 ++	dri3_fence_free(dpy, &fence);
143.37792 ++
143.37793 ++	XSync(dpy, True);
143.37794 ++	ret += !!_x_error_occurred;
143.37795 ++
143.37796 ++	return ret;
143.37797 ++}
143.37798 ++
143.37799 ++static int test_race(Display *dpy, int dummy)
143.37800 ++{
143.37801 ++	Display *mgr = XOpenDisplay(NULL);
143.37802 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.37803 ++	XSetWindowAttributes attr;
143.37804 ++	Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
143.37805 ++	Pixmap pixmap;
143.37806 ++	struct dri3_fence fence;
143.37807 ++	Window root, win;
143.37808 ++	unsigned int width, height;
143.37809 ++	unsigned border, depth;
143.37810 ++	int x, y, ret = 1;
143.37811 ++	const char *phase;
143.37812 ++	uint64_t msc;
143.37813 ++
143.37814 ++	root = DefaultRootWindow(dpy);
143.37815 ++	XGetGeometry(dpy, root,
143.37816 ++		     &win, &x, &y,
143.37817 ++		     &width, &height, &border, &depth);
143.37818 ++
143.37819 ++	_x_error_occurred = 0;
143.37820 ++	attr.override_redirect = 1;
143.37821 ++	switch (dummy) {
143.37822 ++	case 0:
143.37823 ++		win = root;
143.37824 ++		phase = "root";
143.37825 ++		break;
143.37826 ++	case 1:
143.37827 ++		win = XCreateWindow(dpy, root,
143.37828 ++				    0, 0, width, height, 0, depth,
143.37829 ++				    InputOutput, visual,
143.37830 ++				    CWOverrideRedirect, &attr);
143.37831 ++		phase = "fullscreen";
143.37832 ++		break;
143.37833 ++	case 2:
143.37834 ++		width /= 2;
143.37835 ++		height /= 2;
143.37836 ++		win = XCreateWindow(dpy, root,
143.37837 ++				    0, 0, width, height, 0, depth,
143.37838 ++				    InputOutput, visual,
143.37839 ++				    CWOverrideRedirect, &attr);
143.37840 ++		phase = "window";
143.37841 ++		break;
143.37842 ++	case 3:
143.37843 ++		if (!has_composite(dpy))
143.37844 ++			return 0;
143.37845 ++
143.37846 ++		win = XCreateWindow(dpy, root,
143.37847 ++				    0, 0, width, height, 0,
143.37848 ++				    DefaultDepth(dpy, DefaultScreen(dpy)),
143.37849 ++				    InputOutput,
143.37850 ++				    DefaultVisual(dpy, DefaultScreen(dpy)),
143.37851 ++				    CWOverrideRedirect, &attr);
143.37852 ++		XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.37853 ++		phase = "composite";
143.37854 ++		break;
143.37855 ++
143.37856 ++	default:
143.37857 ++		phase = "broken";
143.37858 ++		win = root;
143.37859 ++		abort();
143.37860 ++		break;
143.37861 ++	}
143.37862 ++
143.37863 ++	XMapWindow(dpy, win);
143.37864 ++	XSync(dpy, True);
143.37865 ++	if (_x_error_occurred)
143.37866 ++		return 1;
143.37867 ++
143.37868 ++	if (dri3_create_fence(dpy, win, &fence))
143.37869 ++		return 0;
143.37870 ++
143.37871 ++	printf("%s: Testing race with manager: %dx%d\n", phase, width, height);
143.37872 ++	fflush(stdout);
143.37873 ++	_x_error_occurred = 0;
143.37874 ++
143.37875 ++	xshmfence_reset(fence.addr);
143.37876 ++	msc = wait_vblank(dpy, win);
143.37877 ++
143.37878 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.37879 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.37880 ++			   0, /* valid */
143.37881 ++			   0, /* update */
143.37882 ++			   0, /* x_off */
143.37883 ++			   0, /* y_off */
143.37884 ++			   None,
143.37885 ++			   None, /* wait fence */
143.37886 ++			   fence.xid,
143.37887 ++			   XCB_PRESENT_OPTION_NONE,
143.37888 ++			   (msc + 64) & -64, /* target msc */
143.37889 ++			   64, /* divisor */
143.37890 ++			   32, /* remainder */
143.37891 ++			   0, NULL);
143.37892 ++	XFreePixmap(dpy, pixmap);
143.37893 ++
143.37894 ++	XFlush(dpy);
143.37895 ++	XDestroyWindow(mgr, win);
143.37896 ++	XFlush(mgr);
143.37897 ++
143.37898 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.37899 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.37900 ++			   0, /* valid */
143.37901 ++			   0, /* update */
143.37902 ++			   0, /* x_off */
143.37903 ++			   0, /* y_off */
143.37904 ++			   None,
143.37905 ++			   None, /* wait fence */
143.37906 ++			   None, /* sync fence */
143.37907 ++			   XCB_PRESENT_OPTION_NONE,
143.37908 ++			   (msc + 64) & -64, /* target msc */
143.37909 ++			   64, /* divisor */
143.37910 ++			   48, /* remainder */
143.37911 ++			   0, NULL);
143.37912 ++	XFreePixmap(dpy, pixmap);
143.37913 ++	XFlush(dpy);
143.37914 ++
143.37915 ++	ret = !!xshmfence_await(fence.addr);
143.37916 ++	dri3_fence_free(dpy, &fence);
143.37917 ++
143.37918 ++	XSync(dpy, True);
143.37919 ++	ret += !!_x_error_occurred;
143.37920 ++
143.37921 ++	XCloseDisplay(mgr);
143.37922 ++
143.37923 ++	return ret;
143.37924 ++}
143.37925 ++
143.37926 ++static int has_present(Display *dpy)
143.37927 ++{
143.37928 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.37929 ++	xcb_generic_error_t *error = NULL;
143.37930 ++	void *reply;
143.37931 ++
143.37932 ++	reply = xcb_xfixes_query_version_reply(c,
143.37933 ++					       xcb_xfixes_query_version(c,
143.37934 ++									XCB_XFIXES_MAJOR_VERSION,
143.37935 ++									XCB_XFIXES_MINOR_VERSION),
143.37936 ++					       &error);
143.37937 ++	free(reply);
143.37938 ++	free(error);
143.37939 ++	if (reply == NULL) {
143.37940 ++		fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy));
143.37941 ++		return 0;
143.37942 ++	}
143.37943 ++
143.37944 ++	reply = xcb_dri3_query_version_reply(c,
143.37945 ++					     xcb_dri3_query_version(c,
143.37946 ++								    XCB_DRI3_MAJOR_VERSION,
143.37947 ++								    XCB_DRI3_MINOR_VERSION),
143.37948 ++					     &error);
143.37949 ++	free(reply);
143.37950 ++	free(error);
143.37951 ++	if (reply == NULL) {
143.37952 ++		fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy));
143.37953 ++		return 0;
143.37954 ++	}
143.37955 ++
143.37956 ++	reply = xcb_present_query_version_reply(c,
143.37957 ++						xcb_present_query_version(c,
143.37958 ++									  XCB_PRESENT_MAJOR_VERSION,
143.37959 ++									  XCB_PRESENT_MINOR_VERSION),
143.37960 ++						&error);
143.37961 ++
143.37962 ++	free(reply);
143.37963 ++	free(error);
143.37964 ++	if (reply == NULL) {
143.37965 ++		fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
143.37966 ++		return 0;
143.37967 ++	}
143.37968 ++
143.37969 ++	return 1;
143.37970 ++}
143.37971 ++
143.37972 ++int main(void)
143.37973 ++{
143.37974 ++	Display *dpy;
143.37975 ++	int dummy;
143.37976 ++	int error = 0;
143.37977 ++
143.37978 ++	dpy = XOpenDisplay(NULL);
143.37979 ++	if (dpy == NULL)
143.37980 ++		return 77;
143.37981 ++
143.37982 ++	if (!has_present(dpy))
143.37983 ++		return 77;
143.37984 ++
143.37985 ++	if (DPMSQueryExtension(dpy, &dummy, &dummy))
143.37986 ++		DPMSDisable(dpy);
143.37987 ++
143.37988 ++	signal(SIGALRM, SIG_IGN);
143.37989 ++	XSetErrorHandler(_check_error_handler);
143.37990 ++
143.37991 ++	for (dummy = 0; dummy <= 3; dummy++) {
143.37992 ++		error += test_basic(dpy, dummy);
143.37993 ++		error += test_race(dpy, dummy);
143.37994 ++	}
143.37995 ++
143.37996 ++	if (DPMSQueryExtension(dpy, &dummy, &dummy))
143.37997 ++		DPMSEnable(dpy);
143.37998 ++	return !!error;
143.37999 ++}
143.38000 +diff --git a/test/present-speed.c b/test/present-speed.c
143.38001 +new file mode 100644
143.38002 +index 00000000..eccde931
143.38003 +--- /dev/null
143.38004 ++++ b/test/present-speed.c
143.38005 +@@ -0,0 +1,1015 @@
143.38006 ++/*
143.38007 ++ * Copyright (c) 2015 Intel Corporation
143.38008 ++ *
143.38009 ++ * Permission is hereby granted, free of charge, to any person obtaining a
143.38010 ++ * copy of this software and associated documentation files (the "Software"),
143.38011 ++ * to deal in the Software without restriction, including without limitation
143.38012 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
143.38013 ++ * and/or sell copies of the Software, and to permit persons to whom the
143.38014 ++ * Software is furnished to do so, subject to the following conditions:
143.38015 ++ *
143.38016 ++ * The above copyright notice and this permission notice (including the next
143.38017 ++ * paragraph) shall be included in all copies or substantial portions of the
143.38018 ++ * Software.
143.38019 ++ *
143.38020 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
143.38021 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
143.38022 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
143.38023 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143.38024 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
143.38025 ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
143.38026 ++ * SOFTWARE.
143.38027 ++ *
143.38028 ++ */
143.38029 ++
143.38030 ++#ifdef HAVE_CONFIG_H
143.38031 ++#include "config.h"
143.38032 ++#endif
143.38033 ++
143.38034 ++#include <X11/Xlib.h>
143.38035 ++#include <X11/Xatom.h>
143.38036 ++#include <X11/Xlib-xcb.h>
143.38037 ++#include <X11/xshmfence.h>
143.38038 ++#include <X11/Xutil.h>
143.38039 ++#include <X11/Xlibint.h>
143.38040 ++#include <X11/extensions/Xcomposite.h>
143.38041 ++#include <X11/extensions/Xdamage.h>
143.38042 ++#include <X11/extensions/dpms.h>
143.38043 ++#include <X11/extensions/randr.h>
143.38044 ++#include <X11/extensions/Xrandr.h>
143.38045 ++#include <xcb/xcb.h>
143.38046 ++#include <xcb/present.h>
143.38047 ++#include <xcb/dri3.h>
143.38048 ++#include <xcb/xfixes.h>
143.38049 ++#include <xf86drm.h>
143.38050 ++#include <i915_drm.h>
143.38051 ++
143.38052 ++#include <stdio.h>
143.38053 ++#include <string.h>
143.38054 ++#include <fcntl.h>
143.38055 ++#include <unistd.h>
143.38056 ++#include <assert.h>
143.38057 ++#include <errno.h>
143.38058 ++#include <setjmp.h>
143.38059 ++#include <signal.h>
143.38060 ++#include <sys/wait.h>
143.38061 ++
143.38062 ++#include "dri3.h"
143.38063 ++
143.38064 ++static int _x_error_occurred;
143.38065 ++static uint32_t stamp;
143.38066 ++
143.38067 ++struct list {
143.38068 ++    struct list *next, *prev;
143.38069 ++};
143.38070 ++
143.38071 ++static void
143.38072 ++list_init(struct list *list)
143.38073 ++{
143.38074 ++    list->next = list->prev = list;
143.38075 ++}
143.38076 ++
143.38077 ++static inline void
143.38078 ++__list_add(struct list *entry,
143.38079 ++	    struct list *prev,
143.38080 ++	    struct list *next)
143.38081 ++{
143.38082 ++    next->prev = entry;
143.38083 ++    entry->next = next;
143.38084 ++    entry->prev = prev;
143.38085 ++    prev->next = entry;
143.38086 ++}
143.38087 ++
143.38088 ++static inline void
143.38089 ++list_add(struct list *entry, struct list *head)
143.38090 ++{
143.38091 ++    __list_add(entry, head, head->next);
143.38092 ++}
143.38093 ++
143.38094 ++static inline void
143.38095 ++__list_del(struct list *prev, struct list *next)
143.38096 ++{
143.38097 ++	next->prev = prev;
143.38098 ++	prev->next = next;
143.38099 ++}
143.38100 ++
143.38101 ++static inline void
143.38102 ++_list_del(struct list *entry)
143.38103 ++{
143.38104 ++    __list_del(entry->prev, entry->next);
143.38105 ++}
143.38106 ++
143.38107 ++static inline void
143.38108 ++list_move(struct list *list, struct list *head)
143.38109 ++{
143.38110 ++	if (list->prev != head) {
143.38111 ++		_list_del(list);
143.38112 ++		list_add(list, head);
143.38113 ++	}
143.38114 ++}
143.38115 ++
143.38116 ++#define __container_of(ptr, sample, member)				\
143.38117 ++    (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
143.38118 ++
143.38119 ++#define list_for_each_entry(pos, head, member)				\
143.38120 ++    for (pos = __container_of((head)->next, pos, member);		\
143.38121 ++	 &pos->member != (head);					\
143.38122 ++	 pos = __container_of(pos->member.next, pos, member))
143.38123 ++
143.38124 ++static int
143.38125 ++_check_error_handler(Display     *display,
143.38126 ++		     XErrorEvent *event)
143.38127 ++{
143.38128 ++	if (_x_error_occurred < 0)
143.38129 ++		return True;
143.38130 ++
143.38131 ++	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
143.38132 ++	       DisplayString(display),
143.38133 ++	       event->serial,
143.38134 ++	       event->error_code,
143.38135 ++	       event->request_code,
143.38136 ++	       event->minor_code);
143.38137 ++	_x_error_occurred++;
143.38138 ++	return False; /* ignored */
143.38139 ++}
143.38140 ++
143.38141 ++static double elapsed(const struct timespec *start,
143.38142 ++		      const struct timespec *end)
143.38143 ++{
143.38144 ++	return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
143.38145 ++}
143.38146 ++
143.38147 ++struct buffer {
143.38148 ++	struct list link;
143.38149 ++	Pixmap pixmap;
143.38150 ++	struct dri3_fence fence;
143.38151 ++	int fd;
143.38152 ++	int busy;
143.38153 ++	int id;
143.38154 ++};
143.38155 ++
143.38156 ++#define DRI3 1
143.38157 ++#define NOCOPY 2
143.38158 ++#define ASYNC 4
143.38159 ++static void run(Display *dpy, Window win, const char *name, unsigned options)
143.38160 ++{
143.38161 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.38162 ++	struct timespec start, end;
143.38163 ++#define N_BACK 8
143.38164 ++	char test_name[128];
143.38165 ++	struct buffer buffer[N_BACK];
143.38166 ++	struct list mru;
143.38167 ++	Window root;
143.38168 ++	unsigned int width, height;
143.38169 ++	unsigned border, depth;
143.38170 ++	unsigned present_flags = 0;
143.38171 ++	xcb_xfixes_region_t update = 0;
143.38172 ++	int completed = 0;
143.38173 ++	int queued = 0;
143.38174 ++	uint32_t eid = 0;
143.38175 ++	void *Q = NULL;
143.38176 ++	int i, n;
143.38177 ++
143.38178 ++	list_init(&mru);
143.38179 ++
143.38180 ++	XGetGeometry(dpy, win,
143.38181 ++		     &root, &i, &n, &width, &height, &border, &depth);
143.38182 ++
143.38183 ++	_x_error_occurred = 0;
143.38184 ++
143.38185 ++	for (n = 0; n < N_BACK; n++) {
143.38186 ++		buffer[n].pixmap = xcb_generate_id(c);
143.38187 ++		xcb_create_pixmap(c, depth, buffer[n].pixmap, win,
143.38188 ++				  width, height);
143.38189 ++		buffer[n].fence.xid = 0;
143.38190 ++		buffer[n].fd = -1;
143.38191 ++		buffer[n].id = n;
143.38192 ++		if (options & DRI3) {
143.38193 ++			xcb_dri3_buffer_from_pixmap_reply_t *reply;
143.38194 ++			int *fds;
143.38195 ++
143.38196 ++			if (dri3_create_fence(dpy, win, &buffer[n].fence))
143.38197 ++				return;
143.38198 ++
143.38199 ++			reply = xcb_dri3_buffer_from_pixmap_reply (c,
143.38200 ++								   xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
143.38201 ++								   NULL);
143.38202 ++			if (reply == NULL)
143.38203 ++				return;
143.38204 ++
143.38205 ++			fds = xcb_dri3_buffer_from_pixmap_reply_fds (c, reply);
143.38206 ++			buffer[n].fd = fds[0];
143.38207 ++			free(reply);
143.38208 ++
143.38209 ++			/* start idle */
143.38210 ++			xshmfence_trigger(buffer[n].fence.addr);
143.38211 ++		}
143.38212 ++		buffer[n].busy = 0;
143.38213 ++		list_add(&buffer[n].link, &mru);
143.38214 ++	}
143.38215 ++	if (options & ASYNC)
143.38216 ++		present_flags |= XCB_PRESENT_OPTION_ASYNC;
143.38217 ++	if (options & NOCOPY) {
143.38218 ++		update = xcb_generate_id(c);
143.38219 ++		xcb_xfixes_create_region(c, update, 0, NULL);
143.38220 ++		present_flags |= XCB_PRESENT_OPTION_COPY;
143.38221 ++	}
143.38222 ++
143.38223 ++	if (!(options & DRI3)) {
143.38224 ++		eid = xcb_generate_id(c);
143.38225 ++		xcb_present_select_input(c, eid, win,
143.38226 ++					 (options & NOCOPY ? 0 : XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY) |
143.38227 ++					 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
143.38228 ++		Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp);
143.38229 ++	}
143.38230 ++
143.38231 ++	clock_gettime(CLOCK_MONOTONIC, &start);
143.38232 ++	do {
143.38233 ++		for (n = 0; n < 1000; n++) {
143.38234 ++			struct buffer *tmp, *b = NULL;
143.38235 ++retry:
143.38236 ++			list_for_each_entry(tmp, &mru, link) {
143.38237 ++				if (tmp->fence.xid)
143.38238 ++					tmp->busy = !xshmfence_query(tmp->fence.addr);
143.38239 ++				if (!tmp->busy) {
143.38240 ++					b = tmp;
143.38241 ++					break;
143.38242 ++				}
143.38243 ++			}
143.38244 ++			if (options & DRI3) {
143.38245 ++				if (b == NULL)
143.38246 ++					goto retry;
143.38247 ++
143.38248 ++				xshmfence_reset(b->fence.addr);
143.38249 ++				queued--;
143.38250 ++				completed++;
143.38251 ++			} else while (b == NULL) {
143.38252 ++				xcb_present_generic_event_t *ev;
143.38253 ++
143.38254 ++				ev = (xcb_present_generic_event_t *)
143.38255 ++					xcb_wait_for_special_event(c, Q);
143.38256 ++				if (ev == NULL)
143.38257 ++					abort();
143.38258 ++
143.38259 ++				do {
143.38260 ++					switch (ev->evtype) {
143.38261 ++					case XCB_PRESENT_COMPLETE_NOTIFY:
143.38262 ++						completed++;
143.38263 ++						queued--;
143.38264 ++						break;
143.38265 ++
143.38266 ++					case XCB_PRESENT_EVENT_IDLE_NOTIFY:
143.38267 ++						{
143.38268 ++							xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
143.38269 ++							assert(ie->serial < N_BACK);
143.38270 ++							buffer[ie->serial].busy = 0;
143.38271 ++							if (b == NULL)
143.38272 ++								b = &buffer[ie->serial];
143.38273 ++							break;
143.38274 ++						}
143.38275 ++					}
143.38276 ++					free(ev);
143.38277 ++				} while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
143.38278 ++			}
143.38279 ++
143.38280 ++			b->busy = (options & NOCOPY) == 0;
143.38281 ++			xcb_present_pixmap(c, win, b->pixmap, b->id,
143.38282 ++					   0, /* valid */
143.38283 ++					   update, /* update */
143.38284 ++					   0, /* x_off */
143.38285 ++					   0, /* y_off */
143.38286 ++					   None,
143.38287 ++					   None, /* wait fence */
143.38288 ++					   b->fence.xid,
143.38289 ++					   present_flags,
143.38290 ++					   0, /* target msc */
143.38291 ++					   0, /* divisor */
143.38292 ++					   0, /* remainder */
143.38293 ++					   0, NULL);
143.38294 ++			list_move(&b->link, &mru);
143.38295 ++			queued++;
143.38296 ++			xcb_flush(c);
143.38297 ++		}
143.38298 ++		clock_gettime(CLOCK_MONOTONIC, &end);
143.38299 ++	} while (end.tv_sec < start.tv_sec + 10);
143.38300 ++
143.38301 ++	if (options & DRI3) {
143.38302 ++		struct buffer *b;
143.38303 ++		XID pixmap;
143.38304 ++
143.38305 ++		pixmap = xcb_generate_id(c);
143.38306 ++		xcb_create_pixmap(c, depth, pixmap, win, width, height);
143.38307 ++		xcb_present_pixmap(c, win, pixmap, 0xdeadbeef,
143.38308 ++				   0, /* valid */
143.38309 ++				   None, /* update */
143.38310 ++				   0, /* x_off */
143.38311 ++				   0, /* y_off */
143.38312 ++				   None,
143.38313 ++				   None, /* wait fence */
143.38314 ++				   None,
143.38315 ++				   0,
143.38316 ++				   0, /* target msc */
143.38317 ++				   0, /* divisor */
143.38318 ++				   0, /* remainder */
143.38319 ++				   0, NULL);
143.38320 ++		xcb_flush(c);
143.38321 ++
143.38322 ++		list_for_each_entry(b, &mru, link)
143.38323 ++			xshmfence_await(b->fence.addr);
143.38324 ++
143.38325 ++		xcb_free_pixmap(c, pixmap);
143.38326 ++		completed += queued;
143.38327 ++	} else while (queued) {
143.38328 ++		xcb_present_generic_event_t *ev;
143.38329 ++
143.38330 ++		ev = (xcb_present_generic_event_t *)
143.38331 ++			xcb_wait_for_special_event(c, Q);
143.38332 ++		if (ev == NULL)
143.38333 ++			abort();
143.38334 ++
143.38335 ++		do {
143.38336 ++			switch (ev->evtype) {
143.38337 ++			case XCB_PRESENT_COMPLETE_NOTIFY:
143.38338 ++				completed++;
143.38339 ++				queued--;
143.38340 ++				break;
143.38341 ++
143.38342 ++			case XCB_PRESENT_EVENT_IDLE_NOTIFY:
143.38343 ++				break;
143.38344 ++			}
143.38345 ++			free(ev);
143.38346 ++		} while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
143.38347 ++	}
143.38348 ++	clock_gettime(CLOCK_MONOTONIC, &end);
143.38349 ++
143.38350 ++	if (update)
143.38351 ++		xcb_xfixes_destroy_region(c, update);
143.38352 ++	for (n = 0; n < N_BACK; n++) {
143.38353 ++		if (buffer[n].fence.xid)
143.38354 ++			dri3_fence_free(dpy, &buffer[n].fence);
143.38355 ++		if (buffer[n].fd != -1)
143.38356 ++			close(buffer[n].fd);
143.38357 ++		xcb_free_pixmap(c, buffer[n].pixmap);
143.38358 ++	}
143.38359 ++
143.38360 ++	if (Q) {
143.38361 ++		xcb_discard_reply(c, xcb_present_select_input_checked(c, eid, win, 0).sequence);
143.38362 ++		XSync(dpy, True);
143.38363 ++		xcb_unregister_for_special_event(c, Q);
143.38364 ++	}
143.38365 ++
143.38366 ++	test_name[0] = '\0';
143.38367 ++	if (options) {
143.38368 ++		snprintf(test_name, sizeof(test_name), "(%s%s%s )",
143.38369 ++			 options & NOCOPY ? " no-copy" : "",
143.38370 ++			 options & DRI3 ? " dri3" : "",
143.38371 ++			 options & ASYNC ? " async" : "");
143.38372 ++	}
143.38373 ++	printf("%s%s: Completed %d presents in %.1fs, %.3fus each (%.1f FPS)\n",
143.38374 ++	       name, test_name,
143.38375 ++	       completed, elapsed(&start, &end) / 1000000,
143.38376 ++	       elapsed(&start, &end) / completed,
143.38377 ++	       completed / (elapsed(&start, &end) / 1000000));
143.38378 ++}
143.38379 ++
143.38380 ++struct perpixel {
143.38381 ++	Window win;
143.38382 ++	struct buffer buffer[N_BACK];
143.38383 ++	struct list mru;
143.38384 ++	uint32_t eid;
143.38385 ++	void *Q;
143.38386 ++	int queued;
143.38387 ++};
143.38388 ++
143.38389 ++static void perpixel(Display *dpy,
143.38390 ++		     int max_width, int max_height, unsigned options)
143.38391 ++{
143.38392 ++	//const int sz = max_width * max_height;
143.38393 ++	const int sz = 1048;
143.38394 ++	struct perpixel *pp;
143.38395 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.38396 ++	struct timespec start, end;
143.38397 ++	char test_name[128];
143.38398 ++	unsigned present_flags = 0;
143.38399 ++	xcb_xfixes_region_t update = 0;
143.38400 ++	int completed = 0;
143.38401 ++	int i, n;
143.38402 ++
143.38403 ++	pp = calloc(sz, sizeof(*pp));
143.38404 ++	if (!pp)
143.38405 ++		return;
143.38406 ++
143.38407 ++	for (i = 0; i < sz; i++) {
143.38408 ++		XSetWindowAttributes attr = { .override_redirect = 1 };
143.38409 ++		int depth = DefaultDepth(dpy, DefaultScreen(dpy));
143.38410 ++		pp[i].win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.38411 ++					  i % max_width, i / max_width, 1, 1, 0, depth,
143.38412 ++					  InputOutput,
143.38413 ++					  DefaultVisual(dpy, DefaultScreen(dpy)),
143.38414 ++					  CWOverrideRedirect, &attr);
143.38415 ++		XMapWindow(dpy, pp[i].win);
143.38416 ++		list_init(&pp[i].mru);
143.38417 ++		for (n = 0; n < N_BACK; n++) {
143.38418 ++			pp[i].buffer[n].pixmap = xcb_generate_id(c);
143.38419 ++			xcb_create_pixmap(c, depth, pp[i].buffer[n].pixmap,
143.38420 ++					  pp[i].win, 1, 1);
143.38421 ++			pp[i].buffer[n].fence.xid = 0;
143.38422 ++			pp[i].buffer[n].fd = -1;
143.38423 ++			pp[i].buffer[n].id = n;
143.38424 ++			if (options & DRI3) {
143.38425 ++				xcb_dri3_buffer_from_pixmap_reply_t *reply;
143.38426 ++				int *fds;
143.38427 ++
143.38428 ++				if (dri3_create_fence(dpy, pp[i].win, &pp[i].buffer[n].fence))
143.38429 ++					return;
143.38430 ++
143.38431 ++				reply = xcb_dri3_buffer_from_pixmap_reply(c,
143.38432 ++									  xcb_dri3_buffer_from_pixmap(c, pp[i].buffer[n].pixmap),
143.38433 ++									  NULL);
143.38434 ++				if (reply == NULL)
143.38435 ++					return;
143.38436 ++
143.38437 ++				fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, reply);
143.38438 ++				pp[i].buffer[n].fd = fds[0];
143.38439 ++				free(reply);
143.38440 ++
143.38441 ++				/* start idle */
143.38442 ++				xshmfence_trigger(pp[i].buffer[n].fence.addr);
143.38443 ++			}
143.38444 ++			pp[i].buffer[n].busy = 0;
143.38445 ++			list_add(&pp[i].buffer[n].link, &pp[i].mru);
143.38446 ++		}
143.38447 ++
143.38448 ++		if (!(options & DRI3)) {
143.38449 ++			pp[i].eid = xcb_generate_id(c);
143.38450 ++			xcb_present_select_input(c, pp[i].eid, pp[i].win,
143.38451 ++						 (options & NOCOPY ? 0 : XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY) |
143.38452 ++						 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
143.38453 ++			pp[i].Q = xcb_register_for_special_xge(c, &xcb_present_id, pp[i].eid, &stamp);
143.38454 ++		}
143.38455 ++		pp[i].queued = 0;
143.38456 ++	}
143.38457 ++
143.38458 ++	XSync(dpy, True);
143.38459 ++	_x_error_occurred = 0;
143.38460 ++
143.38461 ++	if (options & ASYNC)
143.38462 ++		present_flags |= XCB_PRESENT_OPTION_ASYNC;
143.38463 ++	if (options & NOCOPY) {
143.38464 ++		update = xcb_generate_id(c);
143.38465 ++		xcb_xfixes_create_region(c, update, 0, NULL);
143.38466 ++		present_flags |= XCB_PRESENT_OPTION_COPY;
143.38467 ++	}
143.38468 ++
143.38469 ++	clock_gettime(CLOCK_MONOTONIC, &start);
143.38470 ++	do {
143.38471 ++		for (i = 0; i < sz; i++) {
143.38472 ++			struct buffer *tmp, *b = NULL;
143.38473 ++retry:
143.38474 ++			list_for_each_entry(tmp, &pp[i].mru, link) {
143.38475 ++				if (tmp->fence.xid)
143.38476 ++					tmp->busy = !xshmfence_query(tmp->fence.addr);
143.38477 ++				if (!tmp->busy) {
143.38478 ++					b = tmp;
143.38479 ++					break;
143.38480 ++				}
143.38481 ++			}
143.38482 ++			if (options & DRI3) {
143.38483 ++				if (b == NULL)
143.38484 ++					goto retry;
143.38485 ++
143.38486 ++				xshmfence_reset(b->fence.addr);
143.38487 ++				pp[i].queued--;
143.38488 ++				completed++;
143.38489 ++			} else while (b == NULL) {
143.38490 ++				xcb_present_generic_event_t *ev;
143.38491 ++
143.38492 ++				ev = (xcb_present_generic_event_t *)
143.38493 ++					xcb_wait_for_special_event(c, pp[i].Q);
143.38494 ++				if (ev == NULL)
143.38495 ++					abort();
143.38496 ++
143.38497 ++				do {
143.38498 ++					switch (ev->evtype) {
143.38499 ++					case XCB_PRESENT_COMPLETE_NOTIFY:
143.38500 ++						completed++;
143.38501 ++						pp[i].queued--;
143.38502 ++						break;
143.38503 ++
143.38504 ++					case XCB_PRESENT_EVENT_IDLE_NOTIFY:
143.38505 ++						{
143.38506 ++							xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
143.38507 ++							assert(ie->serial < N_BACK);
143.38508 ++							pp[i].buffer[ie->serial].busy = 0;
143.38509 ++							if (b == NULL)
143.38510 ++								b = &pp[i].buffer[ie->serial];
143.38511 ++							break;
143.38512 ++						}
143.38513 ++					}
143.38514 ++					free(ev);
143.38515 ++				} while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, pp[i].Q)));
143.38516 ++			}
143.38517 ++
143.38518 ++			b->busy = (options & NOCOPY) == 0;
143.38519 ++			xcb_present_pixmap(c, pp[i].win, b->pixmap, b->id,
143.38520 ++					   0, /* valid */
143.38521 ++					   update, /* update */
143.38522 ++					   0, /* x_off */
143.38523 ++					   0, /* y_off */
143.38524 ++					   None,
143.38525 ++					   None, /* wait fence */
143.38526 ++					   b->fence.xid,
143.38527 ++					   present_flags,
143.38528 ++					   0, /* target msc */
143.38529 ++					   0, /* divisor */
143.38530 ++					   0, /* remainder */
143.38531 ++					   0, NULL);
143.38532 ++			list_move(&b->link, &pp[i].mru);
143.38533 ++			pp[i].queued++;
143.38534 ++		}
143.38535 ++		xcb_flush(c);
143.38536 ++		clock_gettime(CLOCK_MONOTONIC, &end);
143.38537 ++	} while (end.tv_sec < start.tv_sec + 10);
143.38538 ++
143.38539 ++	for (i = 0; i < sz; i++) {
143.38540 ++		if (options & DRI3) {
143.38541 ++			int depth = DefaultDepth(dpy, DefaultScreen(dpy));
143.38542 ++			struct buffer *b;
143.38543 ++			XID pixmap;
143.38544 ++
143.38545 ++			pixmap = xcb_generate_id(c);
143.38546 ++			xcb_create_pixmap(c, depth, pixmap, pp[i].win, 1, 1);
143.38547 ++			xcb_present_pixmap(c, pp[i].win, pixmap, 0xdeadbeef,
143.38548 ++					   0, /* valid */
143.38549 ++					   None, /* update */
143.38550 ++					   0, /* x_off */
143.38551 ++					   0, /* y_off */
143.38552 ++					   None,
143.38553 ++					   None, /* wait fence */
143.38554 ++					   None,
143.38555 ++					   0,
143.38556 ++					   0, /* target msc */
143.38557 ++					   0, /* divisor */
143.38558 ++					   0, /* remainder */
143.38559 ++					   0, NULL);
143.38560 ++			xcb_flush(c);
143.38561 ++
143.38562 ++			list_for_each_entry(b, &pp[i].mru, link)
143.38563 ++				xshmfence_await(b->fence.addr);
143.38564 ++
143.38565 ++			xcb_free_pixmap(c, pixmap);
143.38566 ++			completed += pp[i].queued;
143.38567 ++		} else while (pp[i].queued) {
143.38568 ++			xcb_present_generic_event_t *ev;
143.38569 ++
143.38570 ++			ev = (xcb_present_generic_event_t *)
143.38571 ++				xcb_wait_for_special_event(c, pp[i].Q);
143.38572 ++			if (ev == NULL)
143.38573 ++				abort();
143.38574 ++
143.38575 ++			do {
143.38576 ++				switch (ev->evtype) {
143.38577 ++				case XCB_PRESENT_COMPLETE_NOTIFY:
143.38578 ++					completed++;
143.38579 ++					pp[i].queued--;
143.38580 ++					break;
143.38581 ++
143.38582 ++				case XCB_PRESENT_EVENT_IDLE_NOTIFY:
143.38583 ++					break;
143.38584 ++				}
143.38585 ++				free(ev);
143.38586 ++			} while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, pp[i].Q)));
143.38587 ++		}
143.38588 ++	}
143.38589 ++	clock_gettime(CLOCK_MONOTONIC, &end);
143.38590 ++
143.38591 ++	if (update)
143.38592 ++		xcb_xfixes_destroy_region(c, update);
143.38593 ++
143.38594 ++	for (i = 0; i < sz; i++) {
143.38595 ++		for (n = 0; n < N_BACK; n++) {
143.38596 ++			if (pp[i].buffer[n].fence.xid)
143.38597 ++				dri3_fence_free(dpy, &pp[i].buffer[n].fence);
143.38598 ++			if (pp[i].buffer[n].fd != -1)
143.38599 ++				close(pp[i].buffer[n].fd);
143.38600 ++			xcb_free_pixmap(c, pp[i].buffer[n].pixmap);
143.38601 ++		}
143.38602 ++
143.38603 ++		if (pp[i].Q) {
143.38604 ++			xcb_discard_reply(c, xcb_present_select_input_checked(c, pp[i].eid, pp[i].win, 0).sequence);
143.38605 ++			XSync(dpy, True);
143.38606 ++			xcb_unregister_for_special_event(c, pp[i].Q);
143.38607 ++		}
143.38608 ++
143.38609 ++		XDestroyWindow(dpy, pp[i].win);
143.38610 ++	}
143.38611 ++	free(pp);
143.38612 ++
143.38613 ++	test_name[0] = '\0';
143.38614 ++	if (options) {
143.38615 ++		snprintf(test_name, sizeof(test_name), "(%s%s%s )",
143.38616 ++			 options & NOCOPY ? " no-copy" : "",
143.38617 ++			 options & DRI3 ? " dri3" : "",
143.38618 ++			 options & ASYNC ? " async" : "");
143.38619 ++	}
143.38620 ++	printf("%s%s: Completed %d presents in %.1fs, %.3fus each (%.1f FPS)\n",
143.38621 ++	       __func__, test_name,
143.38622 ++	       completed, elapsed(&start, &end) / 1000000,
143.38623 ++	       elapsed(&start, &end) / completed,
143.38624 ++	       completed / (elapsed(&start, &end) / 1000000));
143.38625 ++}
143.38626 ++
143.38627 ++static int isqrt(int x)
143.38628 ++{
143.38629 ++	int i;
143.38630 ++
143.38631 ++	for (i = 2; i*i < x; i++)
143.38632 ++		;
143.38633 ++	return i;
143.38634 ++}
143.38635 ++
143.38636 ++struct sibling {
143.38637 ++	pthread_t thread;
143.38638 ++	Display *dpy;
143.38639 ++	int x, y;
143.38640 ++	int width, height;
143.38641 ++	unsigned options;
143.38642 ++};
143.38643 ++
143.38644 ++static void *sibling(void *arg)
143.38645 ++{
143.38646 ++	struct sibling *s = arg;
143.38647 ++	XSetWindowAttributes attr = { .override_redirect = 1 };
143.38648 ++	Window win = XCreateWindow(s->dpy, DefaultRootWindow(s->dpy),
143.38649 ++				   s->x, s->y, s->width, s->height, 0,
143.38650 ++				   DefaultDepth(s->dpy, DefaultScreen(s->dpy)),
143.38651 ++				   InputOutput,
143.38652 ++				   DefaultVisual(s->dpy, DefaultScreen(s->dpy)),
143.38653 ++				   CWOverrideRedirect, &attr);
143.38654 ++	XMapWindow(s->dpy, win);
143.38655 ++	run(s->dpy, win, "sibling", s->options);
143.38656 ++	return NULL;
143.38657 ++}
143.38658 ++
143.38659 ++static void siblings(Display *dpy,
143.38660 ++		     int max_width, int max_height, int ncpus, unsigned options)
143.38661 ++{
143.38662 ++	int sq_ncpus = isqrt(ncpus);
143.38663 ++	int width = max_width / sq_ncpus;
143.38664 ++	int height = max_height/ sq_ncpus;
143.38665 ++	struct sibling s[ncpus];
143.38666 ++	int child;
143.38667 ++
143.38668 ++	if (ncpus <= 1)
143.38669 ++		return;
143.38670 ++
143.38671 ++	for (child = 0; child < ncpus; child++) {
143.38672 ++		s[child].dpy = dpy;
143.38673 ++		s[child].x = (child % sq_ncpus) * width;
143.38674 ++		s[child].y = (child / sq_ncpus) * height;
143.38675 ++		s[child].width = width;
143.38676 ++		s[child].height = height;
143.38677 ++		s[child].options = options;
143.38678 ++		pthread_create(&s[child].thread, NULL, sibling, &s[child]);
143.38679 ++	}
143.38680 ++
143.38681 ++	for (child = 0; child < ncpus; child++)
143.38682 ++		pthread_join(s[child].thread, NULL);
143.38683 ++}
143.38684 ++
143.38685 ++static void cousins(int max_width, int max_height, int ncpus, unsigned options)
143.38686 ++{
143.38687 ++	int sq_ncpus = isqrt(ncpus);
143.38688 ++	int width = max_width / sq_ncpus;
143.38689 ++	int height = max_height/ sq_ncpus;
143.38690 ++	int child;
143.38691 ++
143.38692 ++	if (ncpus <= 1)
143.38693 ++		return;
143.38694 ++
143.38695 ++	for (child = 0; child < ncpus; child++) {
143.38696 ++		for (; fork() == 0; exit(0)) {
143.38697 ++			int x = (child % sq_ncpus) * width;
143.38698 ++			int y = (child / sq_ncpus) * height;
143.38699 ++			XSetWindowAttributes attr = { .override_redirect = 1 };
143.38700 ++			Display *dpy = XOpenDisplay(NULL);
143.38701 ++			Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
143.38702 ++						   x, y, width, height, 0,
143.38703 ++						   DefaultDepth(dpy, DefaultScreen(dpy)),
143.38704 ++						   InputOutput,
143.38705 ++						   DefaultVisual(dpy, DefaultScreen(dpy)),
143.38706 ++						   CWOverrideRedirect, &attr);
143.38707 ++			XMapWindow(dpy, win);
143.38708 ++			run(dpy, win, "cousin", options);
143.38709 ++		}
143.38710 ++	}
143.38711 ++
143.38712 ++	while (child) {
143.38713 ++		int status = -1;
143.38714 ++		pid_t pid = wait(&status);
143.38715 ++		if (pid == -1)
143.38716 ++			continue;
143.38717 ++		child--;
143.38718 ++	}
143.38719 ++}
143.38720 ++
143.38721 ++static int has_present(Display *dpy)
143.38722 ++{
143.38723 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.38724 ++	xcb_generic_error_t *error = NULL;
143.38725 ++	void *reply;
143.38726 ++
143.38727 ++	reply = xcb_present_query_version_reply(c,
143.38728 ++						xcb_present_query_version(c,
143.38729 ++									  XCB_PRESENT_MAJOR_VERSION,
143.38730 ++									  XCB_PRESENT_MINOR_VERSION),
143.38731 ++						&error);
143.38732 ++
143.38733 ++	free(reply);
143.38734 ++	free(error);
143.38735 ++	if (reply == NULL) {
143.38736 ++		fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
143.38737 ++		return 0;
143.38738 ++	}
143.38739 ++
143.38740 ++	return 1;
143.38741 ++}
143.38742 ++
143.38743 ++static int has_composite(Display *dpy)
143.38744 ++{
143.38745 ++	int event, error;
143.38746 ++	int major, minor;
143.38747 ++
143.38748 ++	if (!XDamageQueryExtension (dpy, &event, &error))
143.38749 ++		return 0;
143.38750 ++
143.38751 ++	if (!XCompositeQueryExtension(dpy, &event, &error))
143.38752 ++		return 0;
143.38753 ++
143.38754 ++	XCompositeQueryVersion(dpy, &major, &minor);
143.38755 ++
143.38756 ++	return major > 0 || minor >= 4;
143.38757 ++}
143.38758 ++
143.38759 ++static int dri3_query_version(Display *dpy, int *major, int *minor)
143.38760 ++{
143.38761 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.38762 ++	xcb_dri3_query_version_reply_t *reply;
143.38763 ++	xcb_generic_error_t *error;
143.38764 ++
143.38765 ++	*major = *minor = -1;
143.38766 ++
143.38767 ++	reply = xcb_dri3_query_version_reply(c,
143.38768 ++					     xcb_dri3_query_version(c,
143.38769 ++								    XCB_DRI3_MAJOR_VERSION,
143.38770 ++								    XCB_DRI3_MINOR_VERSION),
143.38771 ++					     &error);
143.38772 ++	free(error);
143.38773 ++	if (reply == NULL)
143.38774 ++		return -1;
143.38775 ++
143.38776 ++	*major = reply->major_version;
143.38777 ++	*minor = reply->minor_version;
143.38778 ++	free(reply);
143.38779 ++
143.38780 ++	return 0;
143.38781 ++}
143.38782 ++
143.38783 ++static int has_dri3(Display *dpy)
143.38784 ++{
143.38785 ++	const xcb_query_extension_reply_t *ext;
143.38786 ++	int major, minor;
143.38787 ++
143.38788 ++	ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
143.38789 ++	if (ext == NULL || !ext->present)
143.38790 ++		return 0;
143.38791 ++
143.38792 ++	if (dri3_query_version(dpy, &major, &minor) < 0)
143.38793 ++		return 0;
143.38794 ++
143.38795 ++	return major >= 0;
143.38796 ++}
143.38797 ++
143.38798 ++static int has_xfixes(Display *dpy)
143.38799 ++{
143.38800 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.38801 ++	const xcb_query_extension_reply_t *ext;
143.38802 ++	void *reply;
143.38803 ++
143.38804 ++	ext = xcb_get_extension_data(c, &xcb_xfixes_id);
143.38805 ++	if (ext == NULL || !ext->present)
143.38806 ++		return 0;
143.38807 ++
143.38808 ++	reply = xcb_xfixes_query_version_reply(c,
143.38809 ++					       xcb_xfixes_query_version(c,
143.38810 ++									XCB_XFIXES_MAJOR_VERSION,
143.38811 ++									XCB_XFIXES_MINOR_VERSION),
143.38812 ++					       NULL);
143.38813 ++	free(reply);
143.38814 ++
143.38815 ++	return reply != NULL;
143.38816 ++}
143.38817 ++
143.38818 ++static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
143.38819 ++{
143.38820 ++	XRRScreenResources *res;
143.38821 ++
143.38822 ++	res = XRRGetScreenResourcesCurrent(dpy, window);
143.38823 ++	if (res == NULL)
143.38824 ++		res = XRRGetScreenResources(dpy, window);
143.38825 ++
143.38826 ++	return res;
143.38827 ++}
143.38828 ++
143.38829 ++static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
143.38830 ++{
143.38831 ++	int i;
143.38832 ++
143.38833 ++	for (i = 0; i < res->nmode; i++) {
143.38834 ++		if (res->modes[i].id == id)
143.38835 ++			return &res->modes[i];
143.38836 ++	}
143.38837 ++
143.38838 ++	return NULL;
143.38839 ++}
143.38840 ++
143.38841 ++static void fullscreen(Display *dpy, Window win)
143.38842 ++{
143.38843 ++	Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
143.38844 ++	XChangeProperty(dpy, win,
143.38845 ++			XInternAtom(dpy, "_NET_WM_STATE", False),
143.38846 ++			XA_ATOM, 32, PropModeReplace,
143.38847 ++			(unsigned char *)&atom, 1);
143.38848 ++}
143.38849 ++
143.38850 ++static void loop(Display *dpy, XRRScreenResources *res, unsigned options)
143.38851 ++{
143.38852 ++	Window root = DefaultRootWindow(dpy);
143.38853 ++	Window win;
143.38854 ++	XSetWindowAttributes attr;
143.38855 ++	int i, j;
143.38856 ++
143.38857 ++	attr.override_redirect = 1;
143.38858 ++
143.38859 ++	run(dpy, root, "off", options);
143.38860 ++	XSync(dpy, True);
143.38861 ++
143.38862 ++	for (i = 0; i < res->noutput; i++) {
143.38863 ++		XRROutputInfo *output;
143.38864 ++		XRRModeInfo *mode;
143.38865 ++
143.38866 ++		output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
143.38867 ++		if (output == NULL)
143.38868 ++			continue;
143.38869 ++
143.38870 ++		mode = NULL;
143.38871 ++		if (res->nmode)
143.38872 ++			mode = lookup_mode(res, output->modes[0]);
143.38873 ++
143.38874 ++		for (j = 0; mode && j < 2*output->ncrtc; j++) {
143.38875 ++			int c = j;
143.38876 ++			if (c >= output->ncrtc)
143.38877 ++				c = 2*output->ncrtc - j - 1;
143.38878 ++
143.38879 ++			printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld: %dx%d\n",
143.38880 ++			       i, c, (long)res->outputs[i], (long)output->crtcs[c],
143.38881 ++			       mode->width, mode->height);
143.38882 ++			XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
143.38883 ++					 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
143.38884 ++
143.38885 ++			run(dpy, root, "root", options);
143.38886 ++			XSync(dpy, True);
143.38887 ++
143.38888 ++			win = XCreateWindow(dpy, root,
143.38889 ++					    0, 0, mode->width, mode->height, 0,
143.38890 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.38891 ++					    InputOutput,
143.38892 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.38893 ++					    CWOverrideRedirect, &attr);
143.38894 ++			fullscreen(dpy, win);
143.38895 ++			XMapWindow(dpy, win);
143.38896 ++			run(dpy, win, "fullscreen", options);
143.38897 ++			XDestroyWindow(dpy, win);
143.38898 ++			XSync(dpy, True);
143.38899 ++
143.38900 ++			win = XCreateWindow(dpy, root,
143.38901 ++					    0, 0, mode->width, mode->height, 0,
143.38902 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.38903 ++					    InputOutput,
143.38904 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.38905 ++					    CWOverrideRedirect, &attr);
143.38906 ++			XMapWindow(dpy, win);
143.38907 ++			run(dpy, win, "windowed", options);
143.38908 ++			XDestroyWindow(dpy, win);
143.38909 ++			XSync(dpy, True);
143.38910 ++
143.38911 ++			if (has_composite(dpy)) {
143.38912 ++				Damage damage;
143.38913 ++
143.38914 ++				_x_error_occurred = 0;
143.38915 ++				win = XCreateWindow(dpy, root,
143.38916 ++						    0, 0, mode->width, mode->height, 0,
143.38917 ++						    DefaultDepth(dpy, DefaultScreen(dpy)),
143.38918 ++						    InputOutput,
143.38919 ++						    DefaultVisual(dpy, DefaultScreen(dpy)),
143.38920 ++						    CWOverrideRedirect, &attr);
143.38921 ++				XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.38922 ++				damage = XDamageCreate(dpy, win, XDamageReportNonEmpty);
143.38923 ++				XMapWindow(dpy, win);
143.38924 ++				XSync(dpy, True);
143.38925 ++				if (!_x_error_occurred)
143.38926 ++					run(dpy, win, "composited", options);
143.38927 ++				XDamageDestroy(dpy, damage);
143.38928 ++				XDestroyWindow(dpy, win);
143.38929 ++				XSync(dpy, True);
143.38930 ++			}
143.38931 ++
143.38932 ++			win = XCreateWindow(dpy, root,
143.38933 ++					    0, 0, mode->width/2, mode->height/2, 0,
143.38934 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.38935 ++					    InputOutput,
143.38936 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.38937 ++					    CWOverrideRedirect, &attr);
143.38938 ++			XMapWindow(dpy, win);
143.38939 ++			run(dpy, win, "half", options);
143.38940 ++			XDestroyWindow(dpy, win);
143.38941 ++			XSync(dpy, True);
143.38942 ++
143.38943 ++			perpixel(dpy, mode->width, mode->height, options);
143.38944 ++
143.38945 ++			siblings(dpy, mode->width, mode->height,
143.38946 ++				 sysconf(_SC_NPROCESSORS_ONLN),
143.38947 ++				 options);
143.38948 ++
143.38949 ++			cousins(mode->width, mode->height,
143.38950 ++				sysconf(_SC_NPROCESSORS_ONLN),
143.38951 ++				options);
143.38952 ++
143.38953 ++			XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
143.38954 ++					 0, 0, None, RR_Rotate_0, NULL, 0);
143.38955 ++		}
143.38956 ++
143.38957 ++		XRRFreeOutputInfo(output);
143.38958 ++	}
143.38959 ++
143.38960 ++}
143.38961 ++
143.38962 ++int main(void)
143.38963 ++{
143.38964 ++	Display *dpy;
143.38965 ++	XRRScreenResources *res;
143.38966 ++	XRRCrtcInfo **original_crtc;
143.38967 ++	int i;
143.38968 ++
143.38969 ++	XInitThreads();
143.38970 ++
143.38971 ++	dpy = XOpenDisplay(NULL);
143.38972 ++	if (dpy == NULL)
143.38973 ++		return 77;
143.38974 ++
143.38975 ++	if (!has_present(dpy))
143.38976 ++		return 77;
143.38977 ++
143.38978 ++	if (DPMSQueryExtension(dpy, &i, &i))
143.38979 ++		DPMSDisable(dpy);
143.38980 ++
143.38981 ++	signal(SIGALRM, SIG_IGN);
143.38982 ++	XSetErrorHandler(_check_error_handler);
143.38983 ++
143.38984 ++	res = NULL;
143.38985 ++	if (XRRQueryVersion(dpy, &i, &i))
143.38986 ++		res = _XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy));
143.38987 ++	if (res == NULL)
143.38988 ++		return 77;
143.38989 ++
143.38990 ++	original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
143.38991 ++	for (i = 0; i < res->ncrtc; i++)
143.38992 ++		original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
143.38993 ++
143.38994 ++	printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
143.38995 ++	for (i = 0; i < res->ncrtc; i++)
143.38996 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
143.38997 ++				 0, 0, None, RR_Rotate_0, NULL, 0);
143.38998 ++
143.38999 ++	loop(dpy, res, 0);
143.39000 ++	loop(dpy, res, ASYNC);
143.39001 ++	if (has_xfixes(dpy))
143.39002 ++		loop(dpy, res, NOCOPY);
143.39003 ++	if (has_dri3(dpy)) {
143.39004 ++		loop(dpy, res, DRI3);
143.39005 ++		loop(dpy, res, DRI3 | ASYNC);
143.39006 ++	}
143.39007 ++
143.39008 ++	for (i = 0; i < res->ncrtc; i++)
143.39009 ++		XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
143.39010 ++				 original_crtc[i]->x,
143.39011 ++				 original_crtc[i]->y,
143.39012 ++				 original_crtc[i]->mode,
143.39013 ++				 original_crtc[i]->rotation,
143.39014 ++				 original_crtc[i]->outputs,
143.39015 ++				 original_crtc[i]->noutput);
143.39016 ++
143.39017 ++	if (DPMSQueryExtension(dpy, &i, &i))
143.39018 ++		DPMSEnable(dpy);
143.39019 ++	return 0;
143.39020 ++}
143.39021 +diff --git a/test/present-test.c b/test/present-test.c
143.39022 +index 6b562eb0..5a12a24f 100644
143.39023 +--- a/test/present-test.c
143.39024 ++++ b/test/present-test.c
143.39025 +@@ -31,7 +31,9 @@
143.39026 + #include <X11/xshmfence.h>
143.39027 + #include <X11/Xutil.h>
143.39028 + #include <X11/Xlibint.h>
143.39029 ++#include <X11/extensions/dpms.h>
143.39030 + #include <X11/extensions/randr.h>
143.39031 ++#include <X11/extensions/Xcomposite.h>
143.39032 + #include <X11/extensions/Xrandr.h>
143.39033 + #include <X11/extensions/Xrender.h>
143.39034 + #include <X11/extensions/XShm.h>
143.39035 +@@ -44,6 +46,8 @@
143.39036 + #endif
143.39037 + #include <xcb/xcb.h>
143.39038 + #include <xcb/present.h>
143.39039 ++#include <xcb/xfixes.h>
143.39040 ++#include <xcb/dri3.h>
143.39041 + #include <xf86drm.h>
143.39042 + #include <i915_drm.h>
143.39043 + 
143.39044 +@@ -134,12 +138,14 @@ static void *setup_msc(Display *dpy,  Window win)
143.39045 + 	return q;
143.39046 + }
143.39047 + 
143.39048 +-static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
143.39049 ++static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc, uint64_t *ust)
143.39050 + {
143.39051 + 	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39052 ++	static uint32_t serial = 1;
143.39053 + 	uint64_t msc = 0;
143.39054 ++	int complete = 0;
143.39055 + 
143.39056 +-	xcb_present_notify_msc(c, win, 0, 0, 0, 0);
143.39057 ++	xcb_present_notify_msc(c, win, serial ^ 0xcc00ffee, 0, 0, 0);
143.39058 + 	xcb_flush(c);
143.39059 + 
143.39060 + 	do {
143.39061 +@@ -151,82 +157,1268 @@ static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
143.39062 + 			break;
143.39063 + 
143.39064 + 		ce = (xcb_present_complete_notify_event_t *)ev;
143.39065 +-		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
143.39066 ++		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
143.39067 ++		    ce->serial == (serial ^ 0xcc00ffee)) {
143.39068 ++			msc = ce->msc;
143.39069 ++			if (ust)
143.39070 ++				*ust = ce->ust;
143.39071 ++			complete = 1;
143.39072 ++		}
143.39073 ++		free(ev);
143.39074 ++	} while (!complete);
143.39075 ++
143.39076 ++	if ((int64_t)(msc - last_msc) < 0) {
143.39077 ++		printf("Invalid MSC: was %llu, now %llu\n",
143.39078 ++		       (long long)last_msc, (long long)msc);
143.39079 ++	}
143.39080 ++
143.39081 ++	if (++serial == 0)
143.39082 ++		serial = 1;
143.39083 ++
143.39084 ++	return msc;
143.39085 ++}
143.39086 ++
143.39087 ++static uint64_t wait_vblank(Display *dpy, Window win, void *q)
143.39088 ++{
143.39089 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39090 ++	static uint32_t serial = 1;
143.39091 ++	uint64_t msc = 0;
143.39092 ++	int complete = 0;
143.39093 ++
143.39094 ++	xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0);
143.39095 ++	xcb_flush(c);
143.39096 ++
143.39097 ++	do {
143.39098 ++		xcb_present_complete_notify_event_t *ce;
143.39099 ++		xcb_generic_event_t *ev;
143.39100 ++
143.39101 ++		ev = xcb_wait_for_special_event(c, q);
143.39102 ++		if (ev == NULL)
143.39103 ++			break;
143.39104 ++
143.39105 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.39106 ++		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
143.39107 ++		    ce->serial == (serial ^ 0xdeadbeef)) {
143.39108 + 			msc = ce->msc;
143.39109 ++			complete = 1;
143.39110 ++		}
143.39111 ++		free(ev);
143.39112 ++	} while (!complete);
143.39113 ++
143.39114 ++	if (++serial == 0)
143.39115 ++		serial = 1;
143.39116 ++
143.39117 ++	return msc;
143.39118 ++}
143.39119 ++
143.39120 ++static uint64_t msc_interval(Display *dpy, Window win, void *q)
143.39121 ++{
143.39122 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39123 ++	uint64_t msc, ust;
143.39124 ++	int complete = 0;
143.39125 ++
143.39126 ++	msc = check_msc(dpy, win, q, 0, NULL);
143.39127 ++
143.39128 ++	xcb_present_notify_msc(c, win, 0xc0ffee00, msc, 0, 0);
143.39129 ++	xcb_present_notify_msc(c, win, 0xc0ffee01, msc + 10, 0, 0);
143.39130 ++	xcb_flush(c);
143.39131 ++
143.39132 ++	ust = msc = 0;
143.39133 ++	do {
143.39134 ++		xcb_present_complete_notify_event_t *ce;
143.39135 ++		xcb_generic_event_t *ev;
143.39136 ++
143.39137 ++		ev = xcb_wait_for_special_event(c, q);
143.39138 ++		if (ev == NULL)
143.39139 ++			break;
143.39140 ++
143.39141 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.39142 ++		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
143.39143 ++		    ce->serial == 0xc0ffee00) {
143.39144 ++			msc -= ce->msc;
143.39145 ++			ust -= ce->ust;
143.39146 ++			complete++;
143.39147 ++		}
143.39148 ++		if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
143.39149 ++		    ce->serial == 0xc0ffee01) {
143.39150 ++			msc += ce->msc;
143.39151 ++			ust += ce->ust;
143.39152 ++			complete++;
143.39153 ++		}
143.39154 ++		free(ev);
143.39155 ++	} while (complete != 2);
143.39156 ++
143.39157 ++	printf("10 frame interval: msc=%lld, ust=%lld\n",
143.39158 ++	       (long long)msc, (long long)ust);
143.39159 ++	XSync(dpy, True);
143.39160 ++	if (msc == 0)
143.39161 ++		return 0;
143.39162 ++
143.39163 ++	return (ust + msc/2) / msc;
143.39164 ++}
143.39165 ++
143.39166 ++static void teardown_msc(Display *dpy, void *q)
143.39167 ++{
143.39168 ++	xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
143.39169 ++}
143.39170 ++
143.39171 ++static int test_whole(Display *dpy, Window win, const char *phase)
143.39172 ++{
143.39173 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39174 ++	Pixmap pixmap;
143.39175 ++	struct dri3_fence fence;
143.39176 ++	Window root;
143.39177 ++	unsigned int width, height;
143.39178 ++	unsigned border, depth;
143.39179 ++	int x, y, ret = 1;
143.39180 ++
143.39181 ++	XGetGeometry(dpy, win,
143.39182 ++		     &root, &x, &y, &width, &height, &border, &depth);
143.39183 ++
143.39184 ++	if (dri3_create_fence(dpy, win, &fence))
143.39185 ++		return 0;
143.39186 ++
143.39187 ++	printf("%s: Testing simple flip: %dx%d\n", phase, width, height);
143.39188 ++	_x_error_occurred = 0;
143.39189 ++
143.39190 ++	xshmfence_reset(fence.addr);
143.39191 ++
143.39192 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.39193 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.39194 ++			   0, /* valid */
143.39195 ++			   0, /* update */
143.39196 ++			   0, /* x_off */
143.39197 ++			   0, /* y_off */
143.39198 ++			   None,
143.39199 ++			   None, /* wait fence */
143.39200 ++			   fence.xid,
143.39201 ++			   XCB_PRESENT_OPTION_NONE,
143.39202 ++			   0, /* target msc */
143.39203 ++			   0, /* divisor */
143.39204 ++			   0, /* remainder */
143.39205 ++			   0, NULL);
143.39206 ++	XFreePixmap(dpy, pixmap);
143.39207 ++
143.39208 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.39209 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.39210 ++			   0, /* valid */
143.39211 ++			   0, /* update */
143.39212 ++			   0, /* x_off */
143.39213 ++			   0, /* y_off */
143.39214 ++			   None,
143.39215 ++			   None, /* wait fence */
143.39216 ++			   None, /* sync fence */
143.39217 ++			   XCB_PRESENT_OPTION_NONE,
143.39218 ++			   0, /* target msc */
143.39219 ++			   0, /* divisor */
143.39220 ++			   0, /* remainder */
143.39221 ++			   0, NULL);
143.39222 ++	XFreePixmap(dpy, pixmap);
143.39223 ++	XFlush(dpy);
143.39224 ++
143.39225 ++	ret = !!xshmfence_await(fence.addr);
143.39226 ++	dri3_fence_free(dpy, &fence);
143.39227 ++
143.39228 ++	XSync(dpy, True);
143.39229 ++	ret += !!_x_error_occurred;
143.39230 ++
143.39231 ++	return ret;
143.39232 ++}
143.39233 ++
143.39234 ++static uint64_t flush_flips(Display *dpy, Window win, Pixmap pixmap, void *Q, uint64_t *ust)
143.39235 ++{
143.39236 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39237 ++	uint64_t msc;
143.39238 ++	int complete;
143.39239 ++
143.39240 ++	msc = check_msc(dpy, win, Q, 0, NULL);
143.39241 ++	xcb_present_pixmap(c, win, pixmap,
143.39242 ++			   0xdeadbeef, /* serial */
143.39243 ++			   0, /* valid */
143.39244 ++			   0, /* update */
143.39245 ++			   0, /* x_off */
143.39246 ++			   0, /* y_off */
143.39247 ++			   None,
143.39248 ++			   None, /* wait fence */
143.39249 ++			   None,
143.39250 ++			   XCB_PRESENT_OPTION_NONE,
143.39251 ++			   msc + 60, /* target msc */
143.39252 ++			   0, /* divisor */
143.39253 ++			   0, /* remainder */
143.39254 ++			   0, NULL);
143.39255 ++	xcb_flush(c);
143.39256 ++	complete = 0;
143.39257 ++	do {
143.39258 ++		xcb_present_complete_notify_event_t *ce;
143.39259 ++		xcb_generic_event_t *ev;
143.39260 ++
143.39261 ++		ev = xcb_wait_for_special_event(c, Q);
143.39262 ++		if (ev == NULL)
143.39263 ++			break;
143.39264 ++
143.39265 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.39266 ++		complete = (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
143.39267 ++			    ce->serial == 0xdeadbeef);
143.39268 ++		free(ev);
143.39269 ++	} while (!complete);
143.39270 ++	XSync(dpy, True);
143.39271 ++
143.39272 ++	return check_msc(dpy, win, Q, msc, ust);
143.39273 ++}
143.39274 ++
143.39275 ++static int test_double(Display *dpy, Window win, const char *phase, void *Q)
143.39276 ++{
143.39277 ++#define COUNT (15*60)
143.39278 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39279 ++	Pixmap pixmap;
143.39280 ++	Window root;
143.39281 ++	unsigned int width, height;
143.39282 ++	unsigned border, depth;
143.39283 ++	int x, y, n, ret;
143.39284 ++	struct {
143.39285 ++		uint64_t msc, ust;
143.39286 ++	} frame[COUNT+1];
143.39287 ++	int offset = 0;
143.39288 ++
143.39289 ++	XGetGeometry(dpy, win,
143.39290 ++		     &root, &x, &y, &width, &height, &border, &depth);
143.39291 ++
143.39292 ++	printf("%s: Testing flip double buffering: %dx%d\n", phase, width, height);
143.39293 ++	_x_error_occurred = 0;
143.39294 ++
143.39295 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.39296 ++	flush_flips(dpy, win, pixmap, Q, NULL);
143.39297 ++	for (n = 0; n <= COUNT; n++) {
143.39298 ++		int complete;
143.39299 ++
143.39300 ++		xcb_present_pixmap(c, win, pixmap, n,
143.39301 ++				   0, /* valid */
143.39302 ++				   0, /* update */
143.39303 ++				   0, /* x_off */
143.39304 ++				   0, /* y_off */
143.39305 ++				   None,
143.39306 ++				   None, /* wait fence */
143.39307 ++				   None,
143.39308 ++				   XCB_PRESENT_OPTION_NONE,
143.39309 ++				   0, /* target msc */
143.39310 ++				   0, /* divisor */
143.39311 ++				   0, /* remainder */
143.39312 ++				   0, NULL);
143.39313 ++		xcb_flush(c);
143.39314 ++
143.39315 ++		complete = 0;
143.39316 ++		do {
143.39317 ++			xcb_present_complete_notify_event_t *ce;
143.39318 ++			xcb_generic_event_t *ev;
143.39319 ++
143.39320 ++			ev = xcb_wait_for_special_event(c, Q);
143.39321 ++			if (ev == NULL)
143.39322 ++				break;
143.39323 ++
143.39324 ++			ce = (xcb_present_complete_notify_event_t *)ev;
143.39325 ++			if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
143.39326 ++			    ce->serial == n) {
143.39327 ++				frame[n].msc = ce->msc;
143.39328 ++				frame[n].ust = ce->ust;
143.39329 ++				complete = 1;
143.39330 ++			}
143.39331 ++			free(ev);
143.39332 ++		} while (!complete);
143.39333 ++	}
143.39334 ++	XFreePixmap(dpy, pixmap);
143.39335 ++
143.39336 ++	XSync(dpy, True);
143.39337 ++	ret = !!_x_error_occurred;
143.39338 ++
143.39339 ++	if (frame[COUNT].msc - frame[0].msc != COUNT) {
143.39340 ++		printf("Expected %d frames interval, %d elapsed instead\n",
143.39341 ++		       COUNT, (int)(frame[COUNT].msc - frame[0].msc));
143.39342 ++		for (n = 0; n <= COUNT; n++) {
143.39343 ++			if (frame[n].msc - frame[0].msc != n + offset) {
143.39344 ++				printf("frame[%d]: msc=%03lld, ust=%lld\n", n,
143.39345 ++				       (long long)(frame[n].msc - frame[0].msc),
143.39346 ++				       (long long)(frame[n].ust - frame[0].ust));
143.39347 ++				offset = frame[n].msc - frame[0].msc - n;
143.39348 ++				ret++;
143.39349 ++			}
143.39350 ++		}
143.39351 ++	}
143.39352 ++
143.39353 ++	return ret;
143.39354 ++}
143.39355 ++
143.39356 ++static int test_future(Display *dpy, Window win, const char *phase, void *Q)
143.39357 ++{
143.39358 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39359 ++	Pixmap pixmap;
143.39360 ++	struct dri3_fence fence;
143.39361 ++	Window root;
143.39362 ++	unsigned int width, height;
143.39363 ++	unsigned border, depth;
143.39364 ++	int x, y, ret = 0, n;
143.39365 ++	uint64_t msc, ust;
143.39366 ++	int complete, count;
143.39367 ++	int early = 0, late = 0;
143.39368 ++	int earliest = 0, latest = 0;
143.39369 ++	uint64_t interval;
143.39370 ++
143.39371 ++	XGetGeometry(dpy, win,
143.39372 ++		     &root, &x, &y, &width, &height, &border, &depth);
143.39373 ++
143.39374 ++	if (dri3_create_fence(dpy, win, &fence))
143.39375 ++		return 0;
143.39376 ++
143.39377 ++	printf("%s: Testing flips into the future: %dx%d\n", phase, width, height);
143.39378 ++	_x_error_occurred = 0;
143.39379 ++
143.39380 ++	interval = msc_interval(dpy, win, Q);
143.39381 ++	if (interval == 0) {
143.39382 ++		printf("Zero delay between frames\n");
143.39383 ++		return 1;
143.39384 ++	}
143.39385 ++
143.39386 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.39387 ++	msc = flush_flips(dpy, win, pixmap, Q, &ust);
143.39388 ++	for (n = 1; n <= 10; n++)
143.39389 ++		xcb_present_pixmap(c, win, pixmap,
143.39390 ++				   n, /* serial */
143.39391 ++				   0, /* valid */
143.39392 ++				   0, /* update */
143.39393 ++				   0, /* x_off */
143.39394 ++				   0, /* y_off */
143.39395 ++				   None,
143.39396 ++				   None, /* wait fence */
143.39397 ++				   None,
143.39398 ++				   XCB_PRESENT_OPTION_NONE,
143.39399 ++				   msc + 60 + n*15*60, /* target msc */
143.39400 ++				   0, /* divisor */
143.39401 ++				   0, /* remainder */
143.39402 ++				   0, NULL);
143.39403 ++	xcb_present_pixmap(c, win, pixmap,
143.39404 ++			   0xdeadbeef, /* serial */
143.39405 ++			   0, /* valid */
143.39406 ++			   0, /* update */
143.39407 ++			   0, /* x_off */
143.39408 ++			   0, /* y_off */
143.39409 ++			   None,
143.39410 ++			   None, /* wait fence */
143.39411 ++			   None,
143.39412 ++			   XCB_PRESENT_OPTION_NONE,
143.39413 ++			   msc + 60 + n*15*60, /* target msc */
143.39414 ++			   0, /* divisor */
143.39415 ++			   0, /* remainder */
143.39416 ++			   0, NULL);
143.39417 ++	xcb_flush(c);
143.39418 ++
143.39419 ++	complete = 0;
143.39420 ++	count = 0;
143.39421 ++	do {
143.39422 ++		xcb_present_complete_notify_event_t *ce;
143.39423 ++		xcb_generic_event_t *ev;
143.39424 ++
143.39425 ++		ev = xcb_wait_for_special_event(c, Q);
143.39426 ++		if (ev == NULL)
143.39427 ++			break;
143.39428 ++
143.39429 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.39430 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
143.39431 ++
143.39432 ++		if (ce->serial == 0xdeadbeef) {
143.39433 ++			int64_t time;
143.39434 ++
143.39435 ++			time = ce->ust - (ust + (60 + 15*60*n) * interval);
143.39436 ++			if (time < -(int64_t)interval) {
143.39437 ++				fprintf(stderr,
143.39438 ++					"\tflips completed too early by %lldms\n",
143.39439 ++					(long long)(-time / 1000));
143.39440 ++			} else if (time > (int64_t)interval) {
143.39441 ++				fprintf(stderr,
143.39442 ++					"\tflips completed too late by %lldms\n",
143.39443 ++					(long long)(time / 1000));
143.39444 ++			}
143.39445 ++			complete = 1;
143.39446 ++		} else {
143.39447 ++			int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60));
143.39448 ++			if (diff < 0) {
143.39449 ++				if (-diff > earliest) {
143.39450 ++					fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff);
143.39451 ++					earliest = -diff;
143.39452 ++				}
143.39453 ++				early++;
143.39454 ++				ret++;
143.39455 ++			} else if (diff > 0) {
143.39456 ++				if (diff > latest) {
143.39457 ++					fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
143.39458 ++					latest = diff;
143.39459 ++				}
143.39460 ++				late++;
143.39461 ++				ret++;
143.39462 ++			}
143.39463 ++			count++;
143.39464 ++		}
143.39465 ++		free(ev);
143.39466 ++	} while (!complete);
143.39467 ++
143.39468 ++	if (early)
143.39469 ++		printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
143.39470 ++	if (late)
143.39471 ++		printf("\t%d frames shown too late (worst %d)!\n", late, latest);
143.39472 ++
143.39473 ++	if (count != 10) {
143.39474 ++		fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", 10 - count);
143.39475 ++		ret++;
143.39476 ++
143.39477 ++		do {
143.39478 ++			xcb_present_complete_notify_event_t *ce;
143.39479 ++			xcb_generic_event_t *ev;
143.39480 ++
143.39481 ++			ev = xcb_wait_for_special_event(c, Q);
143.39482 ++			if (ev == NULL)
143.39483 ++				break;
143.39484 ++
143.39485 ++			ce = (xcb_present_complete_notify_event_t *)ev;
143.39486 ++			assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
143.39487 ++			free(ev);
143.39488 ++		} while (++count != 10);
143.39489 ++	}
143.39490 ++
143.39491 ++	ret += !!_x_error_occurred;
143.39492 ++
143.39493 ++	return ret;
143.39494 ++}
143.39495 ++
143.39496 ++static int test_exhaustion(Display *dpy, Window win, const char *phase, void *Q)
143.39497 ++{
143.39498 ++#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
143.39499 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39500 ++	Pixmap pixmap;
143.39501 ++	struct dri3_fence fence[2];
143.39502 ++	Window root;
143.39503 ++	xcb_xfixes_region_t region;
143.39504 ++	unsigned int width, height;
143.39505 ++	unsigned border, depth;
143.39506 ++	int x, y, ret = 0, n;
143.39507 ++	uint64_t target, final;
143.39508 ++
143.39509 ++	XGetGeometry(dpy, win,
143.39510 ++		     &root, &x, &y, &width, &height, &border, &depth);
143.39511 ++
143.39512 ++	if (dri3_create_fence(dpy, win, &fence[0]) ||
143.39513 ++	    dri3_create_fence(dpy, win, &fence[1]))
143.39514 ++		return 0;
143.39515 ++
143.39516 ++	printf("%s: Testing flips with long vblank queues: %dx%d\n", phase, width, height);
143.39517 ++	_x_error_occurred = 0;
143.39518 ++
143.39519 ++	region = xcb_generate_id(c);
143.39520 ++	xcb_xfixes_create_region(c, region, 0, NULL);
143.39521 ++
143.39522 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.39523 ++	xshmfence_reset(fence[0].addr);
143.39524 ++	xshmfence_reset(fence[1].addr);
143.39525 ++	target = check_msc(dpy, win, Q, 0, NULL);
143.39526 ++	for (n = N_VBLANKS; n--; )
143.39527 ++		xcb_present_pixmap(c, win, pixmap, 0,
143.39528 ++				   0, /* valid */
143.39529 ++				   region, /* update */
143.39530 ++				   0, /* x_off */
143.39531 ++				   0, /* y_off */
143.39532 ++				   None,
143.39533 ++				   None, /* wait fence */
143.39534 ++				   None,
143.39535 ++				   XCB_PRESENT_OPTION_NONE,
143.39536 ++				   target + N_VBLANKS, /* target msc */
143.39537 ++				   1, /* divisor */
143.39538 ++				   0, /* remainder */
143.39539 ++				   0, NULL);
143.39540 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.39541 ++			   region, /* valid */
143.39542 ++			   region, /* update */
143.39543 ++			   0, /* x_off */
143.39544 ++			   0, /* y_off */
143.39545 ++			   None,
143.39546 ++			   None, /* wait fence */
143.39547 ++			   fence[0].xid,
143.39548 ++			   XCB_PRESENT_OPTION_NONE,
143.39549 ++			   target, /* target msc */
143.39550 ++			   0, /* divisor */
143.39551 ++			   0, /* remainder */
143.39552 ++			   0, NULL);
143.39553 ++	for (n = 1; n < N_VBLANKS; n++)
143.39554 ++		xcb_present_pixmap(c, win, pixmap, 0,
143.39555 ++				   region, /* valid */
143.39556 ++				   region, /* update */
143.39557 ++				   0, /* x_off */
143.39558 ++				   0, /* y_off */
143.39559 ++				   None,
143.39560 ++				   None, /* wait fence */
143.39561 ++				   None,
143.39562 ++				   XCB_PRESENT_OPTION_NONE,
143.39563 ++				   target + n, /* target msc */
143.39564 ++				   0, /* divisor */
143.39565 ++				   0, /* remainder */
143.39566 ++				   0, NULL);
143.39567 ++	xcb_present_pixmap(c, win, pixmap, 0,
143.39568 ++			   region, /* valid */
143.39569 ++			   region, /* update */
143.39570 ++			   0, /* x_off */
143.39571 ++			   0, /* y_off */
143.39572 ++			   None,
143.39573 ++			   None, /* wait fence */
143.39574 ++			   fence[1].xid,
143.39575 ++			   XCB_PRESENT_OPTION_NONE,
143.39576 ++			   target + N_VBLANKS, /* target msc */
143.39577 ++			   0, /* divisor */
143.39578 ++			   0, /* remainder */
143.39579 ++			   0, NULL);
143.39580 ++	xcb_flush(c);
143.39581 ++
143.39582 ++	ret += !!xshmfence_await(fence[0].addr);
143.39583 ++	final = check_msc(dpy, win, Q, 0, NULL);
143.39584 ++	if (final < target) {
143.39585 ++		printf("\tFirst flip too early, MSC was %llu, expected %llu\n",
143.39586 ++		       (long long)final, (long long)target);
143.39587 ++		ret++;
143.39588 ++	} else if (final > target + 1) {
143.39589 ++		printf("\tFirst flip too late, MSC was %llu, expected %llu\n",
143.39590 ++		       (long long)final, (long long)target);
143.39591 ++		ret++;
143.39592 ++	}
143.39593 ++
143.39594 ++	ret += !!xshmfence_await(fence[1].addr);
143.39595 ++	final = check_msc(dpy, win, Q, 0, NULL);
143.39596 ++	if (final < target + N_VBLANKS) {
143.39597 ++		printf("\tLast flip too early, MSC was %llu, expected %llu\n",
143.39598 ++		       (long long)final, (long long)(target + N_VBLANKS));
143.39599 ++		ret++;
143.39600 ++	} else if (final > target + N_VBLANKS + 1) {
143.39601 ++		printf("\tLast flip too late, MSC was %llu, expected %llu\n",
143.39602 ++		       (long long)final, (long long)(target + N_VBLANKS));
143.39603 ++		ret++;
143.39604 ++	}
143.39605 ++
143.39606 ++	flush_flips(dpy, win, pixmap, Q, NULL);
143.39607 ++
143.39608 ++	XFreePixmap(dpy, pixmap);
143.39609 ++	xcb_xfixes_destroy_region(c, region);
143.39610 ++	dri3_fence_free(dpy, &fence[1]);
143.39611 ++	dri3_fence_free(dpy, &fence[0]);
143.39612 ++
143.39613 ++	XSync(dpy, True);
143.39614 ++	ret += !!_x_error_occurred;
143.39615 ++
143.39616 ++	return ret;
143.39617 ++#undef N_VBLANKS
143.39618 ++}
143.39619 ++
143.39620 ++static int test_accuracy(Display *dpy, Window win, const char *phase, void *Q)
143.39621 ++{
143.39622 ++#define N_VBLANKS (60 * 120) /* ~2 minutes */
143.39623 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39624 ++	Pixmap pixmap;
143.39625 ++	Window root;
143.39626 ++	unsigned int width, height;
143.39627 ++	unsigned border, depth;
143.39628 ++	int x, y, ret = 0, n;
143.39629 ++	uint64_t target;
143.39630 ++	int early = 0, late = 0;
143.39631 ++	int earliest = 0, latest = 0;
143.39632 ++	int complete, count;
143.39633 ++
143.39634 ++	XGetGeometry(dpy, win,
143.39635 ++		     &root, &x, &y, &width, &height, &border, &depth);
143.39636 ++
143.39637 ++	printf("%s: Testing flip accuracy: %dx%d\n", phase, width, height);
143.39638 ++	_x_error_occurred = 0;
143.39639 ++
143.39640 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.39641 ++	target = flush_flips(dpy, win, pixmap, Q, NULL);
143.39642 ++	for (n = 0; n <= N_VBLANKS; n++)
143.39643 ++		xcb_present_pixmap(c, win, pixmap,
143.39644 ++				   n, /* serial */
143.39645 ++				   0, /* valid */
143.39646 ++				   0, /* update */
143.39647 ++				   0, /* x_off */
143.39648 ++				   0, /* y_off */
143.39649 ++				   None,
143.39650 ++				   None, /* wait fence */
143.39651 ++				   None,
143.39652 ++				   XCB_PRESENT_OPTION_NONE,
143.39653 ++				   target + 60 + n, /* target msc */
143.39654 ++				   0, /* divisor */
143.39655 ++				   0, /* remainder */
143.39656 ++				   0, NULL);
143.39657 ++	xcb_present_pixmap(c, win, pixmap,
143.39658 ++			   0xdeadbeef, /* serial */
143.39659 ++			   0, /* valid */
143.39660 ++			   0, /* update */
143.39661 ++			   0, /* x_off */
143.39662 ++			   0, /* y_off */
143.39663 ++			   None,
143.39664 ++			   None, /* wait fence */
143.39665 ++			   None,
143.39666 ++			   XCB_PRESENT_OPTION_NONE,
143.39667 ++			   target + 60 + n, /* target msc */
143.39668 ++			   0, /* divisor */
143.39669 ++			   0, /* remainder */
143.39670 ++			   0, NULL);
143.39671 ++	xcb_flush(c);
143.39672 ++
143.39673 ++	complete = 0;
143.39674 ++	count = 0;
143.39675 ++	do {
143.39676 ++		xcb_present_complete_notify_event_t *ce;
143.39677 ++		xcb_generic_event_t *ev;
143.39678 ++
143.39679 ++		ev = xcb_wait_for_special_event(c, Q);
143.39680 ++		if (ev == NULL)
143.39681 ++			break;
143.39682 ++
143.39683 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.39684 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
143.39685 ++
143.39686 ++		if (ce->serial != 0xdeadbeef) {
143.39687 ++			int diff = (int64_t)(ce->msc - (target + ce->serial + 60));
143.39688 ++			if (diff < 0) {
143.39689 ++				if (-diff > earliest) {
143.39690 ++					fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff);
143.39691 ++					earliest = -diff;
143.39692 ++				}
143.39693 ++				early++;
143.39694 ++				ret++;
143.39695 ++			} else if (diff > 0) {
143.39696 ++				if (diff > latest) {
143.39697 ++					fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
143.39698 ++					latest = diff;
143.39699 ++				}
143.39700 ++				late++;
143.39701 ++				ret++;
143.39702 ++			}
143.39703 ++			count++;
143.39704 ++		} else
143.39705 ++			complete = 1;
143.39706 + 		free(ev);
143.39707 +-	} while (msc == 0);
143.39708 ++	} while (!complete);
143.39709 ++
143.39710 ++	if (early)
143.39711 ++		printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
143.39712 ++	if (late)
143.39713 ++		printf("\t%d frames shown too late (worst %d)!\n", late, latest);
143.39714 ++
143.39715 ++	if (count != N_VBLANKS+1) {
143.39716 ++		fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", N_VBLANKS+1 - count);
143.39717 ++		ret++;
143.39718 ++		do {
143.39719 ++			xcb_present_complete_notify_event_t *ce;
143.39720 ++			xcb_generic_event_t *ev;
143.39721 ++
143.39722 ++			ev = xcb_wait_for_special_event(c, Q);
143.39723 ++			if (ev == NULL)
143.39724 ++				break;
143.39725 ++
143.39726 ++			ce = (xcb_present_complete_notify_event_t *)ev;
143.39727 ++			assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
143.39728 ++			free(ev);
143.39729 ++		} while (++count != N_VBLANKS+1);
143.39730 ++	}
143.39731 ++
143.39732 ++	XFreePixmap(dpy, pixmap);
143.39733 ++
143.39734 ++	XSync(dpy, True);
143.39735 ++	ret += !!_x_error_occurred;
143.39736 ++
143.39737 ++	return ret;
143.39738 ++#undef N_VBLANKS
143.39739 ++}
143.39740 ++
143.39741 ++static int test_modulus(Display *dpy, Window win, const char *phase, void *Q)
143.39742 ++{
143.39743 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39744 ++	Pixmap pixmap;
143.39745 ++	Window root;
143.39746 ++	unsigned int width, height;
143.39747 ++	unsigned border, depth;
143.39748 ++	xcb_xfixes_region_t region;
143.39749 ++	int x, y, ret = 0;
143.39750 ++	uint64_t target;
143.39751 ++	int early = 0, late = 0;
143.39752 ++	int earliest = 0, latest = 0;
143.39753 ++	int complete, expect, count;
143.39754 ++
143.39755 ++	XGetGeometry(dpy, win,
143.39756 ++		     &root, &x, &y, &width, &height, &border, &depth);
143.39757 ++
143.39758 ++	printf("%s: Testing flip modulus: %dx%d\n", phase, width, height);
143.39759 ++	_x_error_occurred = 0;
143.39760 ++
143.39761 ++	region = xcb_generate_id(c);
143.39762 ++	xcb_xfixes_create_region(c, region, 0, NULL);
143.39763 ++
143.39764 ++	pixmap = XCreatePixmap(dpy, win, width, height, depth);
143.39765 ++	target = flush_flips(dpy, win, pixmap, Q, NULL);
143.39766 ++	expect = 0;
143.39767 ++	for (x = 1; x <= 7; x++) {
143.39768 ++		for (y = 0; y < x; y++) {
143.39769 ++			xcb_present_pixmap(c, win, pixmap,
143.39770 ++					   y << 16 | x, /* serial */
143.39771 ++					   region, /* valid */
143.39772 ++					   region, /* update */
143.39773 ++					   0, /* x_off */
143.39774 ++					   0, /* y_off */
143.39775 ++					   None,
143.39776 ++					   None, /* wait fence */
143.39777 ++					   None,
143.39778 ++					   XCB_PRESENT_OPTION_NONE,
143.39779 ++					   0, /* target msc */
143.39780 ++					   x, /* divisor */
143.39781 ++					   y, /* remainder */
143.39782 ++					   0, NULL);
143.39783 ++			expect++;
143.39784 ++		}
143.39785 ++	}
143.39786 ++	xcb_present_pixmap(c, win, pixmap,
143.39787 ++			   0xdeadbeef, /* serial */
143.39788 ++			   0, /* valid */
143.39789 ++			   0, /* update */
143.39790 ++			   0, /* x_off */
143.39791 ++			   0, /* y_off */
143.39792 ++			   None,
143.39793 ++			   None, /* wait fence */
143.39794 ++			   None,
143.39795 ++			   XCB_PRESENT_OPTION_NONE,
143.39796 ++			   target + 2*x, /* target msc */
143.39797 ++			   0, /* divisor */
143.39798 ++			   0, /* remainder */
143.39799 ++			   0, NULL);
143.39800 ++	xcb_flush(c);
143.39801 ++
143.39802 ++	complete = 0;
143.39803 ++	count = 0;
143.39804 ++	do {
143.39805 ++		xcb_present_complete_notify_event_t *ce;
143.39806 ++		xcb_generic_event_t *ev;
143.39807 ++
143.39808 ++		ev = xcb_wait_for_special_event(c, Q);
143.39809 ++		if (ev == NULL)
143.39810 ++			break;
143.39811 ++
143.39812 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.39813 ++		if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
143.39814 ++			break;
143.39815 ++
143.39816 ++		assert(ce->serial);
143.39817 ++		if (ce->serial != 0xdeadbeef) {
143.39818 ++			uint64_t msc;
143.39819 ++			int diff;
143.39820 ++
143.39821 ++			x = ce->serial & 0xffff;
143.39822 ++			y = ce->serial >> 16;
143.39823 ++
143.39824 ++			msc = target;
143.39825 ++			msc -= target % x;
143.39826 ++			msc += y;
143.39827 ++			if (msc <= target)
143.39828 ++				msc += x;
143.39829 ++
143.39830 ++			diff = (int64_t)(ce->msc - msc);
143.39831 ++			if (diff < 0) {
143.39832 ++				if (-diff > earliest) {
143.39833 ++					fprintf(stderr, "\tframe (%d, %d) displayed early by %d frames\n", y, x, -diff);
143.39834 ++					earliest = -diff;
143.39835 ++				}
143.39836 ++				early++;
143.39837 ++				ret++;
143.39838 ++			} else if (diff > 0) {
143.39839 ++				if (diff > latest) {
143.39840 ++					fprintf(stderr, "\tframe (%d, %d) displayed late by %d frames\n", y, x, diff);
143.39841 ++					latest = diff;
143.39842 ++				}
143.39843 ++				late++;
143.39844 ++				ret++;
143.39845 ++			}
143.39846 ++			count++;
143.39847 ++		} else
143.39848 ++			complete = 1;
143.39849 ++		free(ev);
143.39850 ++	} while (!complete);
143.39851 ++
143.39852 ++	if (early)
143.39853 ++		printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
143.39854 ++	if (late)
143.39855 ++		printf("\t%d frames shown too late (worst %d)!\n", late, latest);
143.39856 ++
143.39857 ++	if (count != expect) {
143.39858 ++		fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", expect - count);
143.39859 ++		ret++;
143.39860 ++		do {
143.39861 ++			xcb_present_complete_notify_event_t *ce;
143.39862 ++			xcb_generic_event_t *ev;
143.39863 ++
143.39864 ++			ev = xcb_wait_for_special_event(c, Q);
143.39865 ++			if (ev == NULL)
143.39866 ++				break;
143.39867 ++
143.39868 ++			ce = (xcb_present_complete_notify_event_t *)ev;
143.39869 ++			assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.39870 ++			free(ev);
143.39871 ++		} while (++count != expect);
143.39872 ++	}
143.39873 ++
143.39874 ++	XFreePixmap(dpy, pixmap);
143.39875 ++	xcb_xfixes_destroy_region(c, region);
143.39876 ++
143.39877 ++	XSync(dpy, True);
143.39878 ++	ret += !!_x_error_occurred;
143.39879 ++
143.39880 ++	return ret;
143.39881 ++}
143.39882 ++
143.39883 ++static int test_future_msc(Display *dpy, void *Q)
143.39884 ++{
143.39885 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.39886 ++	Window root = DefaultRootWindow(dpy);
143.39887 ++	int ret = 0, n;
143.39888 ++	uint64_t msc, ust;
143.39889 ++	int complete, count;
143.39890 ++	int early = 0, late = 0;
143.39891 ++	int earliest = 0, latest = 0;
143.39892 ++	uint64_t interval;
143.39893 ++
143.39894 ++	printf("Testing notifies into the future\n");
143.39895 ++	_x_error_occurred = 0;
143.39896 ++
143.39897 ++	interval = msc_interval(dpy, root, Q);
143.39898 ++	if (interval == 0) {
143.39899 ++		printf("Zero delay between frames\n");
143.39900 ++		return 1;
143.39901 ++	}
143.39902 ++	msc = check_msc(dpy, root, Q, 0, &ust);
143.39903 ++	printf("Initial msc=%llx, interval between frames %lldus\n",
143.39904 ++	       (long long)msc, (long long)interval);
143.39905 ++
143.39906 ++	for (n = 1; n <= 10; n++)
143.39907 ++		xcb_present_notify_msc(c, root, n, msc + 60 + n*15*60, 0, 0);
143.39908 ++	xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n*15*60, 0, 0);
143.39909 ++	xcb_flush(c);
143.39910 ++
143.39911 ++	complete = 0;
143.39912 ++	count = 0;
143.39913 ++	do {
143.39914 ++		xcb_present_complete_notify_event_t *ce;
143.39915 ++		xcb_generic_event_t *ev;
143.39916 ++
143.39917 ++		ev = xcb_wait_for_special_event(c, Q);
143.39918 ++		if (ev == NULL)
143.39919 ++			break;
143.39920 ++
143.39921 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.39922 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.39923 ++
143.39924 ++		if (ce->serial == 0xdeadbeef) {
143.39925 ++			int64_t time, tolerance;
143.39926 ++
143.39927 ++			tolerance = 60 + 15*60*n/10;
143.39928 ++			if (tolerance < interval)
143.39929 ++				tolerance = interval;
143.39930 ++
143.39931 ++			time = ce->ust - (ust + (60 + 15*60*n) * interval);
143.39932 ++			if (time < -(int64_t)tolerance) {
143.39933 ++				fprintf(stderr,
143.39934 ++					"\tnotifies completed too early by %lldms, tolerance %lldus\n",
143.39935 ++					(long long)(-time / 1000), (long long)tolerance);
143.39936 ++			} else if (time > (int64_t)tolerance) {
143.39937 ++				fprintf(stderr,
143.39938 ++					"\tnotifies completed too late by %lldms, tolerance %lldus\n",
143.39939 ++					(long long)(time / 1000), (long long)tolerance);
143.39940 ++			}
143.39941 ++			complete = 1;
143.39942 ++		} else {
143.39943 ++			int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60));
143.39944 ++
143.39945 ++			if (ce->serial != count + 1) {
143.39946 ++				fprintf(stderr, "vblank received out of order! expected %d, received %d\n",
143.39947 ++					count + 1, (int)ce->serial);
143.39948 ++				ret++;
143.39949 ++			}
143.39950 ++			count++;
143.39951 ++
143.39952 ++			if (diff < 0) {
143.39953 ++				if (-diff > earliest) {
143.39954 ++					fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff);
143.39955 ++					earliest = -diff;
143.39956 ++				}
143.39957 ++				early++;
143.39958 ++				ret++;
143.39959 ++			} else if (diff > 0) {
143.39960 ++				if (diff > latest) {
143.39961 ++					fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff);
143.39962 ++					latest = diff;
143.39963 ++				}
143.39964 ++				late++;
143.39965 ++				ret++;
143.39966 ++			}
143.39967 ++		}
143.39968 ++		free(ev);
143.39969 ++	} while (!complete);
143.39970 ++
143.39971 ++	if (early)
143.39972 ++		printf("\t%d notifies too early (worst %d)!\n", early, earliest);
143.39973 ++	if (late)
143.39974 ++		printf("\t%d notifies too late (worst %d)!\n", late, latest);
143.39975 ++
143.39976 ++	if (count != 10) {
143.39977 ++		fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", 10 - count);
143.39978 ++		ret++;
143.39979 ++		do {
143.39980 ++			xcb_present_complete_notify_event_t *ce;
143.39981 ++			xcb_generic_event_t *ev;
143.39982 ++
143.39983 ++			ev = xcb_wait_for_special_event(c, Q);
143.39984 ++			if (ev == NULL)
143.39985 ++				break;
143.39986 ++
143.39987 ++			ce = (xcb_present_complete_notify_event_t *)ev;
143.39988 ++			assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.39989 ++			free(ev);
143.39990 ++		} while (++count != 10);
143.39991 ++	}
143.39992 ++
143.39993 ++	XSync(dpy, True);
143.39994 ++	ret += !!_x_error_occurred;
143.39995 ++
143.39996 ++	return ret;
143.39997 ++}
143.39998 ++
143.39999 ++static int test_wrap_msc(Display *dpy)
143.40000 ++{
143.40001 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.40002 ++	Window root, win;
143.40003 ++	int x, y;
143.40004 ++	unsigned int width, height;
143.40005 ++	unsigned border, depth;
143.40006 ++	XSetWindowAttributes attr;
143.40007 ++	int ret = 0, n;
143.40008 ++	uint64_t msc, ust;
143.40009 ++	int complete;
143.40010 ++	uint64_t interval;
143.40011 ++	void *Q;
143.40012 ++
143.40013 ++	XGetGeometry(dpy, DefaultRootWindow(dpy),
143.40014 ++		     &root, &x, &y, &width, &height, &border, &depth);
143.40015 ++
143.40016 ++	attr.override_redirect = 1;
143.40017 ++	win = XCreateWindow(dpy, root,
143.40018 ++			    0, 0, width, height, 0, depth,
143.40019 ++			    InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)),
143.40020 ++			    CWOverrideRedirect, &attr);
143.40021 ++	XMapWindow(dpy, win);
143.40022 ++	XSync(dpy, True);
143.40023 ++	if (_x_error_occurred)
143.40024 ++		return 1;
143.40025 + 
143.40026 +-	if (msc < last_msc) {
143.40027 +-		printf("Invalid MSC: was %llu, now %llu\n",
143.40028 +-		       (long long)last_msc, (long long)msc);
143.40029 ++	printf("Testing wraparound notifies\n");
143.40030 ++	_x_error_occurred = 0;
143.40031 ++
143.40032 ++	Q = setup_msc(dpy, win);
143.40033 ++	interval = msc_interval(dpy, win, Q);
143.40034 ++	if (interval == 0) {
143.40035 ++		printf("Zero delay between frames\n");
143.40036 ++		return 1;
143.40037 + 	}
143.40038 ++	msc = check_msc(dpy, win, Q, 0, &ust);
143.40039 ++	printf("Initial msc=%llx, interval between frames %lldus\n",
143.40040 ++	       (long long)msc, (long long)interval);
143.40041 ++
143.40042 ++	for (n = 1; n <= 10; n++)
143.40043 ++		xcb_present_notify_msc(c, win, n,
143.40044 ++				       msc + ((long long)n<<32) + n,
143.40045 ++				       0, 0);
143.40046 ++	for (n = 1; n <= 10; n++)
143.40047 ++		xcb_present_notify_msc(c, win, -n,
143.40048 ++				       0, (long long)n << 32, 0);
143.40049 ++	xcb_present_notify_msc(c, win, 0xdeadbeef, msc + 60*10, 0, 0);
143.40050 ++	xcb_flush(c);
143.40051 + 
143.40052 +-	return msc;
143.40053 ++	complete = 0;
143.40054 ++	do {
143.40055 ++		xcb_present_complete_notify_event_t *ce;
143.40056 ++		xcb_generic_event_t *ev;
143.40057 ++
143.40058 ++		ev = xcb_wait_for_special_event(c, Q);
143.40059 ++		if (ev == NULL)
143.40060 ++			break;
143.40061 ++
143.40062 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.40063 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.40064 ++
143.40065 ++		if (ce->serial == 0xdeadbeef) {
143.40066 ++			complete = 1;
143.40067 ++		} else {
143.40068 ++			fprintf(stderr,
143.40069 ++				"\tnotify %d recieved at +%llu\n",
143.40070 ++				ce->serial, ce->msc - msc);
143.40071 ++			ret++;
143.40072 ++		}
143.40073 ++		free(ev);
143.40074 ++	} while (!complete);
143.40075 ++
143.40076 ++	teardown_msc(dpy, Q);
143.40077 ++	XDestroyWindow(dpy, win);
143.40078 ++	XSync(dpy, True);
143.40079 ++
143.40080 ++	return ret;
143.40081 + }
143.40082 + 
143.40083 +-static void teardown_msc(Display *dpy, void *q)
143.40084 ++static int test_exhaustion_msc(Display *dpy, void *Q)
143.40085 + {
143.40086 +-	xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
143.40087 ++#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
143.40088 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.40089 ++	Window root = DefaultRootWindow(dpy);
143.40090 ++	int ret = 0, n, complete;
143.40091 ++	int earliest = 0, early = 0;
143.40092 ++	int latest = 0, late = 0;
143.40093 ++	uint64_t msc;
143.40094 ++
143.40095 ++	printf("Testing notifies with long queues\n");
143.40096 ++	_x_error_occurred = 0;
143.40097 ++
143.40098 ++	msc = check_msc(dpy, root, Q, 0, NULL);
143.40099 ++	for (n = N_VBLANKS; n--; )
143.40100 ++		xcb_present_notify_msc(c, root, N_VBLANKS, msc + N_VBLANKS, 0, 0);
143.40101 ++	for (n = 1; n <= N_VBLANKS ; n++)
143.40102 ++		xcb_present_notify_msc(c, root, n, msc + n, 0, 0);
143.40103 ++	xcb_flush(c);
143.40104 ++
143.40105 ++	complete = 2*N_VBLANKS;
143.40106 ++	do {
143.40107 ++		xcb_present_complete_notify_event_t *ce;
143.40108 ++		xcb_generic_event_t *ev;
143.40109 ++		int diff;
143.40110 ++
143.40111 ++		ev = xcb_wait_for_special_event(c, Q);
143.40112 ++		if (ev == NULL)
143.40113 ++			break;
143.40114 ++
143.40115 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.40116 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.40117 ++
143.40118 ++		diff = (int64_t)(ce->msc - msc - ce->serial);
143.40119 ++		if (diff < 0) {
143.40120 ++			if (-diff > earliest) {
143.40121 ++				fprintf(stderr, "\tnotify %d early by %d msc\n",(int)ce->serial, -diff);
143.40122 ++				earliest = -diff;
143.40123 ++			}
143.40124 ++			early++;
143.40125 ++			ret++;
143.40126 ++		} else if (diff > 0) {
143.40127 ++			if (diff > latest) {
143.40128 ++				fprintf(stderr, "\tnotify %d late by %d msc\n", (int)ce->serial, diff);
143.40129 ++				latest = diff;
143.40130 ++			}
143.40131 ++			late++;
143.40132 ++			ret++;
143.40133 ++		}
143.40134 ++		free(ev);
143.40135 ++	} while (--complete);
143.40136 ++
143.40137 ++	if (early)
143.40138 ++		printf("\t%d notifies too early (worst %d)!\n", early, earliest);
143.40139 ++	if (late)
143.40140 ++		printf("\t%d notifies too late (worst %d)!\n", late, latest);
143.40141 ++
143.40142 ++	XSync(dpy, True);
143.40143 ++	ret += !!_x_error_occurred;
143.40144 ++
143.40145 ++	return ret;
143.40146 ++#undef N_VBLANKS
143.40147 + }
143.40148 +-static int test_whole(Display *dpy)
143.40149 ++
143.40150 ++static int test_accuracy_msc(Display *dpy, void *Q)
143.40151 + {
143.40152 +-	Pixmap pixmap;
143.40153 +-	struct dri3_fence fence;
143.40154 +-	Window root;
143.40155 +-	unsigned int width, height;
143.40156 +-	unsigned border, depth;
143.40157 +-	int x, y, ret = 1;
143.40158 ++#define N_VBLANKS (60 * 120) /* ~2 minutes */
143.40159 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.40160 ++	Window root = DefaultRootWindow(dpy);
143.40161 ++	int ret = 0, n;
143.40162 ++	uint64_t msc;
143.40163 ++	int early = 0, late = 0;
143.40164 ++	int earliest = 0, latest = 0;
143.40165 ++	int complete, count;
143.40166 + 
143.40167 +-	XGetGeometry(dpy, DefaultRootWindow(dpy),
143.40168 +-		     &root, &x, &y, &width, &height, &border, &depth);
143.40169 ++	printf("Testing notify accuracy\n");
143.40170 ++	_x_error_occurred = 0;
143.40171 + 
143.40172 +-	if (dri3_create_fence(dpy, root, &fence))
143.40173 +-		return 0;
143.40174 ++	msc = check_msc(dpy, root, Q, 0, NULL);
143.40175 ++	for (n = 0; n <= N_VBLANKS; n++)
143.40176 ++		xcb_present_notify_msc(c, root, n, msc + 60 + n, 0, 0);
143.40177 ++	xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n, 0, 0);
143.40178 ++	xcb_flush(c);
143.40179 ++
143.40180 ++	complete = 0;
143.40181 ++	count = 0;
143.40182 ++	do {
143.40183 ++		xcb_present_complete_notify_event_t *ce;
143.40184 ++		xcb_generic_event_t *ev;
143.40185 ++
143.40186 ++		ev = xcb_wait_for_special_event(c, Q);
143.40187 ++		if (ev == NULL)
143.40188 ++			break;
143.40189 ++
143.40190 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.40191 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.40192 ++
143.40193 ++		if (ce->serial != 0xdeadbeef) {
143.40194 ++			int diff = (int64_t)(ce->msc - (msc + ce->serial + 60));
143.40195 ++			if (diff < 0) {
143.40196 ++				if (-diff > earliest) {
143.40197 ++					fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff);
143.40198 ++					earliest = -diff;
143.40199 ++				}
143.40200 ++				early++;
143.40201 ++				ret++;
143.40202 ++			} else if (diff > 0) {
143.40203 ++				if (diff > latest) {
143.40204 ++					fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff);
143.40205 ++					latest = diff;
143.40206 ++				}
143.40207 ++				late++;
143.40208 ++				ret++;
143.40209 ++			}
143.40210 ++			count++;
143.40211 ++		} else
143.40212 ++			complete = 1;
143.40213 ++		free(ev);
143.40214 ++	} while (!complete);
143.40215 ++
143.40216 ++	if (early)
143.40217 ++		printf("\t%d notifies too early (worst %d)!\n", early, earliest);
143.40218 ++	if (late)
143.40219 ++		printf("\t%d notifies too late (worst %d)!\n", late, latest);
143.40220 ++
143.40221 ++	if (count != N_VBLANKS+1) {
143.40222 ++		fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", N_VBLANKS+1 - count);
143.40223 ++		ret++;
143.40224 ++		do {
143.40225 ++			xcb_present_complete_notify_event_t *ce;
143.40226 ++			xcb_generic_event_t *ev;
143.40227 ++
143.40228 ++			ev = xcb_wait_for_special_event(c, Q);
143.40229 ++			if (ev == NULL)
143.40230 ++				break;
143.40231 ++
143.40232 ++			ce = (xcb_present_complete_notify_event_t *)ev;
143.40233 ++			assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.40234 ++			free(ev);
143.40235 ++		} while (++count != N_VBLANKS+1);
143.40236 ++	}
143.40237 ++
143.40238 ++	XSync(dpy, True);
143.40239 ++	ret += !!_x_error_occurred;
143.40240 ++
143.40241 ++	return ret;
143.40242 ++#undef N_VBLANKS
143.40243 ++}
143.40244 + 
143.40245 +-	printf("Testing whole screen flip: %dx%d\n", width, height);
143.40246 ++static int test_modulus_msc(Display *dpy, void *Q)
143.40247 ++{
143.40248 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.40249 ++	Window root = DefaultRootWindow(dpy);
143.40250 ++	xcb_present_complete_notify_event_t *ce;
143.40251 ++	xcb_generic_event_t *ev;
143.40252 ++	int x, y, ret = 0;
143.40253 ++	uint64_t target;
143.40254 ++	int early = 0, late = 0;
143.40255 ++	int earliest = 0, latest = 0;
143.40256 ++	int complete, count, expect;
143.40257 ++
143.40258 ++	printf("Testing notify modulus\n");
143.40259 + 	_x_error_occurred = 0;
143.40260 + 
143.40261 +-	xshmfence_reset(fence.addr);
143.40262 ++	target = wait_vblank(dpy, root, Q);
143.40263 + 
143.40264 +-	pixmap = XCreatePixmap(dpy, root, width, height, depth);
143.40265 +-	xcb_present_pixmap(XGetXCBConnection(dpy),
143.40266 +-			   root, pixmap,
143.40267 +-			   0, /* sbc */
143.40268 +-			   0, /* valid */
143.40269 +-			   0, /* update */
143.40270 +-			   0, /* x_off */
143.40271 +-			   0, /* y_off */
143.40272 +-			   None,
143.40273 +-			   None, /* wait fence */
143.40274 +-			   fence.xid,
143.40275 +-			   XCB_PRESENT_OPTION_NONE,
143.40276 +-			   0, /* target msc */
143.40277 +-			   0, /* divisor */
143.40278 +-			   0, /* remainder */
143.40279 +-			   0, NULL);
143.40280 +-	XFreePixmap(dpy, pixmap);
143.40281 ++	expect = 0;
143.40282 ++	xcb_present_notify_msc(c, root, 0, 0, 0, 0);
143.40283 ++	for (x = 1; x <= 19; x++) {
143.40284 ++		for (y = 0; y < x; y++) {
143.40285 ++			xcb_present_notify_msc(c, root, y << 16 | x, 0, x, y);
143.40286 ++			expect++;
143.40287 ++		}
143.40288 ++	}
143.40289 ++	xcb_present_notify_msc(c, root, 0xdeadbeef, target + 2*x, 0, 0);
143.40290 ++	xcb_flush(c);
143.40291 + 
143.40292 +-	pixmap = XCreatePixmap(dpy, root, width, height, depth);
143.40293 +-	xcb_present_pixmap(XGetXCBConnection(dpy),
143.40294 +-			   root, pixmap,
143.40295 +-			   0, /* sbc */
143.40296 +-			   0, /* valid */
143.40297 +-			   0, /* update */
143.40298 +-			   0, /* x_off */
143.40299 +-			   0, /* y_off */
143.40300 +-			   None,
143.40301 +-			   None, /* wait fence */
143.40302 +-			   None, /* sync fence */
143.40303 +-			   XCB_PRESENT_OPTION_NONE,
143.40304 +-			   0, /* target msc */
143.40305 +-			   0, /* divisor */
143.40306 +-			   0, /* remainder */
143.40307 +-			   0, NULL);
143.40308 +-	XFreePixmap(dpy, pixmap);
143.40309 +-	XFlush(dpy);
143.40310 ++	ev = xcb_wait_for_special_event(c, Q);
143.40311 ++	if (ev) {
143.40312 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.40313 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.40314 ++		assert(ce->serial == 0);
143.40315 ++		assert(target == ce->msc);
143.40316 ++		target = ce->msc;
143.40317 ++	}
143.40318 + 
143.40319 +-	ret = !!xshmfence_await(fence.addr);
143.40320 +-	dri3_fence_free(dpy, &fence);
143.40321 ++	complete = 0;
143.40322 ++	count = 0;
143.40323 ++	do {
143.40324 ++		ev = xcb_wait_for_special_event(c, Q);
143.40325 ++		if (ev == NULL)
143.40326 ++			break;
143.40327 ++
143.40328 ++		ce = (xcb_present_complete_notify_event_t *)ev;
143.40329 ++		assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.40330 ++
143.40331 ++		assert(ce->serial);
143.40332 ++		if (ce->serial != 0xdeadbeef) {
143.40333 ++			uint64_t msc;
143.40334 ++			int diff;
143.40335 ++
143.40336 ++			x = ce->serial & 0xffff;
143.40337 ++			y = ce->serial >> 16;
143.40338 ++
143.40339 ++			msc = target;
143.40340 ++			msc -= target % x;
143.40341 ++			msc += y;
143.40342 ++			if (msc <= target)
143.40343 ++				msc += x;
143.40344 ++
143.40345 ++			diff = (int64_t)(ce->msc - msc);
143.40346 ++			if (diff < 0) {
143.40347 ++				if (-diff > earliest) {
143.40348 ++					fprintf(stderr, "\tnotify (%d, %d) early by %d msc (target %lld, reported %lld)\n", y, x, -diff, (long long)msc, (long long)ce->msc);
143.40349 ++					earliest = -diff;
143.40350 ++				}
143.40351 ++				early++;
143.40352 ++				ret++;
143.40353 ++			} else if (diff > 0) {
143.40354 ++				if (diff > latest) {
143.40355 ++					fprintf(stderr, "\tnotify (%d, %d) late by %d msc (target %lld, reported %lld)\n", y, x, diff, (long long)msc, (long long)ce->msc);
143.40356 ++					latest = diff;
143.40357 ++				}
143.40358 ++				late++;
143.40359 ++				ret++;
143.40360 ++			}
143.40361 ++			count++;
143.40362 ++		} else
143.40363 ++			complete = 1;
143.40364 ++		free(ev);
143.40365 ++	} while (!complete);
143.40366 ++
143.40367 ++	if (early)
143.40368 ++		printf("\t%d notifies too early (worst %d)!\n", early, earliest);
143.40369 ++	if (late)
143.40370 ++		printf("\t%d notifies too late (worst %d)!\n", late, latest);
143.40371 ++
143.40372 ++	if (count != expect) {
143.40373 ++		fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", expect - count);
143.40374 ++		ret++;
143.40375 ++		do {
143.40376 ++			ev = xcb_wait_for_special_event(c, Q);
143.40377 ++			if (ev == NULL)
143.40378 ++				break;
143.40379 ++
143.40380 ++			ce = (xcb_present_complete_notify_event_t *)ev;
143.40381 ++			assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
143.40382 ++			free(ev);
143.40383 ++		} while (++count != expect);
143.40384 ++	}
143.40385 + 
143.40386 + 	XSync(dpy, True);
143.40387 + 	ret += !!_x_error_occurred;
143.40388 +@@ -279,8 +1471,6 @@ static int for_each_crtc(Display *dpy,
143.40389 + 	for (i = 0; i < res->ncrtc; i++)
143.40390 + 		original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
143.40391 + 
143.40392 +-	printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
143.40393 +-
143.40394 + 	for (i = 0; i < res->noutput; i++) {
143.40395 + 		XRROutputInfo *output;
143.40396 + 		XRRModeInfo *mode;
143.40397 +@@ -322,7 +1512,7 @@ static int for_each_crtc(Display *dpy,
143.40398 + 	free(original_crtc);
143.40399 + 	XRRFreeScreenResources(res);
143.40400 + 
143.40401 +-	return j;
143.40402 ++	return err;
143.40403 + }
143.40404 + 
143.40405 + struct test_crtc {
143.40406 +@@ -335,6 +1525,7 @@ struct test_crtc {
143.40407 + 	uint64_t msc;
143.40408 + };
143.40409 + #define SYNC 0x1
143.40410 ++#define FUTURE 0x2
143.40411 + 
143.40412 + static int __test_crtc(Display *dpy, RRCrtc crtc,
143.40413 + 		       int width, int height,
143.40414 +@@ -344,7 +1535,7 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
143.40415 + 	Pixmap pixmap;
143.40416 + 	int err = 0;
143.40417 + 
143.40418 +-	test->msc = check_msc(dpy, test->win, test->queue, test->msc);
143.40419 ++	test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
143.40420 + 
143.40421 + 	if (test->flags & SYNC)
143.40422 + 		xshmfence_reset(test->fence.addr);
143.40423 +@@ -361,16 +1552,14 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
143.40424 + 			   None, /* wait fence */
143.40425 + 			   test->flags & SYNC ? test->fence.xid : None,
143.40426 + 			   XCB_PRESENT_OPTION_NONE,
143.40427 +-			   0, /* target msc */
143.40428 ++			   test->msc, /* target msc */
143.40429 + 			   1, /* divisor */
143.40430 + 			   0, /* remainder */
143.40431 + 			   0, NULL);
143.40432 +-	XFreePixmap(dpy, pixmap);
143.40433 +-
143.40434 + 	if (test->flags & SYNC) {
143.40435 +-		pixmap = XCreatePixmap(dpy, test->win, width, height, test->depth);
143.40436 ++		Pixmap tmp = XCreatePixmap(dpy, test->win, width, height, test->depth);
143.40437 + 		xcb_present_pixmap(XGetXCBConnection(dpy),
143.40438 +-				   test->win, pixmap,
143.40439 ++				   test->win, tmp,
143.40440 + 				   1, /* sbc */
143.40441 + 				   0, /* valid */
143.40442 + 				   0, /* update */
143.40443 +@@ -380,16 +1569,17 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
143.40444 + 				   None, /* wait fence */
143.40445 + 				   None, /* sync fence */
143.40446 + 				   XCB_PRESENT_OPTION_NONE,
143.40447 +-				   1, /* target msc */
143.40448 ++				   test->msc + (test->flags & FUTURE ? 5 * 16 : 1), /* target msc */
143.40449 + 				   1, /* divisor */
143.40450 + 				   0, /* remainder */
143.40451 + 				   0, NULL);
143.40452 +-		XFreePixmap(dpy, pixmap);
143.40453 ++		XFreePixmap(dpy, tmp);
143.40454 + 		XFlush(dpy);
143.40455 + 		err += !!xshmfence_await(test->fence.addr);
143.40456 + 	}
143.40457 ++	XFreePixmap(dpy, pixmap);
143.40458 + 
143.40459 +-	test->msc = check_msc(dpy, test->win, test->queue, test->msc);
143.40460 ++	test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
143.40461 + 	return err;
143.40462 + }
143.40463 + 
143.40464 +@@ -410,15 +1600,23 @@ static int test_crtc(Display *dpy, void *queue, uint64_t last_msc)
143.40465 + 
143.40466 + 	printf("Testing each crtc, without waiting for each flip\n");
143.40467 + 	test.flags = 0;
143.40468 ++	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
143.40469 + 	err += for_each_crtc(dpy, __test_crtc, &test);
143.40470 ++	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
143.40471 + 
143.40472 + 	printf("Testing each crtc, waiting for flips to complete\n");
143.40473 + 	test.flags = SYNC;
143.40474 ++	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
143.40475 + 	err += for_each_crtc(dpy, __test_crtc, &test);
143.40476 ++	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
143.40477 + 
143.40478 +-	test.msc = check_msc(dpy, test.win, test.queue, test.msc);
143.40479 +-	dri3_fence_free(dpy, &test.fence);
143.40480 ++	printf("Testing each crtc, with future flips\n");
143.40481 ++	test.flags = FUTURE | SYNC;
143.40482 ++	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
143.40483 ++	err += for_each_crtc(dpy, __test_crtc, &test);
143.40484 ++	test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
143.40485 + 
143.40486 ++	dri3_fence_free(dpy, &test.fence);
143.40487 + 	XSync(dpy, True);
143.40488 + 	err += !!_x_error_occurred;
143.40489 + 
143.40490 +@@ -536,6 +1734,31 @@ static int gem_set_caching(int fd, uint32_t handle, int caching)
143.40491 + 	return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0;
143.40492 + }
143.40493 + 
143.40494 ++static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
143.40495 ++{
143.40496 ++	struct drm_i915_gem_set_tiling set_tiling;
143.40497 ++	int err;
143.40498 ++
143.40499 ++restart:
143.40500 ++	set_tiling.handle = handle;
143.40501 ++	set_tiling.tiling_mode = tiling;
143.40502 ++	set_tiling.stride = stride;
143.40503 ++
143.40504 ++	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
143.40505 ++		return 1;
143.40506 ++
143.40507 ++	err = errno;
143.40508 ++	if (err == EINTR)
143.40509 ++		goto restart;
143.40510 ++
143.40511 ++	if (err == EAGAIN) {
143.40512 ++		sched_yield();
143.40513 ++		goto restart;
143.40514 ++	}
143.40515 ++
143.40516 ++	return 0;
143.40517 ++}
143.40518 ++
143.40519 + static int gem_export(int fd, uint32_t handle)
143.40520 + {
143.40521 + 	struct drm_prime_handle args;
143.40522 +@@ -557,6 +1780,126 @@ static void gem_close(int fd, uint32_t handle)
143.40523 + 	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
143.40524 + }
143.40525 + 
143.40526 ++static int test_dri3_tiling(Display *dpy)
143.40527 ++{
143.40528 ++	Window win = DefaultRootWindow(dpy);
143.40529 ++	const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
143.40530 ++	Window root;
143.40531 ++	unsigned int width, height;
143.40532 ++	unsigned border, depth, bpp;
143.40533 ++	unsigned stride, size;
143.40534 ++	void *Q;
143.40535 ++	int x, y;
143.40536 ++	int device;
143.40537 ++	int line = -1;
143.40538 ++	int t;
143.40539 ++
143.40540 ++	device = dri3_open(dpy);
143.40541 ++	if (device < 0)
143.40542 ++		return 0;
143.40543 ++
143.40544 ++	if (!is_intel(device))
143.40545 ++		return 0;
143.40546 ++
143.40547 ++	printf("Opened Intel DRI3 device\n");
143.40548 ++
143.40549 ++	XGetGeometry(dpy, win, &root, &x, &y,
143.40550 ++		     &width, &height, &border, &depth);
143.40551 ++
143.40552 ++	switch (depth) {
143.40553 ++	case 8: bpp = 8; break;
143.40554 ++	case 15: case 16: bpp = 16; break;
143.40555 ++	case 24: case 32: bpp = 32; break;
143.40556 ++	default: return 0;
143.40557 ++	}
143.40558 ++
143.40559 ++	stride = ALIGN(width * bpp/8, 512);
143.40560 ++	size = PAGE_ALIGN(stride * ALIGN(height, 32));
143.40561 ++	printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for GTT\n",
143.40562 ++	       width, height, stride, size);
143.40563 ++
143.40564 ++	_x_error_occurred = 0;
143.40565 ++	Q = setup_msc(dpy, root);
143.40566 ++
143.40567 ++	for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
143.40568 ++		uint64_t msc;
143.40569 ++		uint32_t src;
143.40570 ++		int src_fd;
143.40571 ++		Pixmap src_pix;
143.40572 ++
143.40573 ++		src = gem_create(device, size);
143.40574 ++		if (!src) {
143.40575 ++			line = __LINE__;
143.40576 ++			goto fail;
143.40577 ++		}
143.40578 ++
143.40579 ++		gem_set_tiling(device, src, tiling[t], stride);
143.40580 ++
143.40581 ++		src_fd = gem_export(device, src);
143.40582 ++		if (src_fd < 0) {
143.40583 ++			line = __LINE__;
143.40584 ++			goto fail;
143.40585 ++		}
143.40586 ++
143.40587 ++		src_pix = dri3_create_pixmap(dpy, root,
143.40588 ++					     width, height, depth,
143.40589 ++					     src_fd, bpp, stride, size);
143.40590 ++
143.40591 ++		msc = wait_vblank(dpy, root, Q);
143.40592 ++
143.40593 ++		xcb_present_pixmap(XGetXCBConnection(dpy),
143.40594 ++				   win, src_pix,
143.40595 ++				   0, /* sbc */
143.40596 ++				   0, /* valid */
143.40597 ++				   0, /* update */
143.40598 ++				   0, /* x_off */
143.40599 ++				   0, /* y_off */
143.40600 ++				   None,
143.40601 ++				   None, /* wait fence */
143.40602 ++				   None,
143.40603 ++				   XCB_PRESENT_OPTION_NONE,
143.40604 ++				   msc + 2, /* target msc */
143.40605 ++				   1, /* divisor */
143.40606 ++				   0, /* remainder */
143.40607 ++				   0, NULL);
143.40608 ++
143.40609 ++		xcb_present_pixmap(XGetXCBConnection(dpy),
143.40610 ++				   win, src_pix,
143.40611 ++				   0, /* sbc */
143.40612 ++				   0, /* valid */
143.40613 ++				   0, /* update */
143.40614 ++				   0, /* x_off */
143.40615 ++				   0, /* y_off */
143.40616 ++				   None,
143.40617 ++				   None, /* wait fence */
143.40618 ++				   None,
143.40619 ++				   XCB_PRESENT_OPTION_NONE,
143.40620 ++				   msc + 3, /* target msc */
143.40621 ++				   1, /* divisor */
143.40622 ++				   0, /* remainder */
143.40623 ++				   0, NULL);
143.40624 ++
143.40625 ++		XSync(dpy, True);
143.40626 ++		if (_x_error_occurred) {
143.40627 ++			line = __LINE__;
143.40628 ++			goto fail;
143.40629 ++		}
143.40630 ++		XFreePixmap(dpy, src_pix);
143.40631 ++		_x_error_occurred = 0;
143.40632 ++
143.40633 ++		close(src_fd);
143.40634 ++		gem_close(device, src);
143.40635 ++	}
143.40636 ++
143.40637 ++	teardown_msc(dpy, Q);
143.40638 ++	return 0;
143.40639 ++
143.40640 ++fail:
143.40641 ++	printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
143.40642 ++	teardown_msc(dpy, Q);
143.40643 ++	return 1;
143.40644 ++}
143.40645 ++
143.40646 + static int test_dri3(Display *dpy)
143.40647 + {
143.40648 + 	Window win = DefaultRootWindow(dpy);
143.40649 +@@ -670,8 +2013,32 @@ fail:
143.40650 + static int has_present(Display *dpy)
143.40651 + {
143.40652 + 	xcb_connection_t *c = XGetXCBConnection(dpy);
143.40653 +-	xcb_present_query_version_reply_t *reply;
143.40654 + 	xcb_generic_error_t *error = NULL;
143.40655 ++	void *reply;
143.40656 ++
143.40657 ++	reply = xcb_xfixes_query_version_reply(c,
143.40658 ++					       xcb_xfixes_query_version(c,
143.40659 ++									XCB_XFIXES_MAJOR_VERSION,
143.40660 ++									XCB_XFIXES_MINOR_VERSION),
143.40661 ++					       &error);
143.40662 ++	free(reply);
143.40663 ++	free(error);
143.40664 ++	if (reply == NULL) {
143.40665 ++		fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy));
143.40666 ++		return 0;
143.40667 ++	}
143.40668 ++
143.40669 ++	reply = xcb_dri3_query_version_reply(c,
143.40670 ++					     xcb_dri3_query_version(c,
143.40671 ++								    XCB_DRI3_MAJOR_VERSION,
143.40672 ++								    XCB_DRI3_MINOR_VERSION),
143.40673 ++					     &error);
143.40674 ++	free(reply);
143.40675 ++	free(error);
143.40676 ++	if (reply == NULL) {
143.40677 ++		fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy));
143.40678 ++		return 0;
143.40679 ++	}
143.40680 + 
143.40681 + 	reply = xcb_present_query_version_reply(c,
143.40682 + 						xcb_present_query_version(c,
143.40683 +@@ -681,14 +2048,32 @@ static int has_present(Display *dpy)
143.40684 + 
143.40685 + 	free(reply);
143.40686 + 	free(error);
143.40687 ++	if (reply == NULL) {
143.40688 ++		fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
143.40689 ++		return 0;
143.40690 ++	}
143.40691 ++
143.40692 ++	return 1;
143.40693 ++}
143.40694 ++
143.40695 ++static int has_composite(Display *dpy)
143.40696 ++{
143.40697 ++	int event, error;
143.40698 ++	int major, minor;
143.40699 ++
143.40700 ++	if (!XCompositeQueryExtension(dpy, &event, &error))
143.40701 ++		return 0;
143.40702 ++
143.40703 ++	XCompositeQueryVersion(dpy, &major, &minor);
143.40704 + 
143.40705 +-	return reply != NULL;
143.40706 ++	return major > 0 || minor >= 4;
143.40707 + }
143.40708 + 
143.40709 + int main(void)
143.40710 + {
143.40711 + 	Display *dpy;
143.40712 + 	Window root;
143.40713 ++	int dummy;
143.40714 + 	int error = 0;
143.40715 + 	uint64_t last_msc;
143.40716 + 	void *queue;
143.40717 +@@ -700,27 +2085,135 @@ int main(void)
143.40718 + 	if (!has_present(dpy))
143.40719 + 		return 77;
143.40720 + 
143.40721 ++	if (DPMSQueryExtension(dpy, &dummy, &dummy))
143.40722 ++		DPMSDisable(dpy);
143.40723 ++
143.40724 + 	root = DefaultRootWindow(dpy);
143.40725 + 
143.40726 + 	signal(SIGALRM, SIG_IGN);
143.40727 + 	XSetErrorHandler(_check_error_handler);
143.40728 + 
143.40729 + 	queue = setup_msc(dpy, root);
143.40730 +-	last_msc = check_msc(dpy, root, queue, 0);
143.40731 ++	last_msc = check_msc(dpy, root, queue, 0, NULL);
143.40732 ++
143.40733 ++	error += test_future_msc(dpy, queue);
143.40734 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40735 ++
143.40736 ++	error += test_wrap_msc(dpy);
143.40737 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40738 ++
143.40739 ++	error += test_accuracy_msc(dpy, queue);
143.40740 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40741 ++
143.40742 ++	error += test_modulus_msc(dpy, queue);
143.40743 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40744 ++
143.40745 ++	error += test_exhaustion_msc(dpy, queue);
143.40746 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40747 ++
143.40748 ++	for (dummy = 0; dummy <= 3; dummy++) {
143.40749 ++		Window win;
143.40750 ++		uint64_t msc = 0;
143.40751 ++		XSetWindowAttributes attr;
143.40752 ++		Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
143.40753 ++		unsigned int width, height;
143.40754 ++		unsigned border, depth;
143.40755 ++		const char *phase;
143.40756 ++		int x, y;
143.40757 ++		void *Q;
143.40758 ++
143.40759 ++		attr.override_redirect = 1;
143.40760 ++
143.40761 ++		XGetGeometry(dpy, root, &win, &x, &y,
143.40762 ++			     &width, &height, &border, &depth);
143.40763 ++
143.40764 ++		_x_error_occurred = 0;
143.40765 ++		switch (dummy) {
143.40766 ++		case 0:
143.40767 ++			win = root;
143.40768 ++			phase = "root";
143.40769 ++			break;
143.40770 ++		case 1:
143.40771 ++			win = XCreateWindow(dpy, root,
143.40772 ++					    0, 0, width, height, 0, depth,
143.40773 ++					    InputOutput, visual,
143.40774 ++					    CWOverrideRedirect, &attr);
143.40775 ++			phase = "fullscreen";
143.40776 ++			break;
143.40777 ++		case 2:
143.40778 ++			win = XCreateWindow(dpy, root,
143.40779 ++					    0, 0, width/2, height/2, 0, depth,
143.40780 ++					    InputOutput, visual,
143.40781 ++					    CWOverrideRedirect, &attr);
143.40782 ++			phase = "window";
143.40783 ++			break;
143.40784 ++		case 3:
143.40785 ++			if (!has_composite(dpy))
143.40786 ++				continue;
143.40787 ++
143.40788 ++			win = XCreateWindow(dpy, root,
143.40789 ++					    0, 0, width, height, 0,
143.40790 ++					    DefaultDepth(dpy, DefaultScreen(dpy)),
143.40791 ++					    InputOutput,
143.40792 ++					    DefaultVisual(dpy, DefaultScreen(dpy)),
143.40793 ++					    CWOverrideRedirect, &attr);
143.40794 ++			XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
143.40795 ++			phase = "composite";
143.40796 ++			break;
143.40797 ++
143.40798 ++		default:
143.40799 ++			phase = "broken";
143.40800 ++			win = root;
143.40801 ++			abort();
143.40802 ++			break;
143.40803 ++		}
143.40804 ++
143.40805 ++		XMapWindow(dpy, win);
143.40806 ++		XSync(dpy, True);
143.40807 ++		if (_x_error_occurred)
143.40808 ++			continue;
143.40809 ++
143.40810 ++		Q = setup_msc(dpy, win);
143.40811 ++		msc = check_msc(dpy, win, Q, msc, NULL);
143.40812 + 
143.40813 +-	error += test_whole(dpy);
143.40814 +-	last_msc = check_msc(dpy, root, queue, last_msc);
143.40815 ++		error += test_whole(dpy, win, phase);
143.40816 ++		msc = check_msc(dpy, win, Q, msc, NULL);
143.40817 ++
143.40818 ++		error += test_double(dpy, win, phase, Q);
143.40819 ++		msc = check_msc(dpy, win, Q, msc, NULL);
143.40820 ++
143.40821 ++		error += test_future(dpy, win, phase, Q);
143.40822 ++		msc = check_msc(dpy, win, Q, msc, NULL);
143.40823 ++
143.40824 ++		error += test_accuracy(dpy, win, phase, Q);
143.40825 ++		msc = check_msc(dpy, win, Q, msc, NULL);
143.40826 ++
143.40827 ++		error += test_modulus(dpy, win, phase, Q);
143.40828 ++		msc = check_msc(dpy, win, Q, msc, NULL);
143.40829 ++
143.40830 ++		error += test_exhaustion(dpy, win, phase, Q);
143.40831 ++		msc = check_msc(dpy, win, Q, msc, NULL);
143.40832 ++
143.40833 ++		teardown_msc(dpy, Q);
143.40834 ++		if (win != root)
143.40835 ++			XDestroyWindow(dpy, win);
143.40836 ++	}
143.40837 + 
143.40838 + 	error += test_crtc(dpy, queue, last_msc);
143.40839 +-	last_msc = check_msc(dpy, root, queue, last_msc);
143.40840 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40841 + 
143.40842 + 	error += test_shm(dpy);
143.40843 +-	last_msc = check_msc(dpy, root, queue, last_msc);
143.40844 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40845 + 
143.40846 + 	error += test_dri3(dpy);
143.40847 +-	last_msc = check_msc(dpy, root, queue, last_msc);
143.40848 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40849 ++
143.40850 ++	error += test_dri3_tiling(dpy);
143.40851 ++	last_msc = check_msc(dpy, root, queue, last_msc, NULL);
143.40852 + 
143.40853 + 	teardown_msc(dpy, queue);
143.40854 + 
143.40855 ++	if (DPMSQueryExtension(dpy, &dummy, &dummy))
143.40856 ++		DPMSEnable(dpy);
143.40857 + 	return !!error;
143.40858 + }
143.40859 +diff --git a/test/render-glyphs.c b/test/render-glyphs.c
143.40860 +new file mode 100644
143.40861 +index 00000000..8822e36a
143.40862 +--- /dev/null
143.40863 ++++ b/test/render-glyphs.c
143.40864 +@@ -0,0 +1,441 @@
143.40865 ++#include <stdint.h>
143.40866 ++#include <stdio.h>
143.40867 ++#include <stdlib.h>
143.40868 ++#include <stdbool.h>
143.40869 ++#include <stdarg.h>
143.40870 ++#include <string.h>
143.40871 ++
143.40872 ++#include <X11/Xutil.h> /* for XDestroyImage */
143.40873 ++#include <pixman.h> /* for pixman blt functions */
143.40874 ++
143.40875 ++#include "test.h"
143.40876 ++
143.40877 ++static const XRenderColor colors[] = {
143.40878 ++	/* red, green, blue, alpha */
143.40879 ++	{ 0 },
143.40880 ++	{ 0, 0, 0, 0xffff },
143.40881 ++	{ 0xffff, 0, 0, 0xffff },
143.40882 ++	{ 0, 0xffff, 0, 0xffff },
143.40883 ++	{ 0, 0, 0xffff, 0xffff },
143.40884 ++	{ 0xffff, 0xffff, 0xffff, 0xffff },
143.40885 ++};
143.40886 ++
143.40887 ++static struct clip {
143.40888 ++	void *func;
143.40889 ++} clips[] = {
143.40890 ++	{ NULL },
143.40891 ++};
143.40892 ++
143.40893 ++static int _x_error_occurred;
143.40894 ++
143.40895 ++static int
143.40896 ++_check_error_handler(Display     *display,
143.40897 ++		     XErrorEvent *event)
143.40898 ++{
143.40899 ++	_x_error_occurred = 1;
143.40900 ++	return False; /* ignored */
143.40901 ++}
143.40902 ++
143.40903 ++static void clear(struct test_display *dpy,
143.40904 ++		  struct test_target *tt,
143.40905 ++		  const XRenderColor *c)
143.40906 ++{
143.40907 ++	XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, c,
143.40908 ++			     0, 0, tt->width, tt->height);
143.40909 ++}
143.40910 ++
143.40911 ++static bool check_op(struct test_display *dpy, int op, struct test_target *tt)
143.40912 ++{
143.40913 ++	XRenderColor render_color = {0};
143.40914 ++
143.40915 ++	XSync(dpy->dpy, True);
143.40916 ++	_x_error_occurred = 0;
143.40917 ++
143.40918 ++	XRenderFillRectangle(dpy->dpy, op,
143.40919 ++			     tt->picture, &render_color,
143.40920 ++			     0, 0, 0, 0);
143.40921 ++
143.40922 ++	XSync(dpy->dpy, True);
143.40923 ++	return _x_error_occurred == 0;
143.40924 ++}
143.40925 ++
143.40926 ++struct glyph_iter {
143.40927 ++	enum {
143.40928 ++		GLYPHS, OP, DST, SRC, MASK, CLIP,
143.40929 ++	} stage;
143.40930 ++
143.40931 ++	int glyph_format;
143.40932 ++	int op;
143.40933 ++	int dst_color;
143.40934 ++	int src_color;
143.40935 ++	int mask_format;
143.40936 ++	int clip;
143.40937 ++
143.40938 ++	struct {
143.40939 ++		struct test_display *dpy;
143.40940 ++		struct test_target tt;
143.40941 ++		GlyphSet glyphset;
143.40942 ++		Picture src;
143.40943 ++		XRenderPictFormat *mask_format;
143.40944 ++	} ref, out;
143.40945 ++};
143.40946 ++
143.40947 ++static void glyph_iter_init(struct glyph_iter *gi,
143.40948 ++			    struct test *t, enum target target)
143.40949 ++{
143.40950 ++	memset(gi, 0, sizeof(*gi));
143.40951 ++
143.40952 ++	gi->out.dpy = &t->out;
143.40953 ++	test_target_create_render(&t->out, target, &gi->out.tt);
143.40954 ++
143.40955 ++	gi->ref.dpy = &t->ref;
143.40956 ++	test_target_create_render(&t->ref, target, &gi->ref.tt);
143.40957 ++
143.40958 ++	gi->stage = GLYPHS;
143.40959 ++	gi->glyph_format = -1;
143.40960 ++	gi->op = -1;
143.40961 ++	gi->dst_color = -1;
143.40962 ++	gi->src_color = -1;
143.40963 ++	gi->mask_format = -1;
143.40964 ++	gi->clip = -1;
143.40965 ++}
143.40966 ++
143.40967 ++static void render_clear(char *image, int image_size, int bpp)
143.40968 ++{
143.40969 ++	memset(image, 0, image_size);
143.40970 ++}
143.40971 ++
143.40972 ++static void render_black(char *image, int image_size, int bpp)
143.40973 ++{
143.40974 ++	if (bpp == 4) {
143.40975 ++		uint32_t *p = (uint32_t *)image;
143.40976 ++		image_size /= 4;
143.40977 ++		while (image_size--)
143.40978 ++			*p++ = 0x000000ff;
143.40979 ++	} else
143.40980 ++		memset(image, 0x55, image_size);
143.40981 ++}
143.40982 ++
143.40983 ++static void render_green(char *image, int image_size, int bpp)
143.40984 ++{
143.40985 ++	if (bpp == 4) {
143.40986 ++		uint32_t *p = (uint32_t *)image;
143.40987 ++		image_size /= 4;
143.40988 ++		while (image_size--)
143.40989 ++			*p++ = 0xffff0000;
143.40990 ++	} else
143.40991 ++		memset(image, 0xaa, image_size);
143.40992 ++}
143.40993 ++
143.40994 ++static void render_white(char *image, int image_size, int bpp)
143.40995 ++{
143.40996 ++	memset(image, 0xff, image_size);
143.40997 ++}
143.40998 ++
143.40999 ++static GlyphSet create_glyphs(Display *dpy, int format_id)
143.41000 ++{
143.41001 ++#define N_GLYPHS 4
143.41002 ++	XRenderPictFormat *format;
143.41003 ++	XGlyphInfo glyph = { 8, 8, 0, 0, 8, 0 };
143.41004 ++	char image[4*8*8];
143.41005 ++	GlyphSet glyphset;
143.41006 ++	Glyph gid;
143.41007 ++	int image_size;
143.41008 ++	int bpp;
143.41009 ++	int n;
143.41010 ++
143.41011 ++	format = XRenderFindStandardFormat(dpy, format_id);
143.41012 ++	if (format == NULL)
143.41013 ++		return 0;
143.41014 ++
143.41015 ++	switch (format_id) {
143.41016 ++	case PictStandardARGB32:
143.41017 ++	case PictStandardRGB24:
143.41018 ++		image_size = 4 * 8 * 8;
143.41019 ++		bpp = 4;
143.41020 ++		break;
143.41021 ++	case PictStandardA8:
143.41022 ++	case PictStandardA4:
143.41023 ++		image_size = 8 * 8;
143.41024 ++		bpp = 1;
143.41025 ++		break;
143.41026 ++	case PictStandardA1:
143.41027 ++		image_size = 8;
143.41028 ++		bpp = 0;
143.41029 ++		break;
143.41030 ++	default:
143.41031 ++		return 0;
143.41032 ++	}
143.41033 ++
143.41034 ++	glyphset = XRenderCreateGlyphSet(dpy, format);
143.41035 ++	for (n = 0; n < N_GLYPHS; n++) {
143.41036 ++		gid = n;
143.41037 ++
143.41038 ++		switch (n) {
143.41039 ++		case 0: render_clear(image, image_size, bpp); break;
143.41040 ++		case 1: render_black(image, image_size, bpp); break;
143.41041 ++		case 2: render_green(image, image_size, bpp); break;
143.41042 ++		case 3: render_white(image, image_size, bpp); break;
143.41043 ++		}
143.41044 ++
143.41045 ++		XRenderAddGlyphs(dpy, glyphset,
143.41046 ++				 &gid, &glyph, 1, image, image_size);
143.41047 ++	}
143.41048 ++
143.41049 ++	return glyphset;
143.41050 ++}
143.41051 ++
143.41052 ++static const char *glyph_name(int n)
143.41053 ++{
143.41054 ++	switch (n) {
143.41055 ++	case 0: return "clear";
143.41056 ++	case 1: return "black";
143.41057 ++	case 2: return "green";
143.41058 ++	case 3: return "white";
143.41059 ++	default: return "unknown";
143.41060 ++	}
143.41061 ++}
143.41062 ++
143.41063 ++static bool glyph_iter_next(struct glyph_iter *gi)
143.41064 ++{
143.41065 ++restart:
143.41066 ++	if (gi->stage == GLYPHS) {
143.41067 ++		if (++gi->glyph_format == PictStandardNUM)
143.41068 ++			return false;
143.41069 ++
143.41070 ++		if (gi->out.glyphset)
143.41071 ++			XRenderFreeGlyphSet(gi->out.dpy->dpy,
143.41072 ++					    gi->out.glyphset);
143.41073 ++		gi->out.glyphset = create_glyphs(gi->out.dpy->dpy,
143.41074 ++					       gi->glyph_format);
143.41075 ++
143.41076 ++		if (gi->ref.glyphset)
143.41077 ++			XRenderFreeGlyphSet(gi->ref.dpy->dpy,
143.41078 ++					    gi->ref.glyphset);
143.41079 ++		gi->ref.glyphset = create_glyphs(gi->ref.dpy->dpy,
143.41080 ++					       gi->glyph_format);
143.41081 ++
143.41082 ++		gi->stage++;
143.41083 ++	}
143.41084 ++
143.41085 ++	if (gi->stage == OP) {
143.41086 ++		do {
143.41087 ++			if (++gi->op == 255)
143.41088 ++				goto reset_op;
143.41089 ++		} while (!check_op(gi->out.dpy, gi->op, &gi->out.tt) ||
143.41090 ++			 !check_op(gi->ref.dpy, gi->op, &gi->ref.tt));
143.41091 ++
143.41092 ++		gi->stage++;
143.41093 ++	}
143.41094 ++
143.41095 ++	if (gi->stage == DST) {
143.41096 ++		if (++gi->dst_color == ARRAY_SIZE(colors))
143.41097 ++			goto reset_dst;
143.41098 ++
143.41099 ++		gi->stage++;
143.41100 ++	}
143.41101 ++
143.41102 ++	if (gi->stage == SRC) {
143.41103 ++		if (++gi->src_color == ARRAY_SIZE(colors))
143.41104 ++			goto reset_src;
143.41105 ++
143.41106 ++		if (gi->ref.src)
143.41107 ++			XRenderFreePicture(gi->ref.dpy->dpy, gi->ref.src);
143.41108 ++		gi->ref.src = XRenderCreateSolidFill(gi->ref.dpy->dpy,
143.41109 ++						     &colors[gi->src_color]);
143.41110 ++
143.41111 ++		if (gi->out.src)
143.41112 ++			XRenderFreePicture(gi->out.dpy->dpy, gi->out.src);
143.41113 ++		gi->out.src = XRenderCreateSolidFill(gi->out.dpy->dpy,
143.41114 ++						     &colors[gi->src_color]);
143.41115 ++
143.41116 ++		gi->stage++;
143.41117 ++	}
143.41118 ++
143.41119 ++	if (gi->stage == MASK) {
143.41120 ++		if (++gi->mask_format > PictStandardNUM)
143.41121 ++			goto reset_mask;
143.41122 ++
143.41123 ++		if (gi->mask_format == PictStandardRGB24)
143.41124 ++			gi->mask_format++;
143.41125 ++
143.41126 ++		if (gi->mask_format < PictStandardNUM) {
143.41127 ++			gi->out.mask_format = XRenderFindStandardFormat(gi->out.dpy->dpy,
143.41128 ++									gi->mask_format);
143.41129 ++			gi->ref.mask_format = XRenderFindStandardFormat(gi->ref.dpy->dpy,
143.41130 ++									gi->mask_format);
143.41131 ++		} else {
143.41132 ++			gi->out.mask_format = NULL;
143.41133 ++			gi->ref.mask_format = NULL;
143.41134 ++		}
143.41135 ++
143.41136 ++		gi->stage++;
143.41137 ++	}
143.41138 ++
143.41139 ++	if (gi->stage == CLIP) {
143.41140 ++		if (++gi->clip == ARRAY_SIZE(clips))
143.41141 ++			goto reset_clip;
143.41142 ++
143.41143 ++		gi->stage++;
143.41144 ++	}
143.41145 ++
143.41146 ++	gi->stage--;
143.41147 ++	return true;
143.41148 ++
143.41149 ++reset_op:
143.41150 ++	gi->op = -1;
143.41151 ++reset_dst:
143.41152 ++	gi->dst_color = -1;
143.41153 ++reset_src:
143.41154 ++	gi->src_color = -1;
143.41155 ++reset_mask:
143.41156 ++	gi->mask_format = -1;
143.41157 ++reset_clip:
143.41158 ++	gi->clip = -1;
143.41159 ++	gi->stage--;
143.41160 ++	goto restart;
143.41161 ++}
143.41162 ++
143.41163 ++static void glyph_iter_fini(struct glyph_iter *gi)
143.41164 ++{
143.41165 ++	if (gi->out.glyphset)
143.41166 ++		XRenderFreeGlyphSet (gi->out.dpy->dpy, gi->out.glyphset);
143.41167 ++	if (gi->ref.glyphset)
143.41168 ++		XRenderFreeGlyphSet (gi->ref.dpy->dpy, gi->ref.glyphset);
143.41169 ++
143.41170 ++	test_target_destroy_render(gi->out.dpy, &gi->out.tt);
143.41171 ++	test_target_destroy_render(gi->ref.dpy, &gi->ref.tt);
143.41172 ++}
143.41173 ++
143.41174 ++static const char *stdformat_to_str(int id)
143.41175 ++{
143.41176 ++	switch (id) {
143.41177 ++	case PictStandardARGB32: return "ARGB32";
143.41178 ++	case PictStandardRGB24: return "RGB24";
143.41179 ++	case PictStandardA8: return "A8";
143.41180 ++	case PictStandardA4: return "A4";
143.41181 ++	case PictStandardA1: return "A1";
143.41182 ++	default: return "none";
143.41183 ++	}
143.41184 ++}
143.41185 ++
143.41186 ++static char *glyph_iter_to_string(struct glyph_iter *gi,
143.41187 ++				  const char *format,
143.41188 ++				  ...)
143.41189 ++{
143.41190 ++	static char buf[100];
143.41191 ++	va_list ap;
143.41192 ++	int len;
143.41193 ++
143.41194 ++	len = sprintf(buf, "glyphs=%s, op=%d, dst=%08x, src=%08x, mask=%s",
143.41195 ++		      stdformat_to_str(gi->glyph_format), gi->op,
143.41196 ++		      xrender_color(&colors[gi->dst_color]),
143.41197 ++		      xrender_color(&colors[gi->src_color]),
143.41198 ++		      stdformat_to_str(gi->mask_format));
143.41199 ++
143.41200 ++	if (format) {
143.41201 ++		buf[len++] = ' ';
143.41202 ++		va_start(ap, format);
143.41203 ++		vsprintf(buf+len, format, ap);
143.41204 ++		va_end(ap);
143.41205 ++	}
143.41206 ++
143.41207 ++	return buf;
143.41208 ++}
143.41209 ++
143.41210 ++static void single(struct test *t, enum target target)
143.41211 ++{
143.41212 ++	struct glyph_iter gi;
143.41213 ++	int n;
143.41214 ++
143.41215 ++	printf("Testing single glyph (%s): ", test_target_name(target));
143.41216 ++	fflush(stdout);
143.41217 ++
143.41218 ++	glyph_iter_init(&gi, t, target);
143.41219 ++	while (glyph_iter_next(&gi)) {
143.41220 ++		XGlyphElt8 elt;
143.41221 ++		char id[N_GLYPHS];
143.41222 ++
143.41223 ++		for (n = 0; n < N_GLYPHS; n++) {
143.41224 ++			id[n] = n;
143.41225 ++
143.41226 ++			elt.chars = &id[n];
143.41227 ++			elt.nchars = 1;
143.41228 ++			elt.xOff = 0;
143.41229 ++			elt.yOff = 0;
143.41230 ++
143.41231 ++			clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
143.41232 ++			elt.glyphset = gi.out.glyphset;
143.41233 ++			XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
143.41234 ++					       gi.out.src,
143.41235 ++					       gi.out.tt.picture,
143.41236 ++					       gi.out.mask_format,
143.41237 ++					       0, 0,
143.41238 ++					       0, 8,
143.41239 ++					       &elt, 1);
143.41240 ++
143.41241 ++			clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
143.41242 ++			elt.glyphset = gi.ref.glyphset;
143.41243 ++			XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
143.41244 ++					       gi.ref.src,
143.41245 ++					       gi.ref.tt.picture,
143.41246 ++					       gi.ref.mask_format,
143.41247 ++					       0, 0,
143.41248 ++					       0, 8,
143.41249 ++					       &elt, 1);
143.41250 ++			test_compare(t,
143.41251 ++				     gi.out.tt.draw, gi.out.tt.format,
143.41252 ++				     gi.ref.tt.draw, gi.ref.tt.format,
143.41253 ++				     0, 0, gi.out.tt.width, gi.out.tt.height,
143.41254 ++				     glyph_iter_to_string(&gi,
143.41255 ++							  "glyph=%s",
143.41256 ++							  glyph_name(n)));
143.41257 ++		}
143.41258 ++
143.41259 ++		elt.chars = &id[0];
143.41260 ++		elt.nchars = n;
143.41261 ++		clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
143.41262 ++		elt.glyphset = gi.out.glyphset;
143.41263 ++		XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
143.41264 ++				       gi.out.src,
143.41265 ++				       gi.out.tt.picture,
143.41266 ++				       gi.out.mask_format,
143.41267 ++				       0, 0,
143.41268 ++				       0, 8,
143.41269 ++				       &elt, 1);
143.41270 ++
143.41271 ++		clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
143.41272 ++		elt.glyphset = gi.ref.glyphset;
143.41273 ++		XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
143.41274 ++				       gi.ref.src,
143.41275 ++				       gi.ref.tt.picture,
143.41276 ++				       gi.ref.mask_format,
143.41277 ++				       0, 0,
143.41278 ++				       0, 8,
143.41279 ++				       &elt, 1);
143.41280 ++		test_compare(t,
143.41281 ++			     gi.out.tt.draw, gi.out.tt.format,
143.41282 ++			     gi.ref.tt.draw, gi.ref.tt.format,
143.41283 ++			     0, 0, gi.out.tt.width, gi.out.tt.height,
143.41284 ++			     glyph_iter_to_string(&gi, "all"));
143.41285 ++	}
143.41286 ++	glyph_iter_fini(&gi);
143.41287 ++}
143.41288 ++
143.41289 ++int main(int argc, char **argv)
143.41290 ++{
143.41291 ++	struct test test;
143.41292 ++	int t;
143.41293 ++
143.41294 ++	test_init(&test, argc, argv);
143.41295 ++	XSetErrorHandler(_check_error_handler);
143.41296 ++
143.41297 ++	for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
143.41298 ++		single(&test, t);
143.41299 ++		//overlapping(&test, t);
143.41300 ++		//gap(&test, t);
143.41301 ++		//mixed(&test, t);
143.41302 ++	}
143.41303 ++
143.41304 ++	return 0;
143.41305 ++}
143.41306 +diff --git a/test/render-trapezoid.c b/test/render-trapezoid.c
143.41307 +index cd990143..f15a78e3 100644
143.41308 +--- a/test/render-trapezoid.c
143.41309 ++++ b/test/render-trapezoid.c
143.41310 +@@ -403,16 +403,141 @@ static void trap_tests(struct test *t,
143.41311 + 	free(traps);
143.41312 + }
143.41313 + 
143.41314 ++enum edge {
143.41315 ++	EDGE_SHARP = PolyEdgeSharp,
143.41316 ++	EDGE_SMOOTH,
143.41317 ++};
143.41318 ++
143.41319 ++static const char *edge_name(enum edge edge)
143.41320 ++{
143.41321 ++	switch (edge) {
143.41322 ++	default:
143.41323 ++	case EDGE_SHARP: return "sharp";
143.41324 ++	case EDGE_SMOOTH: return "smooth";
143.41325 ++	}
143.41326 ++}
143.41327 ++
143.41328 ++static void set_edge(Display *dpy, Picture p, enum edge edge)
143.41329 ++{
143.41330 ++	XRenderPictureAttributes a;
143.41331 ++
143.41332 ++	a.poly_edge = edge;
143.41333 ++	XRenderChangePicture(dpy, p, CPPolyEdge, &a);
143.41334 ++}
143.41335 ++
143.41336 ++static void edge_test(struct test *t,
143.41337 ++		      enum mask mask,
143.41338 ++		      enum edge edge,
143.41339 ++		      enum target target)
143.41340 ++{
143.41341 ++	struct test_target out, ref;
143.41342 ++	XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
143.41343 ++	Picture src_ref, src_out;
143.41344 ++	XTrapezoid trap;
143.41345 ++	int left_or_right, p;
143.41346 ++
143.41347 ++	test_target_create_render(&t->out, target, &out);
143.41348 ++	set_edge(t->out.dpy, out.picture, edge);
143.41349 ++	src_out = XRenderCreateSolidFill(t->out.dpy, &white);
143.41350 ++
143.41351 ++	test_target_create_render(&t->ref, target, &ref);
143.41352 ++	set_edge(t->ref.dpy, ref.picture, edge);
143.41353 ++	src_ref = XRenderCreateSolidFill(t->ref.dpy, &white);
143.41354 ++
143.41355 ++	printf("Testing edges (with mask %s and %s edges) (%s): ",
143.41356 ++	       mask_name(mask),
143.41357 ++	       edge_name(edge),
143.41358 ++	       test_target_name(target));
143.41359 ++	fflush(stdout);
143.41360 ++
143.41361 ++	for (left_or_right = 0; left_or_right <= 1; left_or_right++) {
143.41362 ++		for (p = -64; p <= out.width + 64; p++) {
143.41363 ++			char buf[80];
143.41364 ++
143.41365 ++			if (left_or_right) {
143.41366 ++				trap.left.p1.x = 0;
143.41367 ++				trap.left.p1.y = 0;
143.41368 ++				trap.left.p2.x = 0;
143.41369 ++				trap.left.p2.y = out.height << 16;
143.41370 ++
143.41371 ++				trap.right.p1.x = p << 16;
143.41372 ++				trap.right.p1.y = 0;
143.41373 ++				trap.right.p2.x = out.width << 16;
143.41374 ++				trap.right.p2.y = out.height << 16;
143.41375 ++			} else {
143.41376 ++				trap.right.p1.x = out.width << 16;
143.41377 ++				trap.right.p1.y = 0;
143.41378 ++				trap.right.p2.x = out.width << 16;
143.41379 ++				trap.right.p2.y = out.height << 16;
143.41380 ++
143.41381 ++				trap.left.p1.x = 0;
143.41382 ++				trap.left.p1.y = 0;
143.41383 ++				trap.left.p2.x = p << 16;
143.41384 ++				trap.left.p2.y = out.height << 16;
143.41385 ++			}
143.41386 ++
143.41387 ++			trap.top = 0;
143.41388 ++			trap.bottom = out.height << 16;
143.41389 ++
143.41390 ++			sprintf(buf,
143.41391 ++				"trap=((%d, %d), (%d, %d)), ((%d, %d), (%d, %d))\n",
143.41392 ++				trap.left.p1.x >> 16, trap.left.p1.y >> 16,
143.41393 ++				trap.left.p2.x >> 16, trap.left.p2.y >> 16,
143.41394 ++				trap.right.p1.x >> 16, trap.right.p1.y >> 16,
143.41395 ++				trap.right.p2.x >> 16, trap.right.p2.y >> 16);
143.41396 ++
143.41397 ++			clear(&t->out, &out);
143.41398 ++			XRenderCompositeTrapezoids(t->out.dpy,
143.41399 ++						   PictOpSrc,
143.41400 ++						   src_out,
143.41401 ++						   out.picture,
143.41402 ++						   mask_format(t->out.dpy, mask),
143.41403 ++						   0, 0,
143.41404 ++						   &trap, 1);
143.41405 ++
143.41406 ++			clear(&t->ref, &ref);
143.41407 ++			XRenderCompositeTrapezoids(t->ref.dpy,
143.41408 ++						   PictOpSrc,
143.41409 ++						   src_ref,
143.41410 ++						   ref.picture,
143.41411 ++						   mask_format(t->ref.dpy, mask),
143.41412 ++						   0, 0,
143.41413 ++						   &trap, 1);
143.41414 ++
143.41415 ++			test_compare(t,
143.41416 ++				     out.draw, out.format,
143.41417 ++				     ref.draw, ref.format,
143.41418 ++				     0, 0, out.width, out.height,
143.41419 ++				     buf);
143.41420 ++		}
143.41421 ++	}
143.41422 ++
143.41423 ++	XRenderFreePicture(t->out.dpy, src_out);
143.41424 ++	test_target_destroy_render(&t->out, &out);
143.41425 ++
143.41426 ++	XRenderFreePicture(t->ref.dpy, src_ref);
143.41427 ++	test_target_destroy_render(&t->ref, &ref);
143.41428 ++
143.41429 ++	printf("pass\n");
143.41430 ++}
143.41431 ++
143.41432 + int main(int argc, char **argv)
143.41433 + {
143.41434 + 	struct test test;
143.41435 + 	int i, dx, dy;
143.41436 + 	enum target target;
143.41437 + 	enum mask mask;
143.41438 ++	enum edge edge;
143.41439 + 	enum trapezoid trapezoid;
143.41440 + 
143.41441 + 	test_init(&test, argc, argv);
143.41442 + 
143.41443 ++	for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
143.41444 ++		for (mask = MASK_NONE; mask <= MASK_A8; mask++)
143.41445 ++			for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++)
143.41446 ++				edge_test(&test, mask, edge, target);
143.41447 ++	}
143.41448 ++
143.41449 + 	for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
143.41450 + 		int reps = REPS(i), sets = SETS(i);
143.41451 + 
143.41452 +diff --git a/test/render-triangle.c b/test/render-triangle.c
143.41453 +new file mode 100644
143.41454 +index 00000000..165834ce
143.41455 +--- /dev/null
143.41456 ++++ b/test/render-triangle.c
143.41457 +@@ -0,0 +1,180 @@
143.41458 ++#include <stdint.h>
143.41459 ++#include <stdio.h>
143.41460 ++#include <stdlib.h>
143.41461 ++
143.41462 ++#include "test.h"
143.41463 ++
143.41464 ++enum edge {
143.41465 ++	EDGE_SHARP = PolyEdgeSharp,
143.41466 ++	EDGE_SMOOTH,
143.41467 ++};
143.41468 ++
143.41469 ++static void set_edge(Display *dpy, Picture p, enum edge edge)
143.41470 ++{
143.41471 ++	XRenderPictureAttributes a;
143.41472 ++
143.41473 ++	a.poly_edge = edge;
143.41474 ++	XRenderChangePicture(dpy, p, CPPolyEdge, &a);
143.41475 ++}
143.41476 ++
143.41477 ++static XRenderPictFormat *mask_format(Display *dpy, enum mask mask)
143.41478 ++{
143.41479 ++	switch (mask) {
143.41480 ++	default:
143.41481 ++	case MASK_NONE: return NULL;
143.41482 ++	case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1);
143.41483 ++	case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8);
143.41484 ++	}
143.41485 ++}
143.41486 ++
143.41487 ++static const char *mask_name(enum mask mask)
143.41488 ++{
143.41489 ++	switch (mask) {
143.41490 ++	default:
143.41491 ++	case MASK_NONE: return "none";
143.41492 ++	case MASK_A1: return "a1";
143.41493 ++	case MASK_A8: return "a8";
143.41494 ++	}
143.41495 ++}
143.41496 ++
143.41497 ++static const char *edge_name(enum edge edge)
143.41498 ++{
143.41499 ++	switch (edge) {
143.41500 ++	default:
143.41501 ++	case EDGE_SHARP: return "sharp";
143.41502 ++	case EDGE_SMOOTH: return "smooth";
143.41503 ++	}
143.41504 ++}
143.41505 ++
143.41506 ++static void clear(struct test_display *dpy, struct test_target *tt)
143.41507 ++{
143.41508 ++	XRenderColor render_color = {0};
143.41509 ++	XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
143.41510 ++			     0, 0, tt->width, tt->height);
143.41511 ++}
143.41512 ++
143.41513 ++static void step_to_point(int step, int width, int height, XPointFixed *p)
143.41514 ++{
143.41515 ++	do {
143.41516 ++		p->x = (step - 64) << 16;
143.41517 ++		p->y = -64 << 16;
143.41518 ++
143.41519 ++		step -= width - 128;
143.41520 ++		if (step <= 0)
143.41521 ++			return;
143.41522 ++
143.41523 ++		p->x = (width + 64) << 16;
143.41524 ++		p->y = (step - 64) << 16;
143.41525 ++		step -= height - 128;
143.41526 ++
143.41527 ++		if (step <= 0)
143.41528 ++			return;
143.41529 ++
143.41530 ++		p->x = (width + 64 - step) << 16;
143.41531 ++		p->y = (height + 64) << 16;
143.41532 ++		step -= width - 128;
143.41533 ++
143.41534 ++		if (step <= 0)
143.41535 ++			return;
143.41536 ++
143.41537 ++		p->x = -64 << 16;
143.41538 ++		p->y = (height + 64 - step) << 16;
143.41539 ++		step -= height - 128;
143.41540 ++	} while (step > 0);
143.41541 ++}
143.41542 ++
143.41543 ++static void edge_test(struct test *t,
143.41544 ++		      enum mask mask,
143.41545 ++		      enum edge edge,
143.41546 ++		      enum target target)
143.41547 ++{
143.41548 ++	struct test_target out, ref;
143.41549 ++	XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
143.41550 ++	Picture src_ref, src_out;
143.41551 ++	XTriangle tri;
143.41552 ++	unsigned step, max;
143.41553 ++
143.41554 ++	test_target_create_render(&t->out, target, &out);
143.41555 ++	set_edge(t->out.dpy, out.picture, edge);
143.41556 ++	src_out = XRenderCreateSolidFill(t->out.dpy, &white);
143.41557 ++
143.41558 ++	test_target_create_render(&t->ref, target, &ref);
143.41559 ++	set_edge(t->ref.dpy, ref.picture, edge);
143.41560 ++	src_ref = XRenderCreateSolidFill(t->ref.dpy, &white);
143.41561 ++
143.41562 ++	printf("Testing edges (with mask %s and %s edges) (%s): ",
143.41563 ++	       mask_name(mask),
143.41564 ++	       edge_name(edge),
143.41565 ++	       test_target_name(target));
143.41566 ++	fflush(stdout);
143.41567 ++
143.41568 ++	max = 2*(out.width + 128 + out.height+128);
143.41569 ++	step = 0;
143.41570 ++	for (step = 0; step <= max; step++) {
143.41571 ++		char buf[80];
143.41572 ++
143.41573 ++		step_to_point(step, out.width, out.height, &tri.p1);
143.41574 ++		step_to_point(step + out.width + 128,
143.41575 ++			      out.width, out.height,
143.41576 ++			      &tri.p2);
143.41577 ++		step_to_point(step + out.height + 128 + 2*(out.width + 128),
143.41578 ++			      out.width, out.height,
143.41579 ++			      &tri.p3);
143.41580 ++
143.41581 ++		sprintf(buf,
143.41582 ++			"tri=((%d, %d), (%d, %d), (%d, %d))\n",
143.41583 ++			tri.p1.x >> 16, tri.p1.y >> 16,
143.41584 ++			tri.p2.x >> 16, tri.p2.y >> 16,
143.41585 ++			tri.p3.x >> 16, tri.p3.y >> 16);
143.41586 ++
143.41587 ++		clear(&t->out, &out);
143.41588 ++		XRenderCompositeTriangles(t->out.dpy,
143.41589 ++					  PictOpSrc,
143.41590 ++					  src_out,
143.41591 ++					  out.picture,
143.41592 ++					  mask_format(t->out.dpy, mask),
143.41593 ++					  0, 0,
143.41594 ++					  &tri, 1);
143.41595 ++
143.41596 ++		clear(&t->ref, &ref);
143.41597 ++		XRenderCompositeTriangles(t->ref.dpy,
143.41598 ++					  PictOpSrc,
143.41599 ++					  src_ref,
143.41600 ++					  ref.picture,
143.41601 ++					  mask_format(t->ref.dpy, mask),
143.41602 ++					  0, 0,
143.41603 ++					  &tri, 1);
143.41604 ++
143.41605 ++		test_compare(t,
143.41606 ++			     out.draw, out.format,
143.41607 ++			     ref.draw, ref.format,
143.41608 ++			     0, 0, out.width, out.height,
143.41609 ++			     buf);
143.41610 ++	}
143.41611 ++
143.41612 ++	XRenderFreePicture(t->out.dpy, src_out);
143.41613 ++	test_target_destroy_render(&t->out, &out);
143.41614 ++
143.41615 ++	XRenderFreePicture(t->ref.dpy, src_ref);
143.41616 ++	test_target_destroy_render(&t->ref, &ref);
143.41617 ++
143.41618 ++	printf("pass\n");
143.41619 ++}
143.41620 ++
143.41621 ++int main(int argc, char **argv)
143.41622 ++{
143.41623 ++	struct test test;
143.41624 ++	enum target target;
143.41625 ++	enum mask mask;
143.41626 ++	enum edge edge;
143.41627 ++
143.41628 ++	test_init(&test, argc, argv);
143.41629 ++
143.41630 ++	for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
143.41631 ++		for (mask = MASK_NONE; mask <= MASK_A8; mask++)
143.41632 ++			for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++)
143.41633 ++				edge_test(&test, mask, edge, target);
143.41634 ++	}
143.41635 ++
143.41636 ++	return 0;
143.41637 ++}
143.41638 +diff --git a/test/test.h b/test/test.h
143.41639 +index a3ef979d..9eec1cf9 100644
143.41640 +--- a/test/test.h
143.41641 ++++ b/test/test.h
143.41642 +@@ -107,6 +107,15 @@ static inline uint32_t color(uint8_t red, uint8_t green, uint8_t blue, uint8_t a
143.41643 + 	return alpha << 24 | ra >> 8 << 16 | ga >> 8 << 8 | ba >> 8;
143.41644 + }
143.41645 + 
143.41646 ++static inline uint32_t xrender_color(const XRenderColor *c)
143.41647 ++{
143.41648 ++	uint32_t ra = c->red * c->alpha;
143.41649 ++	uint32_t ga = c->green * c->alpha;
143.41650 ++	uint32_t ba = c->blue * c->alpha;
143.41651 ++
143.41652 ++	return c->alpha >> 8 << 24 | ra >> 24 << 16 | ga >> 24 << 8 | ba >> 24;
143.41653 ++}
143.41654 ++
143.41655 + void test_timer_start(struct test_display *t, struct timespec *tv);
143.41656 + double test_timer_stop(struct test_display *t, struct timespec *tv);
143.41657 + 
143.41658 +diff --git a/test/test_image.c b/test/test_image.c
143.41659 +index d15a8af8..1c076990 100644
143.41660 +--- a/test/test_image.c
143.41661 ++++ b/test/test_image.c
143.41662 +@@ -197,13 +197,10 @@ void test_compare(struct test *t,
143.41663 + 		  const char *info)
143.41664 + {
143.41665 + 	XImage out_image, ref_image;
143.41666 +-	Pixmap tmp;
143.41667 +-	char *out, *ref;
143.41668 ++	uint32_t *out, *ref;
143.41669 + 	char buf[600];
143.41670 + 	uint32_t mask;
143.41671 + 	int i, j;
143.41672 +-	XGCValues gcv;
143.41673 +-	GC gc;
143.41674 + 
143.41675 + 	if (w * h * 4 > t->out.max_shm_size)
143.41676 + 		return test_compare_fallback(t,
143.41677 +@@ -214,37 +211,24 @@ void test_compare(struct test *t,
143.41678 + 	test_init_image(&out_image, &t->out.shm, out_format, w, h);
143.41679 + 	test_init_image(&ref_image, &t->ref.shm, ref_format, w, h);
143.41680 + 
143.41681 +-	gcv.graphics_exposures = 0;
143.41682 +-
143.41683 + 	die_unless(out_image.depth == ref_image.depth);
143.41684 + 	die_unless(out_image.bits_per_pixel == ref_image.bits_per_pixel);
143.41685 + 	die_unless(out_image.bits_per_pixel == 32);
143.41686 + 
143.41687 +-	mask = depth_mask(out_image.depth);
143.41688 ++	XShmGetImage(t->out.dpy, out_draw, &out_image, x, y, AllPlanes);
143.41689 ++	out = (uint32_t *)out_image.data;
143.41690 + 
143.41691 +-	tmp = XCreatePixmap(t->out.dpy, out_draw, w, h, out_image.depth);
143.41692 +-	gc = XCreateGC(t->out.dpy, tmp, GCGraphicsExposures, &gcv);
143.41693 +-	XCopyArea(t->out.dpy, out_draw, tmp, gc, x, y, w, h, 0, 0);
143.41694 +-	XShmGetImage(t->out.dpy, tmp, &out_image, 0, 0, AllPlanes);
143.41695 +-	XFreeGC(t->out.dpy, gc);
143.41696 +-	XFreePixmap(t->out.dpy, tmp);
143.41697 +-	out = out_image.data;
143.41698 +-
143.41699 +-	tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth);
143.41700 +-	gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv);
143.41701 +-	XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0);
143.41702 +-	XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes);
143.41703 +-	XFreeGC(t->ref.dpy, gc);
143.41704 +-	XFreePixmap(t->ref.dpy, tmp);
143.41705 +-	ref = ref_image.data;
143.41706 ++	XShmGetImage(t->ref.dpy, ref_draw, &ref_image, x, y, AllPlanes);
143.41707 ++	ref = (uint32_t *)ref_image.data;
143.41708 + 
143.41709 + 	/* Start with an exact comparison. However, one quicky desires
143.41710 + 	 * a fuzzy comparator to hide hardware inaccuracies...
143.41711 + 	 */
143.41712 ++	mask = depth_mask(out_image.depth);
143.41713 + 	for (j = 0; j < h; j++) {
143.41714 + 		for (i = 0; i < w; i++) {
143.41715 +-			uint32_t a = ((uint32_t *)out)[i] & mask;
143.41716 +-			uint32_t b = ((uint32_t *)ref)[i] & mask;
143.41717 ++			uint32_t a = out[i] & mask;
143.41718 ++			uint32_t b = ref[i] & mask;
143.41719 + 			if (a != b && pixel_difference(a, b) > MAX_DELTA) {
143.41720 + 				show_pixels(buf,
143.41721 + 					    &out_image, &ref_image,
143.41722 +@@ -255,8 +239,8 @@ void test_compare(struct test *t,
143.41723 + 				    x,i, y,j, a, b, pixel_difference(a, b), buf, info);
143.41724 + 			}
143.41725 + 		}
143.41726 +-		out += out_image.bytes_per_line;
143.41727 +-		ref += ref_image.bytes_per_line;
143.41728 ++		out = (uint32_t *)((char *)out + out_image.bytes_per_line);
143.41729 ++		ref = (uint32_t *)((char *)ref + ref_image.bytes_per_line);
143.41730 + 	}
143.41731 + }
143.41732 + 
143.41733 +diff --git a/test/xvidmode.c b/test/xvidmode.c
143.41734 +new file mode 100644
143.41735 +index 00000000..5cde8286
143.41736 +--- /dev/null
143.41737 ++++ b/test/xvidmode.c
143.41738 +@@ -0,0 +1,54 @@
143.41739 ++#include <stdlib.h>
143.41740 ++#include <stdio.h>
143.41741 ++#include <string.h>
143.41742 ++#include <X11/Xlib.h>
143.41743 ++#include <X11/extensions/xf86vmode.h>
143.41744 ++
143.41745 ++int main(void)
143.41746 ++{
143.41747 ++	Display *dpy;
143.41748 ++	XF86VidModeModeLine current;
143.41749 ++	XF86VidModeModeInfo **modes;
143.41750 ++	int num_modes, i;
143.41751 ++	int saved_mode = -1;
143.41752 ++	int dotclock;
143.41753 ++
143.41754 ++	dpy = XOpenDisplay(NULL);
143.41755 ++	if (dpy == NULL)
143.41756 ++		dpy = XOpenDisplay(":0");
143.41757 ++
143.41758 ++	XF86VidModeGetModeLine(dpy, DefaultScreen(dpy), &dotclock, &current);
143.41759 ++	XF86VidModeGetAllModeLines(dpy, XDefaultScreen(dpy),
143.41760 ++				   &num_modes, &modes);
143.41761 ++	for (i = 0; i < num_modes; i++) {
143.41762 ++		int this;
143.41763 ++
143.41764 ++		this = (current.hdisplay == modes[i]->hdisplay &&
143.41765 ++			current.vdisplay == modes[i]->vdisplay &&
143.41766 ++			dotclock == modes[i]->dotclock);
143.41767 ++		if (this && saved_mode == -1)
143.41768 ++			saved_mode = i;
143.41769 ++
143.41770 ++		printf("[%d] %dx%d%s\n",
143.41771 ++		       i,
143.41772 ++		       modes[i]->hdisplay,
143.41773 ++		       modes[i]->vdisplay,
143.41774 ++		       this ? "*" : "");
143.41775 ++	}
143.41776 ++
143.41777 ++	for (i = 0; i < num_modes; i++) {
143.41778 ++		printf("Switching to mode %dx%d\n",
143.41779 ++		       modes[i]->hdisplay,
143.41780 ++		       modes[i]->vdisplay);
143.41781 ++		XF86VidModeSwitchToMode(dpy, XDefaultScreen(dpy), modes[i]);
143.41782 ++		XSync(dpy, True);
143.41783 ++	}
143.41784 ++
143.41785 ++	if (saved_mode != -1) {
143.41786 ++		XF86VidModeSwitchToMode(dpy, XDefaultScreen(dpy),
143.41787 ++					modes[saved_mode]);
143.41788 ++		XFlush(dpy);
143.41789 ++	}
143.41790 ++
143.41791 ++	return 0;
143.41792 ++}
143.41793 +diff --git a/tools/Makefile.am b/tools/Makefile.am
143.41794 +index b5de2c96..92df266b 100644
143.41795 +--- a/tools/Makefile.am
143.41796 ++++ b/tools/Makefile.am
143.41797 +@@ -26,13 +26,30 @@ AM_CFLAGS = \
143.41798 + drivermandir = $(DRIVER_MAN_DIR)
143.41799 + policydir = $(datarootdir)/polkit-1/actions
143.41800 + 
143.41801 ++bin_PROGRAMS =
143.41802 ++noinst_PROGRAMS =
143.41803 ++libexec_PROGRAMS =
143.41804 ++
143.41805 + if BUILD_TOOLS
143.41806 +-bin_PROGRAMS = intel-virtual-output
143.41807 ++bin_PROGRAMS += intel-virtual-output
143.41808 + driverman_DATA = intel-virtual-output.$(DRIVER_MAN_SUFFIX)
143.41809 + endif
143.41810 + 
143.41811 ++if BUILD_TOOL_CURSOR
143.41812 ++noinst_PROGRAMS += cursor
143.41813 ++cursor_CFLAGS = $(TOOL_CURSOR_CFLAGS)
143.41814 ++cursor_LDADD = $(TOOL_CURSOR_LIBS)
143.41815 ++endif
143.41816 ++
143.41817 ++if X11_DRI3
143.41818 ++noinst_PROGRAMS += dri3info
143.41819 ++dri3info_SOURCES = dri3info.c
143.41820 ++dri3info_CFLAGS = $(X11_DRI3_CFLAGS) $(DRI_CFLAGS)
143.41821 ++dri3info_LDADD = $(X11_DRI3_LIBS) $(DRI_LIBS)
143.41822 ++endif
143.41823 ++
143.41824 + if BUILD_BACKLIGHT_HELPER
143.41825 +-libexec_PROGRAMS = xf86-video-intel-backlight-helper
143.41826 ++libexec_PROGRAMS += xf86-video-intel-backlight-helper
143.41827 + nodist_policy_DATA = org.x.xf86-video-intel.backlight-helper.policy
143.41828 + 
143.41829 + backlight_helper = $(libexecdir)/xf86-video-intel-backlight-helper
143.41830 +diff --git a/tools/backlight_helper.c b/tools/backlight_helper.c
143.41831 +index 8b2667dc..aadb8fac 100644
143.41832 +--- a/tools/backlight_helper.c
143.41833 ++++ b/tools/backlight_helper.c
143.41834 +@@ -1,3 +1,7 @@
143.41835 ++#ifdef HAVE_CONFIG_H
143.41836 ++#include "config.h"
143.41837 ++#endif
143.41838 ++
143.41839 + #include <stdio.h>
143.41840 + #include <string.h>
143.41841 + #include <stdarg.h>
143.41842 +@@ -9,6 +13,12 @@
143.41843 + #include <sys/types.h>
143.41844 + #include <sys/stat.h>
143.41845 + 
143.41846 ++#if MAJOR_IN_MKDEV
143.41847 ++#include <sys/mkdev.h>
143.41848 ++#elif MAJOR_IN_SYSMACROS
143.41849 ++#include <sys/sysmacros.h>
143.41850 ++#endif
143.41851 ++
143.41852 + #define DBG 0
143.41853 + 
143.41854 + #if defined(__GNUC__) && (__GNUC__ > 3)
143.41855 +diff --git a/tools/cursor.c b/tools/cursor.c
143.41856 +new file mode 100644
143.41857 +index 00000000..6a2438ad
143.41858 +--- /dev/null
143.41859 ++++ b/tools/cursor.c
143.41860 +@@ -0,0 +1,127 @@
143.41861 ++/*
143.41862 ++ * Copyright © 2015 Intel Corporation
143.41863 ++ *
143.41864 ++ * Permission is hereby granted, free of charge, to any person obtaining a
143.41865 ++ * copy of this software and associated documentation files (the "Software"),
143.41866 ++ * to deal in the Software without restriction, including without limitation
143.41867 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
143.41868 ++ * and/or sell copies of the Software, and to permit persons to whom the
143.41869 ++ * Software is furnished to do so, subject to the following conditions:
143.41870 ++ *
143.41871 ++ * The above copyright notice and this permission notice (including the next
143.41872 ++ * paragraph) shall be included in all copies or substantial portions of the
143.41873 ++ * Software.
143.41874 ++ *
143.41875 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
143.41876 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
143.41877 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
143.41878 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143.41879 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
143.41880 ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
143.41881 ++ * IN THE SOFTWARE.
143.41882 ++ *
143.41883 ++ */
143.41884 ++
143.41885 ++#ifdef HAVE_CONFIG_H
143.41886 ++#include "config.h"
143.41887 ++#endif
143.41888 ++
143.41889 ++#include <X11/Xlib.h>
143.41890 ++#include <X11/extensions/Xfixes.h>
143.41891 ++
143.41892 ++#include <stdint.h>
143.41893 ++#include <stdio.h>
143.41894 ++#include <stdlib.h>
143.41895 ++#include <png.h>
143.41896 ++
143.41897 ++int main(int argc, char **argv)
143.41898 ++{
143.41899 ++	Display *dpy;
143.41900 ++	XFixesCursorImage *cur;
143.41901 ++	unsigned long *src; /* XXX deep sigh */
143.41902 ++	unsigned x, y;
143.41903 ++	png_struct *png;
143.41904 ++	png_info *info;
143.41905 ++	png_byte **rows;
143.41906 ++	FILE *file;
143.41907 ++
143.41908 ++	dpy = XOpenDisplay(NULL);
143.41909 ++	if (dpy == NULL)
143.41910 ++		return 1;
143.41911 ++
143.41912 ++	if (!XFixesQueryExtension(dpy, (int *)&x, (int *)&y))
143.41913 ++		return 1;
143.41914 ++
143.41915 ++	cur = XFixesGetCursorImage(dpy);
143.41916 ++	if (cur == NULL)
143.41917 ++		return 1;
143.41918 ++
143.41919 ++	printf("Cursor on display '%s': %dx%d, (hotspot %dx%d)\n",
143.41920 ++	       DisplayString(dpy),
143.41921 ++	       cur->width, cur->height,
143.41922 ++	       cur->xhot, cur->yhot);
143.41923 ++
143.41924 ++	if (1) {
143.41925 ++		int x, y;
143.41926 ++
143.41927 ++		src = cur->pixels;
143.41928 ++		for (y = 0; y < cur->height; y++) {
143.41929 ++			for (x = 0; x < cur->width; x++) {
143.41930 ++				if (x == cur->xhot && y == cur->yhot)
143.41931 ++					printf("+");
143.41932 ++				else
143.41933 ++					printf("%c", *src ? *src >> 24 >= 127 ? 'x' : '.' : ' ');
143.41934 ++				src++;
143.41935 ++			}
143.41936 ++			printf("\n");
143.41937 ++		}
143.41938 ++	}
143.41939 ++
143.41940 ++	file = fopen("cursor.png", "wb");
143.41941 ++	if (file == NULL)
143.41942 ++		return 2;
143.41943 ++
143.41944 ++	png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
143.41945 ++	info = png_create_info_struct(png);
143.41946 ++	png_init_io(png, file);
143.41947 ++	png_set_IHDR(png, info,
143.41948 ++		     cur->width, cur->height, 8,
143.41949 ++		     PNG_COLOR_TYPE_RGB_ALPHA,
143.41950 ++		     PNG_INTERLACE_NONE,
143.41951 ++		     PNG_COMPRESSION_TYPE_DEFAULT,
143.41952 ++		     PNG_FILTER_TYPE_DEFAULT);
143.41953 ++	png_write_info(png, info);
143.41954 ++
143.41955 ++	src = cur->pixels;
143.41956 ++	rows = malloc(cur->height*sizeof(png_byte*));
143.41957 ++	if (rows == NULL)
143.41958 ++		return 3;
143.41959 ++
143.41960 ++	for (y = 0; y < cur->height; y++) {
143.41961 ++		rows[y] = malloc(cur->width * 4);
143.41962 ++		for (x = 0; x < cur->width; x++) {
143.41963 ++			uint32_t p = *src++;
143.41964 ++			uint8_t r = p >> 0;
143.41965 ++			uint8_t g = p >> 8;
143.41966 ++			uint8_t b = p >> 16;
143.41967 ++			uint8_t a = p >> 24;
143.41968 ++
143.41969 ++			if (a > 0x00 && a < 0xff) {
143.41970 ++				r = (r * 0xff + a /2) / a;
143.41971 ++				g = (g * 0xff + a /2) / a;
143.41972 ++				b = (b * 0xff + a /2) / a;
143.41973 ++			}
143.41974 ++
143.41975 ++			rows[y][4*x + 0] = b;
143.41976 ++			rows[y][4*x + 1] = g;
143.41977 ++			rows[y][4*x + 2] = r;
143.41978 ++			rows[y][4*x + 3] = a;
143.41979 ++		}
143.41980 ++	}
143.41981 ++
143.41982 ++	png_write_image(png, rows);
143.41983 ++	png_write_end(png, NULL);
143.41984 ++	fclose(file);
143.41985 ++
143.41986 ++	return 0;
143.41987 ++}
143.41988 +diff --git a/tools/dri3info.c b/tools/dri3info.c
143.41989 +new file mode 100644
143.41990 +index 00000000..0c33fc5a
143.41991 +--- /dev/null
143.41992 ++++ b/tools/dri3info.c
143.41993 +@@ -0,0 +1,329 @@
143.41994 ++/*
143.41995 ++ * Copyright (c) 2015 Intel Corporation
143.41996 ++ *
143.41997 ++ * Permission is hereby granted, free of charge, to any person obtaining a
143.41998 ++ * copy of this software and associated documentation files (the "Software"),
143.41999 ++ * to deal in the Software without restriction, including without limitation
143.42000 ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
143.42001 ++ * and/or sell copies of the Software, and to permit persons to whom the
143.42002 ++ * Software is furnished to do so, subject to the following conditions:
143.42003 ++ *
143.42004 ++ * The above copyright notice and this permission notice (including the next
143.42005 ++ * paragraph) shall be included in all copies or substantial portions of the
143.42006 ++ * Software.
143.42007 ++ *
143.42008 ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
143.42009 ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
143.42010 ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
143.42011 ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
143.42012 ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
143.42013 ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
143.42014 ++ * SOFTWARE.
143.42015 ++ *
143.42016 ++ * To compile standalone: gcc -o dri3info dri3info.c `pkg-config --cflags --libs xcb-dri3 x11-xcb xrandr xxf86vm libdrm`
143.42017 ++ */
143.42018 ++
143.42019 ++#include <X11/Xlib.h>
143.42020 ++#include <X11/Xlib-xcb.h>
143.42021 ++#include <xcb/xcb.h>
143.42022 ++#include <xcb/dri3.h>
143.42023 ++#include <unistd.h>
143.42024 ++#include <stdio.h>
143.42025 ++#include <stdlib.h>
143.42026 ++#include <stdint.h>
143.42027 ++#include <string.h>
143.42028 ++#include <sys/stat.h>
143.42029 ++#include <drm.h>
143.42030 ++#include <xf86drm.h>
143.42031 ++
143.42032 ++#include <X11/extensions/Xrandr.h>
143.42033 ++#include <X11/extensions/xf86vmode.h>
143.42034 ++
143.42035 ++static int dri3_query_version(Display *dpy, int *major, int *minor)
143.42036 ++{
143.42037 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.42038 ++	xcb_dri3_query_version_reply_t *reply;
143.42039 ++	xcb_generic_error_t *error;
143.42040 ++
143.42041 ++	*major = *minor = -1;
143.42042 ++
143.42043 ++	reply = xcb_dri3_query_version_reply(c,
143.42044 ++					     xcb_dri3_query_version(c,
143.42045 ++								    XCB_DRI3_MAJOR_VERSION,
143.42046 ++								    XCB_DRI3_MINOR_VERSION),
143.42047 ++					     &error);
143.42048 ++	free(error);
143.42049 ++	if (reply == NULL)
143.42050 ++		return -1;
143.42051 ++
143.42052 ++	*major = reply->major_version;
143.42053 ++	*minor = reply->minor_version;
143.42054 ++	free(reply);
143.42055 ++
143.42056 ++	return 0;
143.42057 ++}
143.42058 ++
143.42059 ++static int dri3_exists(Display *dpy)
143.42060 ++{
143.42061 ++	const xcb_query_extension_reply_t *ext;
143.42062 ++	int major, minor;
143.42063 ++
143.42064 ++	ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
143.42065 ++	if (ext == NULL || !ext->present)
143.42066 ++		return 0;
143.42067 ++
143.42068 ++	if (dri3_query_version(dpy, &major, &minor) < 0)
143.42069 ++		return 0;
143.42070 ++
143.42071 ++	return major >= 0;
143.42072 ++}
143.42073 ++
143.42074 ++static int dri3_open(Display *dpy)
143.42075 ++{
143.42076 ++	xcb_connection_t *c = XGetXCBConnection(dpy);
143.42077 ++	xcb_dri3_open_cookie_t cookie;
143.42078 ++	xcb_dri3_open_reply_t *reply;
143.42079 ++
143.42080 ++	if (!dri3_exists(dpy))
143.42081 ++		return -1;
143.42082 ++
143.42083 ++	cookie = xcb_dri3_open(c, RootWindow(dpy, DefaultScreen(dpy)), None);
143.42084 ++	reply = xcb_dri3_open_reply(c, cookie, NULL);
143.42085 ++
143.42086 ++	if (!reply)
143.42087 ++		return -1;
143.42088 ++
143.42089 ++	if (reply->nfd != 1)
143.42090 ++		return -1;
143.42091 ++
143.42092 ++	return xcb_dri3_open_reply_fds(c, reply)[0];
143.42093 ++}
143.42094 ++
143.42095 ++static void get_device_path(int fd, char *buf, int len)
143.42096 ++{
143.42097 ++	struct stat remote, local;
143.42098 ++	int i;
143.42099 ++
143.42100 ++	if (fstat(fd, &remote))
143.42101 ++		goto out;
143.42102 ++
143.42103 ++	for (i = 0; i < 16; i++) {
143.42104 ++		snprintf(buf, len, "/dev/dri/card%d", i);
143.42105 ++		if (stat(buf, &local))
143.42106 ++			continue;
143.42107 ++
143.42108 ++		if (local.st_mode == remote.st_mode &&
143.42109 ++		    local.st_rdev == remote.st_rdev)
143.42110 ++			return;
143.42111 ++
143.42112 ++		snprintf(buf, len, "/dev/dri/renderD%d", i + 128);
143.42113 ++		if (stat(buf, &local))
143.42114 ++			continue;
143.42115 ++
143.42116 ++		if (local.st_mode == remote.st_mode &&
143.42117 ++		    local.st_rdev == remote.st_rdev)
143.42118 ++			return;
143.42119 ++	}
143.42120 ++
143.42121 ++out:
143.42122 ++	strncpy(buf, "unknown path", len);
143.42123 ++}
143.42124 ++
143.42125 ++static void get_driver_name(int fd, char *name, int len)
143.42126 ++{
143.42127 ++	drm_version_t version;
143.42128 ++
143.42129 ++	memset(name, 0, len);
143.42130 ++	memset(&version, 0, sizeof(version));
143.42131 ++	version.name_len = len;
143.42132 ++	version.name = name;
143.42133 ++
143.42134 ++	(void)drmIoctl(fd, DRM_IOCTL_VERSION, &version);
143.42135 ++}
143.42136 ++
143.42137 ++static int compute_refresh_rate_from_mode(long n, long d, unsigned flags,
143.42138 ++					   int32_t *numerator,
143.42139 ++					   int32_t *denominator)
143.42140 ++{
143.42141 ++	int i;
143.42142 ++
143.42143 ++	/* The mode flags are only defined privately to the Xserver (in xf86str.h)
143.42144 ++	 * but they at least bit compatible between VidMode, RandR and DRM.
143.42145 ++	 */
143.42146 ++# define V_INTERLACE 0x010
143.42147 ++# define V_DBLSCAN   0x020
143.42148 ++
143.42149 ++	if (flags & V_INTERLACE)
143.42150 ++		n *= 2;
143.42151 ++	else if (flags & V_DBLSCAN)
143.42152 ++		d *= 2;
143.42153 ++
143.42154 ++	/* The OML_sync_control spec requires that if the refresh rate is a
143.42155 ++	 * whole number, that the returned numerator be equal to the refresh
143.42156 ++	 * rate and the denominator be 1.
143.42157 ++	 */
143.42158 ++
143.42159 ++	if (n % d == 0) {
143.42160 ++		n /= d;
143.42161 ++		d = 1;
143.42162 ++	}
143.42163 ++	else {
143.42164 ++		static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 };
143.42165 ++
143.42166 ++		/* This is a poor man's way to reduce a fraction.  It's far from
143.42167 ++		 * perfect, but it will work well enough for this situation.
143.42168 ++		 */
143.42169 ++
143.42170 ++		for (i = 0; f[i] != 0; i++) {
143.42171 ++			while (n % f[i] == 0 && d % f[i] == 0) {
143.42172 ++				d /= f[i];
143.42173 ++				n /= f[i];
143.42174 ++			}
143.42175 ++		}
143.42176 ++	}
143.42177 ++
143.42178 ++	*numerator = n;
143.42179 ++	*denominator = d;
143.42180 ++	return 1;
143.42181 ++}
143.42182 ++
143.42183 ++static int RRGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator)
143.42184 ++{
143.42185 ++	int ret = 0;
143.42186 ++	Window root = RootWindow(dpy, DefaultScreen(dpy));
143.42187 ++	XRRScreenResources *res;
143.42188 ++	int rr_event, rr_error;
143.42189 ++	RROutput primary;
143.42190 ++	RRMode mode = 0;
143.42191 ++	int n;
143.42192 ++
143.42193 ++	if (!XRRQueryExtension(dpy, &rr_event, &rr_error))
143.42194 ++		return ret;
143.42195 ++
143.42196 ++	res = XRRGetScreenResourcesCurrent(dpy, root);
143.42197 ++	if (res == NULL)
143.42198 ++		return ret;
143.42199 ++
143.42200 ++	/* Use the primary output if specified, otherwise
143.42201 ++	 * use the mode on the first enabled crtc.
143.42202 ++	 */
143.42203 ++	primary = XRRGetOutputPrimary(dpy, root);
143.42204 ++	if (primary) {
143.42205 ++		XRROutputInfo *output;
143.42206 ++
143.42207 ++		output = XRRGetOutputInfo(dpy, res, primary);
143.42208 ++		if (output != NULL) {
143.42209 ++			if (output->crtc) {
143.42210 ++				XRRCrtcInfo *crtc;
143.42211 ++
143.42212 ++				crtc = XRRGetCrtcInfo(dpy, res, output->crtc);
143.42213 ++				if (crtc) {
143.42214 ++					mode = crtc->mode;
143.42215 ++					XRRFreeCrtcInfo(crtc);
143.42216 ++				}
143.42217 ++			}
143.42218 ++			XRRFreeOutputInfo(output);
143.42219 ++		}
143.42220 ++	}
143.42221 ++
143.42222 ++	for (n = 0; mode == 0 && n < res->ncrtc; n++) {
143.42223 ++		XRRCrtcInfo *crtc;
143.42224 ++
143.42225 ++		crtc = XRRGetCrtcInfo(dpy, res, res->crtcs[n]);
143.42226 ++		if (crtc) {
143.42227 ++			mode = crtc->mode;
143.42228 ++			XRRFreeCrtcInfo(crtc);
143.42229 ++		}
143.42230 ++	}
143.42231 ++
143.42232 ++	for (n = 0; n < res->nmode; n++) {
143.42233 ++		if (res->modes[n].id == mode) {
143.42234 ++			ret = compute_refresh_rate_from_mode(res->modes[n].dotClock,
143.42235 ++							     res->modes[n].hTotal*res->modes[n].vTotal,
143.42236 ++							     res->modes[n].modeFlags,
143.42237 ++							     numerator, denominator);
143.42238 ++			break;
143.42239 ++		}
143.42240 ++	}
143.42241 ++
143.42242 ++	XRRFreeScreenResources(res);
143.42243 ++	return ret;
143.42244 ++}
143.42245 ++
143.42246 ++static int VMGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator)
143.42247 ++{
143.42248 ++	XF86VidModeModeLine mode_line;
143.42249 ++	int dot_clock;
143.42250 ++	int i;
143.42251 ++
143.42252 ++	if (XF86VidModeQueryVersion(dpy, &i, &i) &&
143.42253 ++	    XF86VidModeGetModeLine(dpy, DefaultScreen(dpy), &dot_clock, &mode_line))
143.42254 ++		return compute_refresh_rate_from_mode(dot_clock * 1000,
143.42255 ++						      mode_line.vtotal * mode_line.htotal,
143.42256 ++						      mode_line.flags,
143.42257 ++						      numerator, denominator);
143.42258 ++
143.42259 ++	return 0;
143.42260 ++}
143.42261 ++
143.42262 ++static int get_refresh_rate(Display *dpy,
143.42263 ++			     int32_t *numerator,
143.42264 ++			     int32_t *denominator)
143.42265 ++{
143.42266 ++	if (RRGetMscRate(dpy, numerator, denominator))
143.42267 ++		return 1;
143.42268 ++
143.42269 ++	if (VMGetMscRate(dpy, numerator, denominator))
143.42270 ++		return 1;
143.42271 ++
143.42272 ++	return 0;
143.42273 ++}
143.42274 ++
143.42275 ++static void info(const char *dpyname)
143.42276 ++{
143.42277 ++	Display *dpy;
143.42278 ++	int device;
143.42279 ++	int32_t numerator, denominator;
143.42280 ++
143.42281 ++	dpy = XOpenDisplay(dpyname);
143.42282 ++	if (dpy == NULL) {
143.42283 ++		printf("Unable to connect to display '%s'\n",
143.42284 ++		       dpyname ?: getenv("DISPLAY") ?: "unset");
143.42285 ++		return;
143.42286 ++	}
143.42287 ++
143.42288 ++	printf("Display '%s'\n", DisplayString(dpy));
143.42289 ++	device = dri3_open(dpy);
143.42290 ++	if (device < 0) {
143.42291 ++		printf("\tUnable to connect to DRI3\n");
143.42292 ++	} else {
143.42293 ++		char device_path[1024];
143.42294 ++		char driver_name[1024];
143.42295 ++
143.42296 ++		get_device_path(device, device_path, sizeof(device_path));
143.42297 ++		get_driver_name(device, driver_name, sizeof(driver_name));
143.42298 ++
143.42299 ++		printf("Connected to DRI3, using fd %d which matches %s, driver %s\n",
143.42300 ++		       device, device_path, driver_name);
143.42301 ++		close(device);
143.42302 ++	}
143.42303 ++
143.42304 ++	if (get_refresh_rate(dpy, &numerator, &denominator))
143.42305 ++		printf("\tPrimary refresh rate: %d/%d (%.1fHz)\n",
143.42306 ++		       numerator, denominator, numerator/(float)denominator);
143.42307 ++
143.42308 ++	XCloseDisplay(dpy);
143.42309 ++}
143.42310 ++
143.42311 ++int main(int argc, char **argv)
143.42312 ++{
143.42313 ++	int i;
143.42314 ++
143.42315 ++	if (argc > 1) {
143.42316 ++		for (i = 1; i < argc; i++)
143.42317 ++			info(argv[i]);
143.42318 ++	} else
143.42319 ++		info(NULL);
143.42320 ++
143.42321 ++	return 0;
143.42322 ++}
143.42323 +diff --git a/tools/virtual.c b/tools/virtual.c
143.42324 +index 8e2b4a22..fc8db2b9 100644
143.42325 +--- a/tools/virtual.c
143.42326 ++++ b/tools/virtual.c
143.42327 +@@ -31,6 +31,7 @@
143.42328 + 
143.42329 + #include <X11/Xlibint.h>
143.42330 + #include <X11/extensions/record.h>
143.42331 ++#include <X11/extensions/scrnsaver.h>
143.42332 + #include <X11/extensions/XShm.h>
143.42333 + #if HAVE_X11_EXTENSIONS_SHMPROTO_H
143.42334 + #include <X11/extensions/shmproto.h>
143.42335 +@@ -79,13 +80,15 @@ static int verbose;
143.42336 + #define DRAW 0x8
143.42337 + #define DAMAGE 0x10
143.42338 + #define CURSOR 0x20
143.42339 +-#define POLL 0x40
143.42340 ++#define SCREEN 0x40
143.42341 ++#define POLL 0x80
143.42342 + 
143.42343 + struct display {
143.42344 + 	Display *dpy;
143.42345 + 	struct clone *clone;
143.42346 + 	struct context *ctx;
143.42347 + 
143.42348 ++	int saver_event, saver_error, saver_active;
143.42349 + 	int damage_event, damage_error;
143.42350 + 	int xfixes_event, xfixes_error;
143.42351 + 	int rr_event, rr_error, rr_active;
143.42352 +@@ -98,6 +101,7 @@ struct display {
143.42353 + 	int width;
143.42354 + 	int height;
143.42355 + 	int depth;
143.42356 ++	int active;
143.42357 + 
143.42358 + 	XRenderPictFormat *root_format;
143.42359 + 	XRenderPictFormat *rgb16_format;
143.42360 +@@ -111,7 +115,7 @@ struct display {
143.42361 + 	Cursor invisible_cursor;
143.42362 + 	Cursor visible_cursor;
143.42363 + 
143.42364 +-	XcursorImage cursor_image;
143.42365 ++	XcursorImage cursor_image; /* first only */
143.42366 + 	int cursor_serial;
143.42367 + 	int cursor_x;
143.42368 + 	int cursor_y;
143.42369 +@@ -123,6 +127,13 @@ struct display {
143.42370 + 	int send;
143.42371 + 	int skip_clone;
143.42372 + 	int skip_frame;
143.42373 ++
143.42374 ++	struct {
143.42375 ++		int timeout;
143.42376 ++		int interval;
143.42377 ++		int prefer_blank;
143.42378 ++		int allow_exp;
143.42379 ++	} saver;
143.42380 + };
143.42381 + 
143.42382 + struct output {
143.42383 +@@ -145,6 +156,7 @@ struct output {
143.42384 + 	XRenderPictFormat *use_render;
143.42385 + 
143.42386 + 	int x, y;
143.42387 ++	int width, height;
143.42388 + 	XRRModeInfo mode;
143.42389 + 	Rotation rotation;
143.42390 + };
143.42391 +@@ -218,6 +230,13 @@ static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Wi
143.42392 + static int _x_error_occurred;
143.42393 + 
143.42394 + static int
143.42395 ++_io_error_handler(Display *display)
143.42396 ++{
143.42397 ++	fprintf(stderr, "XIO error on display %s\n", DisplayString(display));
143.42398 ++	abort();
143.42399 ++}
143.42400 ++
143.42401 ++static int
143.42402 + _check_error_handler(Display     *display,
143.42403 + 		     XErrorEvent *event)
143.42404 + {
143.42405 +@@ -243,6 +262,10 @@ can_use_shm(Display *dpy,
143.42406 + 	XExtCodes *codes;
143.42407 + 	int major, minor, has_shm, has_pixmap;
143.42408 + 
143.42409 ++	*shm_event = 0;
143.42410 ++	*shm_opcode = 0;
143.42411 ++	*shm_pixmap = 0;
143.42412 ++
143.42413 + 	if (!XShmQueryExtension(dpy))
143.42414 + 		return 0;
143.42415 + 
143.42416 +@@ -320,6 +343,7 @@ can_use_shm(Display *dpy,
143.42417 + #include <X11/Xlib-xcb.h>
143.42418 + #include <X11/xshmfence.h>
143.42419 + #include <xcb/xcb.h>
143.42420 ++#include <xcb/xcbext.h>
143.42421 + #include <xcb/dri3.h>
143.42422 + #include <xcb/sync.h>
143.42423 + static Pixmap dri3_create_pixmap(Display *dpy,
143.42424 +@@ -357,6 +381,7 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
143.42425 + {
143.42426 + 	xcb_connection_t *c = XGetXCBConnection(dpy);
143.42427 + 	xcb_dri3_query_version_reply_t *reply;
143.42428 ++	xcb_generic_error_t *error;
143.42429 + 
143.42430 + 	*major = *minor = -1;
143.42431 + 
143.42432 +@@ -364,7 +389,8 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
143.42433 + 					     xcb_dri3_query_version(c,
143.42434 + 								    XCB_DRI3_MAJOR_VERSION,
143.42435 + 								    XCB_DRI3_MINOR_VERSION),
143.42436 +-					     NULL);
143.42437 ++					     &error);
143.42438 ++	free(error);
143.42439 + 	if (reply == NULL)
143.42440 + 		return -1;
143.42441 + 
143.42442 +@@ -377,8 +403,13 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
143.42443 + 
143.42444 + static int dri3_exists(Display *dpy)
143.42445 + {
143.42446 ++	const xcb_query_extension_reply_t *ext;
143.42447 + 	int major, minor;
143.42448 + 
143.42449 ++	ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
143.42450 ++	if (ext == NULL || !ext->present)
143.42451 ++		return 0;
143.42452 ++
143.42453 + 	if (dri3_query_version(dpy, &major, &minor) < 0)
143.42454 + 		return 0;
143.42455 + 
143.42456 +@@ -809,6 +840,10 @@ static int clone_update_modes__fixed(struct clone *clone)
143.42457 + 	RRMode id;
143.42458 + 	int i, j, ret = ENOENT;
143.42459 + 
143.42460 ++	DBG(X11, ("%s-%s cloning modes fixed %dx%d\n",
143.42461 ++	     DisplayString(clone->dst.dpy), clone->dst.name,
143.42462 ++	     clone->dst.width, clone->dst.height));
143.42463 ++
143.42464 + 	assert(clone->src.rr_output);
143.42465 + 
143.42466 + 	res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
143.42467 +@@ -837,8 +872,8 @@ static int clone_update_modes__fixed(struct clone *clone)
143.42468 + 
143.42469 + 	/* Create matching mode for the real output on the virtual */
143.42470 + 	memset(&mode, 0, sizeof(mode));
143.42471 +-	mode.width = clone->width;
143.42472 +-	mode.height = clone->height;
143.42473 ++	mode.width = clone->dst.width;
143.42474 ++	mode.height = clone->dst.height;
143.42475 + 	mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height);
143.42476 + 	mode.name = mode_name;
143.42477 + 
143.42478 +@@ -942,6 +977,35 @@ out:
143.42479 + 	return rr_output;
143.42480 + }
143.42481 + 
143.42482 ++static int check_virtual(struct display *display)
143.42483 ++{
143.42484 ++	XRRScreenResources *res;
143.42485 ++	int found = -ENOENT;
143.42486 ++	int i;
143.42487 ++
143.42488 ++	res = _XRRGetScreenResourcesCurrent(display->dpy, display->root);
143.42489 ++	if (res == NULL)
143.42490 ++		return -ENOMEM;
143.42491 ++
143.42492 ++	for (i = 0; found == -ENOENT && i < res->noutput; i++) {
143.42493 ++		XRROutputInfo *output;
143.42494 ++
143.42495 ++		output = XRRGetOutputInfo(display->dpy, res, res->outputs[i]);
143.42496 ++		if (output == NULL)
143.42497 ++			continue;
143.42498 ++
143.42499 ++		if (strcmp(output->name, "VIRTUAL1") == 0)
143.42500 ++			found = 0;
143.42501 ++
143.42502 ++		XRRFreeOutputInfo(output);
143.42503 ++	}
143.42504 ++	XRRFreeScreenResources(res);
143.42505 ++
143.42506 ++	DBG(XRR, ("%s(%s): has VIRTUAL1? %d\n",
143.42507 ++		  __func__, DisplayString(display->dpy), found));
143.42508 ++	return found;
143.42509 ++}
143.42510 ++
143.42511 + static int stride_for_depth(int width, int depth)
143.42512 + {
143.42513 + 	if (depth == 24)
143.42514 +@@ -1082,20 +1146,20 @@ static int clone_init_xfer(struct clone *clone)
143.42515 + 		width = 0;
143.42516 + 		height = 0;
143.42517 + 	} else if (clone->dri3.xid) {
143.42518 +-		width = clone->dst.display->width;
143.42519 +-		height = clone->dst.display->height;
143.42520 ++		width = clone->dst.width;
143.42521 ++		height = clone->dst.height;
143.42522 + 	} else {
143.42523 + 		width = mode_width(&clone->src.mode, clone->src.rotation);
143.42524 + 		height = mode_height(&clone->src.mode, clone->src.rotation);
143.42525 + 	}
143.42526 + 
143.42527 ++	DBG(DRAW, ("%s-%s create xfer, %dx%d (currently %dx%d)\n",
143.42528 ++	     DisplayString(clone->dst.dpy), clone->dst.name,
143.42529 ++	     width, height, clone->width, clone->height));
143.42530 ++
143.42531 + 	if (width == clone->width && height == clone->height)
143.42532 + 		return 0;
143.42533 + 
143.42534 +-	DBG(DRAW, ("%s-%s create xfer, %dx%d\n",
143.42535 +-	     DisplayString(clone->dst.dpy), clone->dst.name,
143.42536 +-	     width, height));
143.42537 +-
143.42538 + 	if (clone->shm.shmaddr) {
143.42539 + 		if (clone->src.use_shm)
143.42540 + 			XShmDetach(clone->src.dpy, &clone->src.shm);
143.42541 +@@ -1225,6 +1289,56 @@ static void clone_update(struct clone *clone)
143.42542 + 	clone->rr_update = 0;
143.42543 + }
143.42544 + 
143.42545 ++static void screensaver_save(struct display *display)
143.42546 ++{
143.42547 ++	display->saver_active =
143.42548 ++		XScreenSaverQueryExtension(display->dpy,
143.42549 ++					   &display->saver_event,
143.42550 ++					   &display->saver_error);
143.42551 ++	DBG(SCREEN,
143.42552 ++	    ("%s screen saver active? %d [event=%d, error=%d]\n",
143.42553 ++	     DisplayString(display->dpy),
143.42554 ++	     display->saver_active,
143.42555 ++	     display->saver_event,
143.42556 ++	     display->saver_error));
143.42557 ++
143.42558 ++	XGetScreenSaver(display->dpy,
143.42559 ++			&display->saver.timeout,
143.42560 ++			&display->saver.interval,
143.42561 ++			&display->saver.prefer_blank,
143.42562 ++			&display->saver.allow_exp);
143.42563 ++
143.42564 ++	DBG(SCREEN,
143.42565 ++	    ("%s saving screen saver defaults: timeout=%d interval=%d prefer_blank=%d allow_exp=%d\n",
143.42566 ++	     DisplayString(display->dpy),
143.42567 ++	     display->saver.timeout,
143.42568 ++	     display->saver.interval,
143.42569 ++	     display->saver.prefer_blank,
143.42570 ++	     display->saver.allow_exp));
143.42571 ++}
143.42572 ++
143.42573 ++static void screensaver_disable(struct display *display)
143.42574 ++{
143.42575 ++	DBG(SCREEN,
143.42576 ++	    ("%s disabling screen saver\n", DisplayString(display->dpy)));
143.42577 ++
143.42578 ++	XSetScreenSaver(display->dpy, 0, 0, DefaultBlanking, DefaultExposures);
143.42579 ++	display_mark_flush(display);
143.42580 ++}
143.42581 ++
143.42582 ++static void screensaver_restore(struct display *display)
143.42583 ++{
143.42584 ++	DBG(SCREEN,
143.42585 ++	    ("%s restoring screen saver\n", DisplayString(display->dpy)));
143.42586 ++
143.42587 ++	XSetScreenSaver(display->dpy,
143.42588 ++			display->saver.timeout,
143.42589 ++			display->saver.interval,
143.42590 ++			display->saver.prefer_blank,
143.42591 ++			display->saver.allow_exp);
143.42592 ++	display_mark_flush(display);
143.42593 ++}
143.42594 ++
143.42595 + static int context_update(struct context *ctx)
143.42596 + {
143.42597 + 	Display *dpy = ctx->display->dpy;
143.42598 +@@ -1325,8 +1439,19 @@ static int context_update(struct context *ctx)
143.42599 + 		struct clone *clone;
143.42600 + 		int x1, x2, y1, y2;
143.42601 + 
143.42602 +-		if (display->rr_active == 0)
143.42603 ++		if (display->rr_active == 0) {
143.42604 ++			for (clone = display->clone; clone; clone = clone->next) {
143.42605 ++				struct output *output = &clone->src;
143.42606 ++				if (output->mode.id) {
143.42607 ++					clone->dst.mode.id = -1;
143.42608 ++					clone->dst.rr_crtc = -1;
143.42609 ++				} else {
143.42610 ++					clone->dst.mode.id = 0;
143.42611 ++					clone->dst.rr_crtc = 0;
143.42612 ++				}
143.42613 ++			}
143.42614 + 			continue;
143.42615 ++		}
143.42616 + 
143.42617 + 		x1 = y1 = INT_MAX;
143.42618 + 		x2 = y2 = INT_MIN;
143.42619 +@@ -1570,6 +1695,13 @@ ungrab:
143.42620 + 		XUngrabServer(display->dpy);
143.42621 + 	}
143.42622 + 
143.42623 ++	for (n = 1; n < ctx->ndisplay; n++) {
143.42624 ++		struct display *display = &ctx->display[n];
143.42625 ++
143.42626 ++		display->active = 0;
143.42627 ++		screensaver_restore(display);
143.42628 ++	}
143.42629 ++
143.42630 + 	ctx->active = NULL;
143.42631 + 	for (n = 0; n < ctx->nclone; n++) {
143.42632 + 		struct clone *clone = &ctx->clones[n];
143.42633 +@@ -1580,7 +1712,10 @@ ungrab:
143.42634 + 			continue;
143.42635 + 
143.42636 + 		DBG(XRR, ("%s-%s: added to active list\n",
143.42637 +-		     DisplayString(clone->dst.display->dpy), clone->dst.name));
143.42638 ++			  DisplayString(clone->dst.display->dpy), clone->dst.name));
143.42639 ++
143.42640 ++		if (clone->dst.display->active++ == 0)
143.42641 ++			screensaver_disable(clone->dst.display);
143.42642 + 
143.42643 + 		clone->active = ctx->active;
143.42644 + 		ctx->active = clone;
143.42645 +@@ -1599,14 +1734,17 @@ static Cursor display_load_invisible_cursor(struct display *display)
143.42646 + 
143.42647 + static Cursor display_get_visible_cursor(struct display *display)
143.42648 + {
143.42649 +-	if (display->cursor_serial != display->cursor_image.size) {
143.42650 +-		DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy)));
143.42651 ++	struct display *first = display->ctx->display;
143.42652 ++
143.42653 ++	if (display->cursor_serial != first->cursor_serial) {
143.42654 ++		DBG(CURSOR, ("%s updating cursor %dx%d, serial %d\n",
143.42655 ++		    DisplayString(display->dpy), first->cursor_image.width, first->cursor_image.height, first->cursor_serial));
143.42656 + 
143.42657 + 		if (display->visible_cursor)
143.42658 + 			XFreeCursor(display->dpy, display->visible_cursor);
143.42659 + 
143.42660 +-		display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image);
143.42661 +-		display->cursor_serial = display->cursor_image.size;
143.42662 ++		display->visible_cursor = XcursorImageLoadCursor(display->dpy, &first->cursor_image);
143.42663 ++		display->cursor_serial = first->cursor_serial;
143.42664 + 	}
143.42665 + 
143.42666 + 	return display->visible_cursor;
143.42667 +@@ -1629,7 +1767,7 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma
143.42668 + 	display->cursor_image.height = cur->height;
143.42669 + 	display->cursor_image.xhot = cur->xhot;
143.42670 + 	display->cursor_image.yhot = cur->yhot;
143.42671 +-	display->cursor_image.size++;
143.42672 ++	display->cursor_serial++;
143.42673 + 
143.42674 + 	n = cur->width*cur->height;
143.42675 + 	src = cur->pixels;
143.42676 +@@ -1637,11 +1775,24 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma
143.42677 + 	while (n--)
143.42678 + 		*dst++ = *src++;
143.42679 + 
143.42680 +-	DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
143.42681 +-	display->cursor_moved++;
143.42682 +-	if (display->cursor != display->invisible_cursor) {
143.42683 +-		display->cursor_visible++;
143.42684 +-		context_enable_timer(display->ctx);
143.42685 ++	if (verbose & CURSOR) {
143.42686 ++		int x, y;
143.42687 ++
143.42688 ++		printf("%s cursor image %dx%d, serial %d:\n",
143.42689 ++		       DisplayString(display->dpy),
143.42690 ++		       cur->width, cur->height,
143.42691 ++		       display->cursor_serial);
143.42692 ++		dst = display->cursor_image.pixels;
143.42693 ++		for (y = 0; y < cur->height; y++) {
143.42694 ++			for (x = 0; x < cur->width; x++) {
143.42695 ++				if (x == cur->xhot && y == cur->yhot)
143.42696 ++					printf("+");
143.42697 ++				else
143.42698 ++					printf("%c", *dst ? *dst >> 24 >= 127 ? 'x' : '.' : ' ');
143.42699 ++				dst++;
143.42700 ++			}
143.42701 ++			printf("\n");
143.42702 ++		}
143.42703 + 	}
143.42704 + }
143.42705 + 
143.42706 +@@ -1685,6 +1836,8 @@ static void display_flush_cursor(struct display *display)
143.42707 + 	if (cursor == None)
143.42708 + 		cursor = display->invisible_cursor;
143.42709 + 	if (cursor != display->cursor) {
143.42710 ++		DBG(CURSOR, ("%s setting cursor shape %lx\n",
143.42711 ++		    DisplayString(display->dpy), (long)cursor));
143.42712 + 		XDefineCursor(display->dpy, display->root, cursor);
143.42713 + 		display->cursor = cursor;
143.42714 + 	}
143.42715 +@@ -1762,6 +1915,8 @@ static void get_src(struct clone *c, const XRectangle *clip)
143.42716 + 	c->image.obdata = (char *)&c->src.shm;
143.42717 + 
143.42718 + 	if (c->src.use_render) {
143.42719 ++		DBG(DRAW, ("%s-%s get_src via XRender\n",
143.42720 ++			   DisplayString(c->dst.dpy), c->dst.name));
143.42721 + 		XRenderComposite(c->src.dpy, PictOpSrc,
143.42722 + 				 c->src.win_picture, 0, c->src.pix_picture,
143.42723 + 				 clip->x, clip->y,
143.42724 +@@ -1782,16 +1937,22 @@ static void get_src(struct clone *c, const XRectangle *clip)
143.42725 + 				     &c->image, 0, 0);
143.42726 + 		}
143.42727 + 	} else if (c->src.pixmap) {
143.42728 ++		DBG(DRAW, ("%s-%s get_src XCopyArea (SHM/DRI3)\n",
143.42729 ++			   DisplayString(c->dst.dpy), c->dst.name));
143.42730 + 		XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
143.42731 + 			  clip->x, clip->y,
143.42732 + 			  clip->width, clip->height,
143.42733 + 			  0, 0);
143.42734 + 		XSync(c->src.dpy, False);
143.42735 + 	} else if (c->src.use_shm) {
143.42736 ++		DBG(DRAW, ("%s-%s get_src XShmGetImage\n",
143.42737 ++			   DisplayString(c->dst.dpy), c->dst.name));
143.42738 + 		ximage_prepare(&c->image, clip->width, clip->height);
143.42739 + 		XShmGetImage(c->src.dpy, c->src.window, &c->image,
143.42740 + 			     clip->x, clip->y, AllPlanes);
143.42741 + 	} else {
143.42742 ++		DBG(DRAW, ("%s-%s get_src XGetSubImage (slow)\n",
143.42743 ++			   DisplayString(c->dst.dpy), c->dst.name));
143.42744 + 		ximage_prepare(&c->image, c->width, c->height);
143.42745 + 		XGetSubImage(c->src.dpy, c->src.window,
143.42746 + 			     clip->x, clip->y, clip->width, clip->height,
143.42747 +@@ -1838,7 +1999,7 @@ static void put_dst(struct clone *c, const XRectangle *clip)
143.42748 + 				 clip->width, clip->height);
143.42749 + 		c->dst.display->send |= c->dst.use_shm;
143.42750 + 	} else if (c->dst.pixmap) {
143.42751 +-		DBG(DRAW, ("%s-%s using SHM pixmap\n",
143.42752 ++		DBG(DRAW, ("%s-%s using SHM or DRI3 pixmap\n",
143.42753 + 		     DisplayString(c->dst.dpy), c->dst.name));
143.42754 + 		c->dst.serial = NextRequest(c->dst.dpy);
143.42755 + 		XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc,
143.42756 +@@ -1870,6 +2031,9 @@ static int clone_paint(struct clone *c)
143.42757 + {
143.42758 + 	XRectangle clip;
143.42759 + 
143.42760 ++	if (c->width == 0 || c->height == 0)
143.42761 ++		return 0;
143.42762 ++
143.42763 + 	DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d,  %d)]\n",
143.42764 + 	     DisplayString(c->dst.dpy), c->dst.name,
143.42765 + 	     c->damaged.x1, c->damaged.y1,
143.42766 +@@ -1944,6 +2108,10 @@ static int clone_paint(struct clone *c)
143.42767 + 		clip.height = c->damaged.y2 - c->damaged.y1;
143.42768 + 		get_src(c, &clip);
143.42769 + 
143.42770 ++		DBG(DRAW, ("%s-%s target offset %dx%d\n",
143.42771 ++			   DisplayString(c->dst.dpy), c->dst.name,
143.42772 ++			   c->dst.x - c->src.x, c->dst.y - c->src.y));
143.42773 ++
143.42774 + 		clip.x += c->dst.x - c->src.x;
143.42775 + 		clip.y += c->dst.y - c->src.y;
143.42776 + 		put_dst(c, &clip);
143.42777 +@@ -1969,8 +2137,9 @@ static void clone_damage(struct clone *c, const XRectangle *rec)
143.42778 + 	if ((v = (int)rec->y + rec->height) > c->damaged.y2)
143.42779 + 		c->damaged.y2 = v;
143.42780 + 
143.42781 +-	DBG(DAMAGE, ("%s-%s damaged: (%d, %d), (%d, %d)\n",
143.42782 ++	DBG(DAMAGE, ("%s-%s damaged: +(%d,%d)x(%d, %d) -> (%d, %d), (%d, %d)\n",
143.42783 + 	     DisplayString(c->dst.display->dpy), c->dst.name,
143.42784 ++	     rec->x, rec->y, rec->width, rec->height,
143.42785 + 	     c->damaged.x1, c->damaged.y1,
143.42786 + 	     c->damaged.x2, c->damaged.y2));
143.42787 + }
143.42788 +@@ -2252,6 +2421,8 @@ static int clone_init_depth(struct clone *clone)
143.42789 + 	if (ret)
143.42790 + 		return ret;
143.42791 + 
143.42792 ++	clone->depth = depth;
143.42793 ++
143.42794 + 	DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n",
143.42795 + 	     DisplayString(clone->dst.dpy), clone->dst.name,
143.42796 + 	     clone->depth,
143.42797 +@@ -2312,6 +2483,8 @@ static int add_display(struct context *ctx, Display *dpy)
143.42798 + 	display->depth = DefaultDepth(dpy, DefaultScreen(dpy));
143.42799 + 	display->visual = DefaultVisual(dpy, DefaultScreen(dpy));
143.42800 + 
143.42801 ++	XSelectInput(dpy, display->root, ExposureMask);
143.42802 ++
143.42803 + 	display->has_shm = can_use_shm(dpy, display->root,
143.42804 + 				       &display->shm_event,
143.42805 + 				       &display->shm_opcode,
143.42806 +@@ -2323,6 +2496,8 @@ static int add_display(struct context *ctx, Display *dpy)
143.42807 + 	     display->shm_opcode,
143.42808 + 	     display->has_shm_pixmap));
143.42809 + 
143.42810 ++	screensaver_save(display);
143.42811 ++
143.42812 + 	display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error);
143.42813 + 	DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n",
143.42814 + 	     DisplayString(dpy),
143.42815 +@@ -2592,6 +2767,11 @@ static int last_display_add_clones__randr(struct context *ctx)
143.42816 + 			return ret;
143.42817 + 		}
143.42818 + 
143.42819 ++		clone->dst.x = 0;
143.42820 ++		clone->dst.y = 0;
143.42821 ++		clone->dst.width = display->width;
143.42822 ++		clone->dst.height = display->height;
143.42823 ++
143.42824 + 		ret = clone_update_modes__randr(clone);
143.42825 + 		if (ret) {
143.42826 + 			fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
143.42827 +@@ -2668,8 +2848,8 @@ static int last_display_add_clones__xinerama(struct context *ctx)
143.42828 + 		}
143.42829 + 
143.42830 + 		/* Replace the modes on the local VIRTUAL output with the remote Screen */
143.42831 +-		clone->width = xi[n].width;
143.42832 +-		clone->height = xi[n].height;
143.42833 ++		clone->dst.width = xi[n].width;
143.42834 ++		clone->dst.height = xi[n].height;
143.42835 + 		clone->dst.x = xi[n].x_org;
143.42836 + 		clone->dst.y = xi[n].y_org;
143.42837 + 		clone->dst.rr_crtc = -1;
143.42838 +@@ -2698,64 +2878,67 @@ static int last_display_add_clones__display(struct context *ctx)
143.42839 + 	Display *dpy = display->dpy;
143.42840 + 	struct clone *clone;
143.42841 + 	Screen *scr;
143.42842 ++	int count, s;
143.42843 + 	char buf[80];
143.42844 + 	int ret;
143.42845 + 	RROutput id;
143.42846 + 
143.42847 ++	count = ScreenCount(dpy);
143.42848 ++	DBG(X11, ("%s(%s) - %d screens\n", __func__, DisplayString(dpy), count));
143.42849 ++	for (s = 0; s < count; s++) {
143.42850 ++		clone = add_clone(ctx);
143.42851 ++		if (clone == NULL)
143.42852 ++			return -ENOMEM;
143.42853 + 
143.42854 +-	DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy)));
143.42855 +-	clone = add_clone(ctx);
143.42856 +-	if (clone == NULL)
143.42857 +-		return -ENOMEM;
143.42858 ++		clone->depth = 24;
143.42859 ++		clone->next = display->clone;
143.42860 ++		display->clone = clone;
143.42861 + 
143.42862 +-	clone->depth = 24;
143.42863 +-	clone->next = display->clone;
143.42864 +-	display->clone = clone;
143.42865 ++		id = claim_virtual(ctx->display, buf, ctx->nclone);
143.42866 ++		if (id == 0) {
143.42867 ++			fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
143.42868 ++				buf, DisplayString(dpy));
143.42869 ++		}
143.42870 ++		ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
143.42871 ++		if (ret) {
143.42872 ++			fprintf(stderr, "Failed to add display \"%s\"\n",
143.42873 ++				DisplayString(ctx->display->dpy));
143.42874 ++			return ret;
143.42875 ++		}
143.42876 + 
143.42877 +-	id = claim_virtual(ctx->display, buf, ctx->nclone);
143.42878 +-	if (id == 0) {
143.42879 +-		fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
143.42880 +-			buf, DisplayString(dpy));
143.42881 +-	}
143.42882 +-	ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
143.42883 +-	if (ret) {
143.42884 +-		fprintf(stderr, "Failed to add display \"%s\"\n",
143.42885 +-			DisplayString(ctx->display->dpy));
143.42886 +-		return ret;
143.42887 +-	}
143.42888 ++		sprintf(buf, "SCREEN%d", s);
143.42889 ++		ret = clone_output_init(clone, &clone->dst, display, buf, 0);
143.42890 ++		if (ret) {
143.42891 ++			fprintf(stderr, "Failed to add display \"%s\"\n",
143.42892 ++				DisplayString(dpy));
143.42893 ++			return ret;
143.42894 ++		}
143.42895 + 
143.42896 +-	sprintf(buf, "WHOLE");
143.42897 +-	ret = clone_output_init(clone, &clone->dst, display, buf, 0);
143.42898 +-	if (ret) {
143.42899 +-		fprintf(stderr, "Failed to add display \"%s\"\n",
143.42900 +-			DisplayString(dpy));
143.42901 +-		return ret;
143.42902 +-	}
143.42903 ++		ret = clone_init_depth(clone);
143.42904 ++		if (ret) {
143.42905 ++			fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
143.42906 ++				DisplayString(dpy));
143.42907 ++			return ret;
143.42908 ++		}
143.42909 + 
143.42910 +-	ret = clone_init_depth(clone);
143.42911 +-	if (ret) {
143.42912 +-		fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
143.42913 +-			DisplayString(dpy));
143.42914 +-		return ret;
143.42915 +-	}
143.42916 ++		/* Replace the modes on the local VIRTUAL output with the remote Screen */
143.42917 ++		scr = ScreenOfDisplay(dpy, s);
143.42918 ++		clone->dst.width = scr->width;
143.42919 ++		clone->dst.height = scr->height;
143.42920 ++		clone->dst.x = 0;
143.42921 ++		clone->dst.y = 0;
143.42922 ++		clone->dst.rr_crtc = -1;
143.42923 ++		ret = clone_update_modes__fixed(clone);
143.42924 ++		if (ret) {
143.42925 ++			fprintf(stderr, "Failed to clone display \"%s\"\n",
143.42926 ++				DisplayString(dpy));
143.42927 ++			return ret;
143.42928 ++		}
143.42929 + 
143.42930 +-	/* Replace the modes on the local VIRTUAL output with the remote Screen */
143.42931 +-	scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
143.42932 +-	clone->width = scr->width;
143.42933 +-	clone->height = scr->height;
143.42934 +-	clone->dst.x = 0;
143.42935 +-	clone->dst.y = 0;
143.42936 +-	clone->dst.rr_crtc = -1;
143.42937 +-	ret = clone_update_modes__fixed(clone);
143.42938 +-	if (ret) {
143.42939 +-		fprintf(stderr, "Failed to clone display \"%s\"\n",
143.42940 +-			DisplayString(dpy));
143.42941 +-		return ret;
143.42942 ++		clone->active = ctx->active;
143.42943 ++		ctx->active = clone;
143.42944 + 	}
143.42945 + 
143.42946 +-	clone->active = ctx->active;
143.42947 +-	ctx->active = clone;
143.42948 +-
143.42949 + 	return 0;
143.42950 + }
143.42951 + 
143.42952 +@@ -3168,6 +3351,33 @@ static void context_cleanup(struct context *ctx)
143.42953 + 	XCloseDisplay(dpy);
143.42954 + }
143.42955 + 
143.42956 ++static void update_cursor_image(struct context *ctx)
143.42957 ++{
143.42958 ++	XFixesCursorImage *cur;
143.42959 ++	int i;
143.42960 ++
143.42961 ++	DBG(CURSOR, ("%s cursor changed\n",
143.42962 ++		     DisplayString(ctx->display->dpy)));
143.42963 ++
143.42964 ++	cur = XFixesGetCursorImage(ctx->display->dpy);
143.42965 ++	if (cur == NULL)
143.42966 ++		return;
143.42967 ++
143.42968 ++	display_load_visible_cursor(&ctx->display[0], cur);
143.42969 ++	for (i = 1; i < ctx->ndisplay; i++) {
143.42970 ++		struct display *display = &ctx->display[i];
143.42971 ++
143.42972 ++		DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
143.42973 ++		display->cursor_moved++;
143.42974 ++		if (display->cursor != display->invisible_cursor) {
143.42975 ++			display->cursor_visible++;
143.42976 ++			context_enable_timer(display->ctx);
143.42977 ++		}
143.42978 ++	}
143.42979 ++
143.42980 ++	XFree(cur);
143.42981 ++}
143.42982 ++
143.42983 + static int done;
143.42984 + 
143.42985 + static void signal_handler(int sig)
143.42986 +@@ -3182,6 +3392,7 @@ int main(int argc, char **argv)
143.42987 + 	uint64_t count;
143.42988 + 	int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1;
143.42989 + 	int i, ret, open, fail;
143.42990 ++	int idle;
143.42991 + 
143.42992 + 	signal(SIGPIPE, SIG_IGN);
143.42993 + 
143.42994 +@@ -3228,6 +3439,7 @@ int main(int argc, char **argv)
143.42995 + 		return -ret;
143.42996 + 
143.42997 + 	XSetErrorHandler(_check_error_handler);
143.42998 ++	XSetIOErrorHandler(_io_error_handler);
143.42999 + 
143.43000 + 	ret = add_fd(&ctx, display_open(&ctx, src_name));
143.43001 + 	if (ret) {
143.43002 +@@ -3237,6 +3449,13 @@ int main(int argc, char **argv)
143.43003 + 		goto out;
143.43004 + 	}
143.43005 + 
143.43006 ++	ret = check_virtual(ctx.display);
143.43007 ++	if (ret) {
143.43008 ++		fprintf(stderr, "No VIRTUAL outputs on \"%s\".\n",
143.43009 ++			DisplayString(ctx.display->dpy));
143.43010 ++		goto out;
143.43011 ++	}
143.43012 ++
143.43013 + 	if (singleton) {
143.43014 + 		XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask);
143.43015 + 		if (first_display_has_singleton(&ctx)) {
143.43016 +@@ -3291,6 +3510,11 @@ int main(int argc, char **argv)
143.43017 + 	if (ret)
143.43018 + 		goto out;
143.43019 + 
143.43020 ++	if (ctx.display->saver_active)
143.43021 ++		XScreenSaverSelectInput(ctx.display->dpy,
143.43022 ++					ctx.display->root,
143.43023 ++					ScreenSaverNotifyMask);
143.43024 ++
143.43025 + 	if ((ctx.display->rr_event | ctx.display->rr_error) == 0) {
143.43026 + 		fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy));
143.43027 + 		ret = EINVAL;
143.43028 +@@ -3348,25 +3572,60 @@ int main(int argc, char **argv)
143.43029 + 	signal(SIGTERM, signal_handler);
143.43030 + 
143.43031 + 	ctx.command_continuation = 0;
143.43032 ++	update_cursor_image(&ctx);
143.43033 ++
143.43034 ++	idle = 0;
143.43035 + 	while (!done) {
143.43036 + 		XEvent e;
143.43037 + 		int reconfigure = 0;
143.43038 + 		int rr_update = 0;
143.43039 + 
143.43040 +-		DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
143.43041 +-		ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
143.43042 +-		if (ret <= 0)
143.43043 +-			break;
143.43044 ++		if (idle) {
143.43045 ++			DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
143.43046 ++			ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
143.43047 ++			if (ret <= 0)
143.43048 ++				break;
143.43049 ++
143.43050 ++			DBG(POLL, ("poll reports %d fd awake\n", ret));
143.43051 ++		}
143.43052 ++		idle = 1;
143.43053 + 
143.43054 + 		/* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */
143.43055 + 
143.43056 +-		DBG(POLL, ("poll reports %d fd awake\n", ret));
143.43057 + 		if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) {
143.43058 + 			DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy)));
143.43059 ++			ctx.pfd[1].revents = 0;
143.43060 ++			idle = 0;
143.43061 ++
143.43062 + 			do {
143.43063 + 				XNextEvent(ctx.display->dpy, &e);
143.43064 + 
143.43065 +-				if (e.type == ctx.display->damage_event + XDamageNotify ) {
143.43066 ++				DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[0].dpy), e.type));
143.43067 ++
143.43068 ++				if (e.type == ctx.display->saver_event + ScreenSaverNotify) {
143.43069 ++					const XScreenSaverNotifyEvent *se = (const XScreenSaverNotifyEvent *)&e;
143.43070 ++					DBG(SCREEN,
143.43071 ++					    ("%s screen saver: state=%d, kind=%d, forced=%d\n",
143.43072 ++					     DisplayString(ctx.display->dpy),
143.43073 ++					     se->state, se->kind, se->forced));
143.43074 ++					for (i = 1; i < ctx.ndisplay; i++) {
143.43075 ++						struct display *display = &ctx.display[i];
143.43076 ++
143.43077 ++						if (!display->active)
143.43078 ++							continue;
143.43079 ++
143.43080 ++						DBG(SCREEN,
143.43081 ++						    ("%s %s screen saver\n",
143.43082 ++						     DisplayString(display->dpy),
143.43083 ++						     se->state == ScreenSaverOn ? "activating" : "resetting\n"));
143.43084 ++
143.43085 ++						if (se->state == ScreenSaverOn)
143.43086 ++							XActivateScreenSaver(display->dpy);
143.43087 ++						else
143.43088 ++							XResetScreenSaver(display->dpy);
143.43089 ++						XFlush(display->dpy);
143.43090 ++					}
143.43091 ++				} else if (e.type == ctx.display->damage_event + XDamageNotify) {
143.43092 + 					const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e;
143.43093 + 					struct clone *clone;
143.43094 + 
143.43095 +@@ -3380,19 +3639,7 @@ int main(int argc, char **argv)
143.43096 + 					if (ctx.active)
143.43097 + 						context_enable_timer(&ctx);
143.43098 + 				} else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) {
143.43099 +-					XFixesCursorImage *cur;
143.43100 +-
143.43101 +-					DBG(CURSOR, ("%s cursor changed\n",
143.43102 +-					     DisplayString(ctx.display->dpy)));
143.43103 +-
143.43104 +-					cur = XFixesGetCursorImage(ctx.display->dpy);
143.43105 +-					if (cur == NULL)
143.43106 +-						continue;
143.43107 +-
143.43108 +-					for (i = 1; i < ctx.ndisplay; i++)
143.43109 +-						display_load_visible_cursor(&ctx.display[i], cur);
143.43110 +-
143.43111 +-					XFree(cur);
143.43112 ++					update_cursor_image(&ctx);
143.43113 + 				} else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) {
143.43114 + 					DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n",
143.43115 + 					     DisplayString(ctx.display->dpy), reconfigure));
143.43116 +@@ -3426,13 +3673,41 @@ int main(int argc, char **argv)
143.43117 + 			if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy))
143.43118 + 				continue;
143.43119 + 
143.43120 ++			ctx.pfd[i+2].revents = 0;
143.43121 ++			idle = 0;
143.43122 ++
143.43123 + 			DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy)));
143.43124 + 			do {
143.43125 + 				XNextEvent(ctx.display[i].dpy, &e);
143.43126 + 
143.43127 + 				DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type));
143.43128 +-				if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
143.43129 +-					XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
143.43130 ++				if (e.type == Expose) {
143.43131 ++					const XExposeEvent *xe = (XExposeEvent *)&e;
143.43132 ++					struct clone *clone;
143.43133 ++					int damaged = 0;
143.43134 ++
143.43135 ++					DBG(DAMAGE, ("%s exposed: (%d, %d)x(%d, %d)\n",
143.43136 ++					     DisplayString(ctx.display[i].dpy),
143.43137 ++					     xe->x, xe->y, xe->width, xe->height));
143.43138 ++
143.43139 ++					for (clone = ctx.active; clone; clone = clone->active) {
143.43140 ++						XRectangle r;
143.43141 ++
143.43142 ++						if (clone->dst.display != &ctx.display[i])
143.43143 ++							continue;
143.43144 ++
143.43145 ++						r.x = clone->src.x + xe->x;
143.43146 ++						r.y = clone->src.y + xe->y;
143.43147 ++						r.width  = xe->width;
143.43148 ++						r.height = xe->height;
143.43149 ++						clone_damage(clone, &r);
143.43150 ++						damaged++;
143.43151 ++					}
143.43152 ++
143.43153 ++					if (damaged)
143.43154 ++						context_enable_timer(&ctx);
143.43155 ++				} else if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
143.43156 ++					const XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
143.43157 + 
143.43158 + 					DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype));
143.43159 + 					if (re->subtype == RRNotify_OutputChange) {
143.43160 +@@ -3480,6 +3755,7 @@ int main(int argc, char **argv)
143.43161 + 
143.43162 + 			DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0));
143.43163 + 			ctx.timer_active = ret != 0;
143.43164 ++			idle = 0;
143.43165 + 		}
143.43166 + 	}
143.43167 + 
   144.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   144.2 +++ b/xorg-xf86-video-intel/stuff/patches/series	Tue Aug 07 00:30:45 2018 +0300
   144.3 @@ -0,0 +1,3 @@
   144.4 +# from Alpine Linux: patch git20170325
   144.5 +# https://git.alpinelinux.org/cgit/aports/tree/main/xf86-video-intel
   144.6 +git.patch
   145.1 --- a/xorg-xf86-video-vesa/receipt	Mon Jul 30 23:44:42 2018 +0300
   145.2 +++ b/xorg-xf86-video-vesa/receipt	Tue Aug 07 00:30:45 2018 +0300
   145.3 @@ -1,7 +1,7 @@
   145.4  # SliTaz package receipt v2.
   145.5  
   145.6  PACKAGE="xorg-xf86-video-vesa"
   145.7 -VERSION="2.3.4"
   145.8 +VERSION="2.4.0"
   145.9  CATEGORY="x-window"
  145.10  SHORT_DESC="Xorg driver for generic VESA video cards"
  145.11  MAINTAINER="pankso@slitaz.org"
   146.1 --- a/xorg-xkbcomp/receipt	Mon Jul 30 23:44:42 2018 +0300
   146.2 +++ b/xorg-xkbcomp/receipt	Tue Aug 07 00:30:45 2018 +0300
   146.3 @@ -1,13 +1,13 @@
   146.4  # SliTaz package receipt v2.
   146.5  
   146.6  PACKAGE="xorg-xkbcomp"
   146.7 -VERSION="1.4.0"
   146.8 +VERSION="1.4.2"
   146.9  CATEGORY="x-window"
  146.10  SHORT_DESC="Compile XKB keyboard description"
  146.11  MAINTAINER="pankso@slitaz.org"
  146.12  LICENSE="MIT"
  146.13  WEB_SITE="https://www.x.org/wiki/"
  146.14 -LFS="http://www.linuxfromscratch.org/blfs/view/stable/x/x7app.html"
  146.15 +LFS="http://www.linuxfromscratch.org/blfs/view/svn/x/x7app.html"
  146.16  REPOLOGY="xkbcomp"
  146.17  
  146.18  TARBALL="xkbcomp-$VERSION.tar.bz2"
   147.1 --- a/xorg-xkeyboard-config/receipt	Mon Jul 30 23:44:42 2018 +0300
   147.2 +++ b/xorg-xkeyboard-config/receipt	Tue Aug 07 00:30:45 2018 +0300
   147.3 @@ -1,7 +1,7 @@
   147.4  # SliTaz package receipt v2.
   147.5  
   147.6  PACKAGE="xorg-xkeyboard-config"
   147.7 -VERSION="2.21"
   147.8 +VERSION="2.24"
   147.9  CATEGORY="x-window"
  147.10  SHORT_DESC="Keyboard configuration database for the X Window System"
  147.11  MAINTAINER="pankso@slitaz.org"
   148.1 --- a/xorg-xprop/receipt	Mon Jul 30 23:44:42 2018 +0300
   148.2 +++ b/xorg-xprop/receipt	Tue Aug 07 00:30:45 2018 +0300
   148.3 @@ -1,7 +1,7 @@
   148.4  # SliTaz package receipt v2.
   148.5  
   148.6  PACKAGE="xorg-xprop"
   148.7 -VERSION="1.2.2"
   148.8 +VERSION="1.2.3"
   148.9  CATEGORY="x-window"
  148.10  SHORT_DESC="Property displayer for X"
  148.11  MAINTAINER="pankso@slitaz.org"
  148.12 @@ -17,7 +17,6 @@
  148.13  
  148.14  compile_rules() {
  148.15  	./configure $CONFIGURE_ARGS &&
  148.16 -	fix libtool &&
  148.17  	make &&
  148.18  	make install
  148.19  }
   149.1 --- a/xorg-xset/receipt	Mon Jul 30 23:44:42 2018 +0300
   149.2 +++ b/xorg-xset/receipt	Tue Aug 07 00:30:45 2018 +0300
   149.3 @@ -1,7 +1,7 @@
   149.4  # SliTaz package receipt v2.
   149.5  
   149.6  PACKAGE="xorg-xset"
   149.7 -VERSION="1.2.3"
   149.8 +VERSION="1.2.4"
   149.9  CATEGORY="x-window"
  149.10  SHORT_DESC="User preference utility for X"
  149.11  MAINTAINER="paul@slitaz.org"
   150.1 --- a/xorg-xwininfo/receipt	Mon Jul 30 23:44:42 2018 +0300
   150.2 +++ b/xorg-xwininfo/receipt	Tue Aug 07 00:30:45 2018 +0300
   150.3 @@ -1,7 +1,7 @@
   150.4  # SliTaz package receipt v2.
   150.5  
   150.6  PACKAGE="xorg-xwininfo"
   150.7 -VERSION="1.1.3"
   150.8 +VERSION="1.1.4"
   150.9  CATEGORY="x-window"
  150.10  SHORT_DESC="Window information utility for X"
  150.11  MAINTAINER="jozee@slitaz.org"
   151.1 --- a/yad/receipt	Mon Jul 30 23:44:42 2018 +0300
   151.2 +++ b/yad/receipt	Tue Aug 07 00:30:45 2018 +0300
   151.3 @@ -1,7 +1,7 @@
   151.4  # SliTaz package receipt v2.
   151.5  
   151.6  PACKAGE="yad"
   151.7 -VERSION="0.39.0"
   151.8 +VERSION="0.40.0"
   151.9  CATEGORY="utilities"
  151.10  SHORT_DESC="Yet Another Dialog"
  151.11  MAINTAINER="devl547@gmail.com"
  151.12 @@ -35,21 +35,20 @@
  151.13  		yad)
  151.14  			copy @std
  151.15  			CAT="utilities|GTK+2"
  151.16 -			DEPENDS="atk cairo fontconfig freetype gdk-pixbuf glib gtk+ pango"
  151.17 +			DEPENDS="cairo gdk-pixbuf glib gtk+ pango"
  151.18  			TAGS="gtk2"
  151.19  			;;
  151.20  		yad-html)
  151.21  			copy @std
  151.22  			CAT="utilities|GTK+2, with HTML widget"
  151.23 -			DEPENDS="atk cairo fontconfig freetype gdk-pixbuf glib gtk+ \
  151.24 -			libsoup pango webkitgtk"
  151.25 +			DEPENDS="cairo gdk-pixbuf glib gtk+ libsoup pango webkitgtk"
  151.26  			TAGS="gtk2"
  151.27  			PROVIDE="yad:webkitgtk"
  151.28  			;;
  151.29  		yad-gtk3)
  151.30  			copy @std
  151.31  			CAT="utilities|GTK+3"
  151.32 -			DEPENDS="atk cairo gdk-pixbuf glib gtk+3 pango"
  151.33 +			DEPENDS="cairo gdk-pixbuf glib gtk+3 pango"
  151.34  			TAGS="gtk3"
  151.35  			PROVIDE="yad:gtk+3"
  151.36  			;;