diff options
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", ®key)) { ++ 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(¤t_mode, sizeof(DEVMODEW)); ++ /* Only change the mode if necessary. */ ++ if (!EnumDisplaySettingsW(This->devname, ENUM_CURRENT_SETTINGS, ¤t_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, ¶ms[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 +} |