summaryrefslogtreecommitdiff
path: root/app-emulation/wine
diff options
context:
space:
mode:
Diffstat (limited to 'app-emulation/wine')
-rw-r--r--app-emulation/wine/Manifest7
-rw-r--r--app-emulation/wine/files/pr66838.c36
-rw-r--r--app-emulation/wine/files/wine-1.4_rc2-multilib-portage.patch40
-rw-r--r--app-emulation/wine/files/wine-1.5.17-osmesa-check.patch38
-rw-r--r--app-emulation/wine/files/wine-1.5.26-winegcc.patch59
-rw-r--r--app-emulation/wine/files/wine-1.6-memset-O3.patch21
-rw-r--r--app-emulation/wine/files/wine-1.7.0-freetype-header-location.patch351
-rw-r--r--app-emulation/wine/files/wine-1.7.12-osmesa-check.patch38
-rw-r--r--app-emulation/wine/files/wine-1.7.19-makefile-race-cond.patch15
-rw-r--r--app-emulation/wine/files/wine-1.7.2-osmesa-check.patch38
-rw-r--r--app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-post.patch58
-rw-r--r--app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-pre.patch48
-rw-r--r--app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-post.patch38
-rw-r--r--app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-pre.patch40
-rw-r--r--app-emulation/wine/files/wine-1.7.45-libunwind-osx-only.patch64
-rw-r--r--app-emulation/wine/files/wine-1.7.47-critical-security-cookie-fix.patch82
-rw-r--r--app-emulation/wine/files/wine-1.7.55-d3d9.patch5366
-rw-r--r--app-emulation/wine/files/wine-gcc-4.9-null-pointer.patch35
-rw-r--r--app-emulation/wine/wine-1.7.55.ebuild446
19 files changed, 6820 insertions, 0 deletions
diff --git a/app-emulation/wine/Manifest b/app-emulation/wine/Manifest
new file mode 100644
index 00000000..d2ad20d1
--- /dev/null
+++ b/app-emulation/wine/Manifest
@@ -0,0 +1,7 @@
+DIST wine-1.7.34-gstreamer-v5.patch.bz2 5703 SHA256 c3bb6f669f46d9f2d7ba494a2264cee457349f559d4b0758db80e39eb22f2aee SHA512 e780394e8739a58593d264322c462bfe9040c1cabce93b84d24f09040026368efb4ac34a6a302beb6048d14b4ac835b87a0c515b52c1a0c143aa4e15691eb01b WHIRLPOOL 1befbb0fbd026d6e833c5d72341064dd6e12157e1b7df58e349b9985648bfbc63f70e9cab45b61155515ac65057968e30ba313e71e183b8027153c9392d89192
+DIST wine-1.7.55.tar.bz2 22814631 SHA256 a148f6c9cb45a75ef1a15e60a7db9c22fce985e0e58fe1350e7931dfe5d36119 SHA512 f47025017836ce1bbf2ed69c7d7421bd8a2f33ff94ced4a5caf92f4fabdf336119c80a28aeb8ba1ebe0239871a6ac62d8af8435d220c317624c17aabc2100dd7 WHIRLPOOL c5575d2ef687caccbdb5cc09a0c6a4ba9f65ec9674cbe3f23ecfced62710dcb0019a11ff66f2ec4c2eafdb30d9891abad158ac4f865cc580a2878067de7304d7
+DIST wine-gentoo-2015.03.07.tar.bz2 85419 SHA256 f13f93dc49bbc33a294c4d511b6e01aec2d38bff77a1e44d07668291add1ab04 SHA512 bae1d2d5575d340d01f44008104f0e5ec0c4a4982995dec37d501594cd21d07a2b4ad4465c4273646d5bf6521996b4b82471097864be75342abe3e7d478a56bd WHIRLPOOL 0f254dd692e87a1f71dd19f6c1c8c59b8a91b994e75912a2e6e3ba5e875b85119fe497a331a95c2ce33bbf5f064143d23ee00275da92c494227de0807c9abb06
+DIST wine-mono-4.5.6.msi 53705216 SHA256 ac681f737f83742d786706529eb85f4bc8d6bdddd8dcdfa9e2e336b71973bc25 SHA512 4d8df04c1d0da09d1abe423dd271e5dd14a193d607fb54e214d2e340827f7c33829342d1580b6907d7cf466e70993d743c6e1ca9a026d4b6225dd7c1fc8b1386 WHIRLPOOL 9a68e502da0be6768e92d88f2ccace607300f3a331e0f9e1b6d60e9c6c2d4eb635b902f03e13aad73461dd5f0c2691c7b41958356ebb7f445e8def4282c675d3
+DIST wine-staging-1.7.55.tar.gz 9604441 SHA256 856b630fe95250e3d2dfc80588529e42e92e37f2e974ce8d3da37b39bf5cc3c3 SHA512 a6fbfa01b6d6efc75f79235aea86091c32ddf91ca300c73325c8347949c627f53ceb0fe085d6c212602797b0496d36c0a79f08eae4644a17774e95906332032d WHIRLPOOL ad232568c9df5d436a79a3557c82e231eed121356d8db1f5a3c0e7249b6c2760d87bb433ff30d6db53ce190b2d49401aa387b06f0c3f74925aefea7b1d73f112
+DIST wine_gecko-2.40-x86.msi 31741440 SHA256 1a29d17435a52b7663cea6f30a0771f74097962b07031947719bb7b46057d302 SHA512 2f203852afede3f6b0899a54ad6eaa27c972a84df51de1632cb21af0c322e369a13150a5f19f68d7c4fcb0610b65e9244658e622c7e6b14c93ae6b7372bb184f WHIRLPOOL 461358782c8aa21be5bf934bdb7b7397717add883036a773dad20d2ba5169a5229c211781c60fb4df46057b476765c6541340f5764a5a7362daf357ab60877b6
+DIST wine_gecko-2.40-x86_64.msi 33056768 SHA256 c3e28988e7d92221596fc4c569d10eb4dd2ca64b9f4970bf77e791f5dd8c9230 SHA512 af171193f221f2cd51f6dc3382a9b1c658ef2553213be32f201c05f7122eb6883838be97c3ec66177b1e3922df64c409745c3223acb01910680a5476c3f01478 WHIRLPOOL d11234b593f4190ae8fa99bec8363c0047f6de08b186752b9f49764519ee9f4aafd017a16c0496581a0f4791e1109273846cec0314d9e320423d51723cd2083a
diff --git a/app-emulation/wine/files/pr66838.c b/app-emulation/wine/files/pr66838.c
new file mode 100644
index 00000000..cd616859
--- /dev/null
+++ b/app-emulation/wine/files/pr66838.c
@@ -0,0 +1,36 @@
+/* From gcc svn, /branches/gcc-5-branch/gcc/testsuite/gcc.target/i386/pr66838.c */
+/* Copyrighted and distributed under the same terms as gcc */
+
+void abort (void);
+
+char global;
+
+__attribute__((sysv_abi, noinline, noclone))
+void sysv_abi_func(char const *desc, void *local)
+{
+ register int esi asm ("esi");
+ register int edi asm ("edi");
+
+ if (local != &global)
+ abort ();
+
+ /* Clobber some of the extra SYSV ABI registers. */
+ asm volatile ("movl\t%2, %0\n\tmovl\t%2, %1"
+ : "=r" (esi), "=r" (edi)
+ : "i" (0xdeadbeef));
+}
+
+__attribute__((ms_abi, noinline, noclone))
+void ms_abi_func ()
+{
+ sysv_abi_func ("1st call", &global);
+ sysv_abi_func ("2nd call", &global);
+ sysv_abi_func ("3rd call", &global);
+}
+
+int
+main(void)
+{
+ ms_abi_func();
+ return 0;
+}
diff --git a/app-emulation/wine/files/wine-1.4_rc2-multilib-portage.patch b/app-emulation/wine/files/wine-1.4_rc2-multilib-portage.patch
new file mode 100644
index 00000000..be6ffc56
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.4_rc2-multilib-portage.patch
@@ -0,0 +1,40 @@
+https://bugs.gentoo.org/show_bug.cgi?id=395615
+
+Explicitly add the required -m32/m64 to *FLAGS; this overrides any
+arch-specific -m* flags that may have been appended by multilib-portage.
+
+Even though -m32/m64 is now added to *FLAGS, -m32/m64 still has to be
+explicitly added to CC and CXX due to wine's build system. For example,
+winegcc saves the build-time value of CC and uses it at runtime.
+
+--- a/configure.ac
++++ b/configure.ac
+@@ -133,12 +133,18 @@
+ then
+ CC="$CC -m64"
+ CXX="$CXX -m64"
++ CFLAGS="$CFLAGS -m64"
++ LDFLAGS="$LDFLAGS -m64"
++ CXXFLAGS="$CXXFLAGS -m64"
+ host_cpu="x86_64"
+ notice_platform="64-bit "
+ AC_SUBST(TARGETFLAGS,"-m64")
+ else
+ CC="$CC -m32"
+ CXX="$CXX -m32"
++ CFLAGS="$CFLAGS -m32"
++ LDFLAGS="$LDFLAGS -m32"
++ CXXFLAGS="$CXXFLAGS -m32"
+ host_cpu="i386"
+ notice_platform="32-bit "
+ AC_SUBST(TARGETFLAGS,"-m32")
+@@ -150,6 +156,9 @@
+ then
+ CC="$CC -m32"
+ CXX="$CXX -m32"
++ CFLAGS="$CFLAGS -m32"
++ LDFLAGS="$LDFLAGS -m32"
++ CXXFLAGS="$CXXFLAGS -m32"
+ AC_MSG_CHECKING([whether $CC works])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM()],AC_MSG_RESULT([yes]),
+ [AC_MSG_RESULT([no])
diff --git a/app-emulation/wine/files/wine-1.5.17-osmesa-check.patch b/app-emulation/wine/files/wine-1.5.17-osmesa-check.patch
new file mode 100644
index 00000000..82361927
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.5.17-osmesa-check.patch
@@ -0,0 +1,38 @@
+From 1ede664b18bd8a88359a3cebb291ad49833ee033 Mon Sep 17 00:00:00 2001
+From: Alexandre Rostovtsev <tetromino@gentoo.org>
+Date: Tue, 7 Aug 2012 01:29:01 -0400
+Subject: [PATCH] Do not check for libGL symbols when checking libOSMesa
+
+If mesa had been built with shared glapi, glAccum is not available in
+libOSMesa without explicitly linking to libGL. In addition, in
+mesa-8.0.x and earlier, libOSMesa needs to be explicitly linked to
+libglapi if mesa was built with shared glapi, see
+https://bugs.gentoo.org/show_bug.cgi?id=399813
+And in mesa-8.1.x, libOSMesa in addition needs libdl, libpthread, and
+libstdc++, see https://bugs.gentoo.org/show_bug.cgi?id=431832
+---
+ configure.ac | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index cc32c24..275b792 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1128,7 +1128,13 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c
+
+ if test "x$with_osmesa" != "xno"
+ then
+- WINE_CHECK_SONAME(OSMesa,glAccum,,,[$X_LIBS $X_PRE_LIBS $XLIB -lm $X_EXTRA_LIBS])
++ WINE_CHECK_SONAME(OSMesa,OSMesaCreateContext,,,[$X_LIBS $X_PRE_LIBS $XLIB -lm $X_EXTRA_LIBS])
++ if test "x$ac_cv_lib_soname_OSMesa" = "x"; then
++ osmesa_save_CC=$CC
++ CC=$CXX
++ WINE_CHECK_SONAME(OSMesa,OSMesaCreateContext,,,[-lglapi -lpthread -ldl $X_LIBS $X_PRE_LIBS $XLIB -lm $X_EXTRA_LIBS])
++ CC=$osmesa_save_CC
++ fi
+ WINE_NOTICE_WITH(osmesa,[test "x$ac_cv_lib_soname_OSMesa" = "x"],
+ [libOSMesa ${notice_platform}development files not found (or too old), OpenGL rendering in bitmaps won't be supported.])
+ fi
+--
+1.8.0
+
diff --git a/app-emulation/wine/files/wine-1.5.26-winegcc.patch b/app-emulation/wine/files/wine-1.5.26-winegcc.patch
new file mode 100644
index 00000000..2045e343
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.5.26-winegcc.patch
@@ -0,0 +1,59 @@
+http://bugs.gentoo.org/260726
+
+diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
+index 16b4165..5c77267 100644
+--- a/tools/winebuild/main.c
++++ b/tools/winebuild/main.c
+@@ -48,10 +48,13 @@ int link_ext_symbols = 0;
+ int force_pointer_size = 0;
+ int unwind_tables = 0;
+
++#undef FORCE_POINTER_SIZE
+ #ifdef __i386__
+ enum target_cpu target_cpu = CPU_x86;
++#define FORCE_POINTER_SIZE
+ #elif defined(__x86_64__)
+ enum target_cpu target_cpu = CPU_x86_64;
++#define FORCE_POINTER_SIZE
+ #elif defined(__powerpc__)
+ enum target_cpu target_cpu = CPU_POWERPC;
+ #elif defined(__arm__)
+@@ -611,6 +614,10 @@ int main(int argc, char **argv)
+ signal( SIGTERM, exit_on_signal );
+ signal( SIGINT, exit_on_signal );
+
++#ifdef FORCE_POINTER_SIZE
++ force_pointer_size = sizeof(size_t);
++#endif
++
+ output_file = stdout;
+ argv = parse_options( argc, argv, spec );
+
+diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c
+index 06aa200..c44d2e3 100644
+--- a/tools/winegcc/winegcc.c
++++ b/tools/winegcc/winegcc.c
+@@ -213,10 +213,13 @@ struct options
+ strarray* files;
+ };
+
++#undef FORCE_POINTER_SIZE
+ #ifdef __i386__
+ static const enum target_cpu build_cpu = CPU_x86;
++#define FORCE_POINTER_SIZE
+ #elif defined(__x86_64__)
+ static const enum target_cpu build_cpu = CPU_x86_64;
++#define FORCE_POINTER_SIZE
+ #elif defined(__powerpc__)
+ static const enum target_cpu build_cpu = CPU_POWERPC;
+ #elif defined(__arm__)
+@@ -1258,6 +1261,9 @@ int main(int argc, char **argv)
+ opts.linker_args = strarray_alloc();
+ opts.compiler_args = strarray_alloc();
+ opts.winebuild_args = strarray_alloc();
++#ifdef FORCE_POINTER_SIZE
++ opts.force_pointer_size = sizeof(size_t);
++#endif
+
+ /* determine the processor type */
+ if (strendswith(argv[0], "winecpp")) opts.processor = proc_cpp;
diff --git a/app-emulation/wine/files/wine-1.6-memset-O3.patch b/app-emulation/wine/files/wine-1.6-memset-O3.patch
new file mode 100644
index 00000000..75372f86
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.6-memset-O3.patch
@@ -0,0 +1,21 @@
+Avoid "undefined reference to `memset'" error when building with
+USE=custom-cflags and -O3 in CFLAGS with gcc-4.8.
+
+See:
+
+http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56888
+http://bugs.winehq.org/show_bug.cgi?id=33521
+https://bugs.gentoo.org/show_bug.cgi?id=480508
+
+diff --git a/configure.ac b/configure.ac
+index d8033cf..fe7cc7d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1767,6 +1767,7 @@ then
+
+ dnl Check for some compiler flags
+ WINE_TRY_CFLAGS([-fno-builtin],[AC_SUBST(BUILTINFLAG,"-fno-builtin")])
++ WINE_TRY_CFLAGS([-fno-tree-loop-distribute-patterns])
+ WINE_TRY_CFLAGS([-fno-strict-aliasing])
+ dnl clang needs to be told to fail on unknown options
+ saved_CFLAGS=$CFLAGS
diff --git a/app-emulation/wine/files/wine-1.7.0-freetype-header-location.patch b/app-emulation/wine/files/wine-1.7.0-freetype-header-location.patch
new file mode 100644
index 00000000..aba4b898
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.0-freetype-header-location.patch
@@ -0,0 +1,351 @@
+From 67f9b6e3c5d2397446d39ab454f691c1ee46d2c0 Mon Sep 17 00:00:00 2001
+From: Alexandre Julliard <julliard@winehq.org>
+Date: Sat, 30 Nov 2013 11:22:25 +0100
+Subject: [PATCH] configure: Update FreeType configure checks for the changed
+ headers location.
+
+---
+ configure | 78 +++++++++++++++------------------------------------
+ configure.ac | 40 +++++++-------------------
+ dlls/gdi32/freetype.c | 62 ++++++++++++++--------------------------
+ include/config.h.in | 33 ----------------------
+ 4 files changed, 54 insertions(+), 159 deletions(-)
+
+diff --git a/configure b/configure
+index 80348f3..9b2f2c2 100755
+--- a/configure
++++ b/configure
+@@ -11419,7 +11419,21 @@ test "$cross_compiling" = yes || FREETYPE_LIBS=${FREETYPE_LIBS:-`(freetype-confi
+ FREETYPE_LIBS=${FREETYPE_LIBS:-"-lfreetype"}
+ ac_save_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS"
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lfreetype" >&5
++for ac_header in ft2build.h
++do :
++ ac_fn_c_check_header_mongrel "$LINENO" "ft2build.h" "ac_cv_header_ft2build_h" "$ac_includes_default"
++if test "x$ac_cv_header_ft2build_h" = xyes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE_FT2BUILD_H 1
++_ACEOF
++
++fi
++
++done
++
++ if test "$ac_cv_header_ft2build_h" = "yes"
++ then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lfreetype" >&5
+ $as_echo_n "checking for -lfreetype... " >&6; }
+ if ${ac_cv_lib_soname_freetype+:} false; then :
+ $as_echo_n "(cached) " >&6
+@@ -11461,7 +11475,7 @@ fi
+ if test "x$ac_cv_lib_soname_freetype" = "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+ $as_echo "not found" >&6; }
+- ft_lib=no
++ FREETYPE_LIBS=""
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_freetype" >&5
+ $as_echo "$ac_cv_lib_soname_freetype" >&6; }
+@@ -11470,51 +11484,11 @@ cat >>confdefs.h <<_ACEOF
+ #define SONAME_LIBFREETYPE "$ac_cv_lib_soname_freetype"
+ _ACEOF
+
+- ft_lib=yes
+-fi
+- if test "$ft_lib" = "yes"
+- then
+- for ac_header in ft2build.h \
+- freetype/freetype.h \
+- freetype/ftglyph.h \
+- freetype/fttypes.h \
+- freetype/tttables.h \
+- freetype/ftsnames.h \
+- freetype/ttnameid.h \
+- freetype/ftoutln.h \
+- freetype/ftwinfnt.h \
+- freetype/ftmodapi.h \
+- freetype/ftlcdfil.h
+-do :
+- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_FT2BUILD_H
+-# include <ft2build.h>
+-#endif
+-"
+-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+- cat >>confdefs.h <<_ACEOF
+-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+-_ACEOF
+-
+-fi
+-
+-done
+-
+- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+-/* end confdefs.h. */
+-#include <ft2build.h>
+-#include <freetype/fttrigon.h>
+-_ACEOF
+-if ac_fn_c_try_cpp "$LINENO"; then :
+
+-$as_echo "#define HAVE_FREETYPE_FTTRIGON_H 1" >>confdefs.h
++$as_echo "#define HAVE_FREETYPE 1" >>confdefs.h
+
+- wine_cv_fttrigon=yes
+-else
+- wine_cv_fttrigon=no
+-fi
+-rm -f conftest.err conftest.i conftest.$ac_ext
+- ac_fn_c_check_type "$LINENO" "FT_TrueTypeEngineType" "ac_cv_type_FT_TrueTypeEngineType" "#include <freetype/ftmodapi.h>
++ ac_fn_c_check_type "$LINENO" "FT_TrueTypeEngineType" "ac_cv_type_FT_TrueTypeEngineType" "#include <ft2build.h>
++#include FT_MODULE_H
+ "
+ if test "x$ac_cv_type_FT_TrueTypeEngineType" = xyes; then :
+
+@@ -11525,15 +11499,9 @@ _ACEOF
+
+ fi
+
+- if test "$ac_cv_header_freetype_freetype_h" = "yes" -a "$wine_cv_fttrigon" = "yes"
+- then
+-
+-$as_echo "#define HAVE_FREETYPE 1" >>confdefs.h
+-
+- else
+- FREETYPE_LIBS=""
+- fi
++fi
+ else
++ FREETYPE_CFLAGS=""
+ FREETYPE_LIBS=""
+ fi
+ CPPFLAGS=$ac_save_CPPFLAGS
+@@ -11541,14 +11509,14 @@ test -z "$FREETYPE_CFLAGS" || FREETYPE_CFLAGS=`echo " $FREETYPE_CFLAGS" | sed 's
+ test -z "$FREETYPE_LIBS" || FREETYPE_LIBS=`echo " $FREETYPE_LIBS" | sed 's/ -L\([^/]\)/ -L\$(top_builddir)\/\1/g'`
+
+ fi
+-if test "x$ac_cv_header_freetype_freetype_h" != xyes -o "x$wine_cv_fttrigon" != xyes; then :
++if test "x$ac_cv_lib_soname_freetype" = x; then :
+ case "x$with_freetype" in
+ xno) ;;
+ *) as_fn_error $? "FreeType ${notice_platform}development files not found. Fonts will not be built.
+ Use the --without-freetype option if you really want this." "$LINENO" 5 ;;
+ esac
+ fi
+-test "x$ac_cv_header_freetype_freetype_h" = xyes -a "x$wine_cv_fttrigon" = xyes || enable_fonts=${enable_fonts:-no}
++test "x$ac_cv_lib_soname_freetype" = x && enable_fonts=${enable_fonts:-no}
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for parport header/ppdev.h" >&5
+ $as_echo_n "checking for parport header/ppdev.h... " >&6; }
+diff --git a/configure.ac b/configure.ac
+index 81b7027..c4021b4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1463,42 +1463,22 @@ then
+ WINE_PACKAGE_FLAGS(FREETYPE,[freetype2],[-lfreetype],
+ [`(freetype-config --cflags || freetype2-config --cflags) 2>/dev/null`],
+ [`(freetype-config --libs || freetype2-config --libs) 2>/dev/null`],
+- [WINE_CHECK_SONAME(freetype,FT_Init_FreeType,[ft_lib=yes],[ft_lib=no],[$FREETYPE_LIBS])
+- if test "$ft_lib" = "yes"
++ [AC_CHECK_HEADERS([ft2build.h])
++ if test "$ac_cv_header_ft2build_h" = "yes"
+ then
+- AC_CHECK_HEADERS(ft2build.h \
+- freetype/freetype.h \
+- freetype/ftglyph.h \
+- freetype/fttypes.h \
+- freetype/tttables.h \
+- freetype/ftsnames.h \
+- freetype/ttnameid.h \
+- freetype/ftoutln.h \
+- freetype/ftwinfnt.h \
+- freetype/ftmodapi.h \
+- freetype/ftlcdfil.h,,,
+- [#ifdef HAVE_FT2BUILD_H
+-# include <ft2build.h>
+-#endif])
+- AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include <ft2build.h>
+-#include <freetype/fttrigon.h>]])],[AC_DEFINE(HAVE_FREETYPE_FTTRIGON_H, 1,
+- [Define if you have the <freetype/fttrigon.h> header file.])
+- wine_cv_fttrigon=yes],[wine_cv_fttrigon=no])
+- AC_CHECK_TYPES(FT_TrueTypeEngineType,,,[#include <freetype/ftmodapi.h>])
+- dnl Check that we have at least freetype/freetype.h
+- if test "$ac_cv_header_freetype_freetype_h" = "yes" -a "$wine_cv_fttrigon" = "yes"
+- then
+- AC_DEFINE(HAVE_FREETYPE, 1, [Define if FreeType 2 is installed])
+- else
+- FREETYPE_LIBS=""
+- fi
++ WINE_CHECK_SONAME(freetype,FT_Init_FreeType,
++ [AC_DEFINE(HAVE_FREETYPE, 1, [Define if FreeType 2 is installed])
++ AC_CHECK_TYPES(FT_TrueTypeEngineType,,,[#include <ft2build.h>
++#include FT_MODULE_H])],
++ [FREETYPE_LIBS=""],[$FREETYPE_LIBS])
+ else
++ FREETYPE_CFLAGS=""
+ FREETYPE_LIBS=""
+ fi])
+ fi
+-WINE_ERROR_WITH(freetype,[test "x$ac_cv_header_freetype_freetype_h" != xyes -o "x$wine_cv_fttrigon" != xyes],
++WINE_ERROR_WITH(freetype,[test "x$ac_cv_lib_soname_freetype" = x],
+ [FreeType ${notice_platform}development files not found. Fonts will not be built.])
+-test "x$ac_cv_header_freetype_freetype_h" = xyes -a "x$wine_cv_fttrigon" = xyes || enable_fonts=${enable_fonts:-no}
++test "x$ac_cv_lib_soname_freetype" = x && enable_fonts=${enable_fonts:-no}
+
+ dnl **** Check for parport (currently Linux only) ****
+ AC_CACHE_CHECK([for parport header/ppdev.h], ac_cv_c_ppdev,
+diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
+index fb4f2af..e230299 100644
+--- a/dlls/gdi32/freetype.c
++++ b/dlls/gdi32/freetype.c
+@@ -77,6 +77,23 @@
+ #undef SetRectRgn
+ #endif /* HAVE_CARBON_CARBON_H */
+
++#ifdef HAVE_FT2BUILD_H
++#include <ft2build.h>
++#include FT_FREETYPE_H
++#include FT_GLYPH_H
++#include FT_TYPES_H
++#include FT_TRUETYPE_TABLES_H
++#include FT_SFNT_NAMES_H
++#include FT_TRUETYPE_IDS_H
++#include FT_OUTLINE_H
++#include FT_TRIGONOMETRY_H
++#include FT_MODULE_H
++#include FT_WINFONTS_H
++#ifdef FT_LCD_FILTER_H
++#include FT_LCD_FILTER_H
++#endif
++#endif /* HAVE_FT2BUILD_H */
++
+ #include "windef.h"
+ #include "winbase.h"
+ #include "winternl.h"
+@@ -95,43 +112,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(font);
+
+ #ifdef HAVE_FREETYPE
+
+-#ifdef HAVE_FT2BUILD_H
+-#include <ft2build.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FREETYPE_H
+-#include <freetype/freetype.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTGLYPH_H
+-#include <freetype/ftglyph.h>
+-#endif
+-#ifdef HAVE_FREETYPE_TTTABLES_H
+-#include <freetype/tttables.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTTYPES_H
+-#include <freetype/fttypes.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTSNAMES_H
+-#include <freetype/ftsnames.h>
+-#endif
+-#ifdef HAVE_FREETYPE_TTNAMEID_H
+-#include <freetype/ttnameid.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTOUTLN_H
+-#include <freetype/ftoutln.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTTRIGON_H
+-#include <freetype/fttrigon.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTWINFNT_H
+-#include <freetype/ftwinfnt.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTMODAPI_H
+-#include <freetype/ftmodapi.h>
+-#endif
+-#ifdef HAVE_FREETYPE_FTLCDFIL_H
+-#include <freetype/ftlcdfil.h>
+-#endif
+-
+ #ifndef HAVE_FT_TRUETYPEENGINETYPE
+ typedef enum
+ {
+@@ -186,7 +166,7 @@ MAKE_FUNCPTR(FT_Vector_Transform);
+ MAKE_FUNCPTR(FT_Vector_Unit);
+ static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
+ static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
+-#ifdef HAVE_FREETYPE_FTLCDFIL_H
++#ifdef FT_LCD_FILTER_H
+ static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
+ #endif
+
+@@ -924,7 +904,7 @@ static BOOL is_hinting_enabled(void)
+
+ static BOOL is_subpixel_rendering_enabled( void )
+ {
+-#ifdef HAVE_FREETYPE_FTLCDFIL_H
++#ifdef FT_LCD_FILTER_H
+ static int enabled = -1;
+ if (enabled == -1)
+ {
+@@ -3918,7 +3898,7 @@ static BOOL init_freetype(void)
+ /* Don't warn if these ones are missing */
+ pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
+ pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
+-#ifdef HAVE_FREETYPE_FTLCDFIL_H
++#ifdef FT_LCD_FILTER_H
+ pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
+ #endif
+
+@@ -6706,7 +6686,7 @@ static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
+ case WINE_GGO_HBGR_BITMAP:
+ case WINE_GGO_VRGB_BITMAP:
+ case WINE_GGO_VBGR_BITMAP:
+-#ifdef HAVE_FREETYPE_FTLCDFIL_H
++#ifdef FT_LCD_FILTER_H
+ {
+ switch (ft_face->glyph->format)
+ {
+diff --git a/include/config.h.in b/include/config.h.in
+index a14db5b..79f8b45 100644
+--- a/include/config.h.in
++++ b/include/config.h.in
+@@ -132,39 +132,6 @@
+ /* Define if FreeType 2 is installed */
+ #undef HAVE_FREETYPE
+
+-/* Define to 1 if you have the <freetype/freetype.h> header file. */
+-#undef HAVE_FREETYPE_FREETYPE_H
+-
+-/* Define to 1 if you have the <freetype/ftglyph.h> header file. */
+-#undef HAVE_FREETYPE_FTGLYPH_H
+-
+-/* Define to 1 if you have the <freetype/ftlcdfil.h> header file. */
+-#undef HAVE_FREETYPE_FTLCDFIL_H
+-
+-/* Define to 1 if you have the <freetype/ftmodapi.h> header file. */
+-#undef HAVE_FREETYPE_FTMODAPI_H
+-
+-/* Define to 1 if you have the <freetype/ftoutln.h> header file. */
+-#undef HAVE_FREETYPE_FTOUTLN_H
+-
+-/* Define to 1 if you have the <freetype/ftsnames.h> header file. */
+-#undef HAVE_FREETYPE_FTSNAMES_H
+-
+-/* Define if you have the <freetype/fttrigon.h> header file. */
+-#undef HAVE_FREETYPE_FTTRIGON_H
+-
+-/* Define to 1 if you have the <freetype/fttypes.h> header file. */
+-#undef HAVE_FREETYPE_FTTYPES_H
+-
+-/* Define to 1 if you have the <freetype/ftwinfnt.h> header file. */
+-#undef HAVE_FREETYPE_FTWINFNT_H
+-
+-/* Define to 1 if you have the <freetype/ttnameid.h> header file. */
+-#undef HAVE_FREETYPE_TTNAMEID_H
+-
+-/* Define to 1 if you have the <freetype/tttables.h> header file. */
+-#undef HAVE_FREETYPE_TTTABLES_H
+-
+ /* Define to 1 if the system has the type `fsblkcnt_t'. */
+ #undef HAVE_FSBLKCNT_T
+
+--
+1.9.1
+
diff --git a/app-emulation/wine/files/wine-1.7.12-osmesa-check.patch b/app-emulation/wine/files/wine-1.7.12-osmesa-check.patch
new file mode 100644
index 00000000..7cafcd4e
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.12-osmesa-check.patch
@@ -0,0 +1,38 @@
+From 6932b9a17c4f64c13f7060895d46334bc7022430 Mon Sep 17 00:00:00 2001
+From: Alexandre Rostovtsev <tetromino@gentoo.org>
+Date: Tue, 7 Aug 2012 01:29:01 -0400
+Subject: [PATCH] Do not check for libGL symbols when checking libOSMesa
+
+If mesa had been built with shared glapi, glAccum is not available in
+libOSMesa without explicitly linking to libGL. In addition, in
+mesa-8.0.x and earlier, libOSMesa needs to be explicitly linked to
+libglapi if mesa was built with shared glapi, see
+https://bugs.gentoo.org/show_bug.cgi?id=399813
+And in mesa-8.1.x, libOSMesa in addition needs libdl, libpthread, and
+libstdc++, see https://bugs.gentoo.org/show_bug.cgi?id=431832
+---
+ configure.ac | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index de807d2..a2e8684 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1233,7 +1233,13 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c
+
+ if test "x$with_osmesa" != "xno"
+ then
+- WINE_CHECK_SONAME(OSMesa,glAccum,,,[$X_LIBS -lm $X_EXTRA_LIBS])
++ WINE_CHECK_SONAME(OSMesa,OSMesaCreateContext,,,[$X_LIBS -lm $X_EXTRA_LIBS])
++ if test "x$ac_cv_lib_soname_OSMesa" = "x"; then
++ osmesa_save_CC=$CC
++ CC=$CXX
++ WINE_CHECK_SONAME(OSMesa,OSMesaCreateContext,,,[-lglapi -lpthread -ldl $X_LIBS -lm $X_EXTRA_LIBS])
++ CC=$osmesa_save_CC
++ fi
+ WINE_NOTICE_WITH(osmesa,[test "x$ac_cv_lib_soname_OSMesa" = "x"],
+ [libOSMesa ${notice_platform}development files not found (or too old), OpenGL rendering in bitmaps won't be supported.])
+ fi
+--
+1.8.5.3
+
diff --git a/app-emulation/wine/files/wine-1.7.19-makefile-race-cond.patch b/app-emulation/wine/files/wine-1.7.19-makefile-race-cond.patch
new file mode 100644
index 00000000..294b5ae9
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.19-makefile-race-cond.patch
@@ -0,0 +1,15 @@
+diff --git a/Makefile.in b/Makefile.in
+index 5c163b8..b600cf7 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -52,7 +52,8 @@ __tooldeps__: libs/port libs/wine libs/wpp
+ __builddeps__: __tooldeps__ include
+ .PHONY: depend check test testclean crosstest __tooldeps__ __builddeps__
+
+-loader server: libs/port libs/wine tools
++loader: libs/port libs/wine tools
++server: libs/port libs/wine tools include
+ fonts: tools/sfnt2fon
+ include: tools tools/widl
+ libs/wine tools: libs/port
+
diff --git a/app-emulation/wine/files/wine-1.7.2-osmesa-check.patch b/app-emulation/wine/files/wine-1.7.2-osmesa-check.patch
new file mode 100644
index 00000000..e20ea2c2
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.2-osmesa-check.patch
@@ -0,0 +1,38 @@
+From b7eb1ff48dd1210aa3e1002afc503d5df75d50b9 Mon Sep 17 00:00:00 2001
+From: Alexandre Rostovtsev <tetromino@gentoo.org>
+Date: Tue, 7 Aug 2012 01:29:01 -0400
+Subject: [PATCH] Do not check for libGL symbols when checking libOSMesa
+
+If mesa had been built with shared glapi, glAccum is not available in
+libOSMesa without explicitly linking to libGL. In addition, in
+mesa-8.0.x and earlier, libOSMesa needs to be explicitly linked to
+libglapi if mesa was built with shared glapi, see
+https://bugs.gentoo.org/show_bug.cgi?id=399813
+And in mesa-8.1.x, libOSMesa in addition needs libdl, libpthread, and
+libstdc++, see https://bugs.gentoo.org/show_bug.cgi?id=431832
+---
+ configure.ac | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 66b4dd6..0303d87 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1213,7 +1213,13 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c
+
+ if test "x$with_osmesa" != "xno"
+ then
+- WINE_CHECK_SONAME(OSMesa,glAccum,,,[$X_LIBS $XLIB -lm $X_EXTRA_LIBS])
++ WINE_CHECK_SONAME(OSMesa,OSMesaCreateContext,,,[$X_LIBS $XLIB -lm $X_EXTRA_LIBS])
++ if test "x$ac_cv_lib_soname_OSMesa" = "x"; then
++ osmesa_save_CC=$CC
++ CC=$CXX
++ WINE_CHECK_SONAME(OSMesa,OSMesaCreateContext,,,[-lglapi -lpthread -ldl $X_LIBS $XLIB -lm $X_EXTRA_LIBS])
++ CC=$osmesa_save_CC
++ fi
+ WINE_NOTICE_WITH(osmesa,[test "x$ac_cv_lib_soname_OSMesa" = "x"],
+ [libOSMesa ${notice_platform}development files not found (or too old), OpenGL rendering in bitmaps won't be supported.])
+ fi
+--
+1.8.3.2
+
diff --git a/app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-post.patch b/app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-post.patch
new file mode 100644
index 00000000..3d653993
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-post.patch
@@ -0,0 +1,58 @@
+From 695c19cdd2fc24aaa7ed89976c4965b376707131 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Wed, 25 Feb 2015 22:45:42 +0100
+Subject: ntdll: Fix race-condition when threads are killed during shutdown.
+
+When exit_thread is executed, nb_threads is decremented before the thread is
+fully shutdown. When another thread runs ExitProcess() this will cause a SIGQUIT
+signal to all threads, effectively decrementing nb_threads twice. The process
+will terminate with a wrong exitcode then because the refcount reaches zero too
+early.
+
+Currently Wine has no locking protection of LdrShutdownProcess(), so it can
+only be executed safely when all other threads have terminated before. Most
+likely there are more Wine bugs in this area, but the attached patch should
+fix the most critical one (messed up refcounting of threads) for now.
+
+[Alexandre Rostovtsev <tetromino@gentoo.org> : rebase to be applied after
+ Maarten Lankhorst's "override pthreads to fix gstreamer v5" patch.]
+---
+ dlls/ntdll/thread.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
+index 4f181dc..1bdbcbf 100755
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -461,6 +461,7 @@ static void exit_thread_common( int status )
+ static void *prev_teb;
+ TEB *teb;
+ #endif
++ sigset_t sigset;
+
+ if (status) /* send the exit code to the server (0 is already the default) */
+ {
+@@ -473,7 +474,7 @@ static void exit_thread_common( int status )
+ SERVER_END_REQ;
+ }
+
+- if (interlocked_xchg_add( &nb_threads, -1 ) <= 1)
++ if (interlocked_xchg_add( &nb_threads, 0 ) <= 1)
+ {
+ LdrShutdownProcess();
+ exit( status );
+@@ -499,6 +500,11 @@ static void exit_thread_common( int status )
+ reap_thread(NtCurrentTeb());
+ #endif
+
++ sigemptyset( &sigset );
++ sigaddset( &sigset, SIGQUIT );
++ pthread_sigmask( SIG_BLOCK, &sigset, NULL );
++ if (interlocked_xchg_add( &nb_threads, -1 ) <= 1) _exit( status );
++
+ close( ntdll_get_thread_data()->wait_fd[0] );
+ close( ntdll_get_thread_data()->wait_fd[1] );
+ close( ntdll_get_thread_data()->reply_fd );
+--
+2.3.1
+
diff --git a/app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-pre.patch b/app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-pre.patch
new file mode 100644
index 00000000..eee42ff9
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.38-gstreamer-v5-staging-pre.patch
@@ -0,0 +1,48 @@
+From 0d92921d264d5d0d1041c66353f022f1bc88577f Mon Sep 17 00:00:00 2001
+From: Alexandre Rostovtsev <tetromino@gentoo.org>
+Date: Sun, 8 Mar 2015 00:10:31 -0500
+Subject: [PATCH] Revert "ntdll: Fix race-condition when threads are killed
+ during shutdown."
+
+This reverts Sebastian Lackner's Wine-Staging patch to allow Maarten
+Lankhorst's "override pthreads to fix gstreamer v5" to apply
+---
+ dlls/ntdll/thread.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
+index 74e64c9..3696c8e 100644
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -370,7 +370,6 @@ void terminate_thread( int status )
+ void exit_thread( int status )
+ {
+ static void *prev_teb;
+- sigset_t sigset;
+ TEB *teb;
+
+ if (status) /* send the exit code to the server (0 is already the default) */
+@@ -384,7 +383,7 @@ void exit_thread( int status )
+ SERVER_END_REQ;
+ }
+
+- if (interlocked_xchg_add( &nb_threads, 0 ) <= 1)
++ if (interlocked_xchg_add( &nb_threads, -1 ) <= 1)
+ {
+ LdrShutdownProcess();
+ exit( status );
+@@ -406,11 +405,6 @@ void exit_thread( int status )
+ }
+ }
+
+- sigemptyset( &sigset );
+- sigaddset( &sigset, SIGQUIT );
+- pthread_sigmask( SIG_BLOCK, &sigset, NULL );
+- if (interlocked_xchg_add( &nb_threads, -1 ) <= 1) _exit( status );
+-
+ close( ntdll_get_thread_data()->wait_fd[0] );
+ close( ntdll_get_thread_data()->wait_fd[1] );
+ close( ntdll_get_thread_data()->reply_fd );
+--
+2.3.1
+
diff --git a/app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-post.patch b/app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-post.patch
new file mode 100644
index 00000000..25eb2357
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-post.patch
@@ -0,0 +1,38 @@
+From b97783fd33b4d9897c149d7a14747aa4969bd9e9 Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Thu, 19 Mar 2015 07:56:04 +0100
+Subject: Reapply various changes conflicting with Maarten Lankhorst's
+ gstreamer hack v5.
+
+---
+ dlls/ntdll/thread.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
+index 1e7f231..cf0461d 100644
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -461,6 +461,8 @@ static void exit_thread_common( int status )
+ static void *prev_teb;
+ TEB *teb;
+ #endif
++ shmlocal_t *shmlocal;
++ sigset_t sigset;
+
+ if (status) /* send the exit code to the server (0 is already the default) */
+ {
+@@ -502,6 +504,11 @@ static void exit_thread_common( int status )
+ reap_thread(NtCurrentTeb());
+ #endif
+
++ sigemptyset( &sigset );
++ sigaddset( &sigset, SIGQUIT );
++ pthread_sigmask( SIG_BLOCK, &sigset, NULL );
++ if (interlocked_xchg_add( &nb_threads, -1 ) <= 1) _exit( status );
++
+ close( ntdll_get_thread_data()->wait_fd[0] );
+ close( ntdll_get_thread_data()->wait_fd[1] );
+ close( ntdll_get_thread_data()->reply_fd );
+--
+2.3.2
+
diff --git a/app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-pre.patch b/app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-pre.patch
new file mode 100644
index 00000000..81aa699b
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.39-gstreamer-v5-staging-pre.patch
@@ -0,0 +1,40 @@
+From 1527fb44c331f2c61224514beb758895a5f85c8d Mon Sep 17 00:00:00 2001
+From: Sebastian Lackner <sebastian@fds-team.de>
+Date: Thu, 19 Mar 2015 07:51:48 +0100
+Subject: Revert various changes conflicting with Maarten Lankhorst's gstreamer
+ hack v5.
+
+Note: These changes have to be reapplied with the corresponding -post patchset
+afterwards.
+---
+ dlls/ntdll/thread.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
+index 30a4720..843be0f 100644
+--- a/dlls/ntdll/thread.c
++++ b/dlls/ntdll/thread.c
+@@ -385,8 +385,6 @@ void terminate_thread( int status )
+ void exit_thread( int status )
+ {
+ static void *prev_teb;
+- shmlocal_t *shmlocal;
+- sigset_t sigset;
+ TEB *teb;
+
+ if (status) /* send the exit code to the server (0 is already the default) */
+@@ -425,11 +423,6 @@ void exit_thread( int status )
+ }
+ }
+
+- sigemptyset( &sigset );
+- sigaddset( &sigset, SIGQUIT );
+- pthread_sigmask( SIG_BLOCK, &sigset, NULL );
+- if (interlocked_xchg_add( &nb_threads, -1 ) <= 1) _exit( status );
+-
+ close( ntdll_get_thread_data()->wait_fd[0] );
+ close( ntdll_get_thread_data()->wait_fd[1] );
+ close( ntdll_get_thread_data()->reply_fd );
+--
+2.3.2
+
diff --git a/app-emulation/wine/files/wine-1.7.45-libunwind-osx-only.patch b/app-emulation/wine/files/wine-1.7.45-libunwind-osx-only.patch
new file mode 100644
index 00000000..e7a79055
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.45-libunwind-osx-only.patch
@@ -0,0 +1,64 @@
+From 36a9f9dd05c3b9df77c44c91663e9bd6cae1c848 Mon Sep 17 00:00:00 2001
+From: Ken Thomases <ken@codeweavers.com>
+Date: Mon, 15 Jun 2015 20:42:33 -0500
+Subject: [PATCH 1/1] configure: Only check for libunwind.h on OS X.
+
+---
+ configure | 13 ++++++++++++-
+ configure.ac | 2 +-
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/configure b/configure
+index a104097..c0951db 100755
+--- a/configure
++++ b/configure
+@@ -6626,7 +6626,6 @@ for ac_header in \
+ lber.h \
+ ldap.h \
+ libproc.h \
+- libunwind.h \
+ link.h \
+ linux/cdrom.h \
+ linux/compiler.h \
+@@ -7849,6 +7848,18 @@ uninstall::
+ ;;
+
+ darwin*|macosx*)
++ for ac_header in libunwind.h
++do :
++ ac_fn_c_check_header_mongrel "$LINENO" "libunwind.h" "ac_cv_header_libunwind_h" "$ac_includes_default"
++if test "x$ac_cv_header_libunwind_h" = xyes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE_LIBUNWIND_H 1
++_ACEOF
++
++fi
++
++done
++
+ LIBEXT="dylib"
+ DLLFLAGS="$DLLFLAGS -fPIC"
+ LIBWINE_LDFLAGS="-multiply_defined suppress"
+diff --git a/configure.ac b/configure.ac
+index df28b27..f9df3f0 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -424,7 +424,6 @@ AC_CHECK_HEADERS(\
+ lber.h \
+ ldap.h \
+ libproc.h \
+- libunwind.h \
+ link.h \
+ linux/cdrom.h \
+ linux/compiler.h \
+@@ -751,6 +750,7 @@ uninstall::
+ ;;
+
+ darwin*|macosx*)
++ AC_CHECK_HEADERS(libunwind.h)
+ LIBEXT="dylib"
+ DLLFLAGS="$DLLFLAGS -fPIC"
+ LIBWINE_LDFLAGS="-multiply_defined suppress"
+--
+1.9.1
+
diff --git a/app-emulation/wine/files/wine-1.7.47-critical-security-cookie-fix.patch b/app-emulation/wine/files/wine-1.7.47-critical-security-cookie-fix.patch
new file mode 100644
index 00000000..9168654a
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.47-critical-security-cookie-fix.patch
@@ -0,0 +1,82 @@
+From: Erich E. Hoover <erich.e.hoover@wine-staging.com>
+Date: Fri, 10 Jul 2015 20:52:33 +0000 (-0600)
+Subject: ntdll: Only set the security cookie if it has not already been set.
+X-Git-Url: http://source.winehq.org/git/wine.git/commitdiff_plain/e9d7cf99ada80ea8345c301481c63a24780f2b63
+
+ntdll: Only set the security cookie if it has not already been set.
+---
+
+diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
+index 410e060..ff947da 100644
+--- a/dlls/ntdll/virtual.c
++++ b/dlls/ntdll/virtual.c
+@@ -61,6 +61,12 @@ WINE_DECLARE_DEBUG_CHANNEL(module);
+ #define MAP_NORESERVE 0
+ #endif
+
++#ifdef _WIN64
++#define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
++#endif
++#define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
++#define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
++
+ /* File view */
+ struct file_view
+ {
+@@ -1053,6 +1059,36 @@ static NTSTATUS stat_mapping_file( struct file_view *view, struct stat *st )
+ return status;
+ }
+
++/***********************************************************************
++ * set_security_cookie
++ *
++ * Create a random security cookie for buffer overflow protection. Make
++ * sure it does not accidentally match the default cookie value.
++ */
++static void set_security_cookie(ULONG_PTR *cookie)
++{
++ static ULONG seed;
++
++ if (!cookie) return;
++ if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
++ while (1)
++ {
++ if (*cookie == DEFAULT_SECURITY_COOKIE_16)
++ *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
++ else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
++ *cookie = RtlRandom( &seed );
++#ifdef DEFAULT_SECURITY_COOKIE_64
++ else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
++ {
++ *cookie = RtlRandom( &seed );
++ /* fill up, but keep the highest word clear */
++ *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
++ }
++#endif
++ else
++ break;
++ }
++}
+
+ /***********************************************************************
+ * map_image
+@@ -1285,18 +1321,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
+ loadcfg = RtlImageDirectoryEntryToData( (HMODULE)ptr, TRUE,
+ IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &loadcfg_size );
+ if (loadcfg && loadcfg_size >= sizeof(*loadcfg))
+- {
+- static ULONG seed;
+- ULONG_PTR *cookie = (ULONG_PTR *)loadcfg->SecurityCookie;
+-
+- if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
+- if (cookie)
+- {
+- *cookie = RtlRandom( &seed );
+- if (sizeof(ULONG_PTR) > sizeof(ULONG)) /* fill up, but keep the highest word clear */
+- *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
+- }
+- }
++ set_security_cookie((ULONG_PTR *)loadcfg->SecurityCookie);
+
+ /* set the image protections */
+
diff --git a/app-emulation/wine/files/wine-1.7.55-d3d9.patch b/app-emulation/wine/files/wine-1.7.55-d3d9.patch
new file mode 100644
index 00000000..7497964b
--- /dev/null
+++ b/app-emulation/wine/files/wine-1.7.55-d3d9.patch
@@ -0,0 +1,5366 @@
+diff --git a/configure.ac b/configure.ac
+index 2d2a168..5f75a99 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -65,6 +65,8 @@ AC_ARG_WITH(openal, AS_HELP_STRING([--without-openal],[do not use OpenAL]),
+ AC_ARG_WITH(opencl, AS_HELP_STRING([--without-opencl],[do not use OpenCL]),
+ [if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi])
+ AC_ARG_WITH(opengl, AS_HELP_STRING([--without-opengl],[do not use OpenGL]))
++AC_ARG_WITH(d3dadapter,AS_HELP_STRING([--without-d3dadapter],[do not use native Direct3D]))
++AC_ARG_WITH(d3dadapter-dri2-fallback, AS_HELP_STRING([--without-d3dadapter-dri2-fallback],[add a DRI2 fallback to d3dadapter DRI3 code]))
+ AC_ARG_WITH(osmesa, AS_HELP_STRING([--without-osmesa],[do not use the OSMesa library]))
+ AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],[do not use the OSS sound support]))
+ AC_ARG_WITH(pcap, AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]),
+@@ -381,6 +383,8 @@ AC_CHECK_LIB(ossaudio,_oss_ioctl)
+
+ AC_SUBST(OPENGL_LIBS,"")
+
++AC_SUBST(D3DADAPTER9_LIBS,"")
++
+ dnl **** Check for header files ****
+
+ AC_SYS_LARGEFILE()
+@@ -1156,6 +1160,45 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c
+ WINE_WARNING_WITH(opengl,[test -n "$opengl_msg"],[$opengl_msg
+ OpenGL and Direct3D won't be supported.])
+
++
++
++ dnl Check for d3dadapter
++ if test "x$with_d3dadapter" != "xno"
++ then
++ D3D_CFLAGS=`pkg-config --cflags d3d`
++ D3D_LIBS=`pkg-config --libs d3d`
++ AC_SUBST(D3D_CFLAGS)
++ AC_SUBST(D3D_LIBS)
++ AC_DEFINE(SONAME_D3DADAPTER9, ["d3dadapter9.so.1"], ["temporary hack"])
++ AC_DEFINE_UNQUOTED(D3D_MODULE_DIR, ["`pkg-config --variable=moduledir d3d`"], ["module dir"])
++ D3DADAPTER9_LIBS=""
++ WINE_CHECK_SONAME(xcb,xcb_request_check, [D3DADAPTER9_LIBS="-lxcb $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb "],[D3Dadapter9 requires libxcb])
++ WINE_CHECK_SONAME(xcb-dri3,xcb_dri3_open, [D3DADAPTER9_LIBS="-lxcb-dri3 $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb-dri3 -lxcb "],[D3Dadapter9 requires libxcb-dri3])
++ WINE_CHECK_SONAME(xcb-present,xcb_present_notify_msc, [D3DADAPTER9_LIBS="-lxcb-present $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libxcb-present])
++ WINE_CHECK_SONAME(X11-xcb,XGetXCBConnection, [D3DADAPTER9_LIBS="-lX11-xcb $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libX11-xcb])
++ WINE_CHECK_SONAME(xcb-xfixes,xcb_xfixes_create_region, [D3DADAPTER9_LIBS="-lxcb-xfixes $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libxcb-xfixes])
++ WINE_CHECK_SONAME(X11,XOpenDisplay, [D3DADAPTER9_LIBS="-lX11 $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libX11])
++ WINE_CHECK_SONAME(Xext,XextRemoveDisplay, [D3DADAPTER9_LIBS="-lXext $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libXext])
++ WINE_CHECK_SONAME(pthread,pthread_mutex_lock, [D3DADAPTER9_LIBS="-lpthread $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lpthread -lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libpthread])
++
++ if test "x$with_d3dadapter_dri2_fallback" != "xno"
++ then
++ AC_DEFINE(D3DADAPTER9_DRI2, 1, [Whether d3dadapter9 DRI2 fallback is compiled])
++ WINE_CHECK_SONAME(GL,glGenFramebuffers, [D3DADAPTER9_LIBS="-lGL $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lGL -lpthread -lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 DRI2 fallback requires libGL])
++ WINE_CHECK_SONAME(EGL,eglCreateContext, [D3DADAPTER9_LIBS="-lEGL $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lEGL -lGL -lpthread -lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 DRI2 fallback requires libEGL])
++ fi
++ fi
++
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ else
+ X_CFLAGS=""
+@@ -2764,6 +2807,7 @@ WINE_CONFIG_DLL(d3d8,,[implib])
+ WINE_CONFIG_TEST(dlls/d3d8/tests)
+ WINE_CONFIG_DLL(d3d9,,[implib])
+ WINE_CONFIG_TEST(dlls/d3d9/tests)
++WINE_CONFIG_DLL(d3d9-nine,,[implib])
+ WINE_CONFIG_DLL(d3dcompiler_33)
+ WINE_CONFIG_DLL(d3dcompiler_34)
+ WINE_CONFIG_DLL(d3dcompiler_35)
+diff --git a/dlls/d3d9-nine/Makefile.in b/dlls/d3d9-nine/Makefile.in
+new file mode 100644
+index 0000000..a761cd7
+--- /dev/null
++++ b/dlls/d3d9-nine/Makefile.in
+@@ -0,0 +1,12 @@
++MODULE = d3d9-nine.dll
++IMPORTS = dxguid uuid advapi32 gdi32 user32
++EXTRAINCL = $(X_CFLAGS)
++EXTRALIBS = $(D3DADAPTER9_LIBS)
++
++C_SRCS = \
++ d3d9_main.c \
++ d3dadapter9.c \
++ present.c \
++ dri3.c
++
++RC_SRCS = version.rc
+diff --git a/dlls/d3d9-nine/d3d9-nine.spec b/dlls/d3d9-nine/d3d9-nine.spec
+new file mode 100644
+index 0000000..a33cba5
+--- /dev/null
++++ b/dlls/d3d9-nine/d3d9-nine.spec
+@@ -0,0 +1,14 @@
++@ stdcall Direct3DShaderValidatorCreate9()
++@ stub PSGPError
++@ stub PSGPSampleTexture
++@ stdcall D3DPERF_BeginEvent(long wstr)
++@ stdcall D3DPERF_EndEvent()
++@ stdcall D3DPERF_GetStatus()
++@ stdcall D3DPERF_QueryRepeatFrame()
++@ stdcall D3DPERF_SetMarker(long wstr)
++@ stdcall D3DPERF_SetOptions(long)
++@ stdcall D3DPERF_SetRegion(long wstr)
++@ stub DebugSetLevel
++@ stdcall DebugSetMute()
++@ stdcall Direct3DCreate9(long)
++@ stdcall Direct3DCreate9Ex(long ptr)
+diff --git a/dlls/d3d9-nine/d3d9_main.c b/dlls/d3d9-nine/d3d9_main.c
+new file mode 100644
+index 0000000..de20475
+--- /dev/null
++++ b/dlls/d3d9-nine/d3d9_main.c
+@@ -0,0 +1,163 @@
++/*
++ * Direct3D 9
++ *
++ * Copyright 2002-2003 Jason Edmeades
++ * Copyright 2002-2003 Raphael Junqueira
++ * Copyright 2005 Oliver Stieber
++ * Copyright 2015 Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ *
++ */
++
++#include "config.h"
++#include "initguid.h"
++#include "wine/debug.h"
++
++#include <dlfcn.h>
++#include <fcntl.h>
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#include <d3dadapter/d3dadapter9.h>
++
++#include "d3dadapter9.h"
++
++#include "wine/library.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter);
++
++static int D3DPERF_event_level = 0;
++static Display *gdi_display;
++
++void WINAPI DebugSetMute(void) {
++ /* nothing to do */
++}
++
++IDirect3D9 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate9(UINT sdk_version)
++{
++ IDirect3D9 *native;
++ TRACE("sdk_version %#x.\n", sdk_version);
++
++ if (SUCCEEDED(d3dadapter9_new(gdi_display, FALSE, (IDirect3D9Ex **)&native))) {
++ return native;
++ }
++
++ return NULL;
++}
++
++HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9Ex **d3d9ex)
++{
++ TRACE("sdk_version %#x, d3d9ex %p.\n", sdk_version, d3d9ex);
++
++ return d3dadapter9_new(gdi_display, TRUE, d3d9ex);
++}
++
++/*******************************************************************
++ * Direct3DShaderValidatorCreate9 (D3D9.@)
++ *
++ * No documentation available for this function.
++ * SDK only says it is internal and shouldn't be used.
++ */
++void* WINAPI Direct3DShaderValidatorCreate9(void)
++{
++ static int once;
++
++ if (!once++) FIXME("stub\n");
++ return NULL;
++}
++
++/*******************************************************************
++ * DllMain
++ */
++BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
++{
++ switch (reason)
++ {
++ case DLL_PROCESS_ATTACH:
++ if (!(gdi_display = XOpenDisplay( NULL ))) {
++ ERR("Failed to open display\n");
++ return FALSE;
++ }
++
++ fcntl( ConnectionNumber(gdi_display), F_SETFD, 1 ); /* set close on exec flag */
++ break;
++ }
++
++ return TRUE;
++}
++
++/***********************************************************************
++ * D3DPERF_BeginEvent (D3D9.@)
++ */
++int WINAPI D3DPERF_BeginEvent(D3DCOLOR color, const WCHAR *name)
++{
++ TRACE("color 0x%08x, name %s.\n", color, debugstr_w(name));
++
++ return D3DPERF_event_level++;
++}
++
++/***********************************************************************
++ * D3DPERF_EndEvent (D3D9.@)
++ */
++int WINAPI D3DPERF_EndEvent(void) {
++ TRACE("(void) : stub\n");
++
++ return --D3DPERF_event_level;
++}
++
++/***********************************************************************
++ * D3DPERF_GetStatus (D3D9.@)
++ */
++DWORD WINAPI D3DPERF_GetStatus(void) {
++ FIXME("(void) : stub\n");
++
++ return 0;
++}
++
++/***********************************************************************
++ * D3DPERF_SetOptions (D3D9.@)
++ *
++ */
++void WINAPI D3DPERF_SetOptions(DWORD options)
++{
++ FIXME("(%#x) : stub\n", options);
++}
++
++/***********************************************************************
++ * D3DPERF_QueryRepeatFrame (D3D9.@)
++ */
++BOOL WINAPI D3DPERF_QueryRepeatFrame(void) {
++ FIXME("(void) : stub\n");
++
++ return FALSE;
++}
++
++/***********************************************************************
++ * D3DPERF_SetMarker (D3D9.@)
++ */
++void WINAPI D3DPERF_SetMarker(D3DCOLOR color, const WCHAR *name)
++{
++ FIXME("color 0x%08x, name %s stub!\n", color, debugstr_w(name));
++}
++
++/***********************************************************************
++ * D3DPERF_SetRegion (D3D9.@)
++ */
++void WINAPI D3DPERF_SetRegion(D3DCOLOR color, const WCHAR *name)
++{
++ FIXME("color 0x%08x, name %s stub!\n", color, debugstr_w(name));
++}
+diff --git a/dlls/d3d9-nine/d3dadapter9.c b/dlls/d3d9-nine/d3dadapter9.c
+new file mode 100644
+index 0000000..f15e44f
+--- /dev/null
++++ b/dlls/d3d9-nine/d3dadapter9.c
+@@ -0,0 +1,865 @@
++/*
++ * Wine IDirect3D9 interface using ID3DAdapter9
++ *
++ * Copyright 2013 Joakim Sindholt
++ * Christoph Bumiller
++ * Copyright 2014 David Heidelberger
++ * Copyright 2014-2015 Axel Davy
++ * Copyright 2015 Nick Sarnie
++ * Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#include "config.h"
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter);
++
++#include <d3dadapter/d3dadapter9.h>
++#include "present.h"
++
++/* this represents a snapshot taken at the moment of creation */
++struct output
++{
++ D3DDISPLAYROTATION rotation; /* current rotation */
++ D3DDISPLAYMODEEX *modes;
++ unsigned nmodes;
++ unsigned nmodesalloc;
++ unsigned current; /* current mode num */
++
++ HMONITOR monitor;
++};
++
++struct adapter_group
++{
++ struct output *outputs;
++ unsigned noutputs;
++ unsigned noutputsalloc;
++
++ /* override driver provided DeviceName with this to homogenize device names
++ * with wine */
++ WCHAR devname[32];
++
++ /* driver stuff */
++ ID3DAdapter9 *adapter;
++};
++
++struct adapter_map
++{
++ unsigned group;
++ unsigned master;
++};
++
++struct d3dadapter9
++{
++ /* COM vtable */
++ void *vtable;
++ /* IUnknown reference count */
++ LONG refs;
++
++ /* adapter groups and mappings */
++ struct adapter_group *groups;
++ struct adapter_map *map;
++ unsigned nadapters;
++ unsigned ngroups;
++ unsigned ngroupsalloc;
++
++ /* true if it implements IDirect3D9Ex */
++ boolean ex;
++ Display *gdi_display;
++};
++
++/* convenience wrapper for calls into ID3D9Adapter */
++#define ADAPTER_GROUP \
++ This->groups[This->map[Adapter].group]
++
++#define ADAPTER_PROC(name, ...) \
++ ID3DAdapter9_##name(ADAPTER_GROUP.adapter, ## __VA_ARGS__)
++
++#define ADAPTER_OUTPUT \
++ ADAPTER_GROUP.outputs[Adapter-This->map[Adapter].master]
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ D3DFORMAT AdapterFormat,
++ DWORD Usage,
++ D3DRESOURCETYPE RType,
++ D3DFORMAT CheckFormat );
++
++static ULONG WINAPI
++d3dadapter9_AddRef( struct d3dadapter9 *This )
++{
++ ULONG refs = InterlockedIncrement(&This->refs);
++ TRACE("%p increasing refcount to %u.\n", This, refs);
++ return refs;
++}
++
++static ULONG WINAPI
++d3dadapter9_Release( struct d3dadapter9 *This )
++{
++ ULONG refs = InterlockedDecrement(&This->refs);
++ TRACE("%p decreasing refcount to %u.\n", This, refs);
++ if (refs == 0) {
++ /* dtor */
++ if (This->map) {
++ HeapFree(GetProcessHeap(), 0, This->map);
++ }
++
++ if (This->groups) {
++ int i, j;
++ for (i = 0; i < This->ngroups; ++i) {
++ if (This->groups[i].outputs) {
++ for (j = 0; j < This->groups[i].noutputs; ++j) {
++ if (This->groups[i].outputs[j].modes) {
++ HeapFree(GetProcessHeap(), 0,
++ This->groups[i].outputs[j].modes);
++ }
++ }
++ HeapFree(GetProcessHeap(), 0, This->groups[i].outputs);
++ }
++
++ if (This->groups[i].adapter) {
++ ID3DAdapter9_Release(This->groups[i].adapter);
++ }
++ }
++ HeapFree(GetProcessHeap(), 0, This->groups);
++ }
++
++ HeapFree(GetProcessHeap(), 0, This);
++ }
++ return refs;
++}
++
++static HRESULT WINAPI
++d3dadapter9_QueryInterface( struct d3dadapter9 *This,
++ REFIID riid,
++ void **ppvObject )
++{
++ if (!ppvObject) { return E_POINTER; }
++ if ((IsEqualGUID(&IID_IDirect3D9Ex, riid) && This->ex) ||
++ IsEqualGUID(&IID_IDirect3D9, riid) ||
++ IsEqualGUID(&IID_IUnknown, riid)) {
++ *ppvObject = This;
++ d3dadapter9_AddRef(This);
++ return S_OK;
++ }
++
++ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++ *ppvObject = NULL;
++
++ return E_NOINTERFACE;
++}
++
++static HRESULT WINAPI
++d3dadapter9_RegisterSoftwareDevice( struct d3dadapter9 *This,
++ void *pInitializeFunction )
++{
++ FIXME("(%p, %p), stub!\n", This, pInitializeFunction);
++ return D3DERR_INVALIDCALL;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterCount( struct d3dadapter9 *This )
++{
++ return This->nadapters;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterIdentifier( struct d3dadapter9 *This,
++ UINT Adapter,
++ DWORD Flags,
++ D3DADAPTER_IDENTIFIER9 *pIdentifier )
++{
++ HRESULT hr;
++ HKEY regkey;
++
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++
++ hr = ADAPTER_PROC(GetAdapterIdentifier, Flags, pIdentifier);
++ if (SUCCEEDED(hr)) {
++ /* Override the driver provided DeviceName with what Wine provided */
++ ZeroMemory(pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName));
++ if (!WideCharToMultiByte(CP_ACP, 0, ADAPTER_GROUP.devname, -1,
++ pIdentifier->DeviceName,
++ sizeof(pIdentifier->DeviceName),
++ NULL, NULL)) {
++ /* Wine does it */
++ return D3DERR_INVALIDCALL;
++ }
++ TRACE("DeviceName overriden: %s\n", pIdentifier->DeviceName);
++
++ /* Override PCI IDs when wined3d registry keys are set */
++ if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &regkey)) {
++ DWORD type, data;
++ DWORD size = sizeof(DWORD);
++
++ if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD)))
++ pIdentifier->DeviceId = data;
++ if(size != sizeof(DWORD)) {
++ ERR("VideoPciDeviceID is not a DWORD\n");
++ size = sizeof(DWORD);
++ }
++ if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD)))
++ pIdentifier->VendorId = data;
++ if(size != sizeof(DWORD))
++ ERR("VideoPciVendorID is not a DWORD\n");
++ RegCloseKey(regkey);
++
++ TRACE("DeviceId:VendorId overridden: %04X:%04X\n", pIdentifier->DeviceId, pIdentifier->VendorId);
++ }
++ }
++ return hr;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterModeCount( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DFORMAT Format )
++{
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++ WARN("Adapter %u does not exist.\n", Adapter);
++ return 0;
++ }
++ if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
++ Format, D3DUSAGE_RENDERTARGET,
++ D3DRTYPE_SURFACE, Format))) {
++ WARN("DeviceFormat not available.\n");
++ return 0;
++ }
++
++ TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes);
++ return ADAPTER_OUTPUT.nmodes;
++}
++
++static HRESULT WINAPI
++d3dadapter9_EnumAdapterModes( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DFORMAT Format,
++ UINT Mode,
++ D3DDISPLAYMODE *pMode )
++{
++ HRESULT hr;
++
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++ WARN("Adapter %u does not exist.\n", Adapter);
++ return D3DERR_INVALIDCALL;
++ }
++
++ hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
++ Format, D3DUSAGE_RENDERTARGET,
++ D3DRTYPE_SURFACE, Format);
++ if (FAILED(hr)) {
++ TRACE("DeviceFormat not available.\n");
++ return hr;
++ }
++
++ if (Mode >= ADAPTER_OUTPUT.nmodes) {
++ WARN("Mode %u does not exist.\n", Mode);
++ return D3DERR_INVALIDCALL;
++ }
++
++ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
++ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
++ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
++ pMode->Format = Format;
++
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterDisplayMode( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDISPLAYMODE *pMode )
++{
++ UINT Mode;
++
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++ WARN("Adapter %u does not exist.\n", Adapter);
++ return D3DERR_INVALIDCALL;
++ }
++
++ Mode = ADAPTER_OUTPUT.current;
++ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
++ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
++ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
++ pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format;
++
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceType( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DevType,
++ D3DFORMAT AdapterFormat,
++ D3DFORMAT BackBufferFormat,
++ BOOL bWindowed )
++{
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++ return ADAPTER_PROC(CheckDeviceType,
++ DevType, AdapterFormat, BackBufferFormat, bWindowed);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ D3DFORMAT AdapterFormat,
++ DWORD Usage,
++ D3DRESOURCETYPE RType,
++ D3DFORMAT CheckFormat )
++{
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++ return ADAPTER_PROC(CheckDeviceFormat,
++ DeviceType, AdapterFormat, Usage, RType, CheckFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceMultiSampleType( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ D3DFORMAT SurfaceFormat,
++ BOOL Windowed,
++ D3DMULTISAMPLE_TYPE MultiSampleType,
++ DWORD *pQualityLevels )
++{
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++ return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat,
++ Windowed, MultiSampleType, pQualityLevels);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDepthStencilMatch( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ D3DFORMAT AdapterFormat,
++ D3DFORMAT RenderTargetFormat,
++ D3DFORMAT DepthStencilFormat )
++{
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++ return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat,
++ RenderTargetFormat, DepthStencilFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormatConversion( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ D3DFORMAT SourceFormat,
++ D3DFORMAT TargetFormat )
++{
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++ return ADAPTER_PROC(CheckDeviceFormatConversion,
++ DeviceType, SourceFormat, TargetFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetDeviceCaps( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ D3DCAPS9 *pCaps )
++{
++ HRESULT hr;
++
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++
++ hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps);
++ if (FAILED(hr)) { return hr; }
++
++ pCaps->MasterAdapterOrdinal = This->map[Adapter].master;
++ pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master;
++ pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs;
++
++ return hr;
++}
++
++static HMONITOR WINAPI
++d3dadapter9_GetAdapterMonitor( struct d3dadapter9 *This,
++ UINT Adapter )
++{
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return (HMONITOR)0; }
++ return (HMONITOR)ADAPTER_OUTPUT.monitor;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ HWND hFocusWindow,
++ DWORD BehaviorFlags,
++ D3DPRESENT_PARAMETERS *pPresentationParameters,
++ D3DDISPLAYMODEEX *pFullscreenDisplayMode,
++ IDirect3DDevice9Ex **ppReturnedDeviceInterface );
++
++static HRESULT WINAPI
++d3dadapter9_CreateDevice( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ HWND hFocusWindow,
++ DWORD BehaviorFlags,
++ D3DPRESENT_PARAMETERS *pPresentationParameters,
++ IDirect3DDevice9 **ppReturnedDeviceInterface )
++{
++ HRESULT hr;
++ hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow,
++ BehaviorFlags, pPresentationParameters,
++ NULL,
++ (IDirect3DDevice9Ex **)ppReturnedDeviceInterface);
++ if (FAILED(hr))
++ return hr;
++ return D3D_OK;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterModeCountEx( struct d3dadapter9 *This,
++ UINT Adapter,
++ const D3DDISPLAYMODEFILTER *pFilter )
++{
++ return 1;
++}
++
++static HRESULT WINAPI
++d3dadapter9_EnumAdapterModesEx( struct d3dadapter9 *This,
++ UINT Adapter,
++ const D3DDISPLAYMODEFILTER *pFilter,
++ UINT Mode,
++ D3DDISPLAYMODEEX *pMode )
++{
++ FIXME("(%p, %u, %p, %u, %p), stub!\n", This, Adapter, pFilter, Mode, pMode);
++ return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterDisplayModeEx( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDISPLAYMODEEX *pMode,
++ D3DDISPLAYROTATION *pRotation )
++{
++ FIXME("(%p, %u, %p, %p), stub!\n", This, Adapter, pMode, pRotation);
++ return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This,
++ UINT Adapter,
++ D3DDEVTYPE DeviceType,
++ HWND hFocusWindow,
++ DWORD BehaviorFlags,
++ D3DPRESENT_PARAMETERS *pPresentationParameters,
++ D3DDISPLAYMODEEX *pFullscreenDisplayMode,
++ IDirect3DDevice9Ex **ppReturnedDeviceInterface )
++{
++ ID3DPresentGroup *present;
++ HRESULT hr;
++ boolean no_window_changes;
++
++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++ WARN("Adapter %u does not exist.\n", Adapter);
++ return D3DERR_INVALIDCALL;
++ }
++
++ {
++ struct adapter_group *group = &ADAPTER_GROUP;
++ unsigned nparams, ordinal;
++
++ if (BehaviorFlags & D3DCREATE_ADAPTERGROUP_DEVICE) {
++ nparams = group->noutputs;
++ ordinal = 0;
++ } else {
++ nparams = 1;
++ ordinal = Adapter - This->map[Adapter].master;
++ }
++ no_window_changes = !!(BehaviorFlags & D3DCREATE_NOWINDOWCHANGES);
++
++ hr = present_create_present_group(This->gdi_display, group->devname, ordinal,
++ hFocusWindow,
++ pPresentationParameters,
++ nparams, &present, This->ex, no_window_changes);
++ }
++
++ if (FAILED(hr)) {
++ WARN("Failed to create PresentGroup.\n");
++ return hr;
++ }
++
++ if (This->ex) {
++ hr = ADAPTER_PROC(CreateDeviceEx, Adapter, DeviceType, hFocusWindow,
++ BehaviorFlags, pPresentationParameters,
++ pFullscreenDisplayMode,
++ (IDirect3D9Ex *)This, present,
++ ppReturnedDeviceInterface);
++ } else { /* CreateDevice on non-ex */
++ hr = ADAPTER_PROC(CreateDevice, Adapter, DeviceType, hFocusWindow,
++ BehaviorFlags, pPresentationParameters,
++ (IDirect3D9 *)This, present,
++ (IDirect3DDevice9 **)ppReturnedDeviceInterface);
++ }
++ if (FAILED(hr)) {
++ WARN("ADAPTER_PROC failed.\n");
++ ID3DPresentGroup_Release(present);
++ }
++
++ return hr;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterLUID( struct d3dadapter9 *This,
++ UINT Adapter,
++ LUID *pLUID )
++{
++ FIXME("(%p, %u, %p), stub!\n", This, Adapter, pLUID);
++ return D3DERR_INVALIDCALL;
++}
++
++static struct adapter_group *
++add_group( struct d3dadapter9 *This )
++{
++ if (This->ngroups >= This->ngroupsalloc) {
++ void *r;
++
++ if (This->ngroupsalloc == 0) {
++ This->ngroupsalloc = 2;
++ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ This->ngroupsalloc*sizeof(struct adapter_group));
++ } else {
++ This->ngroupsalloc <<= 1;
++ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->groups,
++ This->ngroupsalloc*sizeof(struct adapter_group));
++ }
++
++ if (!r) { return NULL; }
++ This->groups = r;
++ }
++
++ return &This->groups[This->ngroups++];
++}
++
++static void
++remove_group( struct d3dadapter9 *This )
++{
++ struct adapter_group *group = &This->groups[This->ngroups-1];
++ int i;
++
++ for (i = 0; i < group->noutputs; ++i) {
++ HeapFree(GetProcessHeap(), 0, group->outputs[i].modes);
++ }
++ HeapFree(GetProcessHeap(), 0, group->outputs);
++
++ ZeroMemory(group, sizeof(struct adapter_group));
++ This->ngroups--;
++}
++
++static struct output *
++add_output( struct d3dadapter9 *This )
++{
++ struct adapter_group *group = &This->groups[This->ngroups-1];
++
++ if (group->noutputs >= group->noutputsalloc) {
++ void *r;
++
++ if (group->noutputsalloc == 0) {
++ group->noutputsalloc = 2;
++ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ group->noutputsalloc*sizeof(struct output));
++ } else {
++ group->noutputsalloc <<= 1;
++ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, group->outputs,
++ group->noutputsalloc*sizeof(struct output));
++ }
++
++ if (!r) { return NULL; }
++ group->outputs = r;
++ }
++
++ return &group->outputs[group->noutputs++];
++}
++
++static void
++remove_output( struct d3dadapter9 *This )
++{
++ struct adapter_group *group = &This->groups[This->ngroups-1];
++ struct output *out = &group->outputs[group->noutputs-1];
++
++ HeapFree(GetProcessHeap(), 0, out->modes);
++
++ ZeroMemory(out, sizeof(struct output));
++ group->noutputs--;
++}
++
++static D3DDISPLAYMODEEX *
++add_mode( struct d3dadapter9 *This )
++{
++ struct adapter_group *group = &This->groups[This->ngroups-1];
++ struct output *out = &group->outputs[group->noutputs-1];
++
++ if (out->nmodes >= out->nmodesalloc) {
++ void *r;
++
++ if (out->nmodesalloc == 0) {
++ out->nmodesalloc = 8;
++ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
++ } else {
++ out->nmodesalloc <<= 1;
++ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, out->modes,
++ out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
++ }
++
++ if (!r) { return NULL; }
++ out->modes = r;
++ }
++
++ return &out->modes[out->nmodes++];
++}
++
++static void
++remove_mode( struct d3dadapter9 *This )
++{
++ struct adapter_group *group = &This->groups[This->ngroups-1];
++ struct output *out = &group->outputs[group->noutputs-1];
++ out->nmodes--;
++}
++
++#ifndef DM_INTERLACED
++#define DM_INTERLACED 2
++#endif /* DM_INTERLACED */
++
++static HRESULT
++fill_groups( struct d3dadapter9 *This )
++{
++ DISPLAY_DEVICEW dd;
++ DEVMODEW dm;
++ POINT pt;
++ HDC hdc;
++ HRESULT hr;
++ int i, j, k;
++
++ WCHAR wdisp[] = {'D','I','S','P','L','A','Y',0};
++
++ ZeroMemory(&dd, sizeof(dd));
++ ZeroMemory(&dm, sizeof(dm));
++ dd.cb = sizeof(dd);
++ dm.dmSize = sizeof(dm);
++
++ for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i) {
++ struct adapter_group *group = add_group(This);
++ if (!group) {
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++
++ hdc = CreateDCW(wdisp, dd.DeviceName, NULL, NULL);
++ if (!hdc) {
++ remove_group(This);
++ WARN("Unable to create DC for display %d.\n", i);
++ goto end_group;
++ }
++
++ hr = present_create_adapter9(This->gdi_display, hdc, &group->adapter);
++ DeleteDC(hdc);
++ if (FAILED(hr)) {
++ remove_group(This);
++ goto end_group;
++ }
++
++ CopyMemory(group->devname, dd.DeviceName, sizeof(group->devname));
++ for (j = 0; EnumDisplayDevicesW(group->devname, j, &dd, 0); ++j) {
++ struct output *out = add_output(This);
++ boolean orient = FALSE, monit = FALSE;
++ if (!out) {
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++
++ for (k = 0; EnumDisplaySettingsExW(dd.DeviceName, k, &dm, 0); ++k) {
++ D3DDISPLAYMODEEX *mode = add_mode(This);
++ if (!out) {
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++
++ mode->Size = sizeof(D3DDISPLAYMODEEX);
++ mode->Width = dm.dmPelsWidth;
++ mode->Height = dm.dmPelsHeight;
++ mode->RefreshRate = dm.dmDisplayFrequency;
++ mode->ScanLineOrdering =
++ (dm.dmDisplayFlags & DM_INTERLACED) ?
++ D3DSCANLINEORDERING_INTERLACED :
++ D3DSCANLINEORDERING_PROGRESSIVE;
++
++ switch (dm.dmBitsPerPel) {
++ case 32: mode->Format = D3DFMT_X8R8G8B8; break;
++ case 24: mode->Format = D3DFMT_R8G8B8; break;
++ case 16: mode->Format = D3DFMT_R5G6B5; break;
++ case 8:
++ remove_mode(This);
++ goto end_mode;
++
++ default:
++ remove_mode(This);
++ WARN("Unknown format (%u bpp) in display %d, monitor "
++ "%d, mode %d.\n", dm.dmBitsPerPel, i, j, k);
++ goto end_mode;
++ }
++
++ if (!orient) {
++ switch (dm.dmDisplayOrientation) {
++ case DMDO_DEFAULT:
++ out->rotation = D3DDISPLAYROTATION_IDENTITY;
++ break;
++
++ case DMDO_90:
++ out->rotation = D3DDISPLAYROTATION_90;
++ break;
++
++ case DMDO_180:
++ out->rotation = D3DDISPLAYROTATION_180;
++ break;
++
++ case DMDO_270:
++ out->rotation = D3DDISPLAYROTATION_270;
++ break;
++
++ default:
++ remove_output(This);
++ WARN("Unknown display rotation in display %d, "
++ "monitor %d\n", i, j);
++ goto end_output;
++ }
++ orient = TRUE;
++ }
++
++ if (!monit) {
++ pt.x = dm.dmPosition.x;
++ pt.y = dm.dmPosition.y;
++ out->monitor = MonitorFromPoint(pt, 0);
++ if (!out->monitor) {
++ remove_output(This);
++ WARN("Unable to get monitor handle for display %d, "
++ "monitor %d.\n", i, j);
++ goto end_output;
++ }
++ monit = TRUE;
++ }
++
++end_mode:
++ ZeroMemory(&dm, sizeof(dm));
++ dm.dmSize = sizeof(dm);
++ }
++
++end_output:
++ ZeroMemory(&dd, sizeof(dd));
++ dd.cb = sizeof(dd);
++ }
++
++end_group:
++ ZeroMemory(&dd, sizeof(dd));
++ dd.cb = sizeof(dd);
++ }
++
++ return D3D_OK;
++}
++
++static IDirect3D9ExVtbl d3dadapter9_vtable = {
++ (void *)d3dadapter9_QueryInterface,
++ (void *)d3dadapter9_AddRef,
++ (void *)d3dadapter9_Release,
++ (void *)d3dadapter9_RegisterSoftwareDevice,
++ (void *)d3dadapter9_GetAdapterCount,
++ (void *)d3dadapter9_GetAdapterIdentifier,
++ (void *)d3dadapter9_GetAdapterModeCount,
++ (void *)d3dadapter9_EnumAdapterModes,
++ (void *)d3dadapter9_GetAdapterDisplayMode,
++ (void *)d3dadapter9_CheckDeviceType,
++ (void *)d3dadapter9_CheckDeviceFormat,
++ (void *)d3dadapter9_CheckDeviceMultiSampleType,
++ (void *)d3dadapter9_CheckDepthStencilMatch,
++ (void *)d3dadapter9_CheckDeviceFormatConversion,
++ (void *)d3dadapter9_GetDeviceCaps,
++ (void *)d3dadapter9_GetAdapterMonitor,
++ (void *)d3dadapter9_CreateDevice,
++ (void *)d3dadapter9_GetAdapterModeCountEx,
++ (void *)d3dadapter9_EnumAdapterModesEx,
++ (void *)d3dadapter9_GetAdapterDisplayModeEx,
++ (void *)d3dadapter9_CreateDeviceEx,
++ (void *)d3dadapter9_GetAdapterLUID
++};
++
++HRESULT
++d3dadapter9_new( Display *gdi_display,
++ boolean ex,
++ IDirect3D9Ex **ppOut )
++{
++ struct d3dadapter9 *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ sizeof(struct d3dadapter9));
++ HRESULT hr;
++ unsigned i, j, k;
++
++ if (!This) {
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++
++ This->vtable = &d3dadapter9_vtable;
++ This->refs = 1;
++ This->ex = ex;
++ This->gdi_display = gdi_display;
++
++ if (!has_d3dadapter(gdi_display)) {
++ ERR("Your display driver doesn't support native D3D9 adapters.\n");
++ d3dadapter9_Release(This);
++ return D3DERR_NOTAVAILABLE;
++ }
++
++ hr = fill_groups(This);
++ if (FAILED(hr)) {
++ d3dadapter9_Release(This);
++ return hr;
++ }
++
++ /* map absolute adapter IDs with internal adapters */
++ for (i = 0; i < This->ngroups; ++i) {
++ for (j = 0; j < This->groups[i].noutputs; ++j) {
++ This->nadapters++;
++ }
++ }
++ if (This->nadapters == 0) {
++ ERR("No available native adapters in system.\n");
++ d3dadapter9_Release(This);
++ return D3DERR_NOTAVAILABLE;
++ }
++
++ This->map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ This->nadapters*sizeof(struct adapter_map));
++ if (!This->map) {
++ d3dadapter9_Release(This);
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++ for (i = k = 0; i < This->ngroups; ++i) {
++ for (j = 0; j < This->groups[i].noutputs; ++j, ++k) {
++ This->map[k].master = k-j;
++ This->map[k].group = i;
++ }
++ }
++
++ *ppOut = (IDirect3D9Ex *)This;
++ FIXME("\033[1;32m\nNative Direct3D 9 is active."
++ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++ return D3D_OK;
++}
+diff --git a/dlls/d3d9-nine/d3dadapter9.h b/dlls/d3d9-nine/d3dadapter9.h
+new file mode 100644
+index 0000000..2fafdf2
+--- /dev/null
++++ b/dlls/d3d9-nine/d3dadapter9.h
+@@ -0,0 +1,30 @@
++/*
++ * D3DAdapter9 interface
++ *
++ * Copyright 2015 Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#ifndef __WINE_D3D9ADAPTER_H
++#define __WINE_D3D9ADAPTER_H
++
++#include <X11/Xlib.h>
++
++void d3dadapter9_init(HINSTANCE hinst);
++void d3dadapter9_destroy(HINSTANCE hinst);
++HRESULT d3dadapter9_new(Display *gdi_display, boolean ex, IDirect3D9Ex **ppOut);
++
++#endif /* __WINE_D3D9ADAPTER_H */
+diff --git a/dlls/d3d9-nine/dri3.c b/dlls/d3d9-nine/dri3.c
+new file mode 100644
+index 0000000..d147b23
+--- /dev/null
++++ b/dlls/d3d9-nine/dri3.c
+@@ -0,0 +1,1344 @@
++/*
++ * Wine DRI3 interface
++ *
++ * Copyright 2014-2015 Axel Davy
++ * Copyright 2015 Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++
++#include "config.h"
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter);
++
++#include <d3dadapter/d3dadapter9.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <pthread.h>
++
++#include "dri3.h"
++#include "winbase.h" /* for Sleep */
++
++#ifdef D3DADAPTER9_DRI2
++#include <unistd.h>
++#include <sys/ioctl.h>
++#include <stdio.h>
++#include <string.h>
++
++#define BOOL X_BOOL
++#define BYTE X_BYTE
++#define INT8 X_INT8
++#define INT16 X_INT16
++#define INT32 X_INT32
++#define INT64 X_INT64
++#include <X11/Xmd.h>
++#include <X11/Xproto.h>
++#undef BOOL
++#undef BYTE
++#undef INT8
++#undef INT16
++#undef INT32
++#undef INT64
++#undef LONG64
++
++#include <X11/Xlibint.h>
++#include <X11/extensions/dri2tokens.h>
++#include <X11/extensions/dri2proto.h>
++#include <X11/extensions/extutil.h>
++#define GL_GLEXT_PROTOTYPES 1
++#define EGL_EGLEXT_PROTOTYPES 1
++#define GL_GLEXT_LEGACY 1
++#include <GL/gl.h>
++/* workaround gl header bug */
++#define glBlendColor glBlendColorLEV
++#define glBlendEquation glBlendEquationLEV
++#include <GL/glext.h>
++#include <EGL/egl.h>
++#include <EGL/eglext.h>
++#include <libdrm/drm_fourcc.h>
++#include <libdrm/drm.h>
++/*GLAPI void GLAPIENTRY glFlush( void );
++
++GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
++GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer);
++GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
++GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
++GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
++GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
++GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures);
++EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);*/
++
++typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
++typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
++typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
++
++#endif
++
++BOOL
++DRI3CheckExtension(Display *dpy, int major, int minor)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_dri3_query_version_cookie_t dri3_cookie;
++ xcb_dri3_query_version_reply_t *dri3_reply;
++ xcb_generic_error_t *error;
++ const xcb_query_extension_reply_t *extension;
++ int fd;
++
++ xcb_prefetch_extension_data(xcb_connection, &xcb_dri3_id);
++
++ extension = xcb_get_extension_data(xcb_connection, &xcb_dri3_id);
++ if (!(extension && extension->present)) {
++ ERR("DRI3 extension is not present\n");
++ return FALSE;
++ }
++
++ dri3_cookie = xcb_dri3_query_version(xcb_connection, major, minor);
++
++ dri3_reply = xcb_dri3_query_version_reply(xcb_connection, dri3_cookie, &error);
++ if (!dri3_reply) {
++ free(error);
++ ERR("Issue getting requested version of DRI3: %d,%d\n", major, minor);
++ return FALSE;
++ }
++
++ if (!DRI3Open(dpy, DefaultScreen(dpy), &fd)) {
++ ERR("DRI3 advertised, but not working\n");
++ return FALSE;
++ }
++ close(fd);
++
++ TRACE("DRI3 version %d,%d found. %d %d requested\n", major, minor, (int)dri3_reply->major_version, (int)dri3_reply->minor_version);
++ free(dri3_reply);
++
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++struct DRI2priv {
++ Display *dpy;
++ EGLDisplay display;
++ EGLContext context;
++ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
++ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
++ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
++};
++
++/* TODO: We don't free memory properly. When exiting, eglTerminate doesn't work well(crash), and things are freed automatically. Rely on it */
++
++BOOL
++DRI2FallbackInit(Display *dpy, struct DRI2priv **priv)
++{
++ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
++ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
++ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT_func;
++ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
++ EGLDisplay display;
++ EGLint major, minor;
++ EGLConfig config;
++ EGLContext context;
++ EGLint i;
++ EGLBoolean b;
++ EGLenum current_api = 0;
++ const char *extensions;
++ EGLint config_attribs[] = {
++ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
++ EGL_NONE
++ };
++ EGLint context_compatibility_attribs[] = {
++ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
++ EGL_NONE
++ };
++
++ current_api = eglQueryAPI();
++ eglGetPlatformDisplayEXT_func = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT");
++ if (!eglGetPlatformDisplayEXT_func)
++ return FALSE;
++ display = eglGetPlatformDisplayEXT_func(EGL_PLATFORM_X11_EXT, dpy, NULL);
++ if (!display)
++ return FALSE;
++ if (eglInitialize(display, &major, &minor) != EGL_TRUE)
++ goto clean_egl_display;
++
++ extensions = eglQueryString(display, EGL_CLIENT_APIS);
++ if (!extensions || !strstr(extensions, "OpenGL"))
++ goto clean_egl_display;
++
++ extensions = eglQueryString(display, EGL_EXTENSIONS);
++ if (!extensions || !strstr(extensions, "EGL_EXT_image_dma_buf_import") ||
++ !strstr(extensions, "EGL_KHR_create_context") ||
++ !strstr(extensions, "EGL_KHR_surfaceless_context") ||
++ !strstr(extensions, "EGL_KHR_image_base"))
++ goto clean_egl_display;
++
++ if (!eglChooseConfig(display, config_attribs, &config, 1, &i))
++ goto clean_egl_display;
++
++ b = eglBindAPI(EGL_OPENGL_API);
++ if (b == EGL_FALSE)
++ goto clean_egl_display;
++ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_compatibility_attribs);
++ if (context == EGL_NO_CONTEXT)
++ goto clean_egl_display;
++
++ glEGLImageTargetTexture2DOES_func = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES");
++ eglCreateImageKHR_func = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
++ eglDestroyImageKHR_func = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
++ if (!eglCreateImageKHR_func || !glEGLImageTargetTexture2DOES_func || !eglDestroyImageKHR_func) {
++ ERR("eglGetProcAddress failed !");
++ goto clean_egl_display;
++ }
++
++ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++
++ *priv = calloc(1, sizeof(struct DRI2priv));
++ if (!*priv)
++ goto clean_egl;
++ (*priv)->dpy = dpy;
++ (*priv)->display = display;
++ (*priv)->context = context;
++ (*priv)->glEGLImageTargetTexture2DOES_func = glEGLImageTargetTexture2DOES_func;
++ (*priv)->eglCreateImageKHR_func = eglCreateImageKHR_func;
++ (*priv)->eglDestroyImageKHR_func = eglDestroyImageKHR_func;
++ eglBindAPI(current_api);
++ return TRUE;
++
++clean_egl:
++clean_egl_display:
++ eglTerminate(display);
++ eglBindAPI(current_api);
++ return FALSE;
++}
++
++/* hypothesis: at this step all textures, etc are destroyed */
++void
++DRI2FallbackDestroy(struct DRI2priv *priv)
++{
++ EGLenum current_api;
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ eglMakeCurrent(priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglDestroyContext(priv->display, priv->context);
++ eglTerminate(priv->display);
++ eglBindAPI(current_api);
++ free(priv);
++}
++
++BOOL
++DRI2FallbackCheckSupport(Display *dpy)
++{
++ struct DRI2priv *priv;
++ int fd;
++ if (!DRI2FallbackInit(dpy, &priv))
++ return FALSE;
++ DRI2FallbackDestroy(priv);
++ if (!DRI2FallbackOpen(dpy, DefaultScreen(dpy), &fd))
++ return FALSE;
++ close(fd);
++ return TRUE;
++}
++
++#endif
++
++BOOL
++PRESENTCheckExtension(Display *dpy, int major, int minor)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_present_query_version_cookie_t present_cookie;
++ xcb_present_query_version_reply_t *present_reply;
++ xcb_generic_error_t *error;
++ const xcb_query_extension_reply_t *extension;
++
++ xcb_prefetch_extension_data(xcb_connection, &xcb_present_id);
++
++ extension = xcb_get_extension_data(xcb_connection, &xcb_present_id);
++ if (!(extension && extension->present)) {
++ ERR("PRESENT extension is not present\n");
++ return FALSE;
++ }
++
++ present_cookie = xcb_present_query_version(xcb_connection, major, minor);
++
++ present_reply = xcb_present_query_version_reply(xcb_connection, present_cookie, &error);
++ if (!present_reply) {
++ free(error);
++ ERR("Issue getting requested version of PRESENT: %d,%d\n", major, minor);
++ return FALSE;
++ }
++
++ TRACE("PRESENT version %d,%d found. %d %d requested\n", major, minor, (int)present_reply->major_version, (int)present_reply->minor_version);
++ free(present_reply);
++
++ return TRUE;
++}
++
++BOOL
++DRI3Open(Display *dpy, int screen, int *device_fd)
++{
++ xcb_dri3_open_cookie_t cookie;
++ xcb_dri3_open_reply_t *reply;
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ int fd;
++ Window root = RootWindow(dpy, screen);
++
++ cookie = xcb_dri3_open(xcb_connection, root, 0);
++
++ reply = xcb_dri3_open_reply(xcb_connection, cookie, NULL);
++ if (!reply)
++ return FALSE;
++
++ if (reply->nfd != 1) {
++ free(reply);
++ return FALSE;
++ }
++
++ fd = xcb_dri3_open_reply_fds(xcb_connection, reply)[0];
++ fcntl(fd, F_SETFD, FD_CLOEXEC);
++
++ *device_fd = fd;
++ free(reply);
++
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++static XExtensionInfo _dri2_info_data;
++static XExtensionInfo *dri2_info = &_dri2_info_data;
++static char dri2_name[] = DRI2_NAME;
++
++#define DRI2CheckExtension(dpy, i, val) \
++ XextCheckExtension(dpy, i, dri2_name, val)
++
++
++static int
++close_display(Display *dpy,
++ XExtCodes *codes);
++static Bool
++wire_to_event(Display *dpy,
++ XEvent *re,
++ xEvent *event);
++static Status
++event_to_wire(Display *dpy,
++ XEvent *re,
++ xEvent *event);
++static int
++error( Display *dpy,
++ xError *err,
++ XExtCodes *codes,
++ int *ret_code );
++static XExtensionHooks dri2_hooks = {
++ NULL, /* create_gc */
++ NULL, /* copy_gc */
++ NULL, /* flush_gc */
++ NULL, /* free_gc */
++ NULL, /* create_font */
++ NULL, /* free_font */
++ close_display, /* close_display */
++ wire_to_event, /* wire_to_event */
++ event_to_wire, /* event_to_wire */
++ error, /* error */
++ NULL, /* error_string */
++};
++static XEXT_GENERATE_CLOSE_DISPLAY(close_display, dri2_info);
++static XEXT_GENERATE_FIND_DISPLAY(find_display, dri2_info,
++ dri2_name, &dri2_hooks, 0, NULL);
++static Bool
++wire_to_event(Display *dpy,
++ XEvent *re,
++ xEvent *event)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ DRI2CheckExtension(dpy, info, False);
++ TRACE("dri2 wire_to_event\n");
++ return False;
++}
++static Status
++event_to_wire(Display *dpy,
++ XEvent *re,
++ xEvent *event)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ DRI2CheckExtension(dpy, info, False);
++ TRACE("dri2 event_to_wire\n");
++ return False;
++}
++static int
++error(Display *dpy,
++ xError *err,
++ XExtCodes *codes,
++ int *ret_code)
++{
++ TRACE("dri2 error\n");
++ return False;
++}
++
++#define XALIGN(x) (((x) + 3) & (~3))
++
++static BOOL
++DRI2Connect(Display *dpy,
++ XID window,
++ unsigned driver_type,
++ char **device )
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ xDRI2ConnectReply rep;
++ xDRI2ConnectReq *req;
++ int dev_len, driv_len;
++ char *driver;
++
++ DRI2CheckExtension(dpy, info, False);
++
++ LockDisplay(dpy);
++ GetReq(DRI2Connect, req);
++ req->reqType = info->codes->major_opcode;
++ req->dri2ReqType = X_DRI2Connect;
++ req->window = window;
++ req->driverType = driver_type;
++ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++
++ /* check string lengths */
++ dev_len = rep.deviceNameLength;
++ driv_len = rep.driverNameLength;
++ if (dev_len == 0 || driv_len == 0) {
++ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++
++ /* read out driver */
++ driver = HeapAlloc(GetProcessHeap(), 0, driv_len + 1);
++ if (!driver) {
++ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ _XReadPad(dpy, driver, driv_len);
++ HeapFree(GetProcessHeap(), 0, driver); /* we don't need the driver */
++
++ /* read out device */
++ *device = HeapAlloc(GetProcessHeap(), 0, dev_len + 1);
++ if (!*device) {
++ _XEatData(dpy, XALIGN(dev_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ _XReadPad(dpy, *device, dev_len);
++ (*device)[dev_len] = '\0';
++
++ UnlockDisplay(dpy);
++ SyncHandle();
++
++ return True;
++}
++
++static Bool
++DRI2Authenticate(Display *dpy,
++ XID window,
++ uint32_t token)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ xDRI2AuthenticateReply rep;
++ xDRI2AuthenticateReq *req;
++
++ DRI2CheckExtension(dpy, info, False);
++
++ LockDisplay(dpy);
++ GetReq(DRI2Authenticate, req);
++ req->reqType = info->codes->major_opcode;
++ req->dri2ReqType = X_DRI2Authenticate;
++ req->window = window;
++ req->magic = token;
++ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ UnlockDisplay(dpy);
++ SyncHandle();
++
++ return rep.authenticated ? True : False;
++}
++
++BOOL
++DRI2FallbackOpen(Display *dpy, int screen, int *device_fd)
++{
++ char *device;
++ int fd;
++ Window root = RootWindow(dpy, screen);
++ drm_auth_t auth;
++
++ if (!DRI2Connect(dpy, root, DRI2DriverDRI, &device))
++ return FALSE;
++
++ fd = open(device, O_RDWR);
++ HeapFree(GetProcessHeap(), 0, device);
++ if (fd < 0)
++ return FALSE;
++
++ if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth) != 0) {
++ close(fd);
++ return FALSE;
++ }
++
++ if (!DRI2Authenticate(dpy, root, auth.magic)) {
++ close(fd);
++ return FALSE;
++ }
++
++ *device_fd = fd;
++
++ return TRUE;
++}
++
++#endif
++
++
++BOOL
++DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ Window root = RootWindow(dpy, screen);
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++
++ cookie = xcb_dri3_pixmap_from_buffer_checked(xcb_connection,
++ (*pixmap = xcb_generate_id(xcb_connection)),
++ root,
++ 0,
++ width, height, stride,
++ depth, bpp, fd);
++ error = xcb_request_check(xcb_connection, cookie); /* performs a flush */
++ if (error) {
++ ERR("Error using DRI3 to convert a DmaBufFd to pixmap\n");
++ return FALSE;
++ }
++ return TRUE;
++}
++
++BOOL
++DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
++ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
++
++ bp_cookie = xcb_dri3_buffer_from_pixmap(xcb_connection, pixmap);
++ bp_reply = xcb_dri3_buffer_from_pixmap_reply(xcb_connection, bp_cookie, NULL);
++ if (!bp_reply)
++ return FALSE;
++ *fd = xcb_dri3_buffer_from_pixmap_reply_fds(xcb_connection, bp_reply)[0];
++ *width = bp_reply->width;
++ *height = bp_reply->height;
++ *stride = bp_reply->stride;
++ *depth = bp_reply->depth;
++ *bpp = bp_reply->depth;
++ return TRUE;
++}
++
++struct PRESENTPriv {
++ xcb_connection_t *xcb_connection;
++ xcb_connection_t *xcb_connection_bis; /* to avoid libxcb thread bugs, use a different connection to present pixmaps */
++ XID window;
++ uint64_t last_msc;
++ uint64_t last_target;
++ uint32_t last_serial_given;
++ xcb_special_event_t *special_event;
++ PRESENTPixmapPriv *first_present_priv;
++ int pixmap_present_pending;
++ BOOL notify_with_serial_pending;
++ pthread_mutex_t mutex_present; /* protect readind/writing present_priv things */
++ pthread_mutex_t mutex_xcb_wait;
++ BOOL xcb_wait;
++};
++
++struct PRESENTPixmapPriv {
++ PRESENTpriv *present_priv;
++ Pixmap pixmap;
++ BOOL released;
++ unsigned int width;
++ unsigned int height;
++ unsigned int depth;
++ BOOL present_complete_pending;
++ uint32_t serial;
++#ifdef D3DADAPTER9_DRI2
++ struct {
++ BOOL is_dri2;
++ struct DRI2priv *dri2_priv;
++ GLuint fbo_read;
++ GLuint fbo_write;
++ GLuint texture_read;
++ GLuint texture_write;
++ } dri2_info;
++#endif
++ BOOL last_present_was_flip;
++ PRESENTPixmapPriv *next;
++};
++
++static PRESENTPixmapPriv *PRESENTFindPixmapPriv(PRESENTpriv *present_priv, uint32_t serial)
++{
++ PRESENTPixmapPriv *current = present_priv->first_present_priv;
++
++ while (current) {
++ if (current->serial == serial)
++ return current;
++ current = current->next;
++ }
++ return NULL;
++}
++
++static void PRESENThandle_events(PRESENTpriv *present_priv, xcb_present_generic_event_t *ge)
++{
++ PRESENTPixmapPriv *present_pixmap_priv = NULL;
++
++ switch (ge->evtype) {
++ case XCB_PRESENT_COMPLETE_NOTIFY: {
++ xcb_present_complete_notify_event_t *ce = (void *) ge;
++ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC) {
++ if (ce->serial)
++ present_priv->notify_with_serial_pending = FALSE;
++ free(ce);
++ return;
++ }
++ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ce->serial);
++ if (!present_pixmap_priv || ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
++ ERR("FATAL ERROR: PRESENT handling failed\n");
++ free(ce);
++ return;
++ }
++ present_pixmap_priv->present_complete_pending = FALSE;
++ switch (ce->mode) {
++ case XCB_PRESENT_COMPLETE_MODE_FLIP:
++ present_pixmap_priv->last_present_was_flip = TRUE;
++ break;
++ case XCB_PRESENT_COMPLETE_MODE_COPY:
++ present_pixmap_priv->last_present_was_flip = FALSE;
++ break;
++ }
++ present_priv->pixmap_present_pending--;
++ present_priv->last_msc = ce->msc;
++ break;
++ }
++ case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
++ xcb_present_idle_notify_event_t *ie = (void *) ge;
++ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ie->serial);
++ if (!present_pixmap_priv || present_pixmap_priv->pixmap != ie->pixmap) {
++ ERR("FATAL ERROR: PRESENT handling failed\n");
++ free(ie);
++ return;
++ }
++ present_pixmap_priv->released = TRUE;
++ break;
++ }
++ }
++ free(ge);
++}
++
++static void PRESENTflush_events(PRESENTpriv *present_priv, BOOL assert_no_other_thread_waiting)
++{
++ xcb_generic_event_t *ev;
++
++ if ((present_priv->xcb_wait && !assert_no_other_thread_waiting) || /* don't steal events to someone waiting */
++ !present_priv->special_event)
++ return;
++
++ while ((ev = xcb_poll_for_special_event(present_priv->xcb_connection, present_priv->special_event)) != NULL) {
++ PRESENThandle_events(present_priv, (void *) ev);
++ }
++}
++
++static BOOL PRESENTwait_events(PRESENTpriv *present_priv, BOOL allow_other_threads)
++{
++ xcb_generic_event_t *ev;
++
++ if (allow_other_threads) {
++ present_priv->xcb_wait = TRUE;
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ }
++ ev = xcb_wait_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ if (allow_other_threads) {
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_lock(&present_priv->mutex_present);
++ present_priv->xcb_wait = FALSE;
++ }
++ if (!ev) {
++ ERR("FATAL error: xcb had an error\n");
++ return FALSE;
++ }
++
++ PRESENThandle_events(present_priv, (void *) ev);
++ return TRUE;
++}
++
++static struct xcb_connection_t *
++create_xcb_connection(Display *dpy)
++{
++ int screen_num = DefaultScreen(dpy);
++ xcb_connection_t *ret;
++ xcb_xfixes_query_version_cookie_t cookie;
++ xcb_xfixes_query_version_reply_t *rep;
++
++ ret = xcb_connect(DisplayString(dpy), &screen_num);
++ cookie = xcb_xfixes_query_version_unchecked(ret, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
++ rep = xcb_xfixes_query_version_reply(ret, cookie, NULL);
++ if (rep)
++ free(rep);
++ return ret;
++}
++
++BOOL
++PRESENTInit(Display *dpy, PRESENTpriv **present_priv)
++{
++ *present_priv = (PRESENTpriv *) calloc(1, sizeof(PRESENTpriv));
++ if (!*present_priv) {
++ return FALSE;
++ }
++ (*present_priv)->xcb_connection = create_xcb_connection(dpy);
++ (*present_priv)->xcb_connection_bis = create_xcb_connection(dpy);
++ pthread_mutex_init(&(*present_priv)->mutex_present, NULL);
++ pthread_mutex_init(&(*present_priv)->mutex_xcb_wait, NULL);
++ return TRUE;
++}
++
++static void PRESENTForceReleases(PRESENTpriv *present_priv)
++{
++ PRESENTPixmapPriv *current = NULL;
++
++ if (!present_priv->window)
++ return;
++
++ /* There should be no other thread listening for events here.
++ * This can happen when hDestWindowOverride changes without reset.
++ * This case should never happen, but can happen in theory.*/
++ if (present_priv->xcb_wait) {
++ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 0, 0, 0, 0);
++ xcb_flush(present_priv->xcb_connection);
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ /* the problem here is that we don't have access to the event the other thread got.
++ * It is either presented event, idle event or notify event.
++ */
++ while (present_priv->pixmap_present_pending >= 2)
++ PRESENTwait_events(present_priv, FALSE);
++ PRESENTflush_events(present_priv, TRUE);
++ /* Remaining events to come can be a pair of present/idle,
++ * or an idle, or nothing. To be sure we are after all pixmaps
++ * have been presented, add an event to the queue that can only
++ * be after the present event, then if we receive an event more,
++ * we are sure all pixmaps were presented */
++ present_priv->notify_with_serial_pending = TRUE;
++ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 1, present_priv->last_target + 5, 0, 0);
++ xcb_flush(present_priv->xcb_connection);
++ while (present_priv->notify_with_serial_pending)
++ PRESENTwait_events(present_priv, FALSE);
++ /* Now we are sure we are not expecting any new event */
++ } else {
++ while (present_priv->pixmap_present_pending) /* wait all sent pixmaps are presented */
++ PRESENTwait_events(present_priv, FALSE);
++ PRESENTflush_events(present_priv, TRUE); /* may be remaining idle event */
++ /* Since idle events are send with the complete events when it is not flips,
++ * we are not expecting any new event here */
++ }
++
++ current = present_priv->first_present_priv;
++ while (current) {
++ if (!current->released) {
++ if (!current->last_present_was_flip && !present_priv->xcb_wait) {
++ ERR("ERROR: a pixmap seems not released by PRESENT for no reason. Code bug.\n");
++ } else {
++ /* Present the same pixmap with a non-valid part to force the copy mode and the releases */
++ xcb_xfixes_region_t valid, update;
++ xcb_rectangle_t rect_update;
++ rect_update.x = 0;
++ rect_update.y = 0;
++ rect_update.width = 8;
++ rect_update.height = 1;
++ valid = xcb_generate_id(present_priv->xcb_connection);
++ update = xcb_generate_id(present_priv->xcb_connection);
++ xcb_xfixes_create_region(present_priv->xcb_connection, valid, 1, &rect_update);
++ xcb_xfixes_create_region(present_priv->xcb_connection, update, 1, &rect_update);
++ /* here we know the pixmap has been presented. Thus if it is on screen,
++ * the following request can only make it released by the server if it is not */
++ xcb_present_pixmap(present_priv->xcb_connection, present_priv->window,
++ current->pixmap, 0, valid, update, 0, 0, None, None,
++ None, XCB_PRESENT_OPTION_COPY | XCB_PRESENT_OPTION_ASYNC, 0, 0, 0, 0, NULL);
++ xcb_flush(present_priv->xcb_connection);
++ PRESENTwait_events(present_priv, FALSE); /* by assumption this can only be idle event */
++ PRESENTflush_events(present_priv, TRUE); /* Shoudln't be needed */
++ }
++ }
++ current = current->next;
++ }
++ /* Now all pixmaps are released (possibility if xcb_wait is true that one is not aware yet),
++ * and we don't expect any new Present event to come from Xserver */
++}
++
++static void PRESENTFreeXcbQueue(PRESENTpriv *present_priv)
++{
++ if (present_priv->window) {
++ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ present_priv->last_msc = 0;
++ present_priv->last_target = 0;
++ present_priv->special_event = NULL;
++ }
++}
++
++static BOOL PRESENTPrivChangeWindow(PRESENTpriv *present_priv, XID window)
++{
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++ xcb_present_event_t eid;
++
++ PRESENTForceReleases(present_priv);
++ PRESENTFreeXcbQueue(present_priv);
++ present_priv->window = window;
++
++ if (window) {
++ cookie = xcb_present_select_input_checked(present_priv->xcb_connection,
++ (eid = xcb_generate_id(present_priv->xcb_connection)),
++ window,
++ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
++ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
++ present_priv->special_event = xcb_register_for_special_xge(present_priv->xcb_connection,
++ &xcb_present_id,
++ eid, NULL);
++ error = xcb_request_check(present_priv->xcb_connection, cookie); /* performs a flush */
++ if (error || !present_priv->special_event) {
++ ERR("FAILED to use the X PRESENT extension. Was the destination a window ?\n");
++ if (present_priv->special_event)
++ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ present_priv->special_event = NULL;
++ present_priv->window = 0;
++ }
++ }
++ return (present_priv->window != 0);
++}
++
++/* Destroy the content, except the link and the struct mem */
++static void
++PRESENTDestroyPixmapContent(Display *dpy, PRESENTPixmapPriv *present_pixmap)
++{
++ XFreePixmap(dpy, present_pixmap->pixmap);
++#ifdef D3DADAPTER9_DRI2
++ if (present_pixmap->dri2_info.is_dri2) {
++ struct DRI2priv *dri2_priv = present_pixmap->dri2_info.dri2_priv;
++ EGLenum current_api;
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_read);
++ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_write);
++ glDeleteTextures(1, &present_pixmap->dri2_info.texture_read);
++ glDeleteTextures(1, &present_pixmap->dri2_info.texture_write);
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ }
++#endif
++}
++
++void
++PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv)
++{
++ PRESENTPixmapPriv *current = NULL;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ PRESENTForceReleases(present_priv);
++
++ current = present_priv->first_present_priv;
++ while (current) {
++ PRESENTPixmapPriv *next = current->next;
++ PRESENTDestroyPixmapContent(dpy, current);
++ free(current);
++ current = next;
++ }
++
++ PRESENTFreeXcbQueue(present_priv);
++
++ xcb_disconnect(present_priv->xcb_connection);
++ xcb_disconnect(present_priv->xcb_connection_bis);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ pthread_mutex_destroy(&present_priv->mutex_present);
++ pthread_mutex_destroy(&present_priv->mutex_xcb_wait);
++
++ free(present_priv);
++}
++
++BOOL
++PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv)
++{
++ xcb_get_geometry_cookie_t cookie;
++ xcb_get_geometry_reply_t *reply;
++
++ cookie = xcb_get_geometry(present_priv->xcb_connection, pixmap);
++ reply = xcb_get_geometry_reply(present_priv->xcb_connection, cookie, NULL);
++
++ if (!reply)
++ return FALSE;
++
++ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv));
++ if (!*present_pixmap_priv) {
++ free(reply);
++ return FALSE;
++ }
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ (*present_pixmap_priv)->released = TRUE;
++ (*present_pixmap_priv)->pixmap = pixmap;
++ (*present_pixmap_priv)->present_priv = present_priv;
++ (*present_pixmap_priv)->next = present_priv->first_present_priv;
++ (*present_pixmap_priv)->width = reply->width;
++ (*present_pixmap_priv)->height = reply->height;
++ (*present_pixmap_priv)->depth = reply->depth;
++#ifdef D3DADAPTER9_DRI2
++ (*present_pixmap_priv)->dri2_info.is_dri2 = FALSE;
++#endif
++ free(reply);
++
++ present_priv->last_serial_given++;
++ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
++ present_priv->first_present_priv = *present_pixmap_priv;
++
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++BOOL
++DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *dri2_priv,
++ int fd, int width, int height, int stride, int depth,
++ int bpp, PRESENTPixmapPriv **present_pixmap_priv)
++{
++ Window root = RootWindow(dri2_priv->dpy, DefaultScreen(dri2_priv->dpy));
++ Pixmap pixmap;
++ EGLImageKHR image;
++ GLuint texture_read, texture_write, fbo_read, fbo_write;
++ EGLint attribs[] = {
++ EGL_WIDTH, 0,
++ EGL_HEIGHT, 0,
++ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
++ EGL_DMA_BUF_PLANE0_FD_EXT, 0,
++ EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
++ EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
++ EGL_NONE
++ };
++ EGLenum current_api;
++ int status;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ pixmap = XCreatePixmap(dri2_priv->dpy, root, width, height, 24);
++ if (!pixmap)
++ goto fail;
++
++ attribs[1] = width;
++ attribs[3] = height;
++ attribs[7] = fd;
++ attribs[11] = stride;
++
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++
++ /* We bind the dma-buf to a EGLImage, then to a texture, and then to a fbo.
++ * Note that we can delete the EGLImage, but we shouldn't delete the texture,
++ * else the fbo is invalid */
++
++ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
++ EGL_NO_CONTEXT,
++ EGL_LINUX_DMA_BUF_EXT,
++ NULL, attribs);
++
++ if (image == EGL_NO_IMAGE_KHR)
++ goto fail;
++ close(fd);
++
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glGenTextures(1, &texture_read);
++ glBindTexture(GL_TEXTURE_2D, texture_read);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
++ glGenFramebuffers(1, &fbo_read);
++ glBindFramebuffer(GL_FRAMEBUFFER, fbo_read);
++ glFramebufferTexture2D(GL_FRAMEBUFFER,
++ GL_COLOR_ATTACHMENT0,
++ GL_TEXTURE_2D, texture_read,
++ 0);
++ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
++ if (status != GL_FRAMEBUFFER_COMPLETE)
++ goto fail;
++ glBindTexture(GL_TEXTURE_2D, 0);
++ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
++
++ /* We bind a newly created pixmap (to which we want to copy the content)
++ * to an EGLImage, then to a texture, then to a fbo. */
++ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
++ dri2_priv->context,
++ EGL_NATIVE_PIXMAP_KHR,
++ (void *)pixmap, NULL);
++ if (image == EGL_NO_IMAGE_KHR)
++ goto fail;
++
++ glGenTextures(1, &texture_write);
++ glBindTexture(GL_TEXTURE_2D, texture_write);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
++ glGenFramebuffers(1, &fbo_write);
++ glBindFramebuffer(GL_FRAMEBUFFER, fbo_write);
++ glFramebufferTexture2D(GL_FRAMEBUFFER,
++ GL_COLOR_ATTACHMENT0,
++ GL_TEXTURE_2D, texture_write,
++ 0);
++ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
++ if (status != GL_FRAMEBUFFER_COMPLETE)
++ goto fail;
++ glBindTexture(GL_TEXTURE_2D, 0);
++ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++
++ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv));
++ if (!*present_pixmap_priv) {
++ goto fail;
++ }
++
++ (*present_pixmap_priv)->released = TRUE;
++ (*present_pixmap_priv)->pixmap = pixmap;
++ (*present_pixmap_priv)->present_priv = present_priv;
++ (*present_pixmap_priv)->next = present_priv->first_present_priv;
++ (*present_pixmap_priv)->width = width;
++ (*present_pixmap_priv)->height = height;
++ (*present_pixmap_priv)->depth = depth;
++ (*present_pixmap_priv)->dri2_info.is_dri2 = TRUE;
++ (*present_pixmap_priv)->dri2_info.dri2_priv = dri2_priv;
++ (*present_pixmap_priv)->dri2_info.fbo_read = fbo_read;
++ (*present_pixmap_priv)->dri2_info.fbo_write = fbo_write;
++ (*present_pixmap_priv)->dri2_info.texture_read = texture_read;
++ (*present_pixmap_priv)->dri2_info.texture_write = texture_write;
++
++ present_priv->last_serial_given++;
++ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
++ present_priv->first_present_priv = *present_pixmap_priv;
++
++ eglBindAPI(current_api);
++
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++fail:
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++}
++
++#endif
++
++BOOL
++PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++ PRESENTPixmapPriv *current;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ if (present_priv->first_present_priv == present_pixmap_priv) {
++ present_priv->first_present_priv = present_pixmap_priv->next;
++ goto free_priv;
++ }
++
++ current = present_priv->first_present_priv;
++ while (current->next != present_pixmap_priv)
++ current = current->next;
++ current->next = present_pixmap_priv->next;
++free_priv:
++ PRESENTDestroyPixmapContent(dpy, present_pixmap_priv);
++ free(present_pixmap_priv);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++BOOL
++PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++
++ uint32_t v = 0;
++ xcb_gcontext_t gc;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (!present_priv->window) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ xcb_create_gc(present_priv->xcb_connection,
++ (gc = xcb_generate_id(present_priv->xcb_connection)),
++ present_priv->window,
++ XCB_GC_GRAPHICS_EXPOSURES,
++ &v);
++ cookie = xcb_copy_area_checked(present_priv->xcb_connection,
++ present_priv->window,
++ present_pixmap_priv->pixmap,
++ gc,
++ 0, 0, 0, 0,
++ present_pixmap_priv->width,
++ present_pixmap_priv->height);
++ error = xcb_request_check(present_priv->xcb_connection, cookie);
++ xcb_free_gc(present_priv->xcb_connection, gc);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return (error != NULL);
++}
++
++BOOL
++PRESENTPixmap(Display *dpy, XID window,
++ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters,
++ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++#ifdef D3DADAPTER9_DRI2
++ struct DRI2priv *dri2_priv = present_pixmap_priv->dri2_info.dri2_priv;
++ EGLenum current_api;
++#endif
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++ int64_t target_msc, presentationInterval;
++ xcb_xfixes_region_t valid, update;
++ int16_t x_off, y_off;
++ uint32_t options = XCB_PRESENT_OPTION_NONE;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (window != present_priv->window)
++ PRESENTPrivChangeWindow(present_priv, window);
++
++ if (!window) {
++ ERR("ERROR: Try to Present a pixmap on a NULL window\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ PRESENTflush_events(present_priv, FALSE);
++ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ ERR("FATAL ERROR: Trying to Present a pixmap not released\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++#ifdef D3DADAPTER9_DRI2
++ if (present_pixmap_priv->dri2_info.is_dri2) {
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glBindFramebuffer(GL_READ_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_read);
++ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_write);
++
++ glBlitFramebuffer(0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
++ 0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
++ GL_COLOR_BUFFER_BIT, GL_NEAREST);
++ glFlush(); /* Perhaps useless */
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ }
++#endif
++ target_msc = present_priv->last_msc;
++ switch(pPresentationParameters->PresentationInterval) {
++ case D3DPRESENT_INTERVAL_DEFAULT:
++ case D3DPRESENT_INTERVAL_ONE:
++ presentationInterval = 1;
++ break;
++ case D3DPRESENT_INTERVAL_TWO:
++ presentationInterval = 2;
++ break;
++ case D3DPRESENT_INTERVAL_THREE:
++ presentationInterval = 3;
++ break;
++ case D3DPRESENT_INTERVAL_FOUR:
++ presentationInterval = 4;
++ break;
++ case D3DPRESENT_INTERVAL_IMMEDIATE:
++ default:
++ presentationInterval = 0;
++ options |= XCB_PRESENT_OPTION_ASYNC;
++ break;
++ }
++ target_msc += presentationInterval * (present_priv->pixmap_present_pending + 1);
++
++ /* Note: PRESENT defines some way to do partial copy:
++ * presentproto:
++ * 'x-off' and 'y-off' define the location in the window where
++ * the 0,0 location of the pixmap will be presented. valid-area
++ * and update-area are relative to the pixmap.
++ */
++ if (!pSourceRect && !pDestRect && !pDirtyRegion) {
++ valid = 0;
++ update = 0;
++ x_off = 0;
++ y_off = 0;
++ } else {
++ xcb_rectangle_t rect_update;
++ xcb_rectangle_t *rect_updates;
++ int i;
++
++ rect_update.x = 0;
++ rect_update.y = 0;
++ rect_update.width = present_pixmap_priv->width;
++ rect_update.height = present_pixmap_priv->height;
++ x_off = 0;
++ y_off = 0;
++ if (pSourceRect) {
++ x_off = -pSourceRect->left;
++ y_off = -pSourceRect->top;
++ rect_update.x = pSourceRect->left;
++ rect_update.y = pSourceRect->top;
++ rect_update.width = pSourceRect->right - pSourceRect->left;
++ rect_update.height = pSourceRect->bottom - pSourceRect->top;
++ }
++ if (pDestRect) {
++ x_off += pDestRect->left;
++ y_off += pDestRect->top;
++ rect_update.width = pDestRect->right - pDestRect->left;
++ rect_update.height = pDestRect->bottom - pDestRect->top;
++ /* Note: the size of pDestRect and pSourceRect are supposed to be the same size
++ * because the driver would have done things to assure that. */
++ }
++ valid = xcb_generate_id(present_priv->xcb_connection_bis);
++ update = xcb_generate_id(present_priv->xcb_connection_bis);
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, valid, 1, &rect_update);
++ if (pDirtyRegion && pDirtyRegion->rdh.nCount) {
++ rect_updates = (void *) calloc(pDirtyRegion->rdh.nCount, sizeof(xcb_rectangle_t));
++ for (i = 0; i < pDirtyRegion->rdh.nCount; i++)
++ {
++ RECT rc;
++ memcpy(&rc, pDirtyRegion->Buffer + i * sizeof(RECT), sizeof(RECT));
++ rect_update.x = rc.left;
++ rect_update.y = rc.top;
++ rect_update.width = rc.right - rc.left;
++ rect_update.height = rc.bottom - rc.top;
++ memcpy(rect_updates + i * sizeof(xcb_rectangle_t), &rect_update, sizeof(xcb_rectangle_t));
++ }
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, pDirtyRegion->rdh.nCount, rect_updates);
++ free(rect_updates);
++ } else
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, 1, &rect_update);
++ }
++ if (pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY)
++ options |= XCB_PRESENT_OPTION_COPY;
++ cookie = xcb_present_pixmap_checked(present_priv->xcb_connection_bis,
++ window,
++ present_pixmap_priv->pixmap,
++ present_pixmap_priv->serial,
++ valid, update, x_off, y_off,
++ None, None, None, options,
++ target_msc, 0, 0, 0, NULL);
++ error = xcb_request_check(present_priv->xcb_connection_bis, cookie); /* performs a flush */
++
++ if (update)
++ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, update);
++ if (valid)
++ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, valid);
++
++ if (error) {
++ xcb_get_geometry_cookie_t cookie_geom;
++ xcb_get_geometry_reply_t *reply;
++
++ cookie_geom = xcb_get_geometry(present_priv->xcb_connection_bis, window);
++ reply = xcb_get_geometry_reply(present_priv->xcb_connection_bis, cookie_geom, NULL);
++
++ ERR("Error using PRESENT. Here some debug info\n");
++ if (!reply) {
++ ERR("Error querying window info. Perhaps it doesn't exist anymore\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ ERR("Pixmap: width=%d, height=%d, depth=%d\n",
++ present_pixmap_priv->width, present_pixmap_priv->height,
++ present_pixmap_priv->depth);
++ ERR("Window: width=%d, height=%d, depth=%d, x=%d, y=%d\n",
++ (int) reply->width, (int) reply->height,
++ (int) reply->depth, (int) reply->x, (int) reply->y);
++ ERR("Present parameter: PresentationInterval=%d, BackBufferCount=%d, Pending presentations=%d\n",
++ pPresentationParameters->PresentationInterval,
++ pPresentationParameters->BackBufferCount,
++ present_priv->pixmap_present_pending
++ );
++ if (present_pixmap_priv->depth != reply->depth)
++ ERR("Depths are different. PRESENT needs the pixmap and the window have same depth\n");
++ free(reply);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ present_priv->last_target = target_msc;
++ present_priv->pixmap_present_pending++;
++ present_pixmap_priv->present_complete_pending = TRUE;
++ present_pixmap_priv->released = FALSE;
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++BOOL
++PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ PRESENTflush_events(present_priv, FALSE);
++
++ while (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ /* Note: following if should not happen because we'll never
++ * use two PRESENTWaitPixmapReleased in parallels on same window.
++ * However it would make it work in that case */
++ if (present_priv->xcb_wait) { /* we allow only one thread to dispatch events */
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ /* here the other thread got an event but hasn't treated it yet */
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ Sleep(10); /* Let it treat the event */
++ pthread_mutex_lock(&present_priv->mutex_present);
++ } else if (!PRESENTwait_events(present_priv, TRUE)) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ }
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
+diff --git a/dlls/d3d9-nine/dri3.h b/dlls/d3d9-nine/dri3.h
+new file mode 100644
+index 0000000..795c3c7
+--- /dev/null
++++ b/dlls/d3d9-nine/dri3.h
+@@ -0,0 +1,106 @@
++/*
++ * Wine X11DRV DRI3 interface
++ *
++ * Copyright 2014 Axel Davy
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#ifndef __WINE_DRI3_H
++#define __WINE_DRI3_H
++
++#ifndef __WINE_CONFIG_H
++# error You must include config.h to use this header
++#endif
++
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include <X11/Xlib-xcb.h>
++#include <xcb/xcb.h>
++#include <xcb/dri3.h>
++#include <xcb/present.h>
++
++BOOL
++DRI3CheckExtension(Display *dpy, int major, int minor);
++
++#ifdef D3DADAPTER9_DRI2
++struct DRI2priv;
++
++BOOL
++DRI2FallbackInit(Display *dpy, struct DRI2priv **priv);
++
++void
++DRI2FallbackDestroy(struct DRI2priv *priv);
++
++BOOL
++DRI2FallbackCheckSupport(Display *dpy);
++#endif
++
++BOOL
++PRESENTCheckExtension(Display *dpy, int major, int minor);
++
++BOOL
++DRI3Open(Display *dpy, int screen, int *device_fd);
++
++#ifdef D3DADAPTER9_DRI2
++BOOL
++DRI2FallbackOpen(Display *dpy, int screen, int *device_fd);
++#endif
++
++BOOL
++DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap);
++
++BOOL
++DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp);
++
++typedef struct PRESENTPriv PRESENTpriv;
++typedef struct PRESENTPixmapPriv PRESENTPixmapPriv;
++
++BOOL
++PRESENTInit(Display *dpy, PRESENTpriv **present_priv);
++
++/* will clean properly and free all PRESENTPixmapPriv associated to PRESENTpriv.
++ * PRESENTPixmapPriv should not be freed by something else.
++ * If never a PRESENTPixmapPriv has to be destroyed,
++ * please destroy the current PRESENTpriv and create a new one.
++ * This will take care than all pixmaps are released */
++void
++PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv);
++
++BOOL
++PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv);
++
++#ifdef D3DADAPTER9_DRI2
++BOOL
++DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *priv,
++ int fd, int width, int height, int stride, int depth,
++ int bpp, PRESENTPixmapPriv **present_pixmap_priv);
++#endif
++
++BOOL
++PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
++
++BOOL
++PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
++
++BOOL
++PRESENTPixmap(Display *dpy, XID window,
++ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters,
++ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion);
++
++BOOL
++PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv);
++
++#endif /* __WINE_DRI3_H */
+diff --git a/dlls/d3d9-nine/libd3d9-nine.def b/dlls/d3d9-nine/libd3d9-nine.def
+new file mode 100644
+index 0000000..4f41fcb
+--- /dev/null
++++ b/dlls/d3d9-nine/libd3d9-nine.def
+@@ -0,0 +1,16 @@
++; File generated automatically from ./dlls/d3d9-nine/d3d9-nine.spec; do not edit!
++
++LIBRARY d3d9-nine.dll
++
++EXPORTS
++ Direct3DShaderValidatorCreate9@0 @1
++ D3DPERF_BeginEvent@8 @4
++ D3DPERF_EndEvent@0 @5
++ D3DPERF_GetStatus@0 @6
++ D3DPERF_QueryRepeatFrame@0 @7
++ D3DPERF_SetMarker@8 @8
++ D3DPERF_SetOptions@4 @9
++ D3DPERF_SetRegion@8 @10
++ DebugSetMute@0 @12
++ Direct3DCreate9@4 @13
++ Direct3DCreate9Ex@8 @14
+diff --git a/dlls/d3d9-nine/present.c b/dlls/d3d9-nine/present.c
+new file mode 100644
+index 0000000..931c784
+--- /dev/null
++++ b/dlls/d3d9-nine/present.c
+@@ -0,0 +1,1333 @@
++/*
++ * Wine ID3DAdapter9 support functions
++ *
++ * Copyright 2013 Joakim Sindholt
++ * Christoph Bumiller
++ * Copyright 2014 Tiziano Bacocco
++ * David Heidelberger
++ * Copyright 2014-2015 Axel Davy
++ * Copyright 2015 Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#include "config.h"
++#include "wine/port.h"
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter);
++
++#include <d3dadapter/d3dadapter9.h>
++#include <d3dadapter/drm.h>
++#include <libdrm/drm.h>
++#include <errno.h>
++#include <fcntl.h>
++
++#include "dri3.h"
++#include "wine/library.h"
++#include "wine/unicode.h"
++
++#ifndef D3DPRESENT_DONOTWAIT
++#define D3DPRESENT_DONOTWAIT 0x00000001
++#endif
++
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR 1
++#ifdef ID3DPresent_GetWindowOccluded
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 1
++#else
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 0
++#endif
++
++static const struct D3DAdapter9DRM *d3d9_drm = NULL;
++#ifdef D3DADAPTER9_DRI2
++static int is_dri2_fallback = 0;
++#endif
++
++#define X11DRV_ESCAPE 6789
++enum x11drv_escape_codes
++{
++ X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
++ X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
++ X11DRV_START_EXPOSURES, /* start graphics exposures */
++ X11DRV_END_EXPOSURES, /* end graphics exposures */
++ X11DRV_FLUSH_GL_DRAWABLE /* flush changes made to the gl drawable */
++};
++
++struct x11drv_escape_get_drawable
++{
++ enum x11drv_escape_codes code; /* escape code (X11DRV_GET_DRAWABLE) */
++ Drawable drawable; /* X drawable */
++ Drawable gl_drawable; /* GL drawable */
++ int pixel_format; /* internal GL pixel format */
++ RECT dc_rect; /* DC rectangle relative to drawable */
++};
++
++static XContext d3d_hwnd_context;
++static CRITICAL_SECTION context_section;
++static CRITICAL_SECTION_DEBUG critsect_debug =
++{
++ 0, 0, &context_section,
++ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
++ 0, 0, { (DWORD_PTR)(__FILE__ ": context_section") }
++};
++static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 };
++
++const GUID IID_ID3DPresent = { 0x77D60E80, 0xF1E6, 0x11DF, { 0x9E, 0x39, 0x95, 0x0C, 0xDF, 0xD7, 0x20, 0x85 } };
++const GUID IID_ID3DPresentGroup = { 0xB9C3016E, 0xF32A, 0x11DF, { 0x9C, 0x18, 0x92, 0xEA, 0xDE, 0xD7, 0x20, 0x85 } };
++
++struct d3d_drawable
++{
++ Drawable drawable; /* X11 drawable */
++ RECT dc_rect; /* rect relative to the X11 drawable */
++ HDC hdc;
++ HWND wnd; /* HWND (for convenience) */
++};
++
++#ifdef ID3DPresent_GetWindowOccluded
++static HHOOK hhook;
++
++struct d3d_wnd_hooks
++{
++ HWND focus_wnd;
++ struct DRI3Present *present;
++ struct d3d_wnd_hooks *prev;
++ struct d3d_wnd_hooks *next;
++};
++
++static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This );
++static HRESULT dri3_present_register_window_hook( struct DRI3Present *This );
++
++static struct d3d_wnd_hooks d3d_hooks;
++#endif
++
++struct DRI3Present
++{
++ /* COM vtable */
++ void *vtable;
++ /* IUnknown reference count */
++ LONG refs;
++
++ D3DPRESENT_PARAMETERS params;
++ HWND focus_wnd;
++ PRESENTpriv *present_priv;
++#ifdef D3DADAPTER9_DRI2
++ struct DRI2priv *dri2_priv;
++#endif
++
++ WCHAR devname[32];
++ HCURSOR hCursor;
++
++ DEVMODEW initial_mode;
++ BOOL device_needs_reset;
++ BOOL occluded;
++ Display *gdi_display;
++ struct d3d_drawable *d3d;
++ boolean ex;
++ boolean no_window_changes;
++ boolean mode_changed;
++ long style;
++ long style_ex;
++ boolean drop_wnd_messages;
++};
++
++struct D3DWindowBuffer
++{
++ PRESENTPixmapPriv *present_pixmap_priv;
++};
++
++static void
++free_d3dadapter_drawable(struct d3d_drawable *d3d)
++{
++ ReleaseDC(d3d->wnd, d3d->hdc);
++ HeapFree(GetProcessHeap(), 0, d3d);
++}
++
++void
++destroy_d3dadapter_drawable(Display *gdi_display, HWND hwnd)
++{
++ struct d3d_drawable *d3d;
++
++ EnterCriticalSection(&context_section);
++ if (!XFindContext(gdi_display, (XID)hwnd,
++ d3d_hwnd_context, (char **)&d3d)) {
++ XDeleteContext(gdi_display, (XID)hwnd, d3d_hwnd_context);
++ free_d3dadapter_drawable(d3d);
++ }
++ LeaveCriticalSection(&context_section);
++}
++
++static struct d3d_drawable *
++create_d3dadapter_drawable(HWND hwnd)
++{
++ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++ struct d3d_drawable *d3d;
++
++ d3d = HeapAlloc(GetProcessHeap(), 0, sizeof(*d3d));
++ if (!d3d) {
++ ERR("Couldn't allocate d3d_drawable.\n");
++ return NULL;
++ }
++
++ d3d->hdc = GetDCEx(hwnd, 0, DCX_CACHE | DCX_CLIPSIBLINGS);
++ if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++ sizeof(extesc), (LPSTR)&extesc) <= 0) {
++ ERR("Unexpected error in X Drawable lookup (hwnd=%p, hdc=%p)\n",
++ hwnd, d3d->hdc);
++ ReleaseDC(hwnd, d3d->hdc);
++ HeapFree(GetProcessHeap(), 0, d3d);
++ return NULL;
++ }
++
++ d3d->drawable = extesc.drawable;
++ d3d->wnd = hwnd;
++ d3d->dc_rect = extesc.dc_rect;
++
++ return d3d;
++}
++
++static struct d3d_drawable *
++get_d3d_drawable(Display *gdi_display, HWND hwnd)
++{
++ struct d3d_drawable *d3d, *race;
++
++ EnterCriticalSection(&context_section);
++ if (!XFindContext(gdi_display, (XID)hwnd,
++ d3d_hwnd_context, (char **)&d3d)) {
++ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++
++ /* check if the window has moved since last we used it */
++ if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++ sizeof(extesc), (LPSTR)&extesc) <= 0) {
++ WARN("Window update check failed (hwnd=%p, hdc=%p)\n",
++ hwnd, d3d->hdc);
++ }
++
++ if (!EqualRect(&d3d->dc_rect, &extesc.dc_rect))
++ d3d->dc_rect = extesc.dc_rect;
++
++ return d3d;
++ }
++ LeaveCriticalSection(&context_section);
++
++ TRACE("No d3d_drawable attached to hwnd %p, creating one.\n", hwnd);
++
++ d3d = create_d3dadapter_drawable(hwnd);
++ if (!d3d) { return NULL; }
++
++ EnterCriticalSection(&context_section);
++ if (!XFindContext(gdi_display, (XID)hwnd,
++ d3d_hwnd_context, (char **)&race)) {
++ /* apparently someone beat us to creating this d3d drawable. Let's not
++ waste more time with X11 calls and just use theirs instead. */
++ free_d3dadapter_drawable(d3d);
++ return race;
++ }
++ XSaveContext(gdi_display, (XID)hwnd, d3d_hwnd_context, (char *)d3d);
++ return d3d;
++}
++
++static void
++release_d3d_drawable(struct d3d_drawable *d3d)
++{
++ if (d3d) { LeaveCriticalSection(&context_section); }
++}
++
++static ULONG WINAPI
++DRI3Present_AddRef( struct DRI3Present *This )
++{
++ ULONG refs = InterlockedIncrement(&This->refs);
++ TRACE("%p increasing refcount to %u.\n", This, refs);
++ return refs;
++}
++
++static ULONG WINAPI
++DRI3Present_Release( struct DRI3Present *This )
++{
++ ULONG refs = InterlockedDecrement(&This->refs);
++ TRACE("%p decreasing refcount to %u.\n", This, refs);
++ if (refs == 0) {
++ /* dtor */
++#ifdef ID3DPresent_GetWindowOccluded
++ dri3_present_unregister_window_hook(This);
++#endif
++ if (This->d3d)
++ destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
++ ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
++
++ PRESENTDestroy(This->gdi_display, This->present_priv);
++#ifdef D3DADAPTER9_DRI2
++ if (is_dri2_fallback)
++ DRI2FallbackDestroy(This->dri2_priv);
++#endif
++ HeapFree(GetProcessHeap(), 0, This);
++ }
++ return refs;
++}
++
++static HRESULT WINAPI
++DRI3Present_QueryInterface( struct DRI3Present *This,
++ REFIID riid,
++ void **ppvObject )
++{
++ if (!ppvObject) { return E_POINTER; }
++
++ if (IsEqualGUID(&IID_ID3DPresent, riid) ||
++ IsEqualGUID(&IID_IUnknown, riid)) {
++ *ppvObject = This;
++ DRI3Present_AddRef(This);
++ return S_OK;
++ }
++
++ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++ *ppvObject = NULL;
++
++ return E_NOINTERFACE;
++}
++
++static HRESULT
++DRI3Present_ChangePresentParameters( struct DRI3Present *This,
++ D3DPRESENT_PARAMETERS *params);
++
++static HRESULT WINAPI
++DRI3Present_SetPresentParameters( struct DRI3Present *This,
++ D3DPRESENT_PARAMETERS *pPresentationParameters,
++ D3DDISPLAYMODEEX *pFullscreenDisplayMode )
++{
++ if (pFullscreenDisplayMode)
++ ERR("Ignoring pFullscreenDisplayMode\n");
++ return DRI3Present_ChangePresentParameters(This, pPresentationParameters);
++}
++
++static HRESULT WINAPI
++DRI3Present_D3DWindowBufferFromDmaBuf( struct DRI3Present *This,
++ int dmaBufFd,
++ int width,
++ int height,
++ int stride,
++ int depth,
++ int bpp,
++ struct D3DWindowBuffer **out)
++{
++ Pixmap pixmap;
++
++#ifdef D3DADAPTER9_DRI2
++ if (is_dri2_fallback) {
++ *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ sizeof(struct D3DWindowBuffer));
++ DRI2FallbackPRESENTPixmap(This->present_priv, This->dri2_priv,
++ dmaBufFd, width, height, stride, depth,
++ bpp,
++ &((*out)->present_pixmap_priv));
++ return D3D_OK;
++ }
++#endif
++ if (!DRI3PixmapFromDmaBuf(This->gdi_display, DefaultScreen(This->gdi_display),
++ dmaBufFd, width, height, stride, depth,
++ bpp, &pixmap ))
++ return D3DERR_DRIVERINTERNALERROR;
++
++ *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ sizeof(struct D3DWindowBuffer));
++ PRESENTPixmapInit(This->present_priv, pixmap, &((*out)->present_pixmap_priv));
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_DestroyD3DWindowBuffer( struct DRI3Present *This,
++ struct D3DWindowBuffer *buffer )
++{
++ /* the pixmap is managed by the PRESENT backend.
++ * But if it can delete it right away, we may have
++ * better performance */
++ PRESENTTryFreePixmap(This->gdi_display, buffer->present_pixmap_priv);
++ HeapFree(GetProcessHeap(), 0, buffer);
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_WaitBufferReleased( struct DRI3Present *This,
++ struct D3DWindowBuffer *buffer)
++{
++ PRESENTWaitPixmapReleased(buffer->present_pixmap_priv);
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_FrontBufferCopy( struct DRI3Present *This,
++ struct D3DWindowBuffer *buffer )
++{
++#ifdef D3DADAPTER9_DRI2
++ if (is_dri2_fallback)
++ return D3DERR_DRIVERINTERNALERROR;
++#endif
++ /* TODO: use dc_rect */
++ if (PRESENTHelperCopyFront(This->gdi_display, buffer->present_pixmap_priv))
++ return D3D_OK;
++ else
++ return D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_PresentBuffer( struct DRI3Present *This,
++ struct D3DWindowBuffer *buffer,
++ HWND hWndOverride,
++ const RECT *pSourceRect,
++ const RECT *pDestRect,
++ const RGNDATA *pDirtyRegion,
++ DWORD Flags )
++{
++ struct d3d_drawable *d3d;
++ RECT dest_translate;
++
++ if (hWndOverride) {
++ d3d = get_d3d_drawable(This->gdi_display, hWndOverride);
++ } else if (This->params.hDeviceWindow) {
++ d3d = get_d3d_drawable(This->gdi_display, This->params.hDeviceWindow);
++ } else {
++ d3d = get_d3d_drawable(This->gdi_display, This->focus_wnd);
++ }
++ if (!d3d) { return D3DERR_DRIVERINTERNALERROR; }
++
++ /* TODO: should we use a list here instead ? */
++ if (This->d3d && (This->d3d->wnd != d3d->wnd)) {
++ destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
++ }
++ This->d3d = d3d;
++
++ if (d3d->dc_rect.top != 0 &&
++ d3d->dc_rect.left != 0) {
++ if (!pDestRect)
++ pDestRect = (const RECT *) &(d3d->dc_rect);
++ else {
++ dest_translate.top = pDestRect->top + d3d->dc_rect.top;
++ dest_translate.left = pDestRect->left + d3d->dc_rect.left;
++ dest_translate.bottom = pDestRect->bottom + d3d->dc_rect.bottom;
++ dest_translate.right = pDestRect->right + d3d->dc_rect.right;
++ pDestRect = (const RECT *) &dest_translate;
++ }
++ }
++
++ if (!PRESENTPixmap(This->gdi_display, d3d->drawable, buffer->present_pixmap_priv,
++ &This->params, pSourceRect, pDestRect, pDirtyRegion))
++ return D3DERR_DRIVERINTERNALERROR;
++
++ release_d3d_drawable(d3d);
++
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetRasterStatus( struct DRI3Present *This,
++ D3DRASTER_STATUS *pRasterStatus )
++{
++ FIXME("(%p, %p), stub!\n", This, pRasterStatus);
++ return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetDisplayMode( struct DRI3Present *This,
++ D3DDISPLAYMODEEX *pMode,
++ D3DDISPLAYROTATION *pRotation )
++{
++ DEVMODEW dm;
++
++ ZeroMemory(&dm, sizeof(dm));
++ dm.dmSize = sizeof(dm);
++
++ EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &dm, 0);
++ pMode->Width = dm.dmPelsWidth;
++ pMode->Height = dm.dmPelsHeight;
++ pMode->RefreshRate = dm.dmDisplayFrequency;
++ pMode->ScanLineOrdering = (dm.dmDisplayFlags & DM_INTERLACED) ?
++ D3DSCANLINEORDERING_INTERLACED :
++ D3DSCANLINEORDERING_PROGRESSIVE;
++
++ /* XXX This is called "guessing" */
++ switch (dm.dmBitsPerPel) {
++ case 32: pMode->Format = D3DFMT_X8R8G8B8; break;
++ case 24: pMode->Format = D3DFMT_R8G8B8; break;
++ case 16: pMode->Format = D3DFMT_R5G6B5; break;
++ default:
++ WARN("Unknown display format with %u bpp.\n", dm.dmBitsPerPel);
++ pMode->Format = D3DFMT_UNKNOWN;
++ }
++
++ switch (dm.dmDisplayOrientation) {
++ case DMDO_DEFAULT: *pRotation = D3DDISPLAYROTATION_IDENTITY; break;
++ case DMDO_90: *pRotation = D3DDISPLAYROTATION_90; break;
++ case DMDO_180: *pRotation = D3DDISPLAYROTATION_180; break;
++ case DMDO_270: *pRotation = D3DDISPLAYROTATION_270; break;
++ default:
++ WARN("Unknown display rotation %u.\n", dm.dmDisplayOrientation);
++ *pRotation = D3DDISPLAYROTATION_IDENTITY;
++ }
++
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetPresentStats( struct DRI3Present *This,
++ D3DPRESENTSTATS *pStats )
++{
++ FIXME("(%p, %p), stub!\n", This, pStats);
++ return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetCursorPos( struct DRI3Present *This,
++ POINT *pPoint )
++{
++ BOOL ok;
++ HWND draw_window;
++
++ if (!pPoint)
++ return D3DERR_INVALIDCALL;
++
++ draw_window = This->params.hDeviceWindow ?
++ This->params.hDeviceWindow : This->focus_wnd;
++
++ ok = GetCursorPos(pPoint);
++ ok = ok && ScreenToClient(draw_window, pPoint);
++ return ok ? S_OK : D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_SetCursorPos( struct DRI3Present *This,
++ POINT *pPoint )
++{
++ BOOL ok;
++ POINT real_pos;
++
++ if (!pPoint)
++ return D3DERR_INVALIDCALL;
++
++ ok = SetCursorPos(pPoint->x, pPoint->y);
++ if (!ok)
++ goto error;
++
++ ok = GetCursorPos(&real_pos);
++ if (!ok || real_pos.x != pPoint->x || real_pos.y != pPoint->y)
++ goto error;
++
++ return D3D_OK;
++
++error:
++ SetCursor(NULL); /* Hide cursor rather than put wrong pos */
++ return D3DERR_DRIVERINTERNALERROR;
++}
++
++
++/* Note: assuming 32x32 cursor */
++static HRESULT WINAPI
++DRI3Present_SetCursor( struct DRI3Present *This,
++ void *pBitmap,
++ POINT *pHotspot,
++ BOOL bShow )
++{
++ if (pBitmap) {
++ ICONINFO info;
++ HCURSOR cursor;
++
++ DWORD mask[32];
++ memset(mask, ~0, sizeof(mask));
++
++ if (!pHotspot)
++ return D3DERR_INVALIDCALL;
++ info.fIcon = FALSE;
++ info.xHotspot = pHotspot->x;
++ info.yHotspot = pHotspot->y;
++ info.hbmMask = CreateBitmap(32, 32, 1, 1, mask);
++ info.hbmColor = CreateBitmap(32, 32, 1, 32, pBitmap);
++
++ cursor = CreateIconIndirect(&info);
++ if (info.hbmMask) DeleteObject(info.hbmMask);
++ if (info.hbmColor) DeleteObject(info.hbmColor);
++ if (cursor)
++ DestroyCursor(This->hCursor);
++ This->hCursor = cursor;
++ }
++ SetCursor(bShow ? This->hCursor : NULL);
++
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_SetGammaRamp( struct DRI3Present *This,
++ const D3DGAMMARAMP *pRamp,
++ HWND hWndOverride )
++{
++ HWND hWnd = hWndOverride ? hWndOverride : This->focus_wnd;
++ HDC hdc;
++ BOOL ok;
++ if (!pRamp) {
++ return D3DERR_INVALIDCALL;
++ }
++ hdc = GetDC(hWnd);
++ ok = SetDeviceGammaRamp(hdc, (void *)pRamp);
++ ReleaseDC(hWnd, hdc);
++ return ok ? D3D_OK : D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetWindowInfo( struct DRI3Present *This,
++ HWND hWnd,
++ int *width, int *height, int *depth )
++{
++ HRESULT hr;
++ RECT pRect;
++
++ if (!hWnd)
++ hWnd = This->focus_wnd;
++ hr = GetClientRect(hWnd, &pRect);
++ if (!hr)
++ return D3DERR_INVALIDCALL;
++ *width = pRect.right - pRect.left;
++ *height = pRect.bottom - pRect.top;
++ *depth = 24; //TODO
++ return D3D_OK;
++}
++
++static LONG fullscreen_style(LONG style)
++{
++ /* Make sure the window is managed, otherwise we won't get keyboard input. */
++ style |= WS_POPUP | WS_SYSMENU;
++ style &= ~(WS_CAPTION | WS_THICKFRAME);
++
++ return style;
++}
++
++static LONG fullscreen_exstyle(LONG exstyle)
++{
++ /* Filter out window decorations. */
++ exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
++
++ return exstyle;
++}
++
++static HRESULT
++DRI3Present_ChangeDisplaySettingsIfNeccessary( struct DRI3Present *This, DEVMODEW *new_mode ) {
++ DEVMODEW current_mode;
++ LONG hr;
++
++ ZeroMemory(&current_mode, sizeof(DEVMODEW));
++ /* Only change the mode if necessary. */
++ if (!EnumDisplaySettingsW(This->devname, ENUM_CURRENT_SETTINGS, &current_mode))
++ {
++ ERR("Failed to get current display mode.\n");
++ } else if (current_mode.dmPelsWidth != new_mode->dmPelsWidth
++ || current_mode.dmPelsHeight != new_mode->dmPelsHeight
++ || (current_mode.dmDisplayFrequency != new_mode->dmDisplayFrequency
++ && (new_mode->dmFields & DM_DISPLAYFREQUENCY)))
++ {
++ hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
++ if (hr != DISP_CHANGE_SUCCESSFUL) {
++ /* try again without display RefreshRate */
++ if (new_mode->dmFields & DM_DISPLAYFREQUENCY) {
++ new_mode->dmFields &= ~DM_DISPLAYFREQUENCY;
++ new_mode->dmDisplayFrequency = 0;
++ hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
++ if (hr != DISP_CHANGE_SUCCESSFUL) {
++ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++ return D3DERR_INVALIDCALL;
++ }
++ } else {
++ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++ return D3DERR_INVALIDCALL;
++ }
++ }
++ }
++ return D3D_OK;
++}
++
++#ifdef ID3DPresent_GetWindowOccluded
++static struct d3d_wnd_hooks *get_last_hook(void) {
++ struct d3d_wnd_hooks *hook = &d3d_hooks;
++ while (hook->next) {
++ hook = hook->next;
++ }
++ return hook;
++}
++
++LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
++{
++ struct d3d_wnd_hooks *hook = &d3d_hooks;
++ boolean drop_wnd_messages;
++
++ if (nCode < 0) {
++ return CallNextHookEx(hhook, nCode, wParam, lParam);
++ }
++
++ if (lParam) {
++ CWPSTRUCT wndprocparams = *((CWPSTRUCT*)lParam);
++ while (hook->next) {
++ hook = hook->next;
++
++ /* skip messages for other hwnds */
++ if (hook->focus_wnd != wndprocparams.hwnd)
++ continue;
++ if (!hook->present)
++ continue;
++
++ switch (wndprocparams.message) {
++ case WM_ACTIVATEAPP:
++ if (hook->present->drop_wnd_messages)
++ return -1;
++
++ drop_wnd_messages = hook->present->drop_wnd_messages;
++ hook->present->drop_wnd_messages = TRUE;
++ if (wndprocparams.wParam == WA_INACTIVE) {
++ hook->present->occluded = TRUE;
++
++ DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &(hook->present->initial_mode));
++
++ if (!hook->present->no_window_changes &&
++ IsWindowVisible(hook->present->params.hDeviceWindow))
++ ShowWindow(hook->present->params.hDeviceWindow, SW_MINIMIZE);
++ } else {
++ hook->present->device_needs_reset |= hook->present->occluded;
++ hook->present->occluded = FALSE;
++
++ if (!hook->present->no_window_changes) {
++ /* restore window */
++ SetWindowPos(hook->present->params.hDeviceWindow, NULL, 0, 0,
++ hook->present->params.BackBufferWidth, hook->present->params.BackBufferHeight,
++ SWP_NOACTIVATE | SWP_NOZORDER);
++ }
++
++ if (hook->present->ex) {
++ DEVMODEW new_mode;
++
++ ZeroMemory(&new_mode, sizeof(DEVMODEW));
++ new_mode.dmPelsWidth = hook->present->params.BackBufferWidth;
++ new_mode.dmPelsHeight = hook->present->params.BackBufferHeight;
++ new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++ if (hook->present->params.FullScreen_RefreshRateInHz) {
++ new_mode.dmFields |= DM_DISPLAYFREQUENCY;
++ new_mode.dmDisplayFrequency = hook->present->params.FullScreen_RefreshRateInHz;
++ }
++ new_mode.dmSize = sizeof(DEVMODEW);
++ DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &new_mode);
++ }
++ }
++ hook->present->drop_wnd_messages = drop_wnd_messages;
++ break;
++ case WM_DISPLAYCHANGE:
++ hook->present->mode_changed = TRUE;
++ hook->present->device_needs_reset = TRUE;
++ break;
++ /* TODO: handle other window messages here */
++ default:
++ break;
++ }
++ }
++ }
++
++ return CallNextHookEx(hhook, nCode, wParam, lParam);
++}
++
++static HRESULT dri3_present_register_window_hook( struct DRI3Present *This ) {
++ struct d3d_wnd_hooks *lasthook;
++ struct d3d_wnd_hooks *hook = &d3d_hooks;
++
++ HWND hWnd = This->focus_wnd;
++
++ /* let's see if already hooked */
++ while (hook->next) {
++ hook = hook->next;
++ if (hook->focus_wnd == hWnd && hook->present == This)
++ return D3DERR_INVALIDCALL;
++ }
++ /* create single WindowsHook in this process */
++ if (!hhook) {
++ // TODO: do we need to handle different threadIDs ?
++ DWORD threadID = GetWindowThreadProcessId(hWnd, NULL);
++ hhook = SetWindowsHookExW(WH_CALLWNDPROC, HookCallback, NULL, threadID);
++ if (!hhook) {
++ ERR("SetWindowsHookEx failed with 0x%08x\n", GetLastError());
++ return D3DERR_DRIVERINTERNALERROR;
++ }
++ }
++ lasthook = get_last_hook();
++ hook = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ sizeof(struct d3d_wnd_hooks));
++ if (!hook)
++ return E_OUTOFMEMORY;
++ /* add window hwnd to list */
++ lasthook->next = hook;
++ hook->prev = lasthook;
++ hook->focus_wnd = hWnd;
++ hook->present = This;
++ return D3D_OK;
++}
++
++static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This ) {
++ struct d3d_wnd_hooks *hook = &d3d_hooks;
++
++ HWND hWnd = This->focus_wnd;
++
++ /* find hook and remove it */
++ while (hook->next) {
++ hook = hook->next;
++ if(hook->focus_wnd == hWnd && hook->present == This) {
++ /* remove hook */
++ hook->prev->next = hook->next;
++ HeapFree(GetProcessHeap(), 0, hook);
++ /* start again at list head */
++ hook = &d3d_hooks;
++ }
++ }
++ /* remove single process WindowsHook */
++ if (get_last_hook() == &d3d_hooks && hhook) {
++ if (!UnhookWindowsHookEx(hhook)) {
++ ERR("UnhookWindowsHookEx failed with 0x%08x\n", GetLastError());
++ }
++ hhook = NULL;
++ }
++
++ return D3D_OK;
++}
++
++static BOOL WINAPI
++DRI3Present_GetWindowOccluded( struct DRI3Present *This )
++{
++ /* we missed to poll occluded */
++ if (This->device_needs_reset) {
++ This->device_needs_reset = FALSE;
++ return TRUE;
++ }
++
++ return This->occluded;
++}
++#endif
++/*----------*/
++
++
++static ID3DPresentVtbl DRI3Present_vtable = {
++ (void *)DRI3Present_QueryInterface,
++ (void *)DRI3Present_AddRef,
++ (void *)DRI3Present_Release,
++ (void *)DRI3Present_SetPresentParameters,
++ (void *)DRI3Present_D3DWindowBufferFromDmaBuf,
++ (void *)DRI3Present_DestroyD3DWindowBuffer,
++ (void *)DRI3Present_WaitBufferReleased,
++ (void *)DRI3Present_FrontBufferCopy,
++ (void *)DRI3Present_PresentBuffer,
++ (void *)DRI3Present_GetRasterStatus,
++ (void *)DRI3Present_GetDisplayMode,
++ (void *)DRI3Present_GetPresentStats,
++ (void *)DRI3Present_GetCursorPos,
++ (void *)DRI3Present_SetCursorPos,
++ (void *)DRI3Present_SetCursor,
++ (void *)DRI3Present_SetGammaRamp,
++ (void *)DRI3Present_GetWindowInfo,
++#ifdef ID3DPresent_GetWindowOccluded
++ (void *)DRI3Present_GetWindowOccluded
++#endif
++};
++
++static HRESULT
++DRI3Present_ChangePresentParameters( struct DRI3Present *This,
++ D3DPRESENT_PARAMETERS *params )
++{
++ HWND draw_window = params->hDeviceWindow;
++ RECT rect;
++ DEVMODEW new_mode;
++
++ if (!GetClientRect(draw_window, &rect)) {
++ WARN("GetClientRect failed.\n");
++ rect.right = 640;
++ rect.bottom = 480;
++ }
++
++ if (params->BackBufferWidth == 0) {
++ params->BackBufferWidth = rect.right - rect.left;
++ }
++ if (params->BackBufferHeight == 0) {
++ params->BackBufferHeight = rect.bottom - rect.top;
++ }
++
++ if ((This->params.BackBufferWidth != params->BackBufferWidth) ||
++ (This->params.BackBufferHeight != params->BackBufferHeight)) {
++ This->mode_changed = TRUE;
++ }
++
++ if (This->mode_changed || (This->params.Windowed != params->Windowed)) {
++ if (!params->Windowed) {
++ /* switch display mode */
++ ZeroMemory(&new_mode, sizeof(DEVMODEW));
++ new_mode.dmPelsWidth = params->BackBufferWidth;
++ new_mode.dmPelsHeight = params->BackBufferHeight;
++ new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++ if (params->FullScreen_RefreshRateInHz) {
++ new_mode.dmFields |= DM_DISPLAYFREQUENCY;
++ new_mode.dmDisplayFrequency = params->FullScreen_RefreshRateInHz;
++ }
++ new_mode.dmSize = sizeof(DEVMODEW);
++ DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &new_mode);
++ } else {
++ DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &This->initial_mode);
++ }
++ This->mode_changed = FALSE;
++
++ if (This->params.Windowed) {
++ if (!params->Windowed) {
++ LONG style, style_ex;
++ boolean drop_wnd_messages;
++
++ /* switch from window to fullscreen */
++#ifdef ID3DPresent_GetWindowOccluded
++ if (dri3_present_register_window_hook(This)) {
++ SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
++ }
++#else
++ SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
++#endif
++ This->style = GetWindowLongW(draw_window, GWL_STYLE);
++ This->style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++ style = fullscreen_style(This->style);
++ style_ex = fullscreen_exstyle(This->style_ex);
++
++ drop_wnd_messages = This->drop_wnd_messages;
++ This->drop_wnd_messages = TRUE;
++
++ SetWindowLongW(draw_window, GWL_STYLE, style);
++ SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++ SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth,
++ params->BackBufferHeight,
++ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++ This->drop_wnd_messages = drop_wnd_messages;
++ }
++ } else {
++ if (!params->Windowed) {
++ /* switch from fullscreen to fullscreen */
++ MoveWindow(draw_window, 0, 0,
++ params->BackBufferWidth,
++ params->BackBufferHeight,
++ TRUE);
++ } else {
++ LONG style, style_ex;
++ boolean drop_wnd_messages;
++
++ /* switch from fullscreen to window */
++ style = GetWindowLongW(draw_window, GWL_STYLE);
++ style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++ /* These flags are set by wined3d_device_setup_fullscreen_window, not the
++ * application, and we want to ignore them in the test below, since it's
++ * not the application's fault that they changed. Additionally, we want to
++ * preserve the current status of these flags (i.e. don't restore them) to
++ * more closely emulate the behavior of Direct3D, which leaves these flags
++ * alone when returning to windowed mode. */
++ This->style ^= (This->style ^ style) & WS_VISIBLE;
++ This->style_ex ^= (This->style_ex ^ style_ex) & WS_EX_TOPMOST;
++
++ /* Only restore the style if the application didn't modify it during the
++ * fullscreen phase. Some applications change it before calling Reset()
++ * when switching between windowed and fullscreen modes (HL2), some
++ * depend on the original style (Eve Online). */
++ drop_wnd_messages = This->drop_wnd_messages;
++ This->drop_wnd_messages = TRUE;
++ if (style == fullscreen_style(This->style) && style_ex == fullscreen_exstyle(This->style_ex))
++ {
++ SetWindowLongW(draw_window, GWL_STYLE, style);
++ SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++ }
++ SetWindowPos(draw_window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED |
++ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
++ SWP_NOACTIVATE);
++ This->drop_wnd_messages = drop_wnd_messages;
++
++#ifdef ID3DPresent_GetWindowOccluded
++ dri3_present_unregister_window_hook(This);
++#endif
++ This->style = 0;
++ This->style_ex = 0;
++ }
++ }
++ } else if (!params->Windowed) {
++ LONG style, style_ex;
++ /* move draw window back to place */
++
++ style = GetWindowLongW(draw_window, GWL_STYLE);
++ style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++ style = fullscreen_style(style);
++ style_ex = fullscreen_exstyle(style_ex);
++
++ SetWindowLongW(draw_window, GWL_STYLE, style);
++ SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++ SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth,
++ params->BackBufferHeight,
++ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++ }
++
++ This->params = *params;
++ return D3D_OK;
++}
++
++static HRESULT
++DRI3Present_new( Display *gdi_display,
++ const WCHAR *devname,
++ D3DPRESENT_PARAMETERS *params,
++ HWND focus_wnd,
++ struct DRI3Present **out,
++ boolean ex,
++ boolean no_window_changes )
++{
++ struct DRI3Present *This;
++
++ if (!focus_wnd) { focus_wnd = params->hDeviceWindow; }
++ if (!focus_wnd) {
++ ERR("No focus HWND specified for presentation backend.\n");
++ return D3DERR_INVALIDCALL;
++ }
++
++ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ sizeof(struct DRI3Present));
++ if (!This) {
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++
++ This->gdi_display = gdi_display;
++ This->vtable = &DRI3Present_vtable;
++ This->refs = 1;
++ This->focus_wnd = focus_wnd;
++ This->params.Windowed = TRUE;
++ This->ex = ex;
++ This->no_window_changes = no_window_changes;
++
++ strcpyW(This->devname, devname);
++
++ ZeroMemory(&(This->initial_mode), sizeof(This->initial_mode));
++ This->initial_mode.dmSize = sizeof(This->initial_mode);
++
++ EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &(This->initial_mode), 0);
++
++ PRESENTInit(gdi_display, &(This->present_priv));
++#ifdef D3DADAPTER9_DRI2
++ if (is_dri2_fallback)
++ DRI2FallbackInit(gdi_display, &(This->dri2_priv));
++#endif
++ *out = This;
++
++ return D3D_OK;
++}
++
++struct DRI3PresentGroup
++{
++ /* COM vtable */
++ void *vtable;
++ /* IUnknown reference count */
++ LONG refs;
++
++ struct DRI3Present **present_backends;
++ unsigned npresent_backends;
++ Display *gdi_display;
++ boolean ex;
++ boolean no_window_changes;
++};
++
++static ULONG WINAPI
++DRI3PresentGroup_AddRef( struct DRI3PresentGroup *This )
++{
++ ULONG refs = InterlockedIncrement(&This->refs);
++ TRACE("%p increasing refcount to %u.\n", This, refs);
++ return refs;
++}
++
++static ULONG WINAPI
++DRI3PresentGroup_Release( struct DRI3PresentGroup *This )
++{
++ ULONG refs = InterlockedDecrement(&This->refs);
++ TRACE("%p decreasing refcount to %u.\n", This, refs);
++ if (refs == 0) {
++ unsigned i;
++ if (This->present_backends) {
++ for (i = 0; i < This->npresent_backends; ++i) {
++ if (This->present_backends[i])
++ DRI3Present_Release(This->present_backends[i]);
++ }
++ HeapFree(GetProcessHeap(), 0, This->present_backends);
++ }
++ HeapFree(GetProcessHeap(), 0, This);
++ }
++ return refs;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_QueryInterface( struct DRI3PresentGroup *This,
++ REFIID riid,
++ void **ppvObject )
++{
++ if (!ppvObject) { return E_POINTER; }
++ if (IsEqualGUID(&IID_ID3DPresentGroup, riid) ||
++ IsEqualGUID(&IID_IUnknown, riid)) {
++ *ppvObject = This;
++ DRI3PresentGroup_AddRef(This);
++ return S_OK;
++ }
++
++ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++ *ppvObject = NULL;
++
++ return E_NOINTERFACE;
++}
++
++static UINT WINAPI
++DRI3PresentGroup_GetMultiheadCount( struct DRI3PresentGroup *This )
++{
++ FIXME("(%p), stub!\n", This);
++ return 1;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_GetPresent( struct DRI3PresentGroup *This,
++ UINT Index,
++ ID3DPresent **ppPresent )
++{
++ if (Index >= DRI3PresentGroup_GetMultiheadCount(This)) {
++ ERR("Index >= MultiHeadCount\n");
++ return D3DERR_INVALIDCALL;
++ }
++ DRI3Present_AddRef(This->present_backends[Index]);
++ *ppPresent = (ID3DPresent *)This->present_backends[Index];
++
++ return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_CreateAdditionalPresent( struct DRI3PresentGroup *This,
++ D3DPRESENT_PARAMETERS *pPresentationParameters,
++ ID3DPresent **ppPresent )
++{
++ HRESULT hr;
++ hr = DRI3Present_new(This->gdi_display, This->present_backends[0]->devname,
++ pPresentationParameters, 0, (struct DRI3Present **)ppPresent,
++ This->ex, This->no_window_changes);
++ return hr;
++}
++
++static void WINAPI
++DRI3PresentGroup_GetVersion( struct DRI3PresentGroup *This,
++ int *major,
++ int *minor)
++{
++ *major = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR;
++ *minor = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR;
++}
++
++static ID3DPresentGroupVtbl DRI3PresentGroup_vtable = {
++ (void *)DRI3PresentGroup_QueryInterface,
++ (void *)DRI3PresentGroup_AddRef,
++ (void *)DRI3PresentGroup_Release,
++ (void *)DRI3PresentGroup_GetMultiheadCount,
++ (void *)DRI3PresentGroup_GetPresent,
++ (void *)DRI3PresentGroup_CreateAdditionalPresent,
++ (void *)DRI3PresentGroup_GetVersion
++};
++
++HRESULT
++present_create_present_group( Display *gdi_display,
++ const WCHAR *device_name,
++ UINT adapter,
++ HWND focus_wnd,
++ D3DPRESENT_PARAMETERS *params,
++ unsigned nparams,
++ ID3DPresentGroup **group,
++ boolean ex,
++ boolean no_window_changes )
++{
++ struct DRI3PresentGroup *This =
++ HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ sizeof(struct DRI3PresentGroup));
++ DISPLAY_DEVICEW dd;
++ HRESULT hr;
++ unsigned i;
++
++ if (!This) {
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++
++ This->gdi_display = gdi_display;
++ This->vtable = &DRI3PresentGroup_vtable;
++ This->refs = 1;
++ This->ex = ex;
++ This->no_window_changes = no_window_changes;
++ This->npresent_backends = nparams;
++ This->present_backends = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ This->npresent_backends *
++ sizeof(struct DRI3Present *));
++ if (!This->present_backends) {
++ DRI3PresentGroup_Release(This);
++ ERR("Out of memory.\n");
++ return E_OUTOFMEMORY;
++ }
++
++ if (nparams != 1) { adapter = 0; }
++ for (i = 0; i < This->npresent_backends; ++i) {
++ ZeroMemory(&dd, sizeof(dd));
++ dd.cb = sizeof(dd);
++ /* find final device name */
++ if (!EnumDisplayDevicesW(device_name, adapter+i, &dd, 0)) {
++ WARN("Couldn't find subdevice %d from `%s'\n",
++ i, debugstr_w(device_name));
++ }
++
++ /* create an ID3DPresent for it */
++ hr = DRI3Present_new(gdi_display, dd.DeviceName, &params[i],
++ focus_wnd, &This->present_backends[i],
++ This->ex, This->no_window_changes);
++ if (FAILED(hr)) {
++ DRI3PresentGroup_Release(This);
++ return hr;
++ }
++ }
++
++ *group = (ID3DPresentGroup *)This;
++ TRACE("Returning %p\n", *group);
++
++ return D3D_OK;
++}
++
++HRESULT
++present_create_adapter9( Display *gdi_display,
++ HDC hdc,
++ ID3DAdapter9 **out )
++{
++ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++ HRESULT hr;
++ int fd;
++
++ if (!d3d9_drm) {
++ ERR("DRM drivers are not supported on your system.\n");
++ return D3DERR_DRIVERINTERNALERROR;
++ }
++
++ if (ExtEscape(hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++ sizeof(extesc), (LPSTR)&extesc) <= 0) {
++ ERR("X11 drawable lookup failed (hdc=%p)\n", hdc);
++ }
++
++#ifdef D3DADAPTER9_DRI2
++ if (!is_dri2_fallback && !DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) {
++#else
++ if (!DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) {
++#endif
++ ERR("DRI3Open failed (fd=%d)\n", fd);
++ return D3DERR_DRIVERINTERNALERROR;
++ }
++#ifdef D3DADAPTER9_DRI2
++ if (is_dri2_fallback && !DRI2FallbackOpen(gdi_display, DefaultScreen(gdi_display), &fd)) {
++ ERR("DRI2Open failed (fd=%d)\n", fd);
++ return D3DERR_DRIVERINTERNALERROR;
++ }
++#endif
++ hr = d3d9_drm->create_adapter(fd, out);
++ if (FAILED(hr)) {
++ ERR("Unable to create ID3DAdapter9 (fd=%d)\n", fd);
++ return hr;
++ }
++
++ TRACE("Created ID3DAdapter9 with fd %d\n", fd);
++
++ return D3D_OK;
++}
++
++BOOL
++has_d3dadapter( Display *gdi_display )
++{
++ static const void * WINAPI (*pD3DAdapter9GetProc)(const char *);
++ static void *handle = NULL;
++ static int done = 0;
++
++ char errbuf[256];
++
++#if !defined(SONAME_D3DADAPTER9)
++ return FALSE;
++#endif
++
++ /* like in opengl.c (single threaded assumption OK?) */
++ if (done) { return handle != NULL; }
++ done = 1;
++
++ handle = wine_dlopen(D3D_MODULE_DIR "/" SONAME_D3DADAPTER9,
++ RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf));
++ if (!handle) {
++ ERR("Failed to load %s: %s\n", SONAME_D3DADAPTER9, errbuf);
++ goto cleanup;
++ }
++
++ /* find our entry point in d3dadapter9 */
++ pD3DAdapter9GetProc = wine_dlsym(handle, "D3DAdapter9GetProc",
++ errbuf, sizeof(errbuf));
++ if (!pD3DAdapter9GetProc) {
++ ERR("Failed to get the entry point from %s: %s",
++ SONAME_D3DADAPTER9, errbuf);
++ goto cleanup;
++ }
++
++ /* get a handle to the drm backend struct */
++ d3d9_drm = pD3DAdapter9GetProc(D3DADAPTER9DRM_NAME);
++ if (!d3d9_drm) {
++ ERR("%s doesn't support the `%s' backend.\n",
++ SONAME_D3DADAPTER9, D3DADAPTER9DRM_NAME);
++ goto cleanup;
++ }
++
++ /* verify that we're binary compatible */
++ if (d3d9_drm->major_version != D3DADAPTER9DRM_MAJOR) {
++ ERR("Version mismatch. %s has %d.%d, was expecting %d.x\n",
++ SONAME_D3DADAPTER9, d3d9_drm->major_version,
++ d3d9_drm->minor_version, D3DADAPTER9DRM_MAJOR);
++ goto cleanup;
++ }
++
++ /* this will be used to store d3d_drawables */
++ d3d_hwnd_context = XUniqueContext();
++
++ if (!PRESENTCheckExtension(gdi_display, 1, 0)) {
++ ERR("Unable to query PRESENT.\n");
++ goto cleanup;
++ }
++
++ if (!DRI3CheckExtension(gdi_display, 1, 0)) {
++#ifndef D3DADAPTER9_DRI2
++ ERR("Unable to query DRI3.\n");
++ goto cleanup;
++#else
++ ERR("Unable to query DRI3. Trying DRI2 fallback (slower performance).\n");
++ is_dri2_fallback = 1;
++ if (!DRI2FallbackCheckSupport(gdi_display)) {
++ ERR("DRI2 fallback unsupported\n");
++ goto cleanup;
++ }
++#endif
++ }
++
++ return TRUE;
++
++cleanup:
++ ERR("\033[1;31m\nNative Direct3D 9 will be unavailable."
++ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++ if (handle) {
++ wine_dlclose(handle, NULL, 0);
++ handle = NULL;
++ }
++
++ return FALSE;
++}
+diff --git a/dlls/d3d9-nine/present.h b/dlls/d3d9-nine/present.h
+new file mode 100644
+index 0000000..52791a5
+--- /dev/null
++++ b/dlls/d3d9-nine/present.h
+@@ -0,0 +1,36 @@
++/*
++ * Wine present interface
++ *
++ * Copyright 2015 Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#ifndef __WINE_PRESENT_H
++#define __WINE_PRESENT_H
++
++#ifndef __WINE_CONFIG_H
++# error You must include config.h to use this header
++#endif
++
++#include <X11/Xlib.h>
++
++HRESULT present_create_present_group(Display *gdi_display, const WCHAR *device_name, UINT adapter, HWND focus, D3DPRESENT_PARAMETERS *params, unsigned nparams, ID3DPresentGroup **group, boolean ex, boolean no_window_changes);
++
++HRESULT present_create_adapter9(Display *gdi_display, HDC hdc, ID3DAdapter9 **adapter);
++
++BOOL has_d3dadapter(Display *gdi_display);
++
++#endif /* __WINE_DRI3_H */
+diff --git a/dlls/d3d9-nine/version.rc b/dlls/d3d9-nine/version.rc
+new file mode 100644
+index 0000000..bfafc2f
+--- /dev/null
++++ b/dlls/d3d9-nine/version.rc
+@@ -0,0 +1,26 @@
++/*
++ * Copyright 2015 Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#define WINE_FILEDESCRIPTION_STR "Wine Gallium Nine Direct3D"
++#define WINE_FILENAME_STR "d3d9-nine.dll"
++#define WINE_FILEVERSION 5,3,1,904
++#define WINE_FILEVERSION_STR "5.3.1.904"
++#define WINE_PRODUCTVERSION 5,3,1,904
++#define WINE_PRODUCTVERSION_STR "5.3.1.904"
++
++#include "wine/wine_common_ver.rc"
+diff --git a/dlls/d3d9/Makefile.in b/dlls/d3d9/Makefile.in
+index 1c05f5a..dc06d68 100644
+--- a/dlls/d3d9/Makefile.in
++++ b/dlls/d3d9/Makefile.in
+@@ -1,6 +1,6 @@
+ MODULE = d3d9.dll
+ IMPORTLIB = d3d9
+-IMPORTS = dxguid uuid wined3d
++IMPORTS = dxguid uuid advapi32 wined3d
+
+ C_SRCS = \
+ buffer.c \
+diff --git a/dlls/d3d9/tests/d3d9ex.c b/dlls/d3d9/tests/d3d9ex.c
+index 151db41..5314915 100644
+--- a/dlls/d3d9/tests/d3d9ex.c
++++ b/dlls/d3d9/tests/d3d9ex.c
+@@ -1410,6 +1410,7 @@ static void test_lost_device(void)
+ HRESULT hr;
+ BOOL ret;
+ struct device_desc desc;
++ IDirect3DSwapChain9 *swapchain;
+
+ window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW,
+ 0, 0, 640, 480, NULL, NULL, NULL, NULL);
+@@ -1434,6 +1435,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL);
+ ok(hr == S_PRESENT_OCCLUDED, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ ret = SetForegroundWindow(GetDesktopWindow());
+ ok(ret, "Failed to set foreground window.\n");
+ hr = IDirect3DDevice9Ex_TestCooperativeLevel(device);
+@@ -1447,6 +1454,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == S_PRESENT_OCCLUDED, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ ret = SetForegroundWindow(window);
+ ok(ret, "Failed to set foreground window.\n");
+ hr = IDirect3DDevice9Ex_TestCooperativeLevel(device);
+@@ -1460,6 +1473,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL);
+ ok(hr == S_PRESENT_OCCLUDED, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ desc.width = 1024;
+ desc.height = 768;
+ hr = reset_device(device, &desc);
+@@ -1489,6 +1508,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL);
+ todo_wine ok(hr == S_PRESENT_MODE_CHANGED, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == S_PRESENT_MODE_CHANGED, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ hr = reset_device(device, &desc);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice9Ex_TestCooperativeLevel(device);
+@@ -1502,6 +1527,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ ret = SetForegroundWindow(GetDesktopWindow());
+ ok(ret, "Failed to set foreground window.\n");
+ hr = IDirect3DDevice9Ex_TestCooperativeLevel(device);
+diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
+index 326e789..0ff7211 100644
+--- a/dlls/d3d9/tests/device.c
++++ b/dlls/d3d9/tests/device.c
+@@ -8222,10 +8222,10 @@ done:
+
+ static void test_vidmem_accounting(void)
+ {
+- IDirect3DDevice9 *device;
++ IDirect3DDevice9 *device, *device2;
+ IDirect3D9 *d3d9;
+ ULONG refcount;
+- HWND window;
++ HWND window, window2;
+ HRESULT hr = D3D_OK;
+ IDirect3DTexture9 *textures[20];
+ unsigned int i;
+@@ -8233,6 +8233,8 @@ static void test_vidmem_accounting(void)
+
+ window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW,
+ 0, 0, 640, 480, 0, 0, 0, 0);
++ window2 = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW,
++ 0, 0, 640, 480, 0, 0, 0, 0);
+ d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+ ok(!!d3d9, "Failed to create a D3D object.\n");
+ if (!(device = create_device(d3d9, window, NULL)))
+@@ -8267,6 +8269,43 @@ static void test_vidmem_accounting(void)
+ IDirect3DTexture9_Release(textures[i]);
+ }
+
++ /* Multi-device testing */
++ if (!(device2 = create_device(d3d9, window2, NULL)))
++ {
++ skip("Failed to create a D3D device, skipping tests.\n");
++ refcount = IDirect3DDevice9_Release(device);
++ ok(!refcount, "Device has %u references left.\n", refcount);
++ IDirect3D9_Release(d3d9);
++ DestroyWindow(window2);
++ DestroyWindow(window);
++ return;
++ }
++
++ vidmem_start = IDirect3DDevice9_GetAvailableTextureMem(device);
++ memset(textures, 0, sizeof(textures));
++ for (i = 0; (i < sizeof(textures) / sizeof(*textures)) && SUCCEEDED(hr); i++)
++ {
++ hr = IDirect3DDevice9_CreateTexture(device2, 1024, 1024, 1, D3DUSAGE_RENDERTARGET,
++ D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &textures[i], NULL);
++ /* D3DERR_OUTOFVIDEOMEMORY is returned when the card runs out of video memory
++ * E_FAIL is returned on address space or system memory exhaustion */
++ ok(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY,
++ "Failed to create texture, hr %#x.\n", hr);
++ }
++ vidmem_end = IDirect3DDevice9_GetAvailableTextureMem(device);
++
++ /* Windows 7 uses device private counters */
++ ok(vidmem_start > vidmem_end || broken(vidmem_start == vidmem_end), "Expected available texture memory to decrease during texture creation.\n");
++ diff = vidmem_start - vidmem_end;
++ ok(diff > 1024 * 1024 * 2 * i || broken(diff == 0), "Expected a video memory difference of at least %u MB, got %u MB.\n",
++ 2 * i, diff / 1024 / 1024);
++
++ for (i = 0; i < sizeof(textures) / sizeof(*textures); i++)
++ {
++ if (textures[i])
++ IDirect3DTexture9_Release(textures[i]);
++ }
++
+ refcount = IDirect3DDevice9_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ IDirect3D9_Release(d3d9);
+@@ -9987,6 +10026,7 @@ static void test_lost_device(void)
+ HWND window;
+ HRESULT hr;
+ BOOL ret;
++ IDirect3DSwapChain9 *swapchain;
+
+ window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW,
+ 0, 0, 640, 480, NULL, NULL, NULL, NULL);
+@@ -10014,6 +10054,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+ ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ ret = ShowWindow(window, SW_RESTORE);
+ ok(ret, "Failed to restore window.\n");
+ ret = SetForegroundWindow(window);
+@@ -10023,6 +10069,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+ ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice9_TestCooperativeLevel(device);
+@@ -10030,6 +10082,12 @@ static void test_lost_device(void)
+ hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
++ hr = IDirect3DDevice9_GetSwapChain(device, 0, &swapchain);
++ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr);
++ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0);
++ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
++ IDirect3DSwapChain9_Release(swapchain);
++
+ device_desc.flags = 0;
+ hr = reset_device(device, &device_desc);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
+index b328b94..74d9dd9 100644
+--- a/dlls/d3d9/tests/visual.c
++++ b/dlls/d3d9/tests/visual.c
+@@ -8535,6 +8535,167 @@ done:
+ DestroyWindow(window);
+ }
+
++static void test_blend_invalid_arg(void)
++{
++ IDirect3DSurface9 *backbuffer, *offscreen;
++ IDirect3DTexture9 *offscreenTexture;
++ IDirect3DDevice9 *device;
++ IDirect3D9 *d3d;
++ D3DCOLOR color;
++ ULONG refcount;
++ HWND window;
++ HRESULT hr;
++ DWORD rs;
++
++ static const struct
++ {
++ struct vec3 position;
++ DWORD diffuse;
++ }
++ quad1[] =
++ {
++ {{-1.0f, -1.0f, 0.1f}, 0x4000ff00},
++ {{-1.0f, 0.0f, 0.1f}, 0x4000ff00},
++ {{ 0.0f, -1.0f, 0.1f}, 0x4000ff00},
++ {{ 0.0f, 0.0f, 0.1f}, 0x4000ff00},
++ },
++ quad2[] =
++ {
++ {{ 0.0f, 0.0f, 0.1f}, 0x4000ff00},
++ {{ 0.0f, 1.0f, 0.1f}, 0x4000ff00},
++ {{ 1.0f, 0.0f, 0.1f}, 0x4000ff00},
++ {{ 1.0f, 1.0f, 0.1f}, 0x4000ff00},
++ },
++ quad3[] =
++ {
++ {{-1.0f, 0.0f, 0.1f}, 0xc00000ff},
++ {{-1.0f, 1.0f, 0.1f}, 0xc00000ff},
++ {{ 0.0f, 0.0f, 0.1f}, 0xc00000ff},
++ {{ 0.0f, 1.0f, 0.1f}, 0xc00000ff},
++ },
++ quad4[] =
++ {
++ {{ 0.0f, -1.0f, 0.1f}, 0xc00000ff},
++ {{ 0.0f, 0.0f, 0.1f}, 0xc00000ff},
++ {{ 1.0f, -1.0f, 0.1f}, 0xc00000ff},
++ {{ 1.0f, 0.0f, 0.1f}, 0xc00000ff},
++ };
++
++ window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
++ 0, 0, 640, 480, NULL, NULL, NULL, NULL);
++ d3d = Direct3DCreate9(D3D_SDK_VERSION);
++ ok(!!d3d, "Failed to create a D3D object.\n");
++ if (!(device = create_device(d3d, window, window, TRUE)))
++ {
++ skip("Failed to create a D3D device, skipping tests.\n");
++ goto done;
++ }
++ /* Clear the render target with alpha = 0.5 */
++ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x80ff0000, 1.0f, 0);
++ ok(hr == D3D_OK, "Clear failed, hr = %08x\n", hr);
++
++ hr = IDirect3DDevice9_CreateTexture(device, 128, 128, 1, D3DUSAGE_RENDERTARGET,
++ D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &offscreenTexture, NULL);
++ ok(SUCCEEDED(hr), "Failed to create texture, hr %#x.\n", hr);
++
++ hr = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
++ ok(hr == D3D_OK, "Can't get back buffer, hr = %08x\n", hr);
++
++ hr = IDirect3DTexture9_GetSurfaceLevel(offscreenTexture, 0, &offscreen);
++ ok(hr == D3D_OK, "Can't get offscreen surface, hr = %08x\n", hr);
++
++ hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE);
++ ok(hr == D3D_OK, "IDirect3DDevice9_SetFVF failed, hr = %#08x\n", hr);
++
++ hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
++ ok(hr == D3D_OK, "SetTextureStageState failed, hr = %08x\n", hr);
++ hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
++ ok(hr == D3D_OK, "SetTextureStageState failed, hr = %08x\n", hr);
++ hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
++ ok(SUCCEEDED(hr), "SetSamplerState D3DSAMP_MINFILTER failed (0x%08x)\n", hr);
++ hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
++ ok(SUCCEEDED(hr), "SetSamplerState D3DSAMP_MAGFILTER failed (0x%08x)\n", hr);
++ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
++ ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %08x\n", hr);
++
++ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHABLENDENABLE, TRUE);
++ ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState failed, hr = %08x\n", hr);
++ hr = IDirect3DDevice9_BeginScene(device);
++ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
++
++ /* draw quad to test default renderstate
++ * expect D3DRS_SRCBLEND == D3DBLEND_ONE
++ * expect D3DRS_DESTBLEND == D3DBLEND_ZERO */
++ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad1, sizeof(quad1[0]));
++ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
++
++ /* set invalid value and expect D3DBLEND_ZERO instead */
++ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_SRCBLEND, 0);
++ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
++ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_SRCBLEND, &rs);
++ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
++ ok(rs == 0, "Unexpected renderstate %#x.\n", rs);
++ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
++ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
++
++ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad2, sizeof(quad2[0]));
++ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
++ /* set non default valid values */
++ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
++ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
++ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_SRCBLEND, &rs);
++ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
++ ok(rs == D3DBLEND_SRCALPHA, "Unexpected renderstate %#x.\n", rs);
++ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
++ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
++ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_DESTBLEND, &rs);
++ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
++ ok(rs == D3DBLEND_INVSRCALPHA, "Failed to get render state, hr %#x.\n", hr);
++
++ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad3, sizeof(quad3[0]));
++ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
++
++ /* set invalid value and expect D3DBLEND_ZERO instead */
++ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, 200);
++ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
++ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_DESTBLEND, &rs);
++ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
++ ok(rs == 200, "Failed to get render state, hr %#x.\n", hr);
++
++ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad4, sizeof(quad4[0]));
++ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
++
++ hr = IDirect3DDevice9_EndScene(device);
++ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
++
++ color = getPixelColor(device, 160, 360);
++ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0x00, 0xff, 0x00), 1),
++ "D3DRS_SRCBLEND ONE returned color %08x, expected 0x0000FF00\n", color);
++
++ color = getPixelColor(device, 480, 120);
++ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0xbf, 0x00, 0x00), 1),
++ "invalid D3DRS_SRCBLEND returned color %08x, expected 0x00bf0000\n", color);
++
++ color = getPixelColor(device, 160, 120);
++ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0x3f, 0x00, 0xC0), 1),
++ "D3DRS_SRCBLEND SRCALPHA returned color %08x, expected 0x003f00C0\n", color);
++
++ color = getPixelColor(device, 480, 360);
++ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0xC0), 1),
++ "invalid D3DRS_DESTBLEND returned color %08x, expected 0x000000C0\n", color);
++
++ IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
++
++ IDirect3DSurface9_Release(backbuffer);
++ IDirect3DTexture9_Release(offscreenTexture);
++ IDirect3DSurface9_Release(offscreen);
++ refcount = IDirect3DDevice9_Release(device);
++ ok(!refcount, "Device has %u references left.\n", refcount);
++done:
++ IDirect3D9_Release(d3d);
++ DestroyWindow(window);
++}
++
+ static void fixed_function_decl_test(void)
+ {
+ IDirect3DVertexDeclaration9 *dcl_float = NULL, *dcl_short = NULL, *dcl_ubyte = NULL, *dcl_color = NULL;
+@@ -12734,6 +12895,9 @@ static void alphatest_test(void)
+ }
+ testdata[] =
+ {
++ /* test invalid values, D3DCMP_NEVER for values less than D3DCMP_NEVER,
++ * D3DCMP_ALWAYS for values greater than D3DCMP_ALWAYS */
++ {D3DCMP_NEVER-1, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_FAILED},
+ {D3DCMP_NEVER, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_FAILED},
+ {D3DCMP_LESS, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_FAILED},
+ {D3DCMP_EQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_FAILED},
+@@ -12742,6 +12906,10 @@ static void alphatest_test(void)
+ {D3DCMP_NOTEQUAL, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_PASSED},
+ {D3DCMP_GREATEREQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_PASSED},
+ {D3DCMP_ALWAYS, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED},
++ {D3DCMP_ALWAYS+1, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED},
++ {D3DCMP_ALWAYS+2, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED},
++ {D3DCMP_ALWAYS+3, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED},
++ {0xdeadbeef, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED},
+ };
+ static const struct
+ {
+@@ -18087,6 +18255,27 @@ static void test_negative_fixedfunction_fog(void)
+ D3DFOG_LINEAR, D3DFOG_NONE, 0x0000ff00, 0x0000ff00, 0x0000ff00},
+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
+ D3DFOG_EXP, D3DFOG_NONE, 0x009b6400, 0x009b6400, 0x009b6400},
++ /* test invalid values, expect a modulo 4 on samplerstate */
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+1, D3DFOG_NONE, 0x0000ff00, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+2, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+3, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+4, D3DFOG_NONE, 0x007f7f00, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+5, D3DFOG_NONE, 0x0000ff00, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+6, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+7, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+8, D3DFOG_NONE, 0x007f7f00, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+9, D3DFOG_NONE, 0x0000ff00, 0x009b6400, 0x009b6400},
++ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f},
++ D3DFOG_LINEAR+10, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400},
+ };
+ D3DCAPS9 caps;
+
+@@ -20511,4 +20700,5 @@ START_TEST(visual)
+ test_depthbias();
+ test_flip();
+ test_uninitialized_varyings();
++ test_blend_invalid_arg();
+ }
+diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
+index 74feb97..d331513 100644
+--- a/dlls/ntdll/loader.c
++++ b/dlls/ntdll/loader.c
+@@ -92,6 +92,7 @@ struct builtin_load_info
+ {
+ const WCHAR *load_path;
+ const WCHAR *filename;
++ const WCHAR *fakemodule;
+ NTSTATUS status;
+ WINE_MODREF *wm;
+ };
+@@ -117,7 +118,8 @@ static WINE_MODREF *cached_modref;
+ static WINE_MODREF *current_modref;
+ static WINE_MODREF *last_failed_modref;
+
+-static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm );
++static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, LPCWSTR fakemodule,
++ DWORD flags, WINE_MODREF** pwm );
+ static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
+ static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
+ DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
+@@ -443,7 +445,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
+ if (!(wm = find_basename_module( mod_name )))
+ {
+ TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
+- if (load_dll( load_path, mod_name, 0, &wm ) == STATUS_SUCCESS &&
++ if (load_dll( load_path, mod_name, NULL, 0, &wm ) == STATUS_SUCCESS &&
+ !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
+ {
+ if (process_attach( wm, NULL ) != STATUS_SUCCESS)
+@@ -592,7 +594,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
+ {
+ ascii_to_unicode( buffer, name, len );
+ buffer[len] = 0;
+- status = load_dll( load_path, buffer, 0, &wmImp );
++ status = load_dll( load_path, buffer, NULL, 0, &wmImp );
+ }
+ else /* need to allocate a larger buffer */
+ {
+@@ -600,7 +602,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
+ if (!ptr) return NULL;
+ ascii_to_unicode( ptr, name, len );
+ ptr[len] = 0;
+- status = load_dll( load_path, ptr, 0, &wmImp );
++ status = load_dll( load_path, ptr, NULL, 0, &wmImp );
+ RtlFreeHeap( GetProcessHeap(), 0, ptr );
+ }
+
+@@ -916,7 +918,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
+ * Allocate a WINE_MODREF structure and add it to the process list
+ * The loader_section must be locked while calling this function.
+ */
+-static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
++static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename, LPCWSTR fakemodule )
+ {
+ WINE_MODREF *wm;
+ const WCHAR *p;
+@@ -939,7 +941,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
+ wm->ldr.TimeDateStamp = 0;
+ wm->ldr.ActivationContext = 0;
+
+- RtlCreateUnicodeString( &wm->ldr.FullDllName, filename );
++ RtlCreateUnicodeString( &wm->ldr.FullDllName, fakemodule ? fakemodule : filename );
+ if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++;
+ else p = wm->ldr.FullDllName.Buffer;
+ RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
+@@ -1578,7 +1580,7 @@ static void load_builtin_callback( void *module, const char *filename )
+ return;
+ }
+
+- wm = alloc_module( module, fullname );
++ wm = alloc_module( module, fullname, builtin_load_info->fakemodule );
+ RtlFreeHeap( GetProcessHeap(), 0, fullname );
+ if (!wm)
+ {
+@@ -1760,8 +1762,8 @@ static NTSTATUS perform_relocations( void *module, SIZE_T len )
+ /******************************************************************************
+ * load_native_dll (internal)
+ */
+-static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
+- DWORD flags, WINE_MODREF** pwm )
++static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, LPCWSTR fakemodule,
++ HANDLE file, DWORD flags, WINE_MODREF** pwm )
+ {
+ void *module;
+ HANDLE mapping;
+@@ -1795,7 +1797,7 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
+
+ /* create the MODREF */
+
+- if (!(wm = alloc_module( module, name )))
++ if (!(wm = alloc_module( module, name, fakemodule )))
+ {
+ status = STATUS_NO_MEMORY;
+ goto done;
+@@ -1859,8 +1861,8 @@ done:
+ /***********************************************************************
+ * load_builtin_dll
+ */
+-static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file,
+- DWORD flags, WINE_MODREF** pwm )
++static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, LPCWSTR fakemodule,
++ HANDLE file, DWORD flags, WINE_MODREF** pwm )
+ {
+ char error[256], dllname[MAX_PATH];
+ const WCHAR *name, *p;
+@@ -1880,6 +1882,7 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file,
+ */
+ info.load_path = load_path;
+ info.filename = NULL;
++ info.fakemodule = fakemodule;
+ info.status = STATUS_SUCCESS;
+ info.wm = NULL;
+
+@@ -2198,14 +2201,14 @@ overflow:
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+-
+ /***********************************************************************
+ * load_dll (internal)
+ *
+ * Load a PE style module according to the load order.
+ * The loader_section must be locked while calling this function.
+ */
+-static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )
++static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, LPCWSTR fakemodule,
++ DWORD flags, WINE_MODREF** pwm )
+ {
+ enum loadorder loadorder;
+ WCHAR buffer[64];
+@@ -2242,6 +2245,25 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
+ }
+
+ main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
++
++ /* handle dll redirection */
++ if (!fakemodule)
++ {
++ BYTE buffer2[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
++ WCHAR *redirect = get_redirect( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL,
++ filename, buffer2, sizeof(buffer2) );
++ if (redirect)
++ {
++ FIXME("Loader redirect from %s to %s\n", debugstr_w(libname), debugstr_w(redirect));
++
++ nts = load_dll( load_path, redirect, filename, flags, pwm );
++
++ if (handle) NtClose( handle );
++ if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
++ return nts;
++ }
++ }
++
+ loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, filename );
+
+ if (handle && is_fake_dll( handle ))
+@@ -2264,22 +2286,22 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
+ if (!handle) nts = STATUS_DLL_NOT_FOUND;
+ else
+ {
+- nts = load_native_dll( load_path, filename, handle, flags, pwm );
++ nts = load_native_dll( load_path, filename, fakemodule, handle, flags, pwm );
+ if (nts == STATUS_INVALID_IMAGE_NOT_MZ)
+ /* not in PE format, maybe it's a builtin */
+- nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
++ nts = load_builtin_dll( load_path, filename, fakemodule, handle, flags, pwm );
+ }
+ if (nts == STATUS_DLL_NOT_FOUND && loadorder == LO_NATIVE_BUILTIN)
+- nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
++ nts = load_builtin_dll( load_path, filename, fakemodule, 0, flags, pwm );
+ break;
+ case LO_BUILTIN:
+ case LO_BUILTIN_NATIVE:
+ case LO_DEFAULT: /* default is builtin,native */
+- nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
++ nts = load_builtin_dll( load_path, filename, fakemodule, handle, flags, pwm );
+ if (!handle) break; /* nothing else we can try */
+ /* file is not a builtin library, try without using the specified file */
+ if (nts != STATUS_SUCCESS)
+- nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
++ nts = load_builtin_dll( load_path, filename, fakemodule, 0, flags, pwm );
+ if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT &&
+ (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS))
+ {
+@@ -2289,7 +2311,7 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
+ nts = STATUS_DLL_NOT_FOUND;
+ }
+ if (nts == STATUS_DLL_NOT_FOUND && loadorder != LO_BUILTIN)
+- nts = load_native_dll( load_path, filename, handle, flags, pwm );
++ nts = load_native_dll( load_path, filename, fakemodule, handle, flags, pwm );
+ break;
+ }
+
+@@ -2322,7 +2344,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
+ RtlEnterCriticalSection( &loader_section );
+
+ if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
+- nts = load_dll( path_name, libname->Buffer, flags, &wm );
++ nts = load_dll( path_name, libname->Buffer, NULL, flags, &wm );
+
+ if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
+ {
+@@ -3285,7 +3307,7 @@ void __wine_process_init(void)
+ /* setup the load callback and create ntdll modref */
+ wine_dll_set_callback( load_builtin_callback );
+
+- if ((status = load_builtin_dll( NULL, kernel32W, 0, 0, &wm )) != STATUS_SUCCESS)
++ if ((status = load_builtin_dll( NULL, kernel32W, NULL, 0, 0, &wm )) != STATUS_SUCCESS)
+ {
+ MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
+ exit(1);
+diff --git a/dlls/ntdll/loadorder.c b/dlls/ntdll/loadorder.c
+index 401d256..c7c4592 100644
+--- a/dlls/ntdll/loadorder.c
++++ b/dlls/ntdll/loadorder.c
+@@ -290,102 +290,165 @@ static inline enum loadorder get_env_load_order( const WCHAR *module )
+
+
+ /***************************************************************************
+- * get_standard_key
++ * open_user_reg_key
++ *
++ * Return a handle to a registry key under HKCU.
++ */
++static HANDLE open_user_reg_key(const WCHAR *key_name)
++{
++ HANDLE hkey, root;
++ OBJECT_ATTRIBUTES attr;
++ UNICODE_STRING nameW;
++
++ RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
++ attr.Length = sizeof(attr);
++ attr.RootDirectory = root;
++ attr.ObjectName = &nameW;
++ attr.Attributes = 0;
++ attr.SecurityDescriptor = NULL;
++ attr.SecurityQualityOfService = NULL;
++ RtlInitUnicodeString( &nameW, key_name );
++
++ if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) hkey = 0;
++ NtClose( root );
++
++ return hkey;
++}
++
++
++/***************************************************************************
++ * open_app_reg_key
++ *
++ * Return a handle to an app-specific registry key.
++ */
++static HANDLE open_app_reg_key( const WCHAR *sub_key, const WCHAR *app_name )
++{
++ static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
++ 'A','p','p','D','e','f','a','u','l','t','s','\\',0};
++ WCHAR *str;
++ HANDLE hkey;
++
++ str = RtlAllocateHeap( GetProcessHeap(), 0,
++ sizeof(AppDefaultsW) +
++ strlenW(sub_key) * sizeof(WCHAR) +
++ strlenW(app_name) * sizeof(WCHAR) );
++ if (!str) return 0;
++ strcpyW( str, AppDefaultsW );
++ strcatW( str, app_name );
++ strcatW( str, sub_key );
++
++ hkey = open_user_reg_key( str );
++ RtlFreeHeap( GetProcessHeap(), 0, str );
++ return hkey;
++}
++
++
++/***************************************************************************
++ * get_override_standard_key
+ *
+ * Return a handle to the standard DllOverrides registry section.
+ */
+-static HANDLE get_standard_key(void)
++static HANDLE get_override_standard_key(void)
+ {
+ static const WCHAR DllOverridesW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
+ 'D','l','l','O','v','e','r','r','i','d','e','s',0};
+ static HANDLE std_key = (HANDLE)-1;
+
+ if (std_key == (HANDLE)-1)
+- {
+- OBJECT_ATTRIBUTES attr;
+- UNICODE_STRING nameW;
+- HANDLE root;
+-
+- RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
+- attr.Length = sizeof(attr);
+- attr.RootDirectory = root;
+- attr.ObjectName = &nameW;
+- attr.Attributes = 0;
+- attr.SecurityDescriptor = NULL;
+- attr.SecurityQualityOfService = NULL;
+- RtlInitUnicodeString( &nameW, DllOverridesW );
+-
+- /* @@ Wine registry key: HKCU\Software\Wine\DllOverrides */
+- if (NtOpenKey( &std_key, KEY_ALL_ACCESS, &attr )) std_key = 0;
+- NtClose( root );
+- }
++ std_key = open_user_reg_key( DllOverridesW );
++
+ return std_key;
+ }
+
+
+ /***************************************************************************
+- * get_app_key
++ * get_override_app_key
+ *
+ * Get the registry key for the app-specific DllOverrides list.
+ */
+-static HANDLE get_app_key( const WCHAR *app_name )
++static HANDLE get_override_app_key( const WCHAR *app_name )
+ {
+- OBJECT_ATTRIBUTES attr;
+- UNICODE_STRING nameW;
+- HANDLE root;
+- WCHAR *str;
+- static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
+- 'A','p','p','D','e','f','a','u','l','t','s','\\',0};
+ static const WCHAR DllOverridesW[] = {'\\','D','l','l','O','v','e','r','r','i','d','e','s',0};
+ static HANDLE app_key = (HANDLE)-1;
+
+- if (app_key != (HANDLE)-1) return app_key;
++ if (app_key == (HANDLE)-1)
++ app_key = open_app_reg_key( DllOverridesW, app_name );
+
+- str = RtlAllocateHeap( GetProcessHeap(), 0,
+- sizeof(AppDefaultsW) + sizeof(DllOverridesW) +
+- strlenW(app_name) * sizeof(WCHAR) );
+- if (!str) return 0;
+- strcpyW( str, AppDefaultsW );
+- strcatW( str, app_name );
+- strcatW( str, DllOverridesW );
++ return app_key;
++}
+
+- RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
+- attr.Length = sizeof(attr);
+- attr.RootDirectory = root;
+- attr.ObjectName = &nameW;
+- attr.Attributes = 0;
+- attr.SecurityDescriptor = NULL;
+- attr.SecurityQualityOfService = NULL;
+- RtlInitUnicodeString( &nameW, str );
+
+- /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DllOverrides */
+- if (NtOpenKey( &app_key, KEY_ALL_ACCESS, &attr )) app_key = 0;
+- NtClose( root );
+- RtlFreeHeap( GetProcessHeap(), 0, str );
++/***************************************************************************
++ * get_redirect_standard_key
++ *
++ * Return a handle to the standard DllRedirects registry section.
++ */
++static HANDLE get_redirect_standard_key(void)
++{
++ static const WCHAR DllRedirectsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
++ 'D','l','l','R','e','d','i','r','e','c','t','s',0};
++ static HANDLE std_key = (HANDLE)-1;
++
++ if (std_key == (HANDLE)-1)
++ std_key = open_user_reg_key( DllRedirectsW );
++
++ return std_key;
++}
++
++
++/***************************************************************************
++ * get_redirect_app_key
++ *
++ * Get the registry key for the app-specific DllRedirects list.
++ */
++static HANDLE get_redirect_app_key( const WCHAR *app_name )
++{
++ static const WCHAR DllRedirectsW[] = {'\\','D','l','l','R','e','d','i','r','e','c','t','s',0};
++ static HANDLE app_key = (HANDLE)-1;
++
++ if (app_key == (HANDLE)-1)
++ app_key = open_app_reg_key( DllRedirectsW, app_name );
++
+ return app_key;
+ }
+
+
+ /***************************************************************************
+- * get_registry_value
++ * get_registry_string
+ *
+- * Load the registry loadorder value for a given module.
++ * Load a registry string for a given module.
+ */
+-static enum loadorder get_registry_value( HANDLE hkey, const WCHAR *module )
++static WCHAR* get_registry_string( HANDLE hkey, const WCHAR *module, BYTE *buffer,
++ ULONG size )
+ {
+ UNICODE_STRING valueW;
+- char buffer[80];
+ DWORD count;
++ WCHAR *ret = NULL;
+
+ RtlInitUnicodeString( &valueW, module );
+-
+- if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation,
+- buffer, sizeof(buffer), &count ))
++ if (size >= sizeof(WCHAR) &&
++ !NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation,
++ buffer, size - sizeof(WCHAR), &count ))
+ {
+- WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
+- return parse_load_order( str );
++ KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer;
++ ret = (WCHAR *)info->Data;
++ ret[info->DataLength / sizeof(WCHAR)] = 0;
+ }
+- return LO_INVALID;
++
++ return ret;
++}
++
++
++/***************************************************************************
++ * get_registry_load_order
++ *
++ * Load the registry loadorder value for a given module.
++ */
++static enum loadorder get_registry_load_order( HANDLE hkey, const WCHAR *module )
++{
++ BYTE buffer[81];
++ WCHAR *str = get_registry_string( hkey, module, buffer, sizeof(buffer) );
++ return str ? parse_load_order( str ) : LO_INVALID;
+ }
+
+
+@@ -407,13 +470,13 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, cons
+ return ret;
+ }
+
+- if (app_key && ((ret = get_registry_value( app_key, module )) != LO_INVALID))
++ if (app_key && ((ret = get_registry_load_order( app_key, module )) != LO_INVALID))
+ {
+ TRACE( "got app defaults %s for %s\n", debugstr_loadorder(ret), debugstr_w(module) );
+ return ret;
+ }
+
+- if (std_key && ((ret = get_registry_value( std_key, module )) != LO_INVALID))
++ if (std_key && ((ret = get_registry_load_order( std_key, module )) != LO_INVALID))
+ {
+ TRACE( "got standard key %s for %s\n", debugstr_loadorder(ret), debugstr_w(module) );
+ return ret;
+@@ -424,24 +487,44 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, cons
+
+
+ /***************************************************************************
+- * get_load_order (internal)
++ * get_redirect_value
+ *
+- * Return the loadorder of a module.
+- * The system directory and '.dll' extension is stripped from the path.
++ * Get the redirect value for the exact specified module string, looking in:
++ * 1. The per-application DllRedirects key
++ * 2. The standard DllRedirects key
+ */
+-enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path )
++static WCHAR* get_redirect_value( HANDLE std_key, HANDLE app_key, const WCHAR *module,
++ BYTE *buffer, ULONG size )
+ {
+- enum loadorder ret = LO_INVALID;
+- HANDLE std_key, app_key = 0;
+- WCHAR *module, *basename;
+- UNICODE_STRING path_str;
+- int len;
++ WCHAR *ret = NULL;
+
+- if (!init_done) init_load_order();
+- std_key = get_standard_key();
+- if (app_name) app_key = get_app_key( app_name );
++ if (app_key && (ret = get_registry_string( app_key, module, buffer, size )))
++ {
++ TRACE( "got app defaults %s for %s\n", debugstr_w(ret), debugstr_w(module) );
++ return ret;
++ }
+
+- TRACE("looking for %s\n", debugstr_w(path));
++ if (std_key && (ret = get_registry_string( std_key, module, buffer, size )))
++ {
++ TRACE( "got standard key %s for %s\n", debugstr_w(ret), debugstr_w(module) );
++ return ret;
++ }
++
++ return ret;
++}
++
++
++/***************************************************************************
++ * get_module_basename
++ *
++ * Determine the module basename. The caller is responsible for releasing
++ * the memory.
++ */
++static WCHAR* get_module_basename( const WCHAR *path, WCHAR **basename )
++{
++ UNICODE_STRING path_str;
++ WCHAR *module;
++ int len;
+
+ /* Strip path information if the module resides in the system directory
+ */
+@@ -453,12 +536,36 @@ enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path )
+ if (!strchrW( p, '\\' ) && !strchrW( p, '/' )) path = p;
+ }
+
+- if (!(len = strlenW(path))) return ret;
+- if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return ret;
++ if (!(len = strlenW(path))) return NULL;
++ if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return NULL;
+ strcpyW( module+1, path ); /* reserve module[0] for the wildcard char */
+- basename = (WCHAR *)get_basename( module+1 );
++ *basename = (WCHAR *)get_basename( module+1 );
+
+ if (len >= 4) remove_dll_ext( module + 1 + len - 4 );
++ return module;
++}
++
++
++/***************************************************************************
++ * get_load_order (internal)
++ *
++ * Return the loadorder of a module.
++ * The system directory and '.dll' extension is stripped from the path.
++ */
++enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path )
++{
++ enum loadorder ret = LO_INVALID;
++ HANDLE std_key, app_key = 0;
++ WCHAR *module, *basename;
++
++ if (!init_done) init_load_order();
++ std_key = get_override_standard_key();
++ if (app_name) app_key = get_override_app_key( app_name );
++
++ TRACE("looking up loadorder for %s\n", debugstr_w(path));
++
++ if (!(module = get_module_basename(path, &basename)))
++ return ret;
+
+ /* first explicit module name */
+ if ((ret = get_load_order_value( std_key, app_key, module+1 )) != LO_INVALID)
+@@ -489,3 +596,46 @@ enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path )
+ RtlFreeHeap( GetProcessHeap(), 0, module );
+ return ret;
+ }
++
++
++/***************************************************************************
++ * get_redirect (internal)
++ *
++ * Return the redirect value of a module.
++ * The system directory and '.dll' extension is stripped from the path.
++ */
++WCHAR* get_redirect( const WCHAR *app_name, const WCHAR *path, BYTE *buffer, ULONG size )
++{
++ WCHAR *ret = NULL;
++ HANDLE std_key, app_key = 0;
++ WCHAR *module, *basename;
++
++ std_key = get_redirect_standard_key();
++ if (app_name) app_key = get_redirect_app_key( app_name );
++
++ TRACE("looking up redirection for %s\n", debugstr_w(path));
++
++ if (!(module = get_module_basename(path, &basename)))
++ return ret;
++
++ /* first explicit module name */
++ if ((ret = get_redirect_value( std_key, app_key, module+1, buffer, size )))
++ goto done;
++
++ /* then module basename preceded by '*' */
++ basename[-1] = '*';
++ if ((ret = get_redirect_value( std_key, app_key, basename-1, buffer, size )))
++ goto done;
++
++ /* then module basename without '*' (only if explicit path) */
++ if (basename != module+1 && (ret = get_redirect_value( std_key, app_key, basename, buffer, size )))
++ goto done;
++
++ /* and last the hard-coded default */
++ ret = NULL;
++ TRACE( "no redirection found for %s\n", debugstr_w(path) );
++
++ done:
++ RtlFreeHeap( GetProcessHeap(), 0, module );
++ return ret;
++}
+diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
+index cbd19db..e522464 100644
+--- a/dlls/ntdll/ntdll_misc.h
++++ b/dlls/ntdll/ntdll_misc.h
+@@ -205,6 +205,7 @@ enum loadorder
+ };
+
+ extern enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) DECLSPEC_HIDDEN;
++extern WCHAR* get_redirect( const WCHAR *app_name, const WCHAR *path, BYTE *buffer, ULONG size ) DECLSPEC_HIDDEN;
+
+ struct debug_info
+ {
+diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c
+index 6bc4fb3..b0024a0 100644
+--- a/dlls/winex11.drv/init.c
++++ b/dlls/winex11.drv/init.c
+@@ -365,6 +365,7 @@ static INT X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_d
+ {
+ struct x11drv_escape_get_drawable *data = out_data;
+ data->drawable = physDev->drawable;
++ data->dc_rect = physDev->dc_rect;
+ return TRUE;
+ }
+ break;
+diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
+index 2694d23..3e94b64 100644
+--- a/dlls/winex11.drv/x11drv.h
++++ b/dlls/winex11.drv/x11drv.h
+@@ -292,6 +292,7 @@ struct x11drv_escape_get_drawable
+ Drawable drawable; /* X drawable */
+ Drawable gl_drawable; /* GL drawable */
+ int pixel_format; /* internal GL pixel format */
++ RECT dc_rect; /* DC rectangle relative to drawable */
+ };
+
+ struct x11drv_escape_flush_gl_drawable
+diff --git a/programs/winecfg/Makefile.in b/programs/winecfg/Makefile.in
+index 7b52a69..c86fdd0 100644
+--- a/programs/winecfg/Makefile.in
++++ b/programs/winecfg/Makefile.in
+@@ -11,6 +11,7 @@ C_SRCS = \
+ driveui.c \
+ libraries.c \
+ main.c \
++ staging.c \
+ theme.c \
+ winecfg.c \
+ x11drvdlg.c
+diff --git a/programs/winecfg/main.c b/programs/winecfg/main.c
+index b8a85fe..de209a9 100644
+--- a/programs/winecfg/main.c
++++ b/programs/winecfg/main.c
+@@ -58,7 +58,7 @@ PropSheetCallback (HWND hWnd, UINT uMsg, LPARAM lParam)
+ return 0;
+ }
+
+-#define NUM_PROPERTY_PAGES 7
++#define NUM_PROPERTY_PAGES 8
+
+ static INT_PTR
+ doPropertySheet (HINSTANCE hInstance, HWND hOwner)
+@@ -139,6 +139,16 @@ doPropertySheet (HINSTANCE hInstance, HWND hOwner)
+ psp[pg].lParam = 0;
+ pg++;
+
++ psp[pg].dwSize = sizeof (PROPSHEETPAGEW);
++ psp[pg].dwFlags = PSP_USETITLE;
++ psp[pg].hInstance = hInstance;
++ psp[pg].u.pszTemplate = MAKEINTRESOURCEW (IDD_STAGING);
++ psp[pg].u2.pszIcon = NULL;
++ psp[pg].pfnDlgProc = StagingDlgProc;
++ psp[pg].pszTitle = load_string (IDS_TAB_STAGING);
++ psp[pg].lParam = 0;
++ pg++;
++
+ /*
+ * Fill out the (General) PROPSHEETPAGE data structure
+ * for the property sheet
+diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h
+index 8604fb4..201e5c3 100644
+--- a/programs/winecfg/resource.h
++++ b/programs/winecfg/resource.h
+@@ -45,6 +45,7 @@
+ #define IDS_SHELL_FOLDER 16
+ #define IDS_LINKS_TO 17
+ #define IDS_WINECFG_TITLE_APP 18 /* App specific title */
++#define IDS_TAB_STAGING 19
+ #define IDI_WINECFG 100
+ #define IDI_LOGO 102
+ #define IDD_ABOUTCFG 107
+@@ -54,6 +55,7 @@
+ #define IDD_DLLCFG 111
+ #define IDD_DRIVECFG 112
+ #define IDD_DESKTOP_INTEGRATION 115
++#define IDD_STAGING 116
+ #define IDC_WINVER 1012
+ #define IDC_DESKTOP_WIDTH 1023
+ #define IDC_DESKTOP_HEIGHT 1024
+@@ -218,3 +220,6 @@
+ #define IDC_ABT_TITLE_TEXT 8436
+ #define IDC_ABT_WEB_LINK 8437
+ #define IDC_ABT_LICENSE_TEXT 8438
++
++/* Staging tab */
++#define IDC_ENABLE_NATIVE_D3D9 9001
+diff --git a/programs/winecfg/staging.c b/programs/winecfg/staging.c
+new file mode 100644
+index 0000000..4a53815
+--- /dev/null
++++ b/programs/winecfg/staging.c
+@@ -0,0 +1,93 @@
++/*
++ * WineCfg Staging panel
++ *
++ * Copyright 2014 Michael Müller
++ * Copyright 2015 Sebastian Lackner
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ *
++ */
++
++#define COBJMACROS
++
++#include "config.h"
++
++#include <windows.h>
++#include <wine/unicode.h>
++#include <wine/debug.h>
++
++#include "resource.h"
++#include "winecfg.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
++
++/*
++ * Gallium nine
++ */
++static BOOL nine_get(void)
++{
++ BOOL ret;
++ char *value = get_reg_key(config_key, keypath("DllRedirects"), "d3d9", NULL);
++ ret = (value && !strcmp(value, "d3d9-nine.dll"));
++ HeapFree(GetProcessHeap(), 0, value);
++ return ret;
++}
++
++static void nine_set(BOOL status)
++{
++ set_reg_key(config_key, keypath("DllRedirects"), "d3d9", status ? "d3d9-nine.dll" : NULL);
++}
++
++
++static void load_staging_settings(HWND dialog)
++{
++ CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, nine_get() ? BST_CHECKED : BST_UNCHECKED);
++#if !defined(SONAME_D3DADAPTER9)
++ disable(IDC_ENABLE_NATIVE_D3D9);
++#endif
++}
++
++INT_PTR CALLBACK StagingDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
++{
++ switch (uMsg)
++ {
++ case WM_INITDIALOG:
++ break;
++
++ case WM_NOTIFY:
++ if (((LPNMHDR)lParam)->code == PSN_SETACTIVE)
++ load_staging_settings(hDlg);
++ break;
++
++ case WM_SHOWWINDOW:
++ set_window_title(hDlg);
++ break;
++
++ case WM_DESTROY:
++ break;
++
++ case WM_COMMAND:
++ if (HIWORD(wParam) != BN_CLICKED) break;
++ switch (LOWORD(wParam))
++ {
++ case IDC_ENABLE_NATIVE_D3D9:
++ nine_set(IsDlgButtonChecked(hDlg, IDC_ENABLE_NATIVE_D3D9) == BST_CHECKED);
++ SendMessageW(GetParent(hDlg), PSM_CHANGED, 0, 0);
++ return TRUE;
++ }
++ break;
++ }
++ return FALSE;
++}
+diff --git a/programs/winecfg/winecfg.h b/programs/winecfg/winecfg.h
+index 110856a..a949474 100644
+--- a/programs/winecfg/winecfg.h
++++ b/programs/winecfg/winecfg.h
+@@ -87,6 +87,7 @@ INT_PTR CALLBACK AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ INT_PTR CALLBACK LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR CALLBACK AudioDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR CALLBACK ThemeDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
++INT_PTR CALLBACK StagingDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ INT_PTR CALLBACK AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ /* Drive management */
+diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc
+index 221916b..ee4c55d 100644
+--- a/programs/winecfg/winecfg.rc
++++ b/programs/winecfg/winecfg.rc
+@@ -39,6 +39,7 @@ BEGIN
+ IDS_TAB_GRAPHICS "Graphics"
+ IDS_TAB_DESKTOP_INTEGRATION "Desktop Integration"
+ IDS_TAB_AUDIO "Audio"
++ IDS_TAB_STAGING "Staging"
+ IDS_TAB_ABOUT "About"
+ IDS_WINECFG_TITLE "Wine configuration"
+ IDS_WINECFG_TITLE_APP "Wine configuration for %s"
+@@ -308,6 +309,15 @@ BEGIN
+ PUSHBUTTON "B&rowse...",IDC_BROWSE_SFPATH,195,195,50,13,WS_DISABLED
+ END
+
++IDD_STAGING DIALOG 0, 0, 260, 220
++STYLE WS_CHILD | WS_DISABLED
++FONT 8, "MS Shell Dlg"
++BEGIN
++ GROUPBOX "Staging settings",IDC_STATIC,8,4,244,210
++ LTEXT "The following settings are experimental and may break stuff!\nMake sure to reset them again in case of a problem.\nGallium Nine requires MESA graphic drivers and AMD/Nvidia GPU.\n",IDC_STATIC,16,16,230,24
++ CONTROL "Enable &Gallium Nine for better D3D9 graphic performance.",IDC_ENABLE_NATIVE_D3D9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,40,230,8
++END
++
+ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+ /* @makedep: winecfg.ico */
diff --git a/app-emulation/wine/files/wine-gcc-4.9-null-pointer.patch b/app-emulation/wine/files/wine-gcc-4.9-null-pointer.patch
new file mode 100644
index 00000000..213f2c6c
--- /dev/null
+++ b/app-emulation/wine/files/wine-gcc-4.9-null-pointer.patch
@@ -0,0 +1,35 @@
+From deb274226783ab886bdb44876944e156757efe2b Mon Sep 17 00:00:00 2001
+From: Daniel Beitler <dan@dablabs.com>
+Date: Sun, 18 May 2014 13:27:42 -0400
+Subject: [PATCH] msi: Prevent call to memset with a null pointer in
+ get_tablecolumns function.
+
+---
+ dlls/msi/table.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/dlls/msi/table.c b/dlls/msi/table.c
+index 8012369..9ed9421 100644
+--- a/dlls/msi/table.c
++++ b/dlls/msi/table.c
+@@ -671,7 +671,7 @@ static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINF
+ /* Note: _Columns table doesn't have non-persistent data */
+
+ /* if maxcount is non-zero, assume it's exactly right for this table */
+- memset( colinfo, 0, maxcount * sizeof(*colinfo) );
++ if (colinfo) memset( colinfo, 0, maxcount * sizeof(*colinfo) );
+ count = table->row_count;
+ for (i = 0; i < count; i++)
+ {
+@@ -684,7 +684,7 @@ static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINF
+ /* check the column number is in range */
+ if (col < 1 || col > maxcount)
+ {
+- ERR("column %d out of range\n", col);
++ ERR("column %d out of range (maxcount: %d)\n", col, maxcount);
+ continue;
+ }
+ /* check if this column was already set */
+--
+1.9.1
+
diff --git a/app-emulation/wine/wine-1.7.55.ebuild b/app-emulation/wine/wine-1.7.55.ebuild
new file mode 100644
index 00000000..882c060d
--- /dev/null
+++ b/app-emulation/wine/wine-1.7.55.ebuild
@@ -0,0 +1,446 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI="5"
+
+AUTOTOOLS_AUTORECONF=1
+PLOCALES="ar bg ca cs da de el en en_US eo es fa fi fr he hi hr hu it ja ko lt ml nb_NO nl or pa pl pt_BR pt_PT rm ro ru sk sl sr_RS@cyrillic sr_RS@latin sv te th tr uk wa zh_CN zh_TW"
+PLOCALE_BACKUP="en"
+
+inherit autotools-utils eutils fdo-mime flag-o-matic gnome2-utils l10n multilib multilib-minimal pax-utils toolchain-funcs virtualx versionator
+
+if [[ ${PV} == "9999" ]] ; then
+ EGIT_REPO_URI="git://source.winehq.org/git/wine.git http://source.winehq.org/git/wine.git"
+ EGIT_BRANCH="master"
+ inherit git-r3
+ SRC_URI=""
+ #KEYWORDS=""
+else
+ MAJOR_V=$(get_version_component_range 1-2)
+ SRC_URI="https://dl.winehq.org/wine/source/${MAJOR_V}/${P}.tar.bz2"
+ KEYWORDS="-* ~amd64 ~x86 ~x86-fbsd"
+fi
+
+GV="2.40"
+MV="4.5.6"
+STAGING_P="wine-staging-${PV}"
+STAGING_DIR="${WORKDIR}/${STAGING_P}"
+WINE_GENTOO="wine-gentoo-2015.03.07"
+GST_P="wine-1.7.34-gstreamer-v5"
+DESCRIPTION="Free implementation of Windows(tm) on Unix"
+HOMEPAGE="http://www.winehq.org/"
+SRC_URI="${SRC_URI}
+ gecko? (
+ abi_x86_32? ( mirror://sourceforge/${PN}/Wine%20Gecko/${GV}/wine_gecko-${GV}-x86.msi )
+ abi_x86_64? ( mirror://sourceforge/${PN}/Wine%20Gecko/${GV}/wine_gecko-${GV}-x86_64.msi )
+ )
+ mono? ( mirror://sourceforge/${PN}/Wine%20Mono/${MV}/wine-mono-${MV}.msi )
+ gstreamer? ( https://dev.gentoo.org/~tetromino/distfiles/${PN}/${GST_P}.patch.bz2 )
+ https://dev.gentoo.org/~tetromino/distfiles/${PN}/${WINE_GENTOO}.tar.bz2"
+
+if [[ ${PV} == "9999" ]] ; then
+ STAGING_EGIT_REPO_URI="git://github.com/wine-compholio/wine-staging.git"
+else
+ SRC_URI="${SRC_URI}
+ staging? ( https://github.com/wine-compholio/wine-staging/archive/v${PV}.tar.gz -> ${STAGING_P}.tar.gz )"
+fi
+
+LICENSE="LGPL-2.1"
+SLOT="0"
+IUSE="+abi_x86_32 +abi_x86_64 +alsa capi cups custom-cflags dos +d3d9 elibc_glibc +fontconfig +gecko gphoto2 gsm gstreamer +jpeg +lcms ldap +mono mp3 ncurses netapi nls odbc openal opencl +opengl osmesa oss +perl pcap pipelight +png prelink pulseaudio +realtime +run-exes s3tc samba scanner selinux +ssl staging test +threads +truetype +udisks v4l vaapi +X +xcomposite xinerama +xml"
+REQUIRED_USE="|| ( abi_x86_32 abi_x86_64 )
+ test? ( abi_x86_32 )
+ d3d9? ( !staging )
+ staging? ( !d3d9 )
+ elibc_glibc? ( threads )
+ mono? ( abi_x86_32 )
+ pipelight? ( staging )
+ s3tc? ( staging )
+ vaapi? ( staging )
+ ?? ( gstreamer staging )
+ osmesa? ( opengl )" #286560
+
+# FIXME: the test suite is unsuitable for us; many tests require net access
+# or fail due to Xvfb's opengl limitations.
+RESTRICT="test"
+
+COMMON_DEPEND="
+ truetype? ( >=media-libs/freetype-2.0.0[${MULTILIB_USEDEP}] )
+ capi? ( net-dialup/capi4k-utils )
+ ncurses? ( >=sys-libs/ncurses-5.2:0=[${MULTILIB_USEDEP}] )
+ udisks? ( sys-apps/dbus[${MULTILIB_USEDEP}] )
+ fontconfig? ( media-libs/fontconfig:=[${MULTILIB_USEDEP}] )
+ gphoto2? ( media-libs/libgphoto2:=[${MULTILIB_USEDEP}] )
+ openal? ( media-libs/openal:=[${MULTILIB_USEDEP}] )
+ gstreamer? (
+ media-libs/gstreamer:0.10[${MULTILIB_USEDEP}]
+ media-libs/gst-plugins-base:0.10[${MULTILIB_USEDEP}]
+ )
+ X? (
+ x11-libs/libXcursor[${MULTILIB_USEDEP}]
+ x11-libs/libXext[${MULTILIB_USEDEP}]
+ x11-libs/libXrandr[${MULTILIB_USEDEP}]
+ x11-libs/libXi[${MULTILIB_USEDEP}]
+ x11-libs/libXxf86vm[${MULTILIB_USEDEP}]
+ )
+ xinerama? ( x11-libs/libXinerama[${MULTILIB_USEDEP}] )
+ alsa? ( media-libs/alsa-lib[${MULTILIB_USEDEP}] )
+ cups? ( net-print/cups:=[${MULTILIB_USEDEP}] )
+ d3d9? ( media-libs/mesa[d3d9] )
+ opencl? ( virtual/opencl[${MULTILIB_USEDEP}] )
+ opengl? (
+ virtual/glu[${MULTILIB_USEDEP}]
+ virtual/opengl[${MULTILIB_USEDEP}]
+ )
+ gsm? ( media-sound/gsm:=[${MULTILIB_USEDEP}] )
+ jpeg? ( virtual/jpeg:0=[${MULTILIB_USEDEP}] )
+ ldap? ( net-nds/openldap:=[${MULTILIB_USEDEP}] )
+ lcms? ( media-libs/lcms:2=[${MULTILIB_USEDEP}] )
+ mp3? ( >=media-sound/mpg123-1.5.0[${MULTILIB_USEDEP}] )
+ netapi? ( net-fs/samba[netapi(+),${MULTILIB_USEDEP}] )
+ nls? ( sys-devel/gettext[${MULTILIB_USEDEP}] )
+ odbc? ( dev-db/unixODBC:=[${MULTILIB_USEDEP}] )
+ osmesa? ( media-libs/mesa[osmesa,${MULTILIB_USEDEP}] )
+ pcap? ( net-libs/libpcap[${MULTILIB_USEDEP}] )
+ pulseaudio? ( media-sound/pulseaudio[${MULTILIB_USEDEP}] )
+ staging? ( sys-apps/attr[${MULTILIB_USEDEP}] )
+ xml? (
+ dev-libs/libxml2[${MULTILIB_USEDEP}]
+ dev-libs/libxslt[${MULTILIB_USEDEP}]
+ )
+ scanner? ( media-gfx/sane-backends:=[${MULTILIB_USEDEP}] )
+ ssl? ( net-libs/gnutls:=[${MULTILIB_USEDEP}] )
+ png? ( media-libs/libpng:0=[${MULTILIB_USEDEP}] )
+ v4l? ( media-libs/libv4l[${MULTILIB_USEDEP}] )
+ vaapi? ( x11-libs/libva[X,${MULTILIB_USEDEP}] )
+ xcomposite? ( x11-libs/libXcomposite[${MULTILIB_USEDEP}] )
+ abi_x86_32? (
+ !app-emulation/emul-linux-x86-baselibs[-abi_x86_32(-)]
+ !<app-emulation/emul-linux-x86-baselibs-20140508-r14
+ !app-emulation/emul-linux-x86-db[-abi_x86_32(-)]
+ !<app-emulation/emul-linux-x86-db-20140508-r3
+ !app-emulation/emul-linux-x86-medialibs[-abi_x86_32(-)]
+ !<app-emulation/emul-linux-x86-medialibs-20140508-r6
+ !app-emulation/emul-linux-x86-opengl[-abi_x86_32(-)]
+ !<app-emulation/emul-linux-x86-opengl-20140508-r1
+ !app-emulation/emul-linux-x86-sdl[-abi_x86_32(-)]
+ !<app-emulation/emul-linux-x86-sdl-20140508-r1
+ !app-emulation/emul-linux-x86-soundlibs[-abi_x86_32(-)]
+ !<app-emulation/emul-linux-x86-soundlibs-20140508
+ !app-emulation/emul-linux-x86-xlibs[-abi_x86_32(-)]
+ !<app-emulation/emul-linux-x86-xlibs-20140508
+ )"
+
+RDEPEND="${COMMON_DEPEND}
+ dos? ( games-emulation/dosbox )
+ perl? ( dev-lang/perl dev-perl/XML-Simple )
+ s3tc? ( >=media-libs/libtxc_dxtn-1.0.1-r1[${MULTILIB_USEDEP}] )
+ samba? ( >=net-fs/samba-3.0.25 )
+ selinux? ( sec-policy/selinux-wine )
+ udisks? ( sys-fs/udisks:2 )
+ pulseaudio? ( realtime? ( sys-auth/rtkit ) )"
+
+# tools/make_requests requires perl
+DEPEND="${COMMON_DEPEND}
+ staging? ( dev-lang/perl dev-perl/XML-Simple )
+ X? (
+ x11-proto/inputproto
+ x11-proto/xextproto
+ x11-proto/xf86vidmodeproto
+ )
+ xinerama? ( x11-proto/xineramaproto )
+ prelink? ( sys-devel/prelink )
+ >=sys-kernel/linux-headers-2.6
+ virtual/pkgconfig
+ virtual/yacc
+ sys-devel/flex"
+
+# These use a non-standard "Wine" category, which is provided by
+# /etc/xdg/applications-merged/wine.menu
+QA_DESKTOP_FILE="usr/share/applications/wine-browsedrive.desktop
+usr/share/applications/wine-notepad.desktop
+usr/share/applications/wine-uninstaller.desktop
+usr/share/applications/wine-winecfg.desktop"
+
+wine_build_environment_check() {
+ [[ ${MERGE_TYPE} = "binary" ]] && return 0
+
+ # bug #549768
+ if use abi_x86_64 && [[ $(gcc-major-version) = 5 && $(gcc-minor-version) -le 2 ]]; then
+ einfo "Checking for gcc-5 ms_abi compiler bug ..."
+ $(tc-getCC) -O2 "${FILESDIR}"/pr66838.c -o "${T}"/pr66838 || die
+ # Run in subshell to prevent "Aborted" message
+ if ! ( "${T}"/pr66838 || false ) >/dev/null 2>&1; then
+ eerror "64-bit wine cannot be built with gcc-5.1 or initial patchset of 5.2.0"
+ eerror "due to compiler bugs; please re-emerge the latest gcc-5.2.x ebuild,"
+ eerror "or use gcc-config to select a different compiler version."
+ eerror "See https://bugs.gentoo.org/549768"
+ eerror
+ return 1
+ fi
+ fi
+
+ if use abi_x86_64 && [[ $(( $(gcc-major-version) * 100 + $(gcc-minor-version) )) -lt 404 ]]; then
+ eerror "You need gcc-4.4+ to build 64-bit wine"
+ eerror
+ return 1
+ fi
+
+ if use abi_x86_32 && use opencl && [[ x$(eselect opencl show 2> /dev/null) = "xintel" ]]; then
+ eerror "You cannot build wine with USE=opencl because intel-ocl-sdk is 64-bit only."
+ eerror "See https://bugs.gentoo.org/487864 for more details."
+ eerror
+ return 1
+ fi
+}
+
+pkg_pretend() {
+ wine_build_environment_check || die
+}
+
+pkg_setup() {
+ wine_build_environment_check || die
+}
+
+src_unpack() {
+ if [[ ${PV} == "9999" ]] ; then
+ git-r3_src_unpack
+ if use staging || use pulseaudio; then
+ EGIT_REPO_URI=${STAGING_EGIT_REPO_URI}
+ unset ${PN}_LIVE_REPO;
+ EGIT_CHECKOUT_DIR=${STAGING_DIR} git-r3_src_unpack
+ fi
+ else
+ unpack ${P}.tar.bz2
+ use staging && unpack "${STAGING_P}.tar.gz"
+ fi
+
+ unpack "${WINE_GENTOO}.tar.bz2"
+ use gstreamer && unpack "${GST_P}.patch.bz2"
+
+ l10n_find_plocales_changes "${S}/po" "" ".po"
+}
+
+src_prepare() {
+ local md5="$(md5sum server/protocol.def)"
+ local PATCHES=(
+ "${FILESDIR}"/${PN}-1.5.26-winegcc.patch #260726
+ "${FILESDIR}"/${PN}-1.4_rc2-multilib-portage.patch #395615
+ "${FILESDIR}"/${PN}-1.7.12-osmesa-check.patch #429386
+ "${FILESDIR}"/${PN}-1.6-memset-O3.patch #480508
+ )
+ if use gstreamer; then
+ # See http://bugs.winehq.org/show_bug.cgi?id=30557
+ ewarn "Applying experimental patch to fix GStreamer support. Note that"
+ ewarn "this patch has been reported to cause crashes in certain games."
+
+ # Wine-Staging 1.7.38 "ntdll: Fix race-condition when threads are killed
+ # during shutdown" patch and "Added patch to implement shared memory
+ # wineserver communication for various user32 functions" prevents the
+ # gstreamer patch from applying cleanly.
+ # So undo the staging patch, apply gstreamer, then re-apply rebased staging
+ # patch on top.
+ if use staging; then
+ PATCHES+=(
+ "${FILESDIR}/${PN}-1.7.39-gstreamer-v5-staging-pre.patch"
+ "${WORKDIR}/${GST_P}.patch"
+ "${FILESDIR}/${PN}-1.7.39-gstreamer-v5-staging-post.patch" )
+ else
+ PATCHES+=( "${WORKDIR}/${GST_P}.patch" )
+ fi
+ fi
+ if use staging; then
+ ewarn "Applying the unofficial Wine-Staging patchset which is unsupported"
+ ewarn "by Wine developers. Please don't report bugs to Wine bugzilla"
+ ewarn "unless you can reproduce them with USE=-staging"
+
+ local STAGING_EXCLUDE=""
+ use pipelight || STAGING_EXCLUDE="${STAGING_EXCLUDE} -W Pipelight"
+
+ # Launch wine-staging patcher in a subshell, using epatch as a backend, and gitapply.sh as a backend for binary patches
+ ebegin "Running Wine-Staging patch installer"
+ (
+ set -- DESTDIR="${S}" --backend=epatch --no-autoconf --all ${STAGING_EXCLUDE}
+ cd "${STAGING_DIR}/patches"
+ source "${STAGING_DIR}/patches/patchinstall.sh"
+ )
+ eend $?
+ fi
+ if use d3d9; then
+ epatch ${FILESDIR}/${P}-d3d9.patch
+ fi
+ autotools-utils_src_prepare
+
+ # Modification of the server protocol requires regenerating the server requests
+ if [[ "$(md5sum server/protocol.def)" != "${md5}" ]]; then
+ einfo "server/protocol.def was patched; running tools/make_requests"
+ tools/make_requests || die #432348
+ fi
+ sed -i '/^UPDATE_DESKTOP_DATABASE/s:=.*:=true:' tools/Makefile.in || die
+ if ! use run-exes; then
+ sed -i '/^MimeType/d' loader/wine.desktop || die #117785
+ fi
+
+ # hi-res default icon, #472990, http://bugs.winehq.org/show_bug.cgi?id=24652
+ cp "${WORKDIR}"/${WINE_GENTOO}/icons/oic_winlogo.ico dlls/user32/resources/ || die
+
+ l10n_get_locales > po/LINGUAS # otherwise wine doesn't respect LINGUAS
+}
+
+src_configure() {
+ export LDCONFIG=/bin/true
+ use custom-cflags || strip-flags
+
+ multilib-minimal_src_configure
+}
+
+multilib_src_configure() {
+ local myconf=(
+ --sysconfdir=/etc/wine
+ $(use_with alsa)
+ $(use_with capi)
+ $(use_with lcms cms)
+ $(use_with cups)
+ $(use_with d3d9 d3dadapter)
+ $(use_with ncurses curses)
+ $(use_with udisks dbus)
+ $(use_with fontconfig)
+ $(use_with ssl gnutls)
+ $(use_enable gecko mshtml)
+ $(use_with gphoto2 gphoto)
+ $(use_with gsm)
+ $(use_with gstreamer)
+ --without-hal
+ $(use_with jpeg)
+ $(use_with ldap)
+ $(use_enable mono mscoree)
+ $(use_with mp3 mpg123)
+ $(use_with netapi)
+ $(use_with nls gettext)
+ $(use_with openal)
+ $(use_with opencl)
+ $(use_with opengl)
+ $(use_with osmesa)
+ $(use_with oss)
+ $(use_with pcap)
+ $(use_with png)
+ $(use_with pulseaudio)
+ $(use_with threads pthread)
+ $(use_with scanner sane)
+ $(use_enable test tests)
+ $(use_with truetype freetype)
+ $(use_with v4l)
+ $(use_with X x)
+ $(use_with xcomposite)
+ $(use_with xinerama)
+ $(use_with xml)
+ $(use_with xml xslt)
+ )
+
+ use staging && myconf+=(
+ --with-xattr
+ $(use_with vaapi va)
+ )
+
+ local PKG_CONFIG AR RANLIB
+ # Avoid crossdev's i686-pc-linux-gnu-pkg-config if building wine32 on amd64; #472038
+ # set AR and RANLIB to make QA scripts happy; #483342
+ tc-export PKG_CONFIG AR RANLIB
+
+ if use amd64; then
+ if [[ ${ABI} == amd64 ]]; then
+ myconf+=( --enable-win64 )
+ else
+ myconf+=( --disable-win64 )
+ fi
+
+ # Note: using --with-wine64 results in problems with multilib.eclass
+ # CC/LD hackery. We're using separate tools instead.
+ fi
+
+ ECONF_SOURCE=${S} \
+ econf "${myconf[@]}"
+ emake depend
+}
+
+multilib_src_test() {
+ # FIXME: win32-only; wine64 tests fail with "could not find the Wine loader"
+ if [[ ${ABI} == x86 ]]; then
+ if [[ $(id -u) == 0 ]]; then
+ ewarn "Skipping tests since they cannot be run under the root user."
+ ewarn "To run the test ${PN} suite, add userpriv to FEATURES in make.conf"
+ return
+ fi
+
+ WINEPREFIX="${T}/.wine-${ABI}" \
+ Xemake test
+ fi
+}
+
+multilib_src_install_all() {
+ local DOCS=( ANNOUNCE AUTHORS README )
+ local l
+ add_locale_docs() {
+ local locale_doc="documentation/README.$1"
+ [[ ! -e ${locale_doc} ]] || DOCS+=( ${locale_doc} )
+ }
+ l10n_for_each_locale_do add_locale_docs
+
+ einstalldocs
+ prune_libtool_files --all
+
+ emake -C "../${WINE_GENTOO}" install DESTDIR="${D}" EPREFIX="${EPREFIX}"
+ if use gecko ; then
+ insinto /usr/share/wine/gecko
+ use abi_x86_32 && doins "${DISTDIR}"/wine_gecko-${GV}-x86.msi
+ use abi_x86_64 && doins "${DISTDIR}"/wine_gecko-${GV}-x86_64.msi
+ fi
+ if use mono ; then
+ insinto /usr/share/wine/mono
+ doins "${DISTDIR}"/wine-mono-${MV}.msi
+ fi
+ if ! use perl ; then # winedump calls function_grep.pl, and winemaker is a perl script
+ rm "${D}"usr/bin/{wine{dump,maker},function_grep.pl} "${D}"usr/share/man/man1/wine{dump,maker}.1 || die
+ fi
+
+ use abi_x86_32 && pax-mark psmr "${D}"usr/bin/wine{,-preloader} #255055
+ use abi_x86_64 && pax-mark psmr "${D}"usr/bin/wine64{,-preloader}
+
+ if use abi_x86_64 && ! use abi_x86_32; then
+ dosym /usr/bin/wine{64,} # 404331
+ dosym /usr/bin/wine{64,}-preloader
+ fi
+
+ # respect LINGUAS when installing man pages, #469418
+ for l in de fr pl; do
+ use linguas_${l} || rm -r "${D}"usr/share/man/${l}*
+ done
+}
+
+pkg_preinst() {
+ gnome2_icon_savelist
+}
+
+pkg_postinst() {
+ gnome2_icon_cache_update
+ fdo-mime_desktop_database_update
+
+ if ! use gecko; then
+ ewarn "Without Wine Gecko, wine prefixes will not have a default"
+ ewarn "implementation of iexplore. Many older windows applications"
+ ewarn "rely upon the existence of an iexplore implementation, so"
+ ewarn "you will likely need to install an external one, like via winetricks"
+ fi
+ if ! use mono; then
+ ewarn "Without Wine Mono, wine prefixes will not have a default"
+ ewarn "implementation of .NET. Many windows applications rely upon"
+ ewarn "the existence of a .NET implementation, so you will likely need"
+ ewarn "to install an external one, like via winetricks"
+ fi
+}
+
+pkg_postrm() {
+ gnome2_icon_cache_update
+ fdo-mime_desktop_database_update
+}