]> Chaos Git - misc/patchrepo.git/commitdiff
Add nine state tracker wine patches, due to NP-hardass' not being up to date.
authorchaoskagami <chaos.kagami@gmail.com>
Mon, 18 Jan 2016 12:08:30 +0000 (07:08 -0500)
committerchaoskagami <chaos.kagami@gmail.com>
Mon, 18 Jan 2016 12:08:30 +0000 (07:08 -0500)
wine/wine-1.9.1-nine.patch [new file with mode: 0644]
wine/wine-1.9.1-nine_for_staging.patch [new file with mode: 0644]

diff --git a/wine/wine-1.9.1-nine.patch b/wine/wine-1.9.1-nine.patch
new file mode 100644 (file)
index 0000000..af23abf
--- /dev/null
@@ -0,0 +1,5529 @@
+This is the gallium nine wine state tracker. They're very freaking far behind.
+Luckily, this isn't terribly hard to fix, but git can no longer auto merge
+as in NP-Hardass' automated patch generator.
+
+This patch was generated through the following:
+       - Diff wine 1.7.55 against iXit/wine.
+       - Remove uneccesary changes.
+       - Generate diff between wine 1.7.55 and the desired version.
+       - Apply nine, then the interversion.
+       - Generate patch.
+
+This is currently based on commit eae055cf of iXit/wine.
+If this is not the latest, I'll make an effort to update.
+
+Please also note that there are two separate versions because a few
+bits of nine conflict with staging. If you wish to have staging, use
+the other patch.
+
+Also, this only imports configure.ac changes. You'll need to run:
+       autoreconf -f
+       ./tools/make_requests
+To properly be able to build this.
+
+diff -urN wine-1.9.1/configure.ac wine-1.9.1-d3d9/configure.ac
+--- wine-1.9.1/configure.ac    2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/configure.ac       2016-01-18 06:22:34.607627423 -0500
+@@ -65,6 +65,8 @@
+ 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_SUBST(OPENGL_LIBS,"")
++AC_SUBST(D3DADAPTER9_LIBS,"")
++
+ dnl **** Check for header files ****
+ AC_SYS_LARGEFILE()
+@@ -1158,6 +1162,195 @@
+     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
++         AC_DEFINE(SONAME_D3DADAPTER9, ["d3dadapter9.so.1"], ["temporary hack"])
++         D3D_MODULE_DIR=`pkg-config --variable=moduledir d3d`
++         CPPFLAGSBAK=$CPPFLAGS
++         # link against libdl
++         CPPFLAGS="$CPPFLAGS -ldl"
++       
++         ac_cv_c_dlopen_d3dadapter=""
++         AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <dlfcn.h>
++#include <stdlib.h>]],[[void *handle = dlopen("${D3D_MODULE_DIR}" "/" SONAME_D3DADAPTER9, RTLD_GLOBAL | RTLD_NOW);
++exit((handle && dlsym(handle, "D3DAdapter9GetProc")) ? 0 : 1)]])],
++             [ac_cv_c_dlopen_d3dadapter=yes],[ac_cv_c_dlopen_d3dadapter=no])
++         if test "x$ac_cv_c_dlopen_d3dadapter" != "xyes"
++         then
++             echo "d3dadapter9.so.1 not found in '$D3D_MODULE_DIR'";
++             # workaround for pkg-config cross-compilation
++             # search for module in known folders
++             for D3D_MODULE_DIR in `$CC -Xlinker --verbose 2>/dev/null | grep SEARCH`
++             do
++                 D3D_MODULE_DIR="`echo \"$D3D_MODULE_DIR\" | sed 's/SEARCH_DIR("//g;s/\/");/\/d3d/g;s/");/\/d3d/g'`"
++                 ac_cv_c_dlopen_d3dadapter=""
++                 AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <dlfcn.h>
++#include <stdlib.h>]],[[void *handle = dlopen("${D3D_MODULE_DIR}" "/" SONAME_D3DADAPTER9, RTLD_GLOBAL | RTLD_NOW);
++exit((handle && dlsym(handle, "D3DAdapter9GetProc")) ? 0 : 1)]])],
++                     [echo "d3dadapter9.so.1 found in '$D3D_MODULE_DIR'";ac_cv_c_dlopen_d3dadapter=yes],
++                     [echo "d3dadapter9.so.1 not found in '$D3D_MODULE_DIR'";ac_cv_c_dlopen_d3dadapter=no])
++                 if test "x$ac_cv_c_dlopen_d3dadapter" = xyes
++                 then
++                     break
++                 fi
++             done
++         fi
++         AC_DEFINE_UNQUOTED(D3D_MODULE_DIR, ["`echo ${D3D_MODULE_DIR}`"], ["module dir"])
++         WINE_NOTICE_WITH(d3dadapter,[test "x$ac_cv_c_dlopen_d3dadapter" = xno],
++                 [d3dadapter9.so.1 module not found, Gallium Nine won't be supported.])
++
++         CPPFLAGS=$CPPFLAGSBAK
++         D3D_CFLAGS="`pkg-config --cflags d3d`"
++         # d3dadapter9.h includes D3D9.h, that relies on non existant headers
++         # the headers are generated by widl after running this script...
++         # hack around by using forward declarations
++         CPPFLAGS="$CPPFLAGS $D3D_CFLAGS -DWINAPI= -D_D3DADAPTER_PRESENT_H_"
++         AC_CHECK_HEADERS([d3dadapter9.h],[],[],[[
++typedef int DWORD;
++typedef int HWND;
++typedef int BOOL;
++typedef int UINT;
++typedef int HRESULT;
++typedef int ULONG;
++typedef struct ID3DPresent ID3DPresent;
++typedef struct ID3DPresentGroup ID3DPresentGroup;
++typedef struct ID3DAdapter9 ID3DAdapter9;
++typedef struct D3DWindowBuffer D3DWindowBuffer;
++typedef struct D3DADAPTER_IDENTIFIER9 D3DADAPTER_IDENTIFIER9;
++typedef struct D3DDEVTYPE D3DDEVTYPE;
++typedef struct D3DRESOURCETYPE D3DRESOURCETYPE;
++typedef struct D3DMULTISAMPLE_TYPE D3DMULTISAMPLE_TYPE;
++typedef struct D3DFORMAT D3DFORMAT;
++typedef struct D3DCAPS9 D3DCAPS9;
++typedef struct IDirect3DDevice9 IDirect3DDevice9;
++typedef struct IDirect3DDevice9Ex IDirect3DDevice9Ex;
++typedef struct IDirect3D9 IDirect3D9;
++typedef struct D3DPRESENT_PARAMETERS D3DPRESENT_PARAMETERS;
++typedef struct D3DDISPLAYMODEEX D3DDISPLAYMODEEX;
++typedef struct IDirect3D9Ex IDirect3D9Ex;
++typedef struct REFIID REFIID;
++]])
++         CPPFLAGS=$CPPFLAGSBAK
++         # pkg-config doesn't support cross-compilation. remove once fixed.
++         if test "x$ac_cv_header_d3dadapter9_h" != xyes
++         then
++             # hardcode path if header isn't found
++             # TODO: use environment var here ?
++             D3D_CFLAGS="-I/usr/include/d3dadapter/"
++             CPPFLAGS="$CPPFLAGS $D3D_CFLAGS -DWINAPI= -D_D3DADAPTER_PRESENT_H_"
++             # clear autoconf cache
++             AS_UNSET([ac_cv_header_d3dadapter9_h])
++         fi
++         AC_SUBST(D3D_CFLAGS)
++
++         D3DADAPTER9_LIBS=""
++         D3DADAPTER9_LIBS_NOT_FOUND=""
++         D3DADAPTER9_HEADER_NOT_FOUND=""
++
++         AC_CHECK_HEADERS([d3dadapter9.h],[],[],[[
++typedef int DWORD;
++typedef int HWND;
++typedef int BOOL;
++typedef int UINT;
++typedef int HRESULT;
++typedef int ULONG;
++typedef struct ID3DPresent ID3DPresent;
++typedef struct ID3DPresentGroup ID3DPresentGroup;
++typedef struct ID3DAdapter9 ID3DAdapter9;
++typedef struct D3DWindowBuffer D3DWindowBuffer;
++typedef struct D3DADAPTER_IDENTIFIER9 D3DADAPTER_IDENTIFIER9;
++typedef struct D3DDEVTYPE D3DDEVTYPE;
++typedef struct D3DRESOURCETYPE D3DRESOURCETYPE;
++typedef struct D3DMULTISAMPLE_TYPE D3DMULTISAMPLE_TYPE;
++typedef struct D3DFORMAT D3DFORMAT;
++typedef struct D3DCAPS9 D3DCAPS9;
++typedef struct IDirect3DDevice9 IDirect3DDevice9;
++typedef struct IDirect3DDevice9Ex IDirect3DDevice9Ex;
++typedef struct IDirect3D9 IDirect3D9;
++typedef struct D3DPRESENT_PARAMETERS D3DPRESENT_PARAMETERS;
++typedef struct D3DDISPLAYMODEEX D3DDISPLAYMODEEX;
++typedef struct IDirect3D9Ex IDirect3D9Ex;
++typedef struct REFIID REFIID;
++]])
++         CPPFLAGS=$CPPFLAGSBAK
++         AC_CHECK_HEADERS([X11/Xlib-xcb.h xcb/dri3.h xcb/present.h X11/Xutil.h X11/Xlib.h pthread.h])
++         test "x$ac_cv_header_d3dadapter9_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="d3dadapter9.h "
++         test "x$ac_cv_header_X11_Xlib_xcb_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}X11/Xlib-xcb.h "
++         test "x$ac_cv_header_xcb_dri3_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}xcb/dri3.h "
++         test "x$ac_cv_header_xcb_present_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}xcb/present.h "
++         test "x$ac_cv_header_X11_Xutil_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}X11/Xutil.h "
++         test "x$ac_cv_header_X11_Xlib_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}X11/Xlib.h "
++         test "x$ac_cv_header_pthread_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}pthread.h "
++         WINE_NOTICE_WITH(d3dadapter,[test "x$D3DADAPTER9_HEADER_NOT_FOUND" != x],
++                 [$D3DADAPTER9_HEADER_NOT_FOUND header not found, Gallium Nine won't be supported.])
++
++         AC_CHECK_LIB(xcb,xcb_request_check,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb"])])
++         test "x$ac_cv_lib_xcb_xcb_request_check" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="libxcb "
++         AC_CHECK_LIB(xcb-dri3,xcb_dri3_open,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb-dri3"])])
++         test "x$ac_cv_lib_xcb_dri3_xcb_dri3_open" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libxcb-dri3 "
++         AC_CHECK_LIB(xcb-present,xcb_present_notify_msc,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb-present"])])
++         test "x$ac_cv_lib_xcb_present_xcb_present_notify_msc" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libxcb-present "
++         AC_CHECK_LIB(xcb-xfixes,xcb_xfixes_create_region,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb-xfixes"])])
++         test "x$ac_cv_lib_xcb_xfixes_xcb_xfixes_create_region" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libxcb-xfixes "
++         AC_CHECK_LIB(X11-xcb,XGetXCBConnection,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lX11-xcb"])])
++         test "x$ac_cv_lib_X11_xcb_XGetXCBConnection" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libX11-xcb "
++         AC_CHECK_LIB(X11,XOpenDisplay,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lX11"])])
++         test "x$ac_cv_lib_X11_XOpenDisplay" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libX11 "
++         AC_CHECK_LIB(Xext,XextRemoveDisplay,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lXext"])])
++         test "x$ac_cv_lib_Xext_XextRemoveDisplay" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libXext "
++         AC_CHECK_LIB(pthread,pthread_mutex_lock,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lpthread"])])
++         test "x$ac_cv_lib_pthread_pthread_mutex_lock" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libpthread "
++
++         if test "x$with_d3dadapter_dri2_fallback" != "xno"
++         then
++             D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND=""
++             D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND=""
++             AC_CHECK_LIB(GL,glGenFramebuffers,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lGL"])])
++             test "x$ac_cv_lib_GL_glGenFramebuffers" != xyes && D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND="libGL "
++             AC_CHECK_LIB(EGL,eglCreateContext,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lEGL"])])
++             test "x$ac_cv_lib_EGL_eglCreateContext" != xyes && D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND="${D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND}libEGL"
++
++             AC_CHECK_HEADERS([X11/Xmd.h X11/Xlibint.h X11/extensions/dri2tokens.h X11/extensions/dri2proto.h X11/extensions/extutil.h GL/gl.h GL/glext.h EGL/egl.h EGL/eglext.h libdrm/drm_fourcc.h libdrm/drm.h],
++                     [],[],[[
++#include <X11/Xlibint.h>
++#include <X11/extensions/dri2tokens.h>
++#include <GL/gl.h>
++#include <EGL/egl.h>
++]])
++             test "x$ac_cv_header_X11_Xmd_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/Xmd.h "
++             test "x$ac_cv_header_X11_Xlibint_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/Xlibint.h "
++             test "x$ac_cv_header_X11_extensions_dri2tokens_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/extensions/dri2tokens.h "
++             test "x$ac_cv_header_X11_extensions_dri2proto_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/extensions/dri2proto.h "
++             test "x$ac_cv_header_X11_extensions_extutil_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/extensions/extutil.h "
++             test "x$ac_cv_header_GL_gl_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}GL/gl.h "
++             test "x$ac_cv_header_GL_glext_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}GL/glext.h "
++             test "x$ac_cv_header_EGL_egl_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}EGL/egl.h "
++             test "x$ac_cv_header_EGL_eglext_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}EGL/eglext.h "
++             test "x$ac_cv_header_libdrm_drm_fourcc_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}libdrm/drm_fourcc.h "
++             test "x$ac_cv_header_libdrm_drm_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}libdrm/drm.h "
++
++             if test "x$D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND" = x -a "x$D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND" = x
++             then
++                 AC_DEFINE(D3DADAPTER9_DRI2, 1, [Whether d3dadapter9 DRI2 fallback is compiled])
++             fi
++             WINE_NOTICE_WITH(d3dadapter_dri2_fallback,[test "x$D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND" != x],
++                     [$D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND ${notice_platform}development files not found, Gallium Nine DRI2 fallback won't be supported.])
++             WINE_NOTICE_WITH(d3dadapter_dri2_fallback,[test "x$D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND" != x],
++                     [$D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND headers not found, Gallium Nine DRI2 fallback won't be supported.])
++         fi
++
++         test "x$D3DADAPTER9_LIBS_NOT_FOUND" != "x" && \
++             "x$D3DADAPTER9_HEADER_NOT_FOUND" != x && \
++             "x$ac_cv_c_dlopen_d3dadapter" != xyes && \
++             enable_d3d9_nine=${enable_d3d9_nine:-no}
++         WINE_NOTICE_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS_NOT_FOUND" != "x"],
++                 [$D3DADAPTER9_LIBS_NOT_FOUND ${notice_platform}development files not found, Gallium Nine won't be supported.])
++    else
++        enable_d3d9_nine=${enable_d3d9_nine:-no}
++        D3D_CFLAGS=""
++    fi
++
+     CPPFLAGS="$ac_save_CPPFLAGS"
+ else
+     X_CFLAGS=""
+@@ -2769,6 +2962,7 @@
+ 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 -urN wine-1.9.1/dlls/d3d9/Makefile.in wine-1.9.1-d3d9/dlls/d3d9/Makefile.in
+--- wine-1.9.1/dlls/d3d9/Makefile.in   2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9/Makefile.in      2016-01-18 06:22:25.038627619 -0500
+@@ -1,6 +1,6 @@
+ MODULE    = d3d9.dll
+ IMPORTLIB = d3d9
+-IMPORTS   = dxguid uuid wined3d
++IMPORTS   = dxguid uuid advapi32 wined3d
+ C_SRCS = \
+       buffer.c \
+diff -urN wine-1.9.1/dlls/d3d9/tests/d3d9ex.c wine-1.9.1-d3d9/dlls/d3d9/tests/d3d9ex.c
+--- wine-1.9.1/dlls/d3d9/tests/d3d9ex.c        2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9/tests/d3d9ex.c   2016-01-18 06:22:34.644627423 -0500
+@@ -1490,6 +1490,7 @@
+     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);
+@@ -1514,6 +1515,12 @@
+     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);
+@@ -1527,6 +1534,12 @@
+     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);
+@@ -1540,6 +1553,12 @@
+     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);
+@@ -1569,6 +1588,12 @@
+     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);
+@@ -1582,6 +1607,12 @@
+     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 -urN wine-1.9.1/dlls/d3d9/tests/device.c wine-1.9.1-d3d9/dlls/d3d9/tests/device.c
+--- wine-1.9.1/dlls/d3d9/tests/device.c        2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9/tests/device.c   2016-01-18 06:22:34.645627423 -0500
+@@ -8300,10 +8300,10 @@
+ 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;
+@@ -8311,6 +8311,8 @@
+     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)))
+@@ -8345,6 +8347,43 @@
+             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);
+@@ -10065,6 +10104,7 @@
+     HWND window;
+     HRESULT hr;
+     BOOL ret;
++    IDirect3DSwapChain9 *swapchain;
+     window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW,
+             0, 0, 640, 480, NULL, NULL, NULL, NULL);
+@@ -10092,6 +10132,12 @@
+     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);
+@@ -10101,6 +10147,12 @@
+     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);
+@@ -10108,6 +10160,12 @@
+     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 -urN wine-1.9.1/dlls/d3d9/tests/visual.c wine-1.9.1-d3d9/dlls/d3d9/tests/visual.c
+--- wine-1.9.1/dlls/d3d9/tests/visual.c        2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9/tests/visual.c   2016-01-18 06:23:32.173626249 -0500
+@@ -8674,6 +8674,167 @@
+     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;
+@@ -12873,6 +13034,9 @@
+     }
+     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},
+@@ -12881,6 +13045,10 @@
+         {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
+     {
+@@ -18226,6 +18394,27 @@
+                 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;
+@@ -21541,6 +21730,7 @@
+     test_depthbias();
+     test_flip();
+     test_uninitialized_varyings();
++    test_blend_invalid_arg();
+     test_multisample_init();
+     test_texture_blending();
+ }
+diff -urN wine-1.9.1/dlls/d3d9-nine/d3d9_main.c wine-1.9.1-d3d9/dlls/d3d9-nine/d3d9_main.c
+--- wine-1.9.1/dlls/d3d9-nine/d3d9_main.c      1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/d3d9_main.c 2016-01-18 06:22:25.046627618 -0500
+@@ -0,0 +1,157 @@
++/*
++ * 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 <fcntl.h>
++
++#include <d3dadapter/d3dadapter9.h>
++
++#include "d3dadapter9.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 -urN wine-1.9.1/dlls/d3d9-nine/d3d9-nine.spec wine-1.9.1-d3d9/dlls/d3d9-nine/d3d9-nine.spec
+--- wine-1.9.1/dlls/d3d9-nine/d3d9-nine.spec   1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/d3d9-nine.spec      2016-01-18 06:22:25.046627618 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/d3dadapter9.c wine-1.9.1-d3d9/dlls/d3d9-nine/d3dadapter9.c
+--- wine-1.9.1/dlls/d3d9-nine/d3dadapter9.c    1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/d3dadapter9.c       2016-01-18 06:22:25.046627618 -0500
+@@ -0,0 +1,865 @@
++/*
++ * Wine IDirect3D9 interface using ID3DAdapter9
++ *
++ * Copyright 2013 Joakim Sindholt
++ *                Christoph Bumiller
++ * Copyright 2014 David Heidelberger
++ * Copyright 2014-2015 Axel Davy
++ * Copyright 2015 Nick Sarnie
++ *                Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#include "config.h"
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter);
++
++#include <d3dadapter/d3dadapter9.h>
++#include "present.h"
++
++/* this represents a snapshot taken at the moment of creation */
++struct output
++{
++    D3DDISPLAYROTATION rotation; /* current rotation */
++    D3DDISPLAYMODEEX *modes;
++    unsigned nmodes;
++    unsigned nmodesalloc;
++    unsigned current; /* current mode num */
++
++    HMONITOR monitor;
++};
++
++struct adapter_group
++{
++    struct output *outputs;
++    unsigned noutputs;
++    unsigned noutputsalloc;
++
++    /* override driver provided DeviceName with this to homogenize device names
++     * with wine */
++    WCHAR devname[32];
++
++    /* driver stuff */
++    ID3DAdapter9 *adapter;
++};
++
++struct adapter_map
++{
++    unsigned group;
++    unsigned master;
++};
++
++struct d3dadapter9
++{
++    /* COM vtable */
++    void *vtable;
++    /* IUnknown reference count */
++    LONG refs;
++
++    /* adapter groups and mappings */
++    struct adapter_group *groups;
++    struct adapter_map *map;
++    unsigned nadapters;
++    unsigned ngroups;
++    unsigned ngroupsalloc;
++
++    /* true if it implements IDirect3D9Ex */
++    boolean ex;
++    Display *gdi_display;
++};
++
++/* convenience wrapper for calls into ID3D9Adapter */
++#define ADAPTER_GROUP \
++    This->groups[This->map[Adapter].group]
++
++#define ADAPTER_PROC(name, ...) \
++    ID3DAdapter9_##name(ADAPTER_GROUP.adapter, ## __VA_ARGS__)
++
++#define ADAPTER_OUTPUT \
++    ADAPTER_GROUP.outputs[Adapter-This->map[Adapter].master]
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This,
++                               UINT Adapter,
++                               D3DDEVTYPE DeviceType,
++                               D3DFORMAT AdapterFormat,
++                               DWORD Usage,
++                               D3DRESOURCETYPE RType,
++                               D3DFORMAT CheckFormat );
++
++static ULONG WINAPI
++d3dadapter9_AddRef( struct d3dadapter9 *This )
++{
++    ULONG refs = InterlockedIncrement(&This->refs);
++    TRACE("%p increasing refcount to %u.\n", This, refs);
++    return refs;
++}
++
++static ULONG WINAPI
++d3dadapter9_Release( struct d3dadapter9 *This )
++{
++    ULONG refs = InterlockedDecrement(&This->refs);
++    TRACE("%p decreasing refcount to %u.\n", This, refs);
++    if (refs == 0) {
++        /* dtor */
++        if (This->map) {
++            HeapFree(GetProcessHeap(), 0, This->map);
++        }
++
++        if (This->groups) {
++            int i, j;
++            for (i = 0; i < This->ngroups; ++i) {
++                if (This->groups[i].outputs) {
++                    for (j = 0; j < This->groups[i].noutputs; ++j) {
++                        if (This->groups[i].outputs[j].modes) {
++                            HeapFree(GetProcessHeap(), 0,
++                                     This->groups[i].outputs[j].modes);
++                        }
++                    }
++                    HeapFree(GetProcessHeap(), 0, This->groups[i].outputs);
++                }
++
++                if (This->groups[i].adapter) {
++                    ID3DAdapter9_Release(This->groups[i].adapter);
++                }
++            }
++            HeapFree(GetProcessHeap(), 0, This->groups);
++        }
++
++        HeapFree(GetProcessHeap(), 0, This);
++    }
++    return refs;
++}
++
++static HRESULT WINAPI
++d3dadapter9_QueryInterface( struct d3dadapter9 *This,
++                            REFIID riid,
++                            void **ppvObject )
++{
++    if (!ppvObject) { return E_POINTER; }
++    if ((IsEqualGUID(&IID_IDirect3D9Ex, riid) && This->ex) ||
++         IsEqualGUID(&IID_IDirect3D9, riid) ||
++         IsEqualGUID(&IID_IUnknown, riid)) {
++        *ppvObject = This;
++        d3dadapter9_AddRef(This);
++        return S_OK;
++    }
++
++    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++    *ppvObject = NULL;
++
++    return E_NOINTERFACE;
++}
++
++static HRESULT WINAPI
++d3dadapter9_RegisterSoftwareDevice( struct d3dadapter9 *This,
++                                    void *pInitializeFunction )
++{
++    FIXME("(%p, %p), stub!\n", This, pInitializeFunction);
++    return D3DERR_INVALIDCALL;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterCount( struct d3dadapter9 *This )
++{
++    return This->nadapters;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterIdentifier( struct d3dadapter9 *This,
++                                  UINT Adapter,
++                                  DWORD Flags,
++                                  D3DADAPTER_IDENTIFIER9 *pIdentifier )
++{
++    HRESULT hr;
++    HKEY regkey;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++
++    hr = ADAPTER_PROC(GetAdapterIdentifier, Flags, pIdentifier);
++    if (SUCCEEDED(hr)) {
++        /* Override the driver provided DeviceName with what Wine provided */
++        ZeroMemory(pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName));
++        if (!WideCharToMultiByte(CP_ACP, 0, ADAPTER_GROUP.devname, -1,
++                                 pIdentifier->DeviceName,
++                                 sizeof(pIdentifier->DeviceName),
++                                 NULL, NULL)) {
++            /* Wine does it */
++            return D3DERR_INVALIDCALL;
++        }
++        TRACE("DeviceName overriden: %s\n", pIdentifier->DeviceName);
++
++        /* Override PCI IDs when wined3d registry keys are set */
++        if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &regkey)) {
++            DWORD type, data;
++            DWORD size = sizeof(DWORD);
++
++            if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD)))
++                pIdentifier->DeviceId = data;
++            if(size != sizeof(DWORD)) {
++                ERR("VideoPciDeviceID is not a DWORD\n");
++                size = sizeof(DWORD);
++            }
++            if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD)))
++                pIdentifier->VendorId = data;
++            if(size != sizeof(DWORD))
++                ERR("VideoPciVendorID is not a DWORD\n");
++            RegCloseKey(regkey);
++
++            TRACE("DeviceId:VendorId overridden: %04X:%04X\n", pIdentifier->DeviceId, pIdentifier->VendorId);
++        }
++    }
++    return hr;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterModeCount( struct d3dadapter9 *This,
++                                 UINT Adapter,
++                                 D3DFORMAT Format )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return 0;
++    }
++    if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
++                                         Format, D3DUSAGE_RENDERTARGET,
++                                         D3DRTYPE_SURFACE, Format))) {
++        WARN("DeviceFormat not available.\n");
++        return 0;
++    }
++
++    TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes);
++    return ADAPTER_OUTPUT.nmodes;
++}
++
++static HRESULT WINAPI
++d3dadapter9_EnumAdapterModes( struct d3dadapter9 *This,
++                              UINT Adapter,
++                              D3DFORMAT Format,
++                              UINT Mode,
++                              D3DDISPLAYMODE *pMode )
++{
++    HRESULT hr;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return D3DERR_INVALIDCALL;
++    }
++
++    hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
++                                   Format, D3DUSAGE_RENDERTARGET,
++                                   D3DRTYPE_SURFACE, Format);
++    if (FAILED(hr)) {
++        TRACE("DeviceFormat not available.\n");
++        return hr;
++    }
++
++    if (Mode >= ADAPTER_OUTPUT.nmodes) {
++        WARN("Mode %u does not exist.\n", Mode);
++        return D3DERR_INVALIDCALL;
++    }
++
++    pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
++    pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
++    pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
++    pMode->Format = Format;
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterDisplayMode( struct d3dadapter9 *This,
++                                   UINT Adapter,
++                                   D3DDISPLAYMODE *pMode )
++{
++    UINT Mode;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return D3DERR_INVALIDCALL;
++    }
++
++    Mode = ADAPTER_OUTPUT.current;
++    pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
++    pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
++    pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
++    pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format;
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceType( struct d3dadapter9 *This,
++                             UINT Adapter,
++                             D3DDEVTYPE DevType,
++                             D3DFORMAT AdapterFormat,
++                             D3DFORMAT BackBufferFormat,
++                             BOOL bWindowed )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceType,
++                        DevType, AdapterFormat, BackBufferFormat, bWindowed);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This,
++                               UINT Adapter,
++                               D3DDEVTYPE DeviceType,
++                               D3DFORMAT AdapterFormat,
++                               DWORD Usage,
++                               D3DRESOURCETYPE RType,
++                               D3DFORMAT CheckFormat )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceFormat,
++                        DeviceType, AdapterFormat, Usage, RType, CheckFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceMultiSampleType( struct d3dadapter9 *This,
++                                        UINT Adapter,
++                                        D3DDEVTYPE DeviceType,
++                                        D3DFORMAT SurfaceFormat,
++                                        BOOL Windowed,
++                                        D3DMULTISAMPLE_TYPE MultiSampleType,
++                                        DWORD *pQualityLevels )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat,
++                        Windowed, MultiSampleType, pQualityLevels);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDepthStencilMatch( struct d3dadapter9 *This,
++                                    UINT Adapter,
++                                    D3DDEVTYPE DeviceType,
++                                    D3DFORMAT AdapterFormat,
++                                    D3DFORMAT RenderTargetFormat,
++                                    D3DFORMAT DepthStencilFormat )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat,
++                        RenderTargetFormat, DepthStencilFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormatConversion( struct d3dadapter9 *This,
++                                     UINT Adapter,
++                                     D3DDEVTYPE DeviceType,
++                                     D3DFORMAT SourceFormat,
++                                     D3DFORMAT TargetFormat )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceFormatConversion,
++                        DeviceType, SourceFormat, TargetFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetDeviceCaps( struct d3dadapter9 *This,
++                           UINT Adapter,
++                           D3DDEVTYPE DeviceType,
++                           D3DCAPS9 *pCaps )
++{
++    HRESULT hr;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++
++    hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps);
++    if (FAILED(hr)) { return hr; }
++
++    pCaps->MasterAdapterOrdinal = This->map[Adapter].master;
++    pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master;
++    pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs;
++
++    return hr;
++}
++
++static HMONITOR WINAPI
++d3dadapter9_GetAdapterMonitor( struct d3dadapter9 *This,
++                               UINT Adapter )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return (HMONITOR)0; }
++    return (HMONITOR)ADAPTER_OUTPUT.monitor;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This,
++                            UINT Adapter,
++                            D3DDEVTYPE DeviceType,
++                            HWND hFocusWindow,
++                            DWORD BehaviorFlags,
++                            D3DPRESENT_PARAMETERS *pPresentationParameters,
++                            D3DDISPLAYMODEEX *pFullscreenDisplayMode,
++                            IDirect3DDevice9Ex **ppReturnedDeviceInterface );
++
++static HRESULT WINAPI
++d3dadapter9_CreateDevice( struct d3dadapter9 *This,
++                          UINT Adapter,
++                          D3DDEVTYPE DeviceType,
++                          HWND hFocusWindow,
++                          DWORD BehaviorFlags,
++                          D3DPRESENT_PARAMETERS *pPresentationParameters,
++                          IDirect3DDevice9 **ppReturnedDeviceInterface )
++{
++    HRESULT hr;
++    hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow,
++                                    BehaviorFlags, pPresentationParameters,
++                                    NULL,
++                                    (IDirect3DDevice9Ex **)ppReturnedDeviceInterface);
++    if (FAILED(hr))
++        return hr;
++    return D3D_OK;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterModeCountEx( struct d3dadapter9 *This,
++                                   UINT Adapter,
++                                   const D3DDISPLAYMODEFILTER *pFilter )
++{
++    return 1;
++}
++
++static HRESULT WINAPI
++d3dadapter9_EnumAdapterModesEx( struct d3dadapter9 *This,
++                                UINT Adapter,
++                                const D3DDISPLAYMODEFILTER *pFilter,
++                                UINT Mode,
++                                D3DDISPLAYMODEEX *pMode )
++{
++    FIXME("(%p, %u, %p, %u, %p), stub!\n", This, Adapter, pFilter, Mode, pMode);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterDisplayModeEx( struct d3dadapter9 *This,
++                                     UINT Adapter,
++                                     D3DDISPLAYMODEEX *pMode,
++                                     D3DDISPLAYROTATION *pRotation )
++{
++    FIXME("(%p, %u, %p, %p), stub!\n", This, Adapter, pMode, pRotation);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This,
++                            UINT Adapter,
++                            D3DDEVTYPE DeviceType,
++                            HWND hFocusWindow,
++                            DWORD BehaviorFlags,
++                            D3DPRESENT_PARAMETERS *pPresentationParameters,
++                            D3DDISPLAYMODEEX *pFullscreenDisplayMode,
++                            IDirect3DDevice9Ex **ppReturnedDeviceInterface )
++{
++    ID3DPresentGroup *present;
++    HRESULT hr;
++    boolean no_window_changes;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return D3DERR_INVALIDCALL;
++    }
++
++    {
++        struct adapter_group *group = &ADAPTER_GROUP;
++        unsigned nparams, ordinal;
++
++        if (BehaviorFlags & D3DCREATE_ADAPTERGROUP_DEVICE) {
++            nparams = group->noutputs;
++            ordinal = 0;
++        } else {
++            nparams = 1;
++            ordinal = Adapter - This->map[Adapter].master;
++        }
++        no_window_changes = !!(BehaviorFlags & D3DCREATE_NOWINDOWCHANGES);
++
++        hr = present_create_present_group(This->gdi_display, group->devname, ordinal,
++                                               hFocusWindow,
++                                               pPresentationParameters,
++                                               nparams, &present, This->ex, no_window_changes);
++    }
++
++    if (FAILED(hr)) {
++        WARN("Failed to create PresentGroup.\n");
++        return hr;
++    }
++
++    if (This->ex) {
++        hr = ADAPTER_PROC(CreateDeviceEx, Adapter, DeviceType, hFocusWindow,
++                          BehaviorFlags, pPresentationParameters,
++                          pFullscreenDisplayMode,
++                          (IDirect3D9Ex *)This, present,
++                          ppReturnedDeviceInterface);
++    } else { /* CreateDevice on non-ex */
++        hr = ADAPTER_PROC(CreateDevice, Adapter, DeviceType, hFocusWindow,
++                          BehaviorFlags, pPresentationParameters,
++                          (IDirect3D9 *)This, present,
++                          (IDirect3DDevice9 **)ppReturnedDeviceInterface);
++    }
++    if (FAILED(hr)) {
++        WARN("ADAPTER_PROC failed.\n");
++        ID3DPresentGroup_Release(present);
++    }
++
++    return hr;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterLUID( struct d3dadapter9 *This,
++                            UINT Adapter,
++                            LUID *pLUID )
++{
++    FIXME("(%p, %u, %p), stub!\n", This, Adapter, pLUID);
++    return D3DERR_INVALIDCALL;
++}
++
++static struct adapter_group *
++add_group( struct d3dadapter9 *This )
++{
++    if (This->ngroups >= This->ngroupsalloc) {
++        void *r;
++
++        if (This->ngroupsalloc == 0) {
++            This->ngroupsalloc = 2;
++            r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          This->ngroupsalloc*sizeof(struct adapter_group));
++        } else {
++            This->ngroupsalloc <<= 1;
++            r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->groups,
++                        This->ngroupsalloc*sizeof(struct adapter_group));
++        }
++
++        if (!r) { return NULL; }
++        This->groups = r;
++    }
++
++    return &This->groups[This->ngroups++];
++}
++
++static void
++remove_group( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    int i;
++
++    for (i = 0; i < group->noutputs; ++i) {
++        HeapFree(GetProcessHeap(), 0, group->outputs[i].modes);
++    }
++    HeapFree(GetProcessHeap(), 0, group->outputs);
++
++    ZeroMemory(group, sizeof(struct adapter_group));
++    This->ngroups--;
++}
++
++static struct output *
++add_output( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++
++    if (group->noutputs >= group->noutputsalloc) {
++        void *r;
++
++        if (group->noutputsalloc == 0) {
++            group->noutputsalloc = 2;
++            r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          group->noutputsalloc*sizeof(struct output));
++        } else {
++            group->noutputsalloc <<= 1;
++            r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, group->outputs,
++                            group->noutputsalloc*sizeof(struct output));
++        }
++
++        if (!r) { return NULL; }
++        group->outputs = r;
++    }
++
++    return &group->outputs[group->noutputs++];
++}
++
++static void
++remove_output( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    struct output *out = &group->outputs[group->noutputs-1];
++
++    HeapFree(GetProcessHeap(), 0, out->modes);
++
++    ZeroMemory(out, sizeof(struct output));
++    group->noutputs--;
++}
++
++static D3DDISPLAYMODEEX *
++add_mode( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    struct output *out = &group->outputs[group->noutputs-1];
++
++    if (out->nmodes >= out->nmodesalloc) {
++        void *r;
++
++        if (out->nmodesalloc == 0) {
++            out->nmodesalloc = 8;
++            r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
++        } else {
++            out->nmodesalloc <<= 1;
++            r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, out->modes,
++                            out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
++        }
++
++        if (!r) { return NULL; }
++        out->modes = r;
++    }
++
++    return &out->modes[out->nmodes++];
++}
++
++static void
++remove_mode( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    struct output *out = &group->outputs[group->noutputs-1];
++    out->nmodes--;
++}
++
++#ifndef DM_INTERLACED
++#define DM_INTERLACED 2
++#endif /* DM_INTERLACED */
++
++static HRESULT
++fill_groups( struct d3dadapter9 *This )
++{
++    DISPLAY_DEVICEW dd;
++    DEVMODEW dm;
++    POINT pt;
++    HDC hdc;
++    HRESULT hr;
++    int i, j, k;
++
++    WCHAR wdisp[] = {'D','I','S','P','L','A','Y',0};
++
++    ZeroMemory(&dd, sizeof(dd));
++    ZeroMemory(&dm, sizeof(dm));
++    dd.cb = sizeof(dd);
++    dm.dmSize = sizeof(dm);
++
++    for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i) {
++        struct adapter_group *group = add_group(This);
++        if (!group) {
++            ERR("Out of memory.\n");
++            return E_OUTOFMEMORY;
++        }
++
++        hdc = CreateDCW(wdisp, dd.DeviceName, NULL, NULL);
++        if (!hdc) {
++            remove_group(This);
++            WARN("Unable to create DC for display %d.\n", i);
++            goto end_group;
++        }
++
++        hr = present_create_adapter9(This->gdi_display, hdc, &group->adapter);
++        DeleteDC(hdc);
++        if (FAILED(hr)) {
++            remove_group(This);
++            goto end_group;
++        }
++
++        CopyMemory(group->devname, dd.DeviceName, sizeof(group->devname));
++        for (j = 0; EnumDisplayDevicesW(group->devname, j, &dd, 0); ++j) {
++            struct output *out = add_output(This);
++            boolean orient = FALSE, monit = FALSE;
++            if (!out) {
++                ERR("Out of memory.\n");
++                return E_OUTOFMEMORY;
++            }
++
++            for (k = 0; EnumDisplaySettingsExW(dd.DeviceName, k, &dm, 0); ++k) {
++                D3DDISPLAYMODEEX *mode = add_mode(This);
++                if (!out) {
++                    ERR("Out of memory.\n");
++                    return E_OUTOFMEMORY;
++                }
++
++                mode->Size = sizeof(D3DDISPLAYMODEEX);
++                mode->Width = dm.dmPelsWidth;
++                mode->Height = dm.dmPelsHeight;
++                mode->RefreshRate = dm.dmDisplayFrequency;
++                mode->ScanLineOrdering =
++                    (dm.dmDisplayFlags & DM_INTERLACED) ?
++                        D3DSCANLINEORDERING_INTERLACED :
++                        D3DSCANLINEORDERING_PROGRESSIVE;
++
++                switch (dm.dmBitsPerPel) {
++                    case 32: mode->Format = D3DFMT_X8R8G8B8; break;
++                    case 24: mode->Format = D3DFMT_R8G8B8; break;
++                    case 16: mode->Format = D3DFMT_R5G6B5; break;
++                    case 8:
++                        remove_mode(This);
++                        goto end_mode;
++
++                    default:
++                        remove_mode(This);
++                        WARN("Unknown format (%u bpp) in display %d, monitor "
++                             "%d, mode %d.\n", dm.dmBitsPerPel, i, j, k);
++                        goto end_mode;
++                }
++
++                if (!orient) {
++                    switch (dm.dmDisplayOrientation) {
++                        case DMDO_DEFAULT:
++                            out->rotation = D3DDISPLAYROTATION_IDENTITY;
++                            break;
++
++                        case DMDO_90:
++                            out->rotation = D3DDISPLAYROTATION_90;
++                            break;
++
++                        case DMDO_180:
++                            out->rotation = D3DDISPLAYROTATION_180;
++                            break;
++
++                        case DMDO_270:
++                            out->rotation = D3DDISPLAYROTATION_270;
++                            break;
++
++                        default:
++                            remove_output(This);
++                            WARN("Unknown display rotation in display %d, "
++                                 "monitor %d\n", i, j);
++                            goto end_output;
++                    }
++                    orient = TRUE;
++                }
++
++                if (!monit) {
++                    pt.x = dm.dmPosition.x;
++                    pt.y = dm.dmPosition.y;
++                    out->monitor = MonitorFromPoint(pt, 0);
++                    if (!out->monitor) {
++                        remove_output(This);
++                        WARN("Unable to get monitor handle for display %d, "
++                             "monitor %d.\n", i, j);
++                        goto end_output;
++                    }
++                    monit = TRUE;
++                }
++
++end_mode:
++                ZeroMemory(&dm, sizeof(dm));
++                dm.dmSize = sizeof(dm);
++            }
++
++end_output:
++            ZeroMemory(&dd, sizeof(dd));
++            dd.cb = sizeof(dd);
++        }
++
++end_group:
++        ZeroMemory(&dd, sizeof(dd));
++        dd.cb = sizeof(dd);
++    }
++
++    return D3D_OK;
++}
++
++static IDirect3D9ExVtbl d3dadapter9_vtable = {
++    (void *)d3dadapter9_QueryInterface,
++    (void *)d3dadapter9_AddRef,
++    (void *)d3dadapter9_Release,
++    (void *)d3dadapter9_RegisterSoftwareDevice,
++    (void *)d3dadapter9_GetAdapterCount,
++    (void *)d3dadapter9_GetAdapterIdentifier,
++    (void *)d3dadapter9_GetAdapterModeCount,
++    (void *)d3dadapter9_EnumAdapterModes,
++    (void *)d3dadapter9_GetAdapterDisplayMode,
++    (void *)d3dadapter9_CheckDeviceType,
++    (void *)d3dadapter9_CheckDeviceFormat,
++    (void *)d3dadapter9_CheckDeviceMultiSampleType,
++    (void *)d3dadapter9_CheckDepthStencilMatch,
++    (void *)d3dadapter9_CheckDeviceFormatConversion,
++    (void *)d3dadapter9_GetDeviceCaps,
++    (void *)d3dadapter9_GetAdapterMonitor,
++    (void *)d3dadapter9_CreateDevice,
++    (void *)d3dadapter9_GetAdapterModeCountEx,
++    (void *)d3dadapter9_EnumAdapterModesEx,
++    (void *)d3dadapter9_GetAdapterDisplayModeEx,
++    (void *)d3dadapter9_CreateDeviceEx,
++    (void *)d3dadapter9_GetAdapterLUID
++};
++
++HRESULT
++d3dadapter9_new( Display *gdi_display,
++                 boolean ex,
++                 IDirect3D9Ex **ppOut )
++{
++    struct d3dadapter9 *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                                         sizeof(struct d3dadapter9));
++    HRESULT hr;
++    unsigned i, j, k;
++
++    if (!This) {
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    This->vtable = &d3dadapter9_vtable;
++    This->refs = 1;
++    This->ex = ex;
++    This->gdi_display = gdi_display;
++
++    if (!has_d3dadapter(gdi_display)) {
++        ERR("Your display driver doesn't support native D3D9 adapters.\n");
++        d3dadapter9_Release(This);
++        return D3DERR_NOTAVAILABLE;
++    }
++
++    hr = fill_groups(This);
++    if (FAILED(hr)) {
++        d3dadapter9_Release(This);
++        return hr;
++    }
++
++    /* map absolute adapter IDs with internal adapters */
++    for (i = 0; i < This->ngroups; ++i) {
++        for (j = 0; j < This->groups[i].noutputs; ++j) {
++            This->nadapters++;
++        }
++    }
++    if (This->nadapters == 0) {
++        ERR("No available native adapters in system.\n");
++        d3dadapter9_Release(This);
++        return D3DERR_NOTAVAILABLE;
++    }
++
++    This->map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          This->nadapters*sizeof(struct adapter_map));
++    if (!This->map) {
++        d3dadapter9_Release(This);
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++    for (i = k = 0; i < This->ngroups; ++i) {
++        for (j = 0; j < This->groups[i].noutputs; ++j, ++k) {
++            This->map[k].master = k-j;
++            This->map[k].group = i;
++        }
++    }
++
++    *ppOut = (IDirect3D9Ex *)This;
++    FIXME("\033[1;32m\nNative Direct3D 9 is active."
++          "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++    return D3D_OK;
++}
+diff -urN wine-1.9.1/dlls/d3d9-nine/d3dadapter9.h wine-1.9.1-d3d9/dlls/d3d9-nine/d3dadapter9.h
+--- wine-1.9.1/dlls/d3d9-nine/d3dadapter9.h    1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/d3dadapter9.h       2016-01-18 06:22:25.047627618 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/dri3.c wine-1.9.1-d3d9/dlls/d3d9-nine/dri3.c
+--- wine-1.9.1/dlls/d3d9-nine/dri3.c   1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/dri3.c      2016-01-18 06:22:25.047627618 -0500
+@@ -0,0 +1,1345 @@
++/*
++ * 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 <fcntl.h>
++#include <unistd.h>
++#include <pthread.h>
++
++#include "dri3.h"
++
++#include <X11/Xlib-xcb.h>
++#include <xcb/dri3.h>
++#include <xcb/present.h>
++
++#include "winbase.h" /* for Sleep */
++
++#ifdef D3DADAPTER9_DRI2
++#include <sys/ioctl.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>
++#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 = 0;
++    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 = 0;
++#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 -urN wine-1.9.1/dlls/d3d9-nine/dri3.h wine-1.9.1-d3d9/dlls/d3d9-nine/dri3.h
+--- wine-1.9.1/dlls/d3d9-nine/dri3.h   1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/dri3.h      2016-01-18 06:22:25.048627618 -0500
+@@ -0,0 +1,101 @@
++/*
++ * 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>
++
++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 -urN wine-1.9.1/dlls/d3d9-nine/libd3d9-nine.def wine-1.9.1-d3d9/dlls/d3d9-nine/libd3d9-nine.def
+--- wine-1.9.1/dlls/d3d9-nine/libd3d9-nine.def 1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/libd3d9-nine.def    2016-01-18 06:22:25.048627618 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/Makefile.in wine-1.9.1-d3d9/dlls/d3d9-nine/Makefile.in
+--- wine-1.9.1/dlls/d3d9-nine/Makefile.in      1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/Makefile.in 2016-01-18 06:22:25.048627618 -0500
+@@ -0,0 +1,12 @@
++MODULE    = d3d9-nine.dll
++IMPORTS   = dxguid uuid advapi32 gdi32 user32
++EXTRAINCL = $(X_CFLAGS) $(D3D_CFLAGS)
++EXTRALIBS = $(D3DADAPTER9_LIBS)
++
++C_SRCS = \
++        d3d9_main.c \
++        d3dadapter9.c \
++        present.c \
++        dri3.c
++
++RC_SRCS = version.rc
+diff -urN wine-1.9.1/dlls/d3d9-nine/present.c wine-1.9.1-d3d9/dlls/d3d9-nine/present.c
+--- wine-1.9.1/dlls/d3d9-nine/present.c        1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/present.c   2016-01-18 06:22:25.049627618 -0500
+@@ -0,0 +1,1332 @@
++/*
++ * 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 <X11/Xutil.h>
++
++#include "dri3.h"
++
++#include "wine/library.h" // for wine_dl*
++#include "wine/unicode.h" // for strcpyW
++
++#ifndef D3DPRESENT_DONOTWAIT
++#define D3DPRESENT_DONOTWAIT      0x00000001
++#endif
++
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR 1
++#ifdef ID3DPresent_GetWindowOccluded
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 1
++#else
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 0
++#endif
++
++static const struct D3DAdapter9DRM *d3d9_drm = NULL;
++#ifdef D3DADAPTER9_DRI2
++static int is_dri2_fallback = 0;
++#endif
++
++#define X11DRV_ESCAPE 6789
++enum x11drv_escape_codes
++{
++    X11DRV_SET_DRAWABLE,     /* set current drawable for a DC */
++    X11DRV_GET_DRAWABLE,     /* get current drawable for a DC */
++    X11DRV_START_EXPOSURES,  /* start graphics exposures */
++    X11DRV_END_EXPOSURES,    /* end graphics exposures */
++    X11DRV_FLUSH_GL_DRAWABLE /* flush changes made to the gl drawable */
++};
++
++struct x11drv_escape_get_drawable
++{
++    enum x11drv_escape_codes code;         /* escape code (X11DRV_GET_DRAWABLE) */
++    Drawable                 drawable;     /* X drawable */
++    Drawable                 gl_drawable;  /* GL drawable */
++    int                      pixel_format; /* internal GL pixel format */
++    RECT                     dc_rect;      /* DC rectangle relative to drawable */
++};
++
++static XContext d3d_hwnd_context;
++static CRITICAL_SECTION context_section;
++static CRITICAL_SECTION_DEBUG critsect_debug =
++{
++    0, 0, &context_section,
++    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
++      0, 0, { (DWORD_PTR)(__FILE__ ": context_section") }
++};
++static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 };
++
++const GUID IID_ID3DPresent = { 0x77D60E80, 0xF1E6, 0x11DF, { 0x9E, 0x39, 0x95, 0x0C, 0xDF, 0xD7, 0x20, 0x85 } };
++const GUID IID_ID3DPresentGroup = { 0xB9C3016E, 0xF32A, 0x11DF, { 0x9C, 0x18, 0x92, 0xEA, 0xDE, 0xD7, 0x20, 0x85 } };
++
++struct d3d_drawable
++{
++    Drawable drawable; /* X11 drawable */
++    RECT dc_rect; /* rect relative to the X11 drawable */
++    HDC hdc;
++    HWND wnd; /* HWND (for convenience) */
++};
++
++#ifdef ID3DPresent_GetWindowOccluded
++static HHOOK hhook;
++
++struct d3d_wnd_hooks
++{
++    HWND focus_wnd;
++    struct DRI3Present *present;
++    struct d3d_wnd_hooks *prev;
++    struct d3d_wnd_hooks *next;
++};
++
++static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This );
++static HRESULT dri3_present_register_window_hook( struct DRI3Present *This );
++
++static struct d3d_wnd_hooks d3d_hooks;
++#endif
++
++struct DRI3Present
++{
++    /* COM vtable */
++    void *vtable;
++    /* IUnknown reference count */
++    LONG refs;
++
++    D3DPRESENT_PARAMETERS params;
++    HWND focus_wnd;
++    PRESENTpriv *present_priv;
++#ifdef D3DADAPTER9_DRI2
++    struct DRI2priv *dri2_priv;
++#endif
++
++    WCHAR devname[32];
++    HCURSOR hCursor;
++
++    DEVMODEW initial_mode;
++    BOOL device_needs_reset;
++    BOOL occluded;
++    Display *gdi_display;
++    struct d3d_drawable *d3d;
++    boolean ex;
++    boolean no_window_changes;
++    boolean mode_changed;
++    long style;
++    long style_ex;
++    boolean drop_wnd_messages;
++};
++
++struct D3DWindowBuffer
++{
++    PRESENTPixmapPriv *present_pixmap_priv;
++};
++
++static void
++free_d3dadapter_drawable(struct d3d_drawable *d3d)
++{
++    ReleaseDC(d3d->wnd, d3d->hdc);
++    HeapFree(GetProcessHeap(), 0, d3d);
++}
++
++void
++destroy_d3dadapter_drawable(Display *gdi_display, HWND hwnd)
++{
++    struct d3d_drawable *d3d;
++
++    EnterCriticalSection(&context_section);
++    if (!XFindContext(gdi_display, (XID)hwnd,
++                      d3d_hwnd_context, (char **)&d3d)) {
++        XDeleteContext(gdi_display, (XID)hwnd, d3d_hwnd_context);
++        free_d3dadapter_drawable(d3d);
++    }
++    LeaveCriticalSection(&context_section);
++}
++
++static struct d3d_drawable *
++create_d3dadapter_drawable(HWND hwnd)
++{
++    struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++    struct d3d_drawable *d3d;
++
++    d3d = HeapAlloc(GetProcessHeap(), 0, sizeof(*d3d));
++    if (!d3d) {
++        ERR("Couldn't allocate d3d_drawable.\n");
++        return NULL;
++    }
++
++    d3d->hdc = GetDCEx(hwnd, 0, DCX_CACHE | DCX_CLIPSIBLINGS);
++    if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++                  sizeof(extesc), (LPSTR)&extesc) <= 0) {
++        ERR("Unexpected error in X Drawable lookup (hwnd=%p, hdc=%p)\n",
++            hwnd, d3d->hdc);
++        ReleaseDC(hwnd, d3d->hdc);
++        HeapFree(GetProcessHeap(), 0, d3d);
++        return NULL;
++    }
++
++    d3d->drawable = extesc.drawable;
++    d3d->wnd = hwnd;
++    d3d->dc_rect = extesc.dc_rect;
++
++    return d3d;
++}
++
++static struct d3d_drawable *
++get_d3d_drawable(Display *gdi_display, HWND hwnd)
++{
++    struct d3d_drawable *d3d, *race;
++
++    EnterCriticalSection(&context_section);
++    if (!XFindContext(gdi_display, (XID)hwnd,
++                      d3d_hwnd_context, (char **)&d3d)) {
++        struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++
++        /* check if the window has moved since last we used it */
++        if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++                      sizeof(extesc), (LPSTR)&extesc) <= 0) {
++            WARN("Window update check failed (hwnd=%p, hdc=%p)\n",
++                 hwnd, d3d->hdc);
++        }
++
++        if (!EqualRect(&d3d->dc_rect, &extesc.dc_rect))
++            d3d->dc_rect = extesc.dc_rect;
++
++        return d3d;
++    }
++    LeaveCriticalSection(&context_section);
++
++    TRACE("No d3d_drawable attached to hwnd %p, creating one.\n", hwnd);
++
++    d3d = create_d3dadapter_drawable(hwnd);
++    if (!d3d) { return NULL; }
++
++    EnterCriticalSection(&context_section);
++    if (!XFindContext(gdi_display, (XID)hwnd,
++                      d3d_hwnd_context, (char **)&race)) {
++        /* apparently someone beat us to creating this d3d drawable. Let's not
++           waste more time with X11 calls and just use theirs instead. */
++        free_d3dadapter_drawable(d3d);
++        return race;
++    }
++    XSaveContext(gdi_display, (XID)hwnd, d3d_hwnd_context, (char *)d3d);
++    return d3d;
++}
++
++static void
++release_d3d_drawable(struct d3d_drawable *d3d)
++{
++    if (d3d) { LeaveCriticalSection(&context_section); }
++}
++
++static ULONG WINAPI
++DRI3Present_AddRef( struct DRI3Present *This )
++{
++    ULONG refs = InterlockedIncrement(&This->refs);
++    TRACE("%p increasing refcount to %u.\n", This, refs);
++    return refs;
++}
++
++static ULONG WINAPI
++DRI3Present_Release( struct DRI3Present *This )
++{
++    ULONG refs = InterlockedDecrement(&This->refs);
++    TRACE("%p decreasing refcount to %u.\n", This, refs);
++    if (refs == 0) {
++        /* dtor */
++#ifdef ID3DPresent_GetWindowOccluded
++        dri3_present_unregister_window_hook(This);
++#endif
++        if (This->d3d)
++            destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
++        ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
++
++        PRESENTDestroy(This->gdi_display, This->present_priv);
++#ifdef D3DADAPTER9_DRI2
++        if (is_dri2_fallback)
++            DRI2FallbackDestroy(This->dri2_priv);
++#endif
++        HeapFree(GetProcessHeap(), 0, This);
++    }
++    return refs;
++}
++
++static HRESULT WINAPI
++DRI3Present_QueryInterface( struct DRI3Present *This,
++                            REFIID riid,
++                            void **ppvObject )
++{
++    if (!ppvObject) { return E_POINTER; }
++
++    if (IsEqualGUID(&IID_ID3DPresent, riid) ||
++        IsEqualGUID(&IID_IUnknown, riid)) {
++        *ppvObject = This;
++        DRI3Present_AddRef(This);
++        return S_OK;
++    }
++
++    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++    *ppvObject = NULL;
++
++    return E_NOINTERFACE;
++}
++
++static HRESULT
++DRI3Present_ChangePresentParameters( struct DRI3Present *This,
++                                    D3DPRESENT_PARAMETERS *params);
++
++static HRESULT WINAPI
++DRI3Present_SetPresentParameters( struct DRI3Present *This,
++                                  D3DPRESENT_PARAMETERS *pPresentationParameters,
++                                  D3DDISPLAYMODEEX *pFullscreenDisplayMode )
++{
++    if (pFullscreenDisplayMode)
++        ERR("Ignoring pFullscreenDisplayMode\n");
++    return DRI3Present_ChangePresentParameters(This, pPresentationParameters);
++}
++
++static HRESULT WINAPI
++DRI3Present_D3DWindowBufferFromDmaBuf( struct DRI3Present *This,
++                       int dmaBufFd,
++                       int width,
++                       int height,
++                       int stride,
++                       int depth,
++                       int bpp,
++                       struct D3DWindowBuffer **out)
++{
++    Pixmap pixmap;
++
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback) {
++        *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                    sizeof(struct D3DWindowBuffer));
++        DRI2FallbackPRESENTPixmap(This->present_priv, This->dri2_priv,
++                                  dmaBufFd, width, height, stride, depth,
++                                  bpp,
++                                  &((*out)->present_pixmap_priv));
++        return D3D_OK;
++    }
++#endif
++    if (!DRI3PixmapFromDmaBuf(This->gdi_display, DefaultScreen(This->gdi_display),
++                              dmaBufFd, width, height, stride, depth,
++                              bpp, &pixmap ))
++        return D3DERR_DRIVERINTERNALERROR;
++
++    *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                    sizeof(struct D3DWindowBuffer));
++    PRESENTPixmapInit(This->present_priv, pixmap, &((*out)->present_pixmap_priv));
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_DestroyD3DWindowBuffer( struct DRI3Present *This,
++                           struct D3DWindowBuffer *buffer )
++{
++    /* the pixmap is managed by the PRESENT backend.
++     * But if it can delete it right away, we may have
++     * better performance */
++    PRESENTTryFreePixmap(This->gdi_display, buffer->present_pixmap_priv);
++    HeapFree(GetProcessHeap(), 0, buffer);
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_WaitBufferReleased( struct DRI3Present *This,
++                                struct D3DWindowBuffer *buffer)
++{
++    PRESENTWaitPixmapReleased(buffer->present_pixmap_priv);
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_FrontBufferCopy( struct DRI3Present *This,
++                             struct D3DWindowBuffer *buffer )
++{
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback)
++        return D3DERR_DRIVERINTERNALERROR;
++#endif
++    /* TODO: use dc_rect */
++    if (PRESENTHelperCopyFront(This->gdi_display, buffer->present_pixmap_priv))
++        return D3D_OK;
++    else
++        return D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_PresentBuffer( struct DRI3Present *This,
++                           struct D3DWindowBuffer *buffer,
++                           HWND hWndOverride,
++                           const RECT *pSourceRect,
++                           const RECT *pDestRect,
++                           const RGNDATA *pDirtyRegion,
++                           DWORD Flags )
++{
++    struct d3d_drawable *d3d;
++    RECT dest_translate;
++
++    if (hWndOverride) {
++        d3d = get_d3d_drawable(This->gdi_display, hWndOverride);
++    } else if (This->params.hDeviceWindow) {
++        d3d = get_d3d_drawable(This->gdi_display, This->params.hDeviceWindow);
++    } else {
++        d3d = get_d3d_drawable(This->gdi_display, This->focus_wnd);
++    }
++    if (!d3d) { return D3DERR_DRIVERINTERNALERROR; }
++
++    /* TODO: should we use a list here instead ? */
++    if (This->d3d && (This->d3d->wnd != d3d->wnd)) {
++        destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
++    }
++    This->d3d = d3d;
++
++    if (d3d->dc_rect.top != 0 &&
++        d3d->dc_rect.left != 0) {
++        if (!pDestRect)
++            pDestRect = (const RECT *) &(d3d->dc_rect);
++        else {
++            dest_translate.top = pDestRect->top + d3d->dc_rect.top;
++            dest_translate.left = pDestRect->left + d3d->dc_rect.left;
++            dest_translate.bottom = pDestRect->bottom + d3d->dc_rect.bottom;
++            dest_translate.right = pDestRect->right + d3d->dc_rect.right;
++            pDestRect = (const RECT *) &dest_translate;
++        }
++    }
++
++    if (!PRESENTPixmap(This->gdi_display, d3d->drawable, buffer->present_pixmap_priv,
++                       &This->params, pSourceRect, pDestRect, pDirtyRegion))
++        return D3DERR_DRIVERINTERNALERROR;
++
++    release_d3d_drawable(d3d);
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetRasterStatus( struct DRI3Present *This,
++                             D3DRASTER_STATUS *pRasterStatus )
++{
++    FIXME("(%p, %p), stub!\n", This, pRasterStatus);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetDisplayMode( struct DRI3Present *This,
++                            D3DDISPLAYMODEEX *pMode,
++                            D3DDISPLAYROTATION *pRotation )
++{
++    DEVMODEW dm;
++
++    ZeroMemory(&dm, sizeof(dm));
++    dm.dmSize = sizeof(dm);
++
++    EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &dm, 0);
++    pMode->Width = dm.dmPelsWidth;
++    pMode->Height = dm.dmPelsHeight;
++    pMode->RefreshRate = dm.dmDisplayFrequency;
++    pMode->ScanLineOrdering = (dm.dmDisplayFlags & DM_INTERLACED) ?
++                                  D3DSCANLINEORDERING_INTERLACED :
++                                  D3DSCANLINEORDERING_PROGRESSIVE;
++
++    /* XXX This is called "guessing" */
++    switch (dm.dmBitsPerPel) {
++        case 32: pMode->Format = D3DFMT_X8R8G8B8; break;
++        case 24: pMode->Format = D3DFMT_R8G8B8; break;
++        case 16: pMode->Format = D3DFMT_R5G6B5; break;
++        default:
++            WARN("Unknown display format with %u bpp.\n", dm.dmBitsPerPel);
++            pMode->Format = D3DFMT_UNKNOWN;
++    }
++
++    switch (dm.dmDisplayOrientation) {
++        case DMDO_DEFAULT: *pRotation = D3DDISPLAYROTATION_IDENTITY; break;
++        case DMDO_90:      *pRotation = D3DDISPLAYROTATION_90; break;
++        case DMDO_180:     *pRotation = D3DDISPLAYROTATION_180; break;
++        case DMDO_270:     *pRotation = D3DDISPLAYROTATION_270; break;
++        default:
++            WARN("Unknown display rotation %u.\n", dm.dmDisplayOrientation);
++            *pRotation = D3DDISPLAYROTATION_IDENTITY;
++    }
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetPresentStats( struct DRI3Present *This,
++                             D3DPRESENTSTATS *pStats )
++{
++    FIXME("(%p, %p), stub!\n", This, pStats);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetCursorPos( struct DRI3Present *This,
++                          POINT *pPoint )
++{
++    BOOL ok;
++    HWND draw_window;
++
++    if (!pPoint)
++        return D3DERR_INVALIDCALL;
++
++    draw_window = This->params.hDeviceWindow ?
++        This->params.hDeviceWindow : This->focus_wnd;
++
++    ok = GetCursorPos(pPoint);
++    ok = ok && ScreenToClient(draw_window, pPoint);
++    return ok ? S_OK : D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_SetCursorPos( struct DRI3Present *This,
++                          POINT *pPoint )
++{
++    BOOL ok;
++    POINT real_pos;
++
++    if (!pPoint)
++        return D3DERR_INVALIDCALL;
++
++    ok = SetCursorPos(pPoint->x, pPoint->y);
++    if (!ok)
++        goto error;
++
++    ok = GetCursorPos(&real_pos);
++    if (!ok || real_pos.x != pPoint->x || real_pos.y != pPoint->y)
++        goto error;
++
++    return D3D_OK;
++
++error:
++    SetCursor(NULL); /* Hide cursor rather than put wrong pos */
++    return D3DERR_DRIVERINTERNALERROR;
++}
++
++
++/* Note: assuming 32x32 cursor */
++static HRESULT WINAPI
++DRI3Present_SetCursor( struct DRI3Present *This,
++                       void *pBitmap,
++                       POINT *pHotspot,
++                       BOOL bShow )
++{
++   if (pBitmap) {
++      ICONINFO info;
++      HCURSOR cursor;
++
++      DWORD mask[32];
++      memset(mask, ~0, sizeof(mask));
++
++      if (!pHotspot)
++         return D3DERR_INVALIDCALL;
++      info.fIcon = FALSE;
++      info.xHotspot = pHotspot->x;
++      info.yHotspot = pHotspot->y;
++      info.hbmMask = CreateBitmap(32, 32, 1, 1, mask);
++      info.hbmColor = CreateBitmap(32, 32, 1, 32, pBitmap);
++
++      cursor = CreateIconIndirect(&info);
++      if (info.hbmMask) DeleteObject(info.hbmMask);
++      if (info.hbmColor) DeleteObject(info.hbmColor);
++      if (cursor)
++         DestroyCursor(This->hCursor);
++      This->hCursor = cursor;
++   }
++   SetCursor(bShow ? This->hCursor : NULL);
++
++   return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_SetGammaRamp( struct DRI3Present *This,
++                          const D3DGAMMARAMP *pRamp,
++                          HWND hWndOverride )
++{
++    HWND hWnd = hWndOverride ? hWndOverride : This->focus_wnd;
++    HDC hdc;
++    BOOL ok;
++    if (!pRamp) {
++        return D3DERR_INVALIDCALL;
++    }
++    hdc = GetDC(hWnd);
++    ok = SetDeviceGammaRamp(hdc, (void *)pRamp);
++    ReleaseDC(hWnd, hdc);
++    return ok ? D3D_OK : D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetWindowInfo( struct DRI3Present *This,
++                           HWND hWnd,
++                           int *width, int *height, int *depth )
++{
++    HRESULT hr;
++    RECT pRect;
++
++    if (!hWnd)
++        hWnd = This->focus_wnd;
++    hr = GetClientRect(hWnd, &pRect);
++    if (!hr)
++        return D3DERR_INVALIDCALL;
++    *width = pRect.right - pRect.left;
++    *height = pRect.bottom - pRect.top;
++    *depth = 24; //TODO
++    return D3D_OK;
++}
++
++static LONG fullscreen_style(LONG style)
++{
++    /* Make sure the window is managed, otherwise we won't get keyboard input. */
++    style |= WS_POPUP | WS_SYSMENU;
++    style &= ~(WS_CAPTION | WS_THICKFRAME);
++
++    return style;
++}
++
++static LONG fullscreen_exstyle(LONG exstyle)
++{
++    /* Filter out window decorations. */
++    exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
++
++    return exstyle;
++}
++
++static HRESULT
++DRI3Present_ChangeDisplaySettingsIfNeccessary( struct DRI3Present *This, DEVMODEW *new_mode ) {
++    DEVMODEW current_mode;
++    LONG hr;
++
++    ZeroMemory(&current_mode, sizeof(DEVMODEW));
++    /* Only change the mode if necessary. */
++    if (!EnumDisplaySettingsW(This->devname, ENUM_CURRENT_SETTINGS, &current_mode))
++    {
++       ERR("Failed to get current display mode.\n");
++    } else if (current_mode.dmPelsWidth != new_mode->dmPelsWidth
++           || current_mode.dmPelsHeight != new_mode->dmPelsHeight
++           || (current_mode.dmDisplayFrequency != new_mode->dmDisplayFrequency
++           && (new_mode->dmFields & DM_DISPLAYFREQUENCY)))
++    {
++        hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
++        if (hr != DISP_CHANGE_SUCCESSFUL) {
++            /* try again without display RefreshRate */
++            if (new_mode->dmFields & DM_DISPLAYFREQUENCY) {
++                new_mode->dmFields &= ~DM_DISPLAYFREQUENCY;
++                new_mode->dmDisplayFrequency = 0;
++                hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
++                if (hr != DISP_CHANGE_SUCCESSFUL) {
++                    ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++                    return D3DERR_INVALIDCALL;
++                }
++            } else {
++                ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++                return D3DERR_INVALIDCALL;
++            }
++        }
++    }
++    return D3D_OK;
++}
++
++#ifdef ID3DPresent_GetWindowOccluded
++static struct d3d_wnd_hooks *get_last_hook(void) {
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++    while (hook->next) {
++        hook = hook->next;
++    }
++    return hook;
++}
++
++LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
++{
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++    boolean drop_wnd_messages;
++
++    if (nCode < 0) {
++        return CallNextHookEx(hhook, nCode, wParam, lParam);
++    }
++
++    if (lParam) {
++        CWPSTRUCT wndprocparams = *((CWPSTRUCT*)lParam);
++        while (hook->next) {
++            hook = hook->next;
++
++            /* skip messages for other hwnds */
++            if (hook->focus_wnd != wndprocparams.hwnd)
++                continue;
++            if (!hook->present)
++                continue;
++
++            switch (wndprocparams.message) {
++                case WM_ACTIVATEAPP:
++                    if (hook->present->drop_wnd_messages)
++                        return -1;
++
++                    drop_wnd_messages = hook->present->drop_wnd_messages;
++                    hook->present->drop_wnd_messages = TRUE;
++                    if (wndprocparams.wParam == WA_INACTIVE) {
++                            hook->present->occluded = TRUE;
++
++                            DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &(hook->present->initial_mode));
++
++                            if (!hook->present->no_window_changes &&
++                                    IsWindowVisible(hook->present->params.hDeviceWindow))
++                                ShowWindow(hook->present->params.hDeviceWindow, SW_MINIMIZE);
++                    } else {
++                            hook->present->device_needs_reset |= hook->present->occluded;
++                            hook->present->occluded = FALSE;
++
++                            if (!hook->present->no_window_changes) {
++                                /* restore window */
++                                SetWindowPos(hook->present->params.hDeviceWindow, NULL, 0, 0,
++                                             hook->present->params.BackBufferWidth, hook->present->params.BackBufferHeight,
++                                             SWP_NOACTIVATE | SWP_NOZORDER);
++                            }
++
++                            if (hook->present->ex) {
++                                DEVMODEW new_mode;
++
++                                ZeroMemory(&new_mode, sizeof(DEVMODEW));
++                                new_mode.dmPelsWidth = hook->present->params.BackBufferWidth;
++                                new_mode.dmPelsHeight = hook->present->params.BackBufferHeight;
++                                new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++                                if (hook->present->params.FullScreen_RefreshRateInHz) {
++                                    new_mode.dmFields |= DM_DISPLAYFREQUENCY;
++                                    new_mode.dmDisplayFrequency = hook->present->params.FullScreen_RefreshRateInHz;
++                                }
++                                new_mode.dmSize = sizeof(DEVMODEW);
++                                DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &new_mode);
++                            }
++                    }
++                    hook->present->drop_wnd_messages = drop_wnd_messages;
++                break;
++                case WM_DISPLAYCHANGE:
++                    hook->present->mode_changed = TRUE;
++                    hook->present->device_needs_reset = TRUE;
++                break;
++                /* TODO: handle other window messages here */
++                default:
++                break;
++            }
++        }
++    }
++
++    return CallNextHookEx(hhook, nCode, wParam, lParam);
++}
++
++static HRESULT dri3_present_register_window_hook( struct DRI3Present *This ) {
++    struct d3d_wnd_hooks *lasthook;
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++
++    HWND hWnd = This->focus_wnd;
++
++    /* let's see if already hooked */
++    while (hook->next) {
++        hook = hook->next;
++        if (hook->focus_wnd == hWnd && hook->present == This)
++            return D3DERR_INVALIDCALL;
++    }
++    /* create single WindowsHook in this process */
++    if (!hhook) {
++        // TODO: do we need to handle different threadIDs ?
++        DWORD threadID = GetWindowThreadProcessId(hWnd, NULL);
++        hhook = SetWindowsHookExW(WH_CALLWNDPROC, HookCallback, NULL, threadID);
++        if (!hhook) {
++            ERR("SetWindowsHookEx failed with 0x%08x\n", GetLastError());
++            return D3DERR_DRIVERINTERNALERROR;
++        }
++    }
++    lasthook = get_last_hook();
++    hook = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++            sizeof(struct d3d_wnd_hooks));
++    if (!hook)
++        return E_OUTOFMEMORY;
++    /* add window hwnd to list */
++    lasthook->next = hook;
++    hook->prev = lasthook;
++    hook->focus_wnd = hWnd;
++    hook->present = This;
++    return D3D_OK;
++}
++
++static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This ) {
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++
++    HWND hWnd = This->focus_wnd;
++
++    /* find hook and remove it */
++    while (hook->next) {
++        hook = hook->next;
++        if(hook->focus_wnd == hWnd && hook->present == This) {
++            /* remove hook */
++            hook->prev->next = hook->next;
++            HeapFree(GetProcessHeap(), 0, hook);
++            /* start again at list head */
++            hook = &d3d_hooks;
++        }
++    }
++    /* remove single process WindowsHook */
++    if (get_last_hook() == &d3d_hooks && hhook) {
++       if (!UnhookWindowsHookEx(hhook)) {
++           ERR("UnhookWindowsHookEx failed with 0x%08x\n", GetLastError());
++       }
++       hhook = NULL;
++    }
++
++    return D3D_OK;
++}
++
++static BOOL WINAPI
++DRI3Present_GetWindowOccluded( struct DRI3Present *This )
++{
++    /* we missed to poll occluded */
++    if (This->device_needs_reset) {
++        This->device_needs_reset = FALSE;
++        return TRUE;
++    }
++
++    return This->occluded;
++}
++#endif
++/*----------*/
++
++
++static ID3DPresentVtbl DRI3Present_vtable = {
++    (void *)DRI3Present_QueryInterface,
++    (void *)DRI3Present_AddRef,
++    (void *)DRI3Present_Release,
++    (void *)DRI3Present_SetPresentParameters,
++    (void *)DRI3Present_D3DWindowBufferFromDmaBuf,
++    (void *)DRI3Present_DestroyD3DWindowBuffer,
++    (void *)DRI3Present_WaitBufferReleased,
++    (void *)DRI3Present_FrontBufferCopy,
++    (void *)DRI3Present_PresentBuffer,
++    (void *)DRI3Present_GetRasterStatus,
++    (void *)DRI3Present_GetDisplayMode,
++    (void *)DRI3Present_GetPresentStats,
++    (void *)DRI3Present_GetCursorPos,
++    (void *)DRI3Present_SetCursorPos,
++    (void *)DRI3Present_SetCursor,
++    (void *)DRI3Present_SetGammaRamp,
++    (void *)DRI3Present_GetWindowInfo,
++#ifdef ID3DPresent_GetWindowOccluded
++    (void *)DRI3Present_GetWindowOccluded
++#endif
++};
++
++static HRESULT
++DRI3Present_ChangePresentParameters( struct DRI3Present *This,
++                                    D3DPRESENT_PARAMETERS *params )
++{
++    HWND draw_window = params->hDeviceWindow;
++    RECT rect;
++    DEVMODEW new_mode;
++
++    if (!GetClientRect(draw_window, &rect)) {
++        WARN("GetClientRect failed.\n");
++        rect.right = 640;
++        rect.bottom = 480;
++    }
++
++    if (params->BackBufferWidth == 0) {
++        params->BackBufferWidth = rect.right - rect.left;
++    }
++    if (params->BackBufferHeight == 0) {
++        params->BackBufferHeight = rect.bottom - rect.top;
++    }
++
++    if ((This->params.BackBufferWidth != params->BackBufferWidth) ||
++        (This->params.BackBufferHeight != params->BackBufferHeight)) {
++        This->mode_changed = TRUE;
++    }
++
++    if (This->mode_changed || (This->params.Windowed != params->Windowed)) {
++        if (!params->Windowed) {
++            /* switch display mode */
++            ZeroMemory(&new_mode, sizeof(DEVMODEW));
++            new_mode.dmPelsWidth = params->BackBufferWidth;
++            new_mode.dmPelsHeight = params->BackBufferHeight;
++            new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++            if (params->FullScreen_RefreshRateInHz) {
++                new_mode.dmFields |= DM_DISPLAYFREQUENCY;
++                new_mode.dmDisplayFrequency = params->FullScreen_RefreshRateInHz;
++            }
++            new_mode.dmSize = sizeof(DEVMODEW);
++            DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &new_mode);
++        } else {
++            DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &This->initial_mode);
++        }
++        This->mode_changed = FALSE;
++
++        if (This->params.Windowed) {
++            if (!params->Windowed) {
++                LONG style, style_ex;
++                boolean drop_wnd_messages;
++
++                /* switch from window to fullscreen */
++#ifdef ID3DPresent_GetWindowOccluded
++                if (dri3_present_register_window_hook(This)) {
++                    SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
++                }
++#else
++                SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
++#endif
++                This->style = GetWindowLongW(draw_window, GWL_STYLE);
++                This->style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++                style = fullscreen_style(This->style);
++                style_ex = fullscreen_exstyle(This->style_ex);
++
++                drop_wnd_messages = This->drop_wnd_messages;
++                This->drop_wnd_messages = TRUE;
++
++                SetWindowLongW(draw_window, GWL_STYLE, style);
++                SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++                SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth,
++                             params->BackBufferHeight,
++                             SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++                This->drop_wnd_messages = drop_wnd_messages;
++            }
++        } else {
++            if (!params->Windowed) {
++                /* switch from fullscreen to fullscreen */
++                MoveWindow(draw_window, 0, 0,
++                        params->BackBufferWidth,
++                        params->BackBufferHeight,
++                        TRUE);
++            } else {
++                LONG style, style_ex;
++                boolean drop_wnd_messages;
++
++                /* switch from fullscreen to window */
++                style = GetWindowLongW(draw_window, GWL_STYLE);
++                style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++                /* These flags are set by wined3d_device_setup_fullscreen_window, not the
++                 * application, and we want to ignore them in the test below, since it's
++                 * not the application's fault that they changed. Additionally, we want to
++                 * preserve the current status of these flags (i.e. don't restore them) to
++                 * more closely emulate the behavior of Direct3D, which leaves these flags
++                 * alone when returning to windowed mode. */
++                This->style ^= (This->style ^ style) & WS_VISIBLE;
++                This->style_ex ^= (This->style_ex ^ style_ex) & WS_EX_TOPMOST;
++
++                /* Only restore the style if the application didn't modify it during the
++                 * fullscreen phase. Some applications change it before calling Reset()
++                 * when switching between windowed and fullscreen modes (HL2), some
++                 * depend on the original style (Eve Online). */
++                drop_wnd_messages = This->drop_wnd_messages;
++                This->drop_wnd_messages = TRUE;
++                if (style == fullscreen_style(This->style) && style_ex == fullscreen_exstyle(This->style_ex))
++                {
++                    SetWindowLongW(draw_window, GWL_STYLE, style);
++                    SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++                }
++                SetWindowPos(draw_window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED |
++                             SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
++                             SWP_NOACTIVATE);
++                This->drop_wnd_messages = drop_wnd_messages;
++
++#ifdef ID3DPresent_GetWindowOccluded
++        dri3_present_unregister_window_hook(This);
++#endif
++                This->style = 0;
++                This->style_ex = 0;
++            }
++        }
++    } else if (!params->Windowed) {
++        LONG style, style_ex;
++        /* move draw window back to place */
++
++        style = GetWindowLongW(draw_window, GWL_STYLE);
++        style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++        style = fullscreen_style(style);
++        style_ex = fullscreen_exstyle(style_ex);
++
++        SetWindowLongW(draw_window, GWL_STYLE, style);
++        SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++        SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth,
++                     params->BackBufferHeight,
++                     SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++    }
++
++    This->params = *params;
++    return D3D_OK;
++}
++
++static HRESULT
++DRI3Present_new( Display *gdi_display,
++                 const WCHAR *devname,
++                 D3DPRESENT_PARAMETERS *params,
++                 HWND focus_wnd,
++                 struct DRI3Present **out,
++                 boolean ex,
++                 boolean no_window_changes )
++{
++    struct DRI3Present *This;
++
++    if (!focus_wnd) { focus_wnd = params->hDeviceWindow; }
++    if (!focus_wnd) {
++        ERR("No focus HWND specified for presentation backend.\n");
++        return D3DERR_INVALIDCALL;
++    }
++
++    This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                     sizeof(struct DRI3Present));
++    if (!This) {
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    This->gdi_display = gdi_display;
++    This->vtable = &DRI3Present_vtable;
++    This->refs = 1;
++    This->focus_wnd = focus_wnd;
++    This->params.Windowed = TRUE;
++    This->ex = ex;
++    This->no_window_changes = no_window_changes;
++
++    strcpyW(This->devname, devname);
++
++    ZeroMemory(&(This->initial_mode), sizeof(This->initial_mode));
++    This->initial_mode.dmSize = sizeof(This->initial_mode);
++
++    EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &(This->initial_mode), 0);
++
++    PRESENTInit(gdi_display, &(This->present_priv));
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback)
++        DRI2FallbackInit(gdi_display, &(This->dri2_priv));
++#endif
++    *out = This;
++
++    return D3D_OK;
++}
++
++struct DRI3PresentGroup
++{
++    /* COM vtable */
++    void *vtable;
++    /* IUnknown reference count */
++    LONG refs;
++
++    struct DRI3Present **present_backends;
++    unsigned npresent_backends;
++    Display *gdi_display;
++    boolean ex;
++    boolean no_window_changes;
++};
++
++static ULONG WINAPI
++DRI3PresentGroup_AddRef( struct DRI3PresentGroup *This )
++{
++    ULONG refs = InterlockedIncrement(&This->refs);
++    TRACE("%p increasing refcount to %u.\n", This, refs);
++    return refs;
++}
++
++static ULONG WINAPI
++DRI3PresentGroup_Release( struct DRI3PresentGroup *This )
++{
++    ULONG refs = InterlockedDecrement(&This->refs);
++    TRACE("%p decreasing refcount to %u.\n", This, refs);
++    if (refs == 0) {
++        unsigned i;
++        if (This->present_backends) {
++            for (i = 0; i < This->npresent_backends; ++i) {
++                if (This->present_backends[i])
++                    DRI3Present_Release(This->present_backends[i]);
++            }
++            HeapFree(GetProcessHeap(), 0, This->present_backends);
++        }
++        HeapFree(GetProcessHeap(), 0, This);
++    }
++    return refs;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_QueryInterface( struct DRI3PresentGroup *This,
++                                 REFIID riid,
++                                 void **ppvObject )
++{
++    if (!ppvObject) { return E_POINTER; }
++    if (IsEqualGUID(&IID_ID3DPresentGroup, riid) ||
++        IsEqualGUID(&IID_IUnknown, riid)) {
++        *ppvObject = This;
++        DRI3PresentGroup_AddRef(This);
++        return S_OK;
++    }
++
++    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++    *ppvObject = NULL;
++
++    return E_NOINTERFACE;
++}
++
++static UINT WINAPI
++DRI3PresentGroup_GetMultiheadCount( struct DRI3PresentGroup *This )
++{
++    FIXME("(%p), stub!\n", This);
++    return 1;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_GetPresent( struct DRI3PresentGroup *This,
++                             UINT Index,
++                             ID3DPresent **ppPresent )
++{
++    if (Index >= DRI3PresentGroup_GetMultiheadCount(This)) {
++        ERR("Index >= MultiHeadCount\n");
++        return D3DERR_INVALIDCALL;
++    }
++    DRI3Present_AddRef(This->present_backends[Index]);
++    *ppPresent = (ID3DPresent *)This->present_backends[Index];
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_CreateAdditionalPresent( struct DRI3PresentGroup *This,
++                                          D3DPRESENT_PARAMETERS *pPresentationParameters,
++                                          ID3DPresent **ppPresent )
++{
++    HRESULT hr;
++    hr = DRI3Present_new(This->gdi_display, This->present_backends[0]->devname,
++                         pPresentationParameters, 0, (struct DRI3Present **)ppPresent,
++                         This->ex, This->no_window_changes);
++    return hr;
++}
++
++static void WINAPI
++DRI3PresentGroup_GetVersion( struct DRI3PresentGroup *This,
++                             int *major,
++                             int *minor)
++{
++    *major = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR;
++    *minor = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR;
++}
++
++static ID3DPresentGroupVtbl DRI3PresentGroup_vtable = {
++    (void *)DRI3PresentGroup_QueryInterface,
++    (void *)DRI3PresentGroup_AddRef,
++    (void *)DRI3PresentGroup_Release,
++    (void *)DRI3PresentGroup_GetMultiheadCount,
++    (void *)DRI3PresentGroup_GetPresent,
++    (void *)DRI3PresentGroup_CreateAdditionalPresent,
++    (void *)DRI3PresentGroup_GetVersion
++};
++
++HRESULT
++present_create_present_group( Display *gdi_display,
++                           const WCHAR *device_name,
++                           UINT adapter,
++                           HWND focus_wnd,
++                           D3DPRESENT_PARAMETERS *params,
++                           unsigned nparams,
++                           ID3DPresentGroup **group,
++                           boolean ex,
++                           boolean no_window_changes )
++{
++    struct DRI3PresentGroup *This =
++        HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                  sizeof(struct DRI3PresentGroup));
++    DISPLAY_DEVICEW dd;
++    HRESULT hr;
++    unsigned i;
++
++    if (!This) {
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    This->gdi_display = gdi_display;
++    This->vtable = &DRI3PresentGroup_vtable;
++    This->refs = 1;
++    This->ex = ex;
++    This->no_window_changes = no_window_changes;
++    This->npresent_backends = nparams;
++    This->present_backends = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                                       This->npresent_backends *
++                                       sizeof(struct DRI3Present *));
++    if (!This->present_backends) {
++        DRI3PresentGroup_Release(This);
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    if (nparams != 1) { adapter = 0; }
++    for (i = 0; i < This->npresent_backends; ++i) {
++        ZeroMemory(&dd, sizeof(dd));
++        dd.cb = sizeof(dd);
++        /* find final device name */
++        if (!EnumDisplayDevicesW(device_name, adapter+i, &dd, 0)) {
++            WARN("Couldn't find subdevice %d from `%s'\n",
++                 i, debugstr_w(device_name));
++        }
++
++        /* create an ID3DPresent for it */
++        hr = DRI3Present_new(gdi_display, dd.DeviceName, &params[i],
++                             focus_wnd, &This->present_backends[i],
++                             This->ex, This->no_window_changes);
++        if (FAILED(hr)) {
++            DRI3PresentGroup_Release(This);
++            return hr;
++        }
++    }
++
++    *group = (ID3DPresentGroup *)This;
++    TRACE("Returning %p\n", *group);
++
++    return D3D_OK;
++}
++
++HRESULT
++present_create_adapter9( Display *gdi_display,
++                      HDC hdc,
++                      ID3DAdapter9 **out )
++{
++    struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++    HRESULT hr;
++    int fd;
++
++    if (!d3d9_drm) {
++        ERR("DRM drivers are not supported on your system.\n");
++        return D3DERR_DRIVERINTERNALERROR;
++    }
++
++    if (ExtEscape(hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++                  sizeof(extesc), (LPSTR)&extesc) <= 0) {
++        ERR("X11 drawable lookup failed (hdc=%p)\n", hdc);
++    }
++
++#ifdef D3DADAPTER9_DRI2
++    if (!is_dri2_fallback && !DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) {
++#else
++    if (!DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) {
++#endif
++        ERR("DRI3Open failed (fd=%d)\n", fd);
++        return D3DERR_DRIVERINTERNALERROR;
++    }
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback && !DRI2FallbackOpen(gdi_display, DefaultScreen(gdi_display), &fd)) {
++        ERR("DRI2Open failed (fd=%d)\n", fd);
++        return D3DERR_DRIVERINTERNALERROR;
++    }
++#endif
++    hr = d3d9_drm->create_adapter(fd, out);
++    if (FAILED(hr)) {
++        ERR("Unable to create ID3DAdapter9 (fd=%d)\n", fd);
++        return hr;
++    }
++
++    TRACE("Created ID3DAdapter9 with fd %d\n", fd);
++
++    return D3D_OK;
++}
++
++BOOL
++has_d3dadapter( Display *gdi_display )
++{
++    static const void * WINAPI (*pD3DAdapter9GetProc)(const char *);
++    static void *handle = NULL;
++    static int done = 0;
++
++    char errbuf[256];
++
++#if !defined(SONAME_D3DADAPTER9)
++    return FALSE;
++#endif
++
++    /* like in opengl.c (single threaded assumption OK?) */
++    if (done) { return handle != NULL; }
++    done = 1;
++
++    handle = wine_dlopen(D3D_MODULE_DIR "/" SONAME_D3DADAPTER9,
++                         RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf));
++    if (!handle) {
++        ERR("Failed to load %s: %s\n", SONAME_D3DADAPTER9, errbuf);
++        goto cleanup;
++    }
++
++    /* find our entry point in d3dadapter9 */
++    pD3DAdapter9GetProc = wine_dlsym(handle, "D3DAdapter9GetProc",
++                                     errbuf, sizeof(errbuf));
++    if (!pD3DAdapter9GetProc) {
++        ERR("Failed to get the entry point from %s: %s",
++            SONAME_D3DADAPTER9, errbuf);
++        goto cleanup;
++    }
++
++    /* get a handle to the drm backend struct */
++    d3d9_drm = pD3DAdapter9GetProc(D3DADAPTER9DRM_NAME);
++    if (!d3d9_drm) {
++        ERR("%s doesn't support the `%s' backend.\n",
++            SONAME_D3DADAPTER9, D3DADAPTER9DRM_NAME);
++        goto cleanup;
++    }
++
++    /* verify that we're binary compatible */
++    if (d3d9_drm->major_version != D3DADAPTER9DRM_MAJOR) {
++        ERR("Version mismatch. %s has %d.%d, was expecting %d.x\n",
++            SONAME_D3DADAPTER9, d3d9_drm->major_version,
++            d3d9_drm->minor_version, D3DADAPTER9DRM_MAJOR);
++        goto cleanup;
++    }
++
++    /* this will be used to store d3d_drawables */
++    d3d_hwnd_context = XUniqueContext();
++
++    if (!PRESENTCheckExtension(gdi_display, 1, 0)) {
++        ERR("Unable to query PRESENT.\n");
++        goto cleanup;
++    }
++
++    if (!DRI3CheckExtension(gdi_display, 1, 0)) {
++#ifndef D3DADAPTER9_DRI2
++        ERR("Unable to query DRI3.\n");
++        goto cleanup;
++#else
++        ERR("Unable to query DRI3. Trying DRI2 fallback (slower performance).\n");
++        is_dri2_fallback = 1;
++        if (!DRI2FallbackCheckSupport(gdi_display)) {
++            ERR("DRI2 fallback unsupported\n");
++            goto cleanup;
++        }
++#endif
++    }
++
++    return TRUE;
++
++cleanup:
++    ERR("\033[1;31m\nNative Direct3D 9 will be unavailable."
++        "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++    if (handle) {
++        wine_dlclose(handle, NULL, 0);
++        handle = NULL;
++    }
++
++    return FALSE;
++}
+diff -urN wine-1.9.1/dlls/d3d9-nine/present.h wine-1.9.1-d3d9/dlls/d3d9-nine/present.h
+--- wine-1.9.1/dlls/d3d9-nine/present.h        1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/present.h   2016-01-18 06:22:25.049627618 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/version.rc wine-1.9.1-d3d9/dlls/d3d9-nine/version.rc
+--- wine-1.9.1/dlls/d3d9-nine/version.rc       1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/d3d9-nine/version.rc  2016-01-18 06:22:25.049627618 -0500
+@@ -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 -urN wine-1.9.1/dlls/ntdll/loader.c wine-1.9.1-d3d9/dlls/ntdll/loader.c
+--- wine-1.9.1/dlls/ntdll/loader.c     2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/ntdll/loader.c        2016-01-18 06:22:25.049627618 -0500
+@@ -92,6 +92,7 @@
+ {
+     const WCHAR *load_path;
+     const WCHAR *filename;
++    const WCHAR *fakemodule;
+     NTSTATUS     status;
+     WINE_MODREF *wm;
+ };
+@@ -117,7 +118,8 @@
+ 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 @@
+     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 @@
+     {
+         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 @@
+         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 @@
+  * 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 @@
+     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 @@
+         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 @@
+ /******************************************************************************
+  *    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 @@
+     /* 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 @@
+ /***********************************************************************
+  *           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 @@
+      */
+     info.load_path = load_path;
+     info.filename  = NULL;
++    info.fakemodule = fakemodule;
+     info.status    = STATUS_SUCCESS;
+     info.wm        = NULL;
+@@ -2198,14 +2201,14 @@
+     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 @@
+     }
+     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 @@
+         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 @@
+             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 @@
+     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 @@
+     /* 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 -urN wine-1.9.1/dlls/ntdll/loadorder.c wine-1.9.1-d3d9/dlls/ntdll/loadorder.c
+--- wine-1.9.1/dlls/ntdll/loadorder.c  2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/ntdll/loadorder.c     2016-01-18 06:22:25.050627618 -0500
+@@ -290,102 +290,165 @@
+ /***************************************************************************
+- *    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 @@
+         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 @@
+ /***************************************************************************
+- *    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 @@
+         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)
+@@ -487,5 +594,48 @@
+  done:
+     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 -urN wine-1.9.1/dlls/ntdll/ntdll_misc.h wine-1.9.1-d3d9/dlls/ntdll/ntdll_misc.h
+--- wine-1.9.1/dlls/ntdll/ntdll_misc.h 2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/ntdll/ntdll_misc.h    2016-01-18 06:22:25.050627618 -0500
+@@ -205,6 +205,7 @@
+ };
+ 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 -urN wine-1.9.1/dlls/winex11.drv/init.c wine-1.9.1-d3d9/dlls/winex11.drv/init.c
+--- wine-1.9.1/dlls/winex11.drv/init.c 2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/winex11.drv/init.c    2016-01-18 06:22:25.050627618 -0500
+@@ -365,6 +365,7 @@
+                 {
+                     struct x11drv_escape_get_drawable *data = out_data;
+                     data->drawable = physDev->drawable;
++                    data->dc_rect = physDev->dc_rect;
+                     return TRUE;
+                 }
+                 break;
+diff -urN wine-1.9.1/dlls/winex11.drv/x11drv.h wine-1.9.1-d3d9/dlls/winex11.drv/x11drv.h
+--- wine-1.9.1/dlls/winex11.drv/x11drv.h       2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/dlls/winex11.drv/x11drv.h  2016-01-18 06:22:25.051627618 -0500
+@@ -292,6 +292,7 @@
+     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 -urN wine-1.9.1/include/config.h.in wine-1.9.1-d3d9/include/config.h.in
+--- wine-1.9.1/include/config.h.in     2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/include/config.h.in        2016-01-18 06:22:34.848627418 -0500
+@@ -4,6 +4,12 @@
+ #define __WINE_CONFIG_H
+ #ifndef WINE_CROSSTEST
++/* Whether d3dadapter9 DRI2 fallback is compiled */
++#undef D3DADAPTER9_DRI2
++
++/* "module dir" */
++#undef D3D_MODULE_DIR
++
+ /* Define to a function attribute for Microsoft hotpatch assembly prefix. */
+ #undef DECLSPEC_HOTPATCH
+@@ -1332,6 +1338,9 @@
+ /* Define to the version of this package. */
+ #undef PACKAGE_VERSION
++/* "temporary hack" */
++#undef SONAME_D3DADAPTER9
++
+ /* Define to the soname of the libcapi20 library. */
+ #undef SONAME_LIBCAPI20
+@@ -1344,6 +1353,9 @@
+ /* Define to the soname of the libdbus-1 library. */
+ #undef SONAME_LIBDBUS_1
++/* Define to the soname of the libEGL library. */
++#undef SONAME_LIBEGL
++
+ /* Define to the soname of the libfontconfig library. */
+ #undef SONAME_LIBFONTCONFIG
+diff -urN wine-1.9.1/programs/winecfg/main.c wine-1.9.1-d3d9/programs/winecfg/main.c
+--- wine-1.9.1/programs/winecfg/main.c 2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/programs/winecfg/main.c    2016-01-18 06:22:25.051627618 -0500
+@@ -58,7 +58,7 @@
+     return 0;
+ }
+-#define NUM_PROPERTY_PAGES 7
++#define NUM_PROPERTY_PAGES 8
+ static INT_PTR
+ doPropertySheet (HINSTANCE hInstance, HWND hOwner)
+@@ -139,6 +139,16 @@
+     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 -urN wine-1.9.1/programs/winecfg/Makefile.in wine-1.9.1-d3d9/programs/winecfg/Makefile.in
+--- wine-1.9.1/programs/winecfg/Makefile.in    2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/programs/winecfg/Makefile.in       2016-01-18 06:22:25.051627618 -0500
+@@ -11,6 +11,7 @@
+       driveui.c \
+       libraries.c \
+       main.c \
++      staging.c \
+       theme.c \
+       winecfg.c \
+       x11drvdlg.c
+diff -urN wine-1.9.1/programs/winecfg/resource.h wine-1.9.1-d3d9/programs/winecfg/resource.h
+--- wine-1.9.1/programs/winecfg/resource.h     2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/programs/winecfg/resource.h        2016-01-18 06:22:25.052627618 -0500
+@@ -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 -urN wine-1.9.1/programs/winecfg/staging.c wine-1.9.1-d3d9/programs/winecfg/staging.c
+--- wine-1.9.1/programs/winecfg/staging.c      1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-d3d9/programs/winecfg/staging.c 2016-01-18 06:22:25.052627618 -0500
+@@ -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 -urN wine-1.9.1/programs/winecfg/winecfg.h wine-1.9.1-d3d9/programs/winecfg/winecfg.h
+--- wine-1.9.1/programs/winecfg/winecfg.h      2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/programs/winecfg/winecfg.h 2016-01-18 06:22:25.052627618 -0500
+@@ -87,6 +87,7 @@
+ 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 -urN wine-1.9.1/programs/winecfg/winecfg.rc wine-1.9.1-d3d9/programs/winecfg/winecfg.rc
+--- wine-1.9.1/programs/winecfg/winecfg.rc     2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-d3d9/programs/winecfg/winecfg.rc        2016-01-18 06:22:34.957627416 -0500
+@@ -39,6 +39,7 @@
+     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 @@
+     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/wine/wine-1.9.1-nine_for_staging.patch b/wine/wine-1.9.1-nine_for_staging.patch
new file mode 100644 (file)
index 0000000..0a2abd6
--- /dev/null
@@ -0,0 +1,4840 @@
+This is the same as the other patch, except it doesn't have any conflicts
+with staging. The other patch applies a few bits of staging: the dll
+redirection, the staging tab, etc.
+
+A few things that should be noted:
+   There's a tiny possibility of error here. There are two directx replacements:
+   CMST and nine, and neither are set mutually exclusive due to the dialog design.
+   I may fix this to make it a three bullet select-one-of.
+
+Read the header of the other patch for more usage details. This should be
+applied AFTER staging, not before it.
+
+diff -urN wine-1.9.1/configure.ac wine-1.9.1-staging+d3d9/configure.ac
+--- wine-1.9.1/configure.ac    2016-01-18 06:51:08.392592452 -0500
++++ wine-1.9.1-staging+d3d9/configure.ac       2016-01-18 06:33:43.818613768 -0500
+@@ -67,6 +67,8 @@
+ 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]),
+@@ -399,6 +401,8 @@
+ AC_SUBST(OPENGL_LIBS,"")
++AC_SUBST(D3DADAPTER9_LIBS,"")
++
+ dnl **** Check for header files ****
+ AC_SYS_LARGEFILE()
+@@ -1205,6 +1209,195 @@
+     WINE_NOTICE_WITH(va,[test "x$ac_cv_lib_soname_va" = "x" -o "x$ac_cv_lib_soname_va_x11" = "x" -o "x$ac_cv_lib_soname_va_drm" = "x"],
+                      [libva ${notice_platform}development files not found, GPU video acceleration won't be supported.])
++    dnl Check for d3dadapter
++    if test "x$with_d3dadapter" != "xno"
++    then
++         AC_DEFINE(SONAME_D3DADAPTER9, ["d3dadapter9.so.1"], ["temporary hack"])
++         D3D_MODULE_DIR=`pkg-config --variable=moduledir d3d`
++         CPPFLAGSBAK=$CPPFLAGS
++         # link against libdl
++         CPPFLAGS="$CPPFLAGS -ldl"
++       
++         ac_cv_c_dlopen_d3dadapter=""
++         AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <dlfcn.h>
++#include <stdlib.h>]],[[void *handle = dlopen("${D3D_MODULE_DIR}" "/" SONAME_D3DADAPTER9, RTLD_GLOBAL | RTLD_NOW);
++exit((handle && dlsym(handle, "D3DAdapter9GetProc")) ? 0 : 1)]])],
++             [ac_cv_c_dlopen_d3dadapter=yes],[ac_cv_c_dlopen_d3dadapter=no])
++         if test "x$ac_cv_c_dlopen_d3dadapter" != "xyes"
++         then
++             echo "d3dadapter9.so.1 not found in '$D3D_MODULE_DIR'";
++             # workaround for pkg-config cross-compilation
++             # search for module in known folders
++             for D3D_MODULE_DIR in `$CC -Xlinker --verbose 2>/dev/null | grep SEARCH`
++             do
++                 D3D_MODULE_DIR="`echo \"$D3D_MODULE_DIR\" | sed 's/SEARCH_DIR("//g;s/\/");/\/d3d/g;s/");/\/d3d/g'`"
++                 ac_cv_c_dlopen_d3dadapter=""
++                 AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <dlfcn.h>
++#include <stdlib.h>]],[[void *handle = dlopen("${D3D_MODULE_DIR}" "/" SONAME_D3DADAPTER9, RTLD_GLOBAL | RTLD_NOW);
++exit((handle && dlsym(handle, "D3DAdapter9GetProc")) ? 0 : 1)]])],
++                     [echo "d3dadapter9.so.1 found in '$D3D_MODULE_DIR'";ac_cv_c_dlopen_d3dadapter=yes],
++                     [echo "d3dadapter9.so.1 not found in '$D3D_MODULE_DIR'";ac_cv_c_dlopen_d3dadapter=no])
++                 if test "x$ac_cv_c_dlopen_d3dadapter" = xyes
++                 then
++                     break
++                 fi
++             done
++         fi
++         AC_DEFINE_UNQUOTED(D3D_MODULE_DIR, ["`echo ${D3D_MODULE_DIR}`"], ["module dir"])
++         WINE_NOTICE_WITH(d3dadapter,[test "x$ac_cv_c_dlopen_d3dadapter" = xno],
++                 [d3dadapter9.so.1 module not found, Gallium Nine won't be supported.])
++
++         CPPFLAGS=$CPPFLAGSBAK
++         D3D_CFLAGS="`pkg-config --cflags d3d`"
++         # d3dadapter9.h includes D3D9.h, that relies on non existant headers
++         # the headers are generated by widl after running this script...
++         # hack around by using forward declarations
++         CPPFLAGS="$CPPFLAGS $D3D_CFLAGS -DWINAPI= -D_D3DADAPTER_PRESENT_H_"
++         AC_CHECK_HEADERS([d3dadapter9.h],[],[],[[
++typedef int DWORD;
++typedef int HWND;
++typedef int BOOL;
++typedef int UINT;
++typedef int HRESULT;
++typedef int ULONG;
++typedef struct ID3DPresent ID3DPresent;
++typedef struct ID3DPresentGroup ID3DPresentGroup;
++typedef struct ID3DAdapter9 ID3DAdapter9;
++typedef struct D3DWindowBuffer D3DWindowBuffer;
++typedef struct D3DADAPTER_IDENTIFIER9 D3DADAPTER_IDENTIFIER9;
++typedef struct D3DDEVTYPE D3DDEVTYPE;
++typedef struct D3DRESOURCETYPE D3DRESOURCETYPE;
++typedef struct D3DMULTISAMPLE_TYPE D3DMULTISAMPLE_TYPE;
++typedef struct D3DFORMAT D3DFORMAT;
++typedef struct D3DCAPS9 D3DCAPS9;
++typedef struct IDirect3DDevice9 IDirect3DDevice9;
++typedef struct IDirect3DDevice9Ex IDirect3DDevice9Ex;
++typedef struct IDirect3D9 IDirect3D9;
++typedef struct D3DPRESENT_PARAMETERS D3DPRESENT_PARAMETERS;
++typedef struct D3DDISPLAYMODEEX D3DDISPLAYMODEEX;
++typedef struct IDirect3D9Ex IDirect3D9Ex;
++typedef struct REFIID REFIID;
++]])
++         CPPFLAGS=$CPPFLAGSBAK
++         # pkg-config doesn't support cross-compilation. remove once fixed.
++         if test "x$ac_cv_header_d3dadapter9_h" != xyes
++         then
++             # hardcode path if header isn't found
++             # TODO: use environment var here ?
++             D3D_CFLAGS="-I/usr/include/d3dadapter/"
++             CPPFLAGS="$CPPFLAGS $D3D_CFLAGS -DWINAPI= -D_D3DADAPTER_PRESENT_H_"
++             # clear autoconf cache
++             AS_UNSET([ac_cv_header_d3dadapter9_h])
++         fi
++         AC_SUBST(D3D_CFLAGS)
++
++         D3DADAPTER9_LIBS=""
++         D3DADAPTER9_LIBS_NOT_FOUND=""
++         D3DADAPTER9_HEADER_NOT_FOUND=""
++
++         AC_CHECK_HEADERS([d3dadapter9.h],[],[],[[
++typedef int DWORD;
++typedef int HWND;
++typedef int BOOL;
++typedef int UINT;
++typedef int HRESULT;
++typedef int ULONG;
++typedef struct ID3DPresent ID3DPresent;
++typedef struct ID3DPresentGroup ID3DPresentGroup;
++typedef struct ID3DAdapter9 ID3DAdapter9;
++typedef struct D3DWindowBuffer D3DWindowBuffer;
++typedef struct D3DADAPTER_IDENTIFIER9 D3DADAPTER_IDENTIFIER9;
++typedef struct D3DDEVTYPE D3DDEVTYPE;
++typedef struct D3DRESOURCETYPE D3DRESOURCETYPE;
++typedef struct D3DMULTISAMPLE_TYPE D3DMULTISAMPLE_TYPE;
++typedef struct D3DFORMAT D3DFORMAT;
++typedef struct D3DCAPS9 D3DCAPS9;
++typedef struct IDirect3DDevice9 IDirect3DDevice9;
++typedef struct IDirect3DDevice9Ex IDirect3DDevice9Ex;
++typedef struct IDirect3D9 IDirect3D9;
++typedef struct D3DPRESENT_PARAMETERS D3DPRESENT_PARAMETERS;
++typedef struct D3DDISPLAYMODEEX D3DDISPLAYMODEEX;
++typedef struct IDirect3D9Ex IDirect3D9Ex;
++typedef struct REFIID REFIID;
++]])
++         CPPFLAGS=$CPPFLAGSBAK
++         AC_CHECK_HEADERS([X11/Xlib-xcb.h xcb/dri3.h xcb/present.h X11/Xutil.h X11/Xlib.h pthread.h])
++         test "x$ac_cv_header_d3dadapter9_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="d3dadapter9.h "
++         test "x$ac_cv_header_X11_Xlib_xcb_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}X11/Xlib-xcb.h "
++         test "x$ac_cv_header_xcb_dri3_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}xcb/dri3.h "
++         test "x$ac_cv_header_xcb_present_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}xcb/present.h "
++         test "x$ac_cv_header_X11_Xutil_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}X11/Xutil.h "
++         test "x$ac_cv_header_X11_Xlib_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}X11/Xlib.h "
++         test "x$ac_cv_header_pthread_h" != xyes && D3DADAPTER9_HEADER_NOT_FOUND="${D3DADAPTER9_HEADER_NOT_FOUND}pthread.h "
++         WINE_NOTICE_WITH(d3dadapter,[test "x$D3DADAPTER9_HEADER_NOT_FOUND" != x],
++                 [$D3DADAPTER9_HEADER_NOT_FOUND header not found, Gallium Nine won't be supported.])
++
++         AC_CHECK_LIB(xcb,xcb_request_check,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb"])])
++         test "x$ac_cv_lib_xcb_xcb_request_check" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="libxcb "
++         AC_CHECK_LIB(xcb-dri3,xcb_dri3_open,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb-dri3"])])
++         test "x$ac_cv_lib_xcb_dri3_xcb_dri3_open" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libxcb-dri3 "
++         AC_CHECK_LIB(xcb-present,xcb_present_notify_msc,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb-present"])])
++         test "x$ac_cv_lib_xcb_present_xcb_present_notify_msc" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libxcb-present "
++         AC_CHECK_LIB(xcb-xfixes,xcb_xfixes_create_region,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lxcb-xfixes"])])
++         test "x$ac_cv_lib_xcb_xfixes_xcb_xfixes_create_region" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libxcb-xfixes "
++         AC_CHECK_LIB(X11-xcb,XGetXCBConnection,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lX11-xcb"])])
++         test "x$ac_cv_lib_X11_xcb_XGetXCBConnection" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libX11-xcb "
++         AC_CHECK_LIB(X11,XOpenDisplay,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lX11"])])
++         test "x$ac_cv_lib_X11_XOpenDisplay" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libX11 "
++         AC_CHECK_LIB(Xext,XextRemoveDisplay,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lXext"])])
++         test "x$ac_cv_lib_Xext_XextRemoveDisplay" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libXext "
++         AC_CHECK_LIB(pthread,pthread_mutex_lock,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lpthread"])])
++         test "x$ac_cv_lib_pthread_pthread_mutex_lock" != xyes && D3DADAPTER9_LIBS_NOT_FOUND="${D3DADAPTER9_LIBS_NOT_FOUND}libpthread "
++
++         if test "x$with_d3dadapter_dri2_fallback" != "xno"
++         then
++             D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND=""
++             D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND=""
++             AC_CHECK_LIB(GL,glGenFramebuffers,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lGL"])])
++             test "x$ac_cv_lib_GL_glGenFramebuffers" != xyes && D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND="libGL "
++             AC_CHECK_LIB(EGL,eglCreateContext,[AC_SUBST(D3DADAPTER9_LIBS,["$D3DADAPTER9_LIBS -lEGL"])])
++             test "x$ac_cv_lib_EGL_eglCreateContext" != xyes && D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND="${D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND}libEGL"
++
++             AC_CHECK_HEADERS([X11/Xmd.h X11/Xlibint.h X11/extensions/dri2tokens.h X11/extensions/dri2proto.h X11/extensions/extutil.h GL/gl.h GL/glext.h EGL/egl.h EGL/eglext.h libdrm/drm_fourcc.h libdrm/drm.h],
++                     [],[],[[
++#include <X11/Xlibint.h>
++#include <X11/extensions/dri2tokens.h>
++#include <GL/gl.h>
++#include <EGL/egl.h>
++]])
++             test "x$ac_cv_header_X11_Xmd_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/Xmd.h "
++             test "x$ac_cv_header_X11_Xlibint_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/Xlibint.h "
++             test "x$ac_cv_header_X11_extensions_dri2tokens_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/extensions/dri2tokens.h "
++             test "x$ac_cv_header_X11_extensions_dri2proto_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/extensions/dri2proto.h "
++             test "x$ac_cv_header_X11_extensions_extutil_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}X11/extensions/extutil.h "
++             test "x$ac_cv_header_GL_gl_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}GL/gl.h "
++             test "x$ac_cv_header_GL_glext_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}GL/glext.h "
++             test "x$ac_cv_header_EGL_egl_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}EGL/egl.h "
++             test "x$ac_cv_header_EGL_eglext_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}EGL/eglext.h "
++             test "x$ac_cv_header_libdrm_drm_fourcc_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}libdrm/drm_fourcc.h "
++             test "x$ac_cv_header_libdrm_drm_h" != xyes && D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND="${D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND}libdrm/drm.h "
++
++             if test "x$D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND" = x -a "x$D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND" = x
++             then
++                 AC_DEFINE(D3DADAPTER9_DRI2, 1, [Whether d3dadapter9 DRI2 fallback is compiled])
++             fi
++             WINE_NOTICE_WITH(d3dadapter_dri2_fallback,[test "x$D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND" != x],
++                     [$D3DADAPTER9_FALLBACK_LIBS_NOT_FOUND ${notice_platform}development files not found, Gallium Nine DRI2 fallback won't be supported.])
++             WINE_NOTICE_WITH(d3dadapter_dri2_fallback,[test "x$D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND" != x],
++                     [$D3DADAPTER9_FALLBACK_HEADERS_NOT_FOUND headers not found, Gallium Nine DRI2 fallback won't be supported.])
++         fi
++
++         test "x$D3DADAPTER9_LIBS_NOT_FOUND" != "x" && \
++             "x$D3DADAPTER9_HEADER_NOT_FOUND" != x && \
++             "x$ac_cv_c_dlopen_d3dadapter" != xyes && \
++             enable_d3d9_nine=${enable_d3d9_nine:-no}
++         WINE_NOTICE_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS_NOT_FOUND" != "x"],
++                 [$D3DADAPTER9_LIBS_NOT_FOUND ${notice_platform}development files not found, Gallium Nine won't be supported.])
++    else
++        enable_d3d9_nine=${enable_d3d9_nine:-no}
++        D3D_CFLAGS=""
++    fi
++
+     CPPFLAGS="$ac_save_CPPFLAGS"
+ else
+     X_CFLAGS=""
+@@ -2839,6 +3032,7 @@
+ 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 -urN wine-1.9.1/dlls/d3d9/Makefile.in wine-1.9.1-staging+d3d9/dlls/d3d9/Makefile.in
+--- wine-1.9.1/dlls/d3d9/Makefile.in   2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9/Makefile.in      2016-01-18 06:33:43.818613768 -0500
+@@ -1,6 +1,6 @@
+ MODULE    = d3d9.dll
+ IMPORTLIB = d3d9
+-IMPORTS   = dxguid uuid wined3d
++IMPORTS   = dxguid uuid advapi32 wined3d
+ C_SRCS = \
+       buffer.c \
+diff -urN wine-1.9.1/dlls/d3d9/tests/d3d9ex.c wine-1.9.1-staging+d3d9/dlls/d3d9/tests/d3d9ex.c
+--- wine-1.9.1/dlls/d3d9/tests/d3d9ex.c        2016-01-09 04:30:39.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9/tests/d3d9ex.c   2016-01-18 06:33:43.818613768 -0500
+@@ -1490,6 +1490,7 @@
+     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);
+@@ -1514,6 +1515,12 @@
+     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);
+@@ -1527,6 +1534,12 @@
+     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);
+@@ -1540,6 +1553,12 @@
+     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);
+@@ -1569,6 +1588,12 @@
+     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);
+@@ -1582,6 +1607,12 @@
+     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 -urN wine-1.9.1/dlls/d3d9/tests/device.c wine-1.9.1-staging+d3d9/dlls/d3d9/tests/device.c
+--- wine-1.9.1/dlls/d3d9/tests/device.c        2016-01-18 06:51:06.822592484 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9/tests/device.c   2016-01-18 06:33:43.821613767 -0500
+@@ -8306,10 +8306,10 @@
+ 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;
+@@ -8317,6 +8317,8 @@
+     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)))
+@@ -8351,6 +8353,43 @@
+             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);
+@@ -10076,6 +10115,7 @@
+     HWND window;
+     HRESULT hr;
+     BOOL ret;
++    IDirect3DSwapChain9 *swapchain;
+     window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW,
+             0, 0, 640, 480, NULL, NULL, NULL, NULL);
+@@ -10103,6 +10143,12 @@
+     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);
+@@ -10112,6 +10158,12 @@
+     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);
+@@ -10119,6 +10171,12 @@
+     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 -urN wine-1.9.1/dlls/d3d9/tests/visual.c wine-1.9.1-staging+d3d9/dlls/d3d9/tests/visual.c
+--- wine-1.9.1/dlls/d3d9/tests/visual.c        2016-01-18 06:51:08.167592457 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9/tests/visual.c   2016-01-18 06:33:43.826613767 -0500
+@@ -8678,6 +8678,167 @@
+     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;
+@@ -12877,6 +13038,9 @@
+     }
+     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},
+@@ -12885,6 +13049,10 @@
+         {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
+     {
+@@ -18234,6 +18402,27 @@
+                 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;
+@@ -21549,6 +21738,7 @@
+     test_depthbias();
+     test_flip();
+     test_uninitialized_varyings();
++    test_blend_invalid_arg();
+     test_multisample_init();
+     test_texture_blending();
+ }
+diff -urN wine-1.9.1/dlls/d3d9-nine/d3d9_main.c wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3d9_main.c
+--- wine-1.9.1/dlls/d3d9-nine/d3d9_main.c      1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3d9_main.c 2016-01-18 06:33:43.827613767 -0500
+@@ -0,0 +1,157 @@
++/*
++ * 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 <fcntl.h>
++
++#include <d3dadapter/d3dadapter9.h>
++
++#include "d3dadapter9.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 -urN wine-1.9.1/dlls/d3d9-nine/d3d9-nine.spec wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3d9-nine.spec
+--- wine-1.9.1/dlls/d3d9-nine/d3d9-nine.spec   1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3d9-nine.spec      2016-01-18 06:33:43.827613767 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/d3dadapter9.c wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3dadapter9.c
+--- wine-1.9.1/dlls/d3d9-nine/d3dadapter9.c    1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3dadapter9.c       2016-01-18 06:33:43.828613767 -0500
+@@ -0,0 +1,865 @@
++/*
++ * Wine IDirect3D9 interface using ID3DAdapter9
++ *
++ * Copyright 2013 Joakim Sindholt
++ *                Christoph Bumiller
++ * Copyright 2014 David Heidelberger
++ * Copyright 2014-2015 Axel Davy
++ * Copyright 2015 Nick Sarnie
++ *                Patrick Rudolph
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++ */
++
++#include "config.h"
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter);
++
++#include <d3dadapter/d3dadapter9.h>
++#include "present.h"
++
++/* this represents a snapshot taken at the moment of creation */
++struct output
++{
++    D3DDISPLAYROTATION rotation; /* current rotation */
++    D3DDISPLAYMODEEX *modes;
++    unsigned nmodes;
++    unsigned nmodesalloc;
++    unsigned current; /* current mode num */
++
++    HMONITOR monitor;
++};
++
++struct adapter_group
++{
++    struct output *outputs;
++    unsigned noutputs;
++    unsigned noutputsalloc;
++
++    /* override driver provided DeviceName with this to homogenize device names
++     * with wine */
++    WCHAR devname[32];
++
++    /* driver stuff */
++    ID3DAdapter9 *adapter;
++};
++
++struct adapter_map
++{
++    unsigned group;
++    unsigned master;
++};
++
++struct d3dadapter9
++{
++    /* COM vtable */
++    void *vtable;
++    /* IUnknown reference count */
++    LONG refs;
++
++    /* adapter groups and mappings */
++    struct adapter_group *groups;
++    struct adapter_map *map;
++    unsigned nadapters;
++    unsigned ngroups;
++    unsigned ngroupsalloc;
++
++    /* true if it implements IDirect3D9Ex */
++    boolean ex;
++    Display *gdi_display;
++};
++
++/* convenience wrapper for calls into ID3D9Adapter */
++#define ADAPTER_GROUP \
++    This->groups[This->map[Adapter].group]
++
++#define ADAPTER_PROC(name, ...) \
++    ID3DAdapter9_##name(ADAPTER_GROUP.adapter, ## __VA_ARGS__)
++
++#define ADAPTER_OUTPUT \
++    ADAPTER_GROUP.outputs[Adapter-This->map[Adapter].master]
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This,
++                               UINT Adapter,
++                               D3DDEVTYPE DeviceType,
++                               D3DFORMAT AdapterFormat,
++                               DWORD Usage,
++                               D3DRESOURCETYPE RType,
++                               D3DFORMAT CheckFormat );
++
++static ULONG WINAPI
++d3dadapter9_AddRef( struct d3dadapter9 *This )
++{
++    ULONG refs = InterlockedIncrement(&This->refs);
++    TRACE("%p increasing refcount to %u.\n", This, refs);
++    return refs;
++}
++
++static ULONG WINAPI
++d3dadapter9_Release( struct d3dadapter9 *This )
++{
++    ULONG refs = InterlockedDecrement(&This->refs);
++    TRACE("%p decreasing refcount to %u.\n", This, refs);
++    if (refs == 0) {
++        /* dtor */
++        if (This->map) {
++            HeapFree(GetProcessHeap(), 0, This->map);
++        }
++
++        if (This->groups) {
++            int i, j;
++            for (i = 0; i < This->ngroups; ++i) {
++                if (This->groups[i].outputs) {
++                    for (j = 0; j < This->groups[i].noutputs; ++j) {
++                        if (This->groups[i].outputs[j].modes) {
++                            HeapFree(GetProcessHeap(), 0,
++                                     This->groups[i].outputs[j].modes);
++                        }
++                    }
++                    HeapFree(GetProcessHeap(), 0, This->groups[i].outputs);
++                }
++
++                if (This->groups[i].adapter) {
++                    ID3DAdapter9_Release(This->groups[i].adapter);
++                }
++            }
++            HeapFree(GetProcessHeap(), 0, This->groups);
++        }
++
++        HeapFree(GetProcessHeap(), 0, This);
++    }
++    return refs;
++}
++
++static HRESULT WINAPI
++d3dadapter9_QueryInterface( struct d3dadapter9 *This,
++                            REFIID riid,
++                            void **ppvObject )
++{
++    if (!ppvObject) { return E_POINTER; }
++    if ((IsEqualGUID(&IID_IDirect3D9Ex, riid) && This->ex) ||
++         IsEqualGUID(&IID_IDirect3D9, riid) ||
++         IsEqualGUID(&IID_IUnknown, riid)) {
++        *ppvObject = This;
++        d3dadapter9_AddRef(This);
++        return S_OK;
++    }
++
++    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++    *ppvObject = NULL;
++
++    return E_NOINTERFACE;
++}
++
++static HRESULT WINAPI
++d3dadapter9_RegisterSoftwareDevice( struct d3dadapter9 *This,
++                                    void *pInitializeFunction )
++{
++    FIXME("(%p, %p), stub!\n", This, pInitializeFunction);
++    return D3DERR_INVALIDCALL;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterCount( struct d3dadapter9 *This )
++{
++    return This->nadapters;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterIdentifier( struct d3dadapter9 *This,
++                                  UINT Adapter,
++                                  DWORD Flags,
++                                  D3DADAPTER_IDENTIFIER9 *pIdentifier )
++{
++    HRESULT hr;
++    HKEY regkey;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++
++    hr = ADAPTER_PROC(GetAdapterIdentifier, Flags, pIdentifier);
++    if (SUCCEEDED(hr)) {
++        /* Override the driver provided DeviceName with what Wine provided */
++        ZeroMemory(pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName));
++        if (!WideCharToMultiByte(CP_ACP, 0, ADAPTER_GROUP.devname, -1,
++                                 pIdentifier->DeviceName,
++                                 sizeof(pIdentifier->DeviceName),
++                                 NULL, NULL)) {
++            /* Wine does it */
++            return D3DERR_INVALIDCALL;
++        }
++        TRACE("DeviceName overriden: %s\n", pIdentifier->DeviceName);
++
++        /* Override PCI IDs when wined3d registry keys are set */
++        if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &regkey)) {
++            DWORD type, data;
++            DWORD size = sizeof(DWORD);
++
++            if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD)))
++                pIdentifier->DeviceId = data;
++            if(size != sizeof(DWORD)) {
++                ERR("VideoPciDeviceID is not a DWORD\n");
++                size = sizeof(DWORD);
++            }
++            if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD)))
++                pIdentifier->VendorId = data;
++            if(size != sizeof(DWORD))
++                ERR("VideoPciVendorID is not a DWORD\n");
++            RegCloseKey(regkey);
++
++            TRACE("DeviceId:VendorId overridden: %04X:%04X\n", pIdentifier->DeviceId, pIdentifier->VendorId);
++        }
++    }
++    return hr;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterModeCount( struct d3dadapter9 *This,
++                                 UINT Adapter,
++                                 D3DFORMAT Format )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return 0;
++    }
++    if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
++                                         Format, D3DUSAGE_RENDERTARGET,
++                                         D3DRTYPE_SURFACE, Format))) {
++        WARN("DeviceFormat not available.\n");
++        return 0;
++    }
++
++    TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes);
++    return ADAPTER_OUTPUT.nmodes;
++}
++
++static HRESULT WINAPI
++d3dadapter9_EnumAdapterModes( struct d3dadapter9 *This,
++                              UINT Adapter,
++                              D3DFORMAT Format,
++                              UINT Mode,
++                              D3DDISPLAYMODE *pMode )
++{
++    HRESULT hr;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return D3DERR_INVALIDCALL;
++    }
++
++    hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
++                                   Format, D3DUSAGE_RENDERTARGET,
++                                   D3DRTYPE_SURFACE, Format);
++    if (FAILED(hr)) {
++        TRACE("DeviceFormat not available.\n");
++        return hr;
++    }
++
++    if (Mode >= ADAPTER_OUTPUT.nmodes) {
++        WARN("Mode %u does not exist.\n", Mode);
++        return D3DERR_INVALIDCALL;
++    }
++
++    pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
++    pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
++    pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
++    pMode->Format = Format;
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterDisplayMode( struct d3dadapter9 *This,
++                                   UINT Adapter,
++                                   D3DDISPLAYMODE *pMode )
++{
++    UINT Mode;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return D3DERR_INVALIDCALL;
++    }
++
++    Mode = ADAPTER_OUTPUT.current;
++    pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
++    pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
++    pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
++    pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format;
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceType( struct d3dadapter9 *This,
++                             UINT Adapter,
++                             D3DDEVTYPE DevType,
++                             D3DFORMAT AdapterFormat,
++                             D3DFORMAT BackBufferFormat,
++                             BOOL bWindowed )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceType,
++                        DevType, AdapterFormat, BackBufferFormat, bWindowed);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This,
++                               UINT Adapter,
++                               D3DDEVTYPE DeviceType,
++                               D3DFORMAT AdapterFormat,
++                               DWORD Usage,
++                               D3DRESOURCETYPE RType,
++                               D3DFORMAT CheckFormat )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceFormat,
++                        DeviceType, AdapterFormat, Usage, RType, CheckFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceMultiSampleType( struct d3dadapter9 *This,
++                                        UINT Adapter,
++                                        D3DDEVTYPE DeviceType,
++                                        D3DFORMAT SurfaceFormat,
++                                        BOOL Windowed,
++                                        D3DMULTISAMPLE_TYPE MultiSampleType,
++                                        DWORD *pQualityLevels )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat,
++                        Windowed, MultiSampleType, pQualityLevels);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDepthStencilMatch( struct d3dadapter9 *This,
++                                    UINT Adapter,
++                                    D3DDEVTYPE DeviceType,
++                                    D3DFORMAT AdapterFormat,
++                                    D3DFORMAT RenderTargetFormat,
++                                    D3DFORMAT DepthStencilFormat )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat,
++                        RenderTargetFormat, DepthStencilFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_CheckDeviceFormatConversion( struct d3dadapter9 *This,
++                                     UINT Adapter,
++                                     D3DDEVTYPE DeviceType,
++                                     D3DFORMAT SourceFormat,
++                                     D3DFORMAT TargetFormat )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++    return ADAPTER_PROC(CheckDeviceFormatConversion,
++                        DeviceType, SourceFormat, TargetFormat);
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetDeviceCaps( struct d3dadapter9 *This,
++                           UINT Adapter,
++                           D3DDEVTYPE DeviceType,
++                           D3DCAPS9 *pCaps )
++{
++    HRESULT hr;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; }
++
++    hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps);
++    if (FAILED(hr)) { return hr; }
++
++    pCaps->MasterAdapterOrdinal = This->map[Adapter].master;
++    pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master;
++    pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs;
++
++    return hr;
++}
++
++static HMONITOR WINAPI
++d3dadapter9_GetAdapterMonitor( struct d3dadapter9 *This,
++                               UINT Adapter )
++{
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return (HMONITOR)0; }
++    return (HMONITOR)ADAPTER_OUTPUT.monitor;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This,
++                            UINT Adapter,
++                            D3DDEVTYPE DeviceType,
++                            HWND hFocusWindow,
++                            DWORD BehaviorFlags,
++                            D3DPRESENT_PARAMETERS *pPresentationParameters,
++                            D3DDISPLAYMODEEX *pFullscreenDisplayMode,
++                            IDirect3DDevice9Ex **ppReturnedDeviceInterface );
++
++static HRESULT WINAPI
++d3dadapter9_CreateDevice( struct d3dadapter9 *This,
++                          UINT Adapter,
++                          D3DDEVTYPE DeviceType,
++                          HWND hFocusWindow,
++                          DWORD BehaviorFlags,
++                          D3DPRESENT_PARAMETERS *pPresentationParameters,
++                          IDirect3DDevice9 **ppReturnedDeviceInterface )
++{
++    HRESULT hr;
++    hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow,
++                                    BehaviorFlags, pPresentationParameters,
++                                    NULL,
++                                    (IDirect3DDevice9Ex **)ppReturnedDeviceInterface);
++    if (FAILED(hr))
++        return hr;
++    return D3D_OK;
++}
++
++static UINT WINAPI
++d3dadapter9_GetAdapterModeCountEx( struct d3dadapter9 *This,
++                                   UINT Adapter,
++                                   const D3DDISPLAYMODEFILTER *pFilter )
++{
++    return 1;
++}
++
++static HRESULT WINAPI
++d3dadapter9_EnumAdapterModesEx( struct d3dadapter9 *This,
++                                UINT Adapter,
++                                const D3DDISPLAYMODEFILTER *pFilter,
++                                UINT Mode,
++                                D3DDISPLAYMODEEX *pMode )
++{
++    FIXME("(%p, %u, %p, %u, %p), stub!\n", This, Adapter, pFilter, Mode, pMode);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterDisplayModeEx( struct d3dadapter9 *This,
++                                     UINT Adapter,
++                                     D3DDISPLAYMODEEX *pMode,
++                                     D3DDISPLAYROTATION *pRotation )
++{
++    FIXME("(%p, %u, %p, %p), stub!\n", This, Adapter, pMode, pRotation);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This,
++                            UINT Adapter,
++                            D3DDEVTYPE DeviceType,
++                            HWND hFocusWindow,
++                            DWORD BehaviorFlags,
++                            D3DPRESENT_PARAMETERS *pPresentationParameters,
++                            D3DDISPLAYMODEEX *pFullscreenDisplayMode,
++                            IDirect3DDevice9Ex **ppReturnedDeviceInterface )
++{
++    ID3DPresentGroup *present;
++    HRESULT hr;
++    boolean no_window_changes;
++
++    if (Adapter >= d3dadapter9_GetAdapterCount(This)) {
++        WARN("Adapter %u does not exist.\n", Adapter);
++        return D3DERR_INVALIDCALL;
++    }
++
++    {
++        struct adapter_group *group = &ADAPTER_GROUP;
++        unsigned nparams, ordinal;
++
++        if (BehaviorFlags & D3DCREATE_ADAPTERGROUP_DEVICE) {
++            nparams = group->noutputs;
++            ordinal = 0;
++        } else {
++            nparams = 1;
++            ordinal = Adapter - This->map[Adapter].master;
++        }
++        no_window_changes = !!(BehaviorFlags & D3DCREATE_NOWINDOWCHANGES);
++
++        hr = present_create_present_group(This->gdi_display, group->devname, ordinal,
++                                               hFocusWindow,
++                                               pPresentationParameters,
++                                               nparams, &present, This->ex, no_window_changes);
++    }
++
++    if (FAILED(hr)) {
++        WARN("Failed to create PresentGroup.\n");
++        return hr;
++    }
++
++    if (This->ex) {
++        hr = ADAPTER_PROC(CreateDeviceEx, Adapter, DeviceType, hFocusWindow,
++                          BehaviorFlags, pPresentationParameters,
++                          pFullscreenDisplayMode,
++                          (IDirect3D9Ex *)This, present,
++                          ppReturnedDeviceInterface);
++    } else { /* CreateDevice on non-ex */
++        hr = ADAPTER_PROC(CreateDevice, Adapter, DeviceType, hFocusWindow,
++                          BehaviorFlags, pPresentationParameters,
++                          (IDirect3D9 *)This, present,
++                          (IDirect3DDevice9 **)ppReturnedDeviceInterface);
++    }
++    if (FAILED(hr)) {
++        WARN("ADAPTER_PROC failed.\n");
++        ID3DPresentGroup_Release(present);
++    }
++
++    return hr;
++}
++
++static HRESULT WINAPI
++d3dadapter9_GetAdapterLUID( struct d3dadapter9 *This,
++                            UINT Adapter,
++                            LUID *pLUID )
++{
++    FIXME("(%p, %u, %p), stub!\n", This, Adapter, pLUID);
++    return D3DERR_INVALIDCALL;
++}
++
++static struct adapter_group *
++add_group( struct d3dadapter9 *This )
++{
++    if (This->ngroups >= This->ngroupsalloc) {
++        void *r;
++
++        if (This->ngroupsalloc == 0) {
++            This->ngroupsalloc = 2;
++            r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          This->ngroupsalloc*sizeof(struct adapter_group));
++        } else {
++            This->ngroupsalloc <<= 1;
++            r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->groups,
++                        This->ngroupsalloc*sizeof(struct adapter_group));
++        }
++
++        if (!r) { return NULL; }
++        This->groups = r;
++    }
++
++    return &This->groups[This->ngroups++];
++}
++
++static void
++remove_group( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    int i;
++
++    for (i = 0; i < group->noutputs; ++i) {
++        HeapFree(GetProcessHeap(), 0, group->outputs[i].modes);
++    }
++    HeapFree(GetProcessHeap(), 0, group->outputs);
++
++    ZeroMemory(group, sizeof(struct adapter_group));
++    This->ngroups--;
++}
++
++static struct output *
++add_output( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++
++    if (group->noutputs >= group->noutputsalloc) {
++        void *r;
++
++        if (group->noutputsalloc == 0) {
++            group->noutputsalloc = 2;
++            r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          group->noutputsalloc*sizeof(struct output));
++        } else {
++            group->noutputsalloc <<= 1;
++            r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, group->outputs,
++                            group->noutputsalloc*sizeof(struct output));
++        }
++
++        if (!r) { return NULL; }
++        group->outputs = r;
++    }
++
++    return &group->outputs[group->noutputs++];
++}
++
++static void
++remove_output( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    struct output *out = &group->outputs[group->noutputs-1];
++
++    HeapFree(GetProcessHeap(), 0, out->modes);
++
++    ZeroMemory(out, sizeof(struct output));
++    group->noutputs--;
++}
++
++static D3DDISPLAYMODEEX *
++add_mode( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    struct output *out = &group->outputs[group->noutputs-1];
++
++    if (out->nmodes >= out->nmodesalloc) {
++        void *r;
++
++        if (out->nmodesalloc == 0) {
++            out->nmodesalloc = 8;
++            r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
++        } else {
++            out->nmodesalloc <<= 1;
++            r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, out->modes,
++                            out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
++        }
++
++        if (!r) { return NULL; }
++        out->modes = r;
++    }
++
++    return &out->modes[out->nmodes++];
++}
++
++static void
++remove_mode( struct d3dadapter9 *This )
++{
++    struct adapter_group *group = &This->groups[This->ngroups-1];
++    struct output *out = &group->outputs[group->noutputs-1];
++    out->nmodes--;
++}
++
++#ifndef DM_INTERLACED
++#define DM_INTERLACED 2
++#endif /* DM_INTERLACED */
++
++static HRESULT
++fill_groups( struct d3dadapter9 *This )
++{
++    DISPLAY_DEVICEW dd;
++    DEVMODEW dm;
++    POINT pt;
++    HDC hdc;
++    HRESULT hr;
++    int i, j, k;
++
++    WCHAR wdisp[] = {'D','I','S','P','L','A','Y',0};
++
++    ZeroMemory(&dd, sizeof(dd));
++    ZeroMemory(&dm, sizeof(dm));
++    dd.cb = sizeof(dd);
++    dm.dmSize = sizeof(dm);
++
++    for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i) {
++        struct adapter_group *group = add_group(This);
++        if (!group) {
++            ERR("Out of memory.\n");
++            return E_OUTOFMEMORY;
++        }
++
++        hdc = CreateDCW(wdisp, dd.DeviceName, NULL, NULL);
++        if (!hdc) {
++            remove_group(This);
++            WARN("Unable to create DC for display %d.\n", i);
++            goto end_group;
++        }
++
++        hr = present_create_adapter9(This->gdi_display, hdc, &group->adapter);
++        DeleteDC(hdc);
++        if (FAILED(hr)) {
++            remove_group(This);
++            goto end_group;
++        }
++
++        CopyMemory(group->devname, dd.DeviceName, sizeof(group->devname));
++        for (j = 0; EnumDisplayDevicesW(group->devname, j, &dd, 0); ++j) {
++            struct output *out = add_output(This);
++            boolean orient = FALSE, monit = FALSE;
++            if (!out) {
++                ERR("Out of memory.\n");
++                return E_OUTOFMEMORY;
++            }
++
++            for (k = 0; EnumDisplaySettingsExW(dd.DeviceName, k, &dm, 0); ++k) {
++                D3DDISPLAYMODEEX *mode = add_mode(This);
++                if (!out) {
++                    ERR("Out of memory.\n");
++                    return E_OUTOFMEMORY;
++                }
++
++                mode->Size = sizeof(D3DDISPLAYMODEEX);
++                mode->Width = dm.dmPelsWidth;
++                mode->Height = dm.dmPelsHeight;
++                mode->RefreshRate = dm.dmDisplayFrequency;
++                mode->ScanLineOrdering =
++                    (dm.dmDisplayFlags & DM_INTERLACED) ?
++                        D3DSCANLINEORDERING_INTERLACED :
++                        D3DSCANLINEORDERING_PROGRESSIVE;
++
++                switch (dm.dmBitsPerPel) {
++                    case 32: mode->Format = D3DFMT_X8R8G8B8; break;
++                    case 24: mode->Format = D3DFMT_R8G8B8; break;
++                    case 16: mode->Format = D3DFMT_R5G6B5; break;
++                    case 8:
++                        remove_mode(This);
++                        goto end_mode;
++
++                    default:
++                        remove_mode(This);
++                        WARN("Unknown format (%u bpp) in display %d, monitor "
++                             "%d, mode %d.\n", dm.dmBitsPerPel, i, j, k);
++                        goto end_mode;
++                }
++
++                if (!orient) {
++                    switch (dm.dmDisplayOrientation) {
++                        case DMDO_DEFAULT:
++                            out->rotation = D3DDISPLAYROTATION_IDENTITY;
++                            break;
++
++                        case DMDO_90:
++                            out->rotation = D3DDISPLAYROTATION_90;
++                            break;
++
++                        case DMDO_180:
++                            out->rotation = D3DDISPLAYROTATION_180;
++                            break;
++
++                        case DMDO_270:
++                            out->rotation = D3DDISPLAYROTATION_270;
++                            break;
++
++                        default:
++                            remove_output(This);
++                            WARN("Unknown display rotation in display %d, "
++                                 "monitor %d\n", i, j);
++                            goto end_output;
++                    }
++                    orient = TRUE;
++                }
++
++                if (!monit) {
++                    pt.x = dm.dmPosition.x;
++                    pt.y = dm.dmPosition.y;
++                    out->monitor = MonitorFromPoint(pt, 0);
++                    if (!out->monitor) {
++                        remove_output(This);
++                        WARN("Unable to get monitor handle for display %d, "
++                             "monitor %d.\n", i, j);
++                        goto end_output;
++                    }
++                    monit = TRUE;
++                }
++
++end_mode:
++                ZeroMemory(&dm, sizeof(dm));
++                dm.dmSize = sizeof(dm);
++            }
++
++end_output:
++            ZeroMemory(&dd, sizeof(dd));
++            dd.cb = sizeof(dd);
++        }
++
++end_group:
++        ZeroMemory(&dd, sizeof(dd));
++        dd.cb = sizeof(dd);
++    }
++
++    return D3D_OK;
++}
++
++static IDirect3D9ExVtbl d3dadapter9_vtable = {
++    (void *)d3dadapter9_QueryInterface,
++    (void *)d3dadapter9_AddRef,
++    (void *)d3dadapter9_Release,
++    (void *)d3dadapter9_RegisterSoftwareDevice,
++    (void *)d3dadapter9_GetAdapterCount,
++    (void *)d3dadapter9_GetAdapterIdentifier,
++    (void *)d3dadapter9_GetAdapterModeCount,
++    (void *)d3dadapter9_EnumAdapterModes,
++    (void *)d3dadapter9_GetAdapterDisplayMode,
++    (void *)d3dadapter9_CheckDeviceType,
++    (void *)d3dadapter9_CheckDeviceFormat,
++    (void *)d3dadapter9_CheckDeviceMultiSampleType,
++    (void *)d3dadapter9_CheckDepthStencilMatch,
++    (void *)d3dadapter9_CheckDeviceFormatConversion,
++    (void *)d3dadapter9_GetDeviceCaps,
++    (void *)d3dadapter9_GetAdapterMonitor,
++    (void *)d3dadapter9_CreateDevice,
++    (void *)d3dadapter9_GetAdapterModeCountEx,
++    (void *)d3dadapter9_EnumAdapterModesEx,
++    (void *)d3dadapter9_GetAdapterDisplayModeEx,
++    (void *)d3dadapter9_CreateDeviceEx,
++    (void *)d3dadapter9_GetAdapterLUID
++};
++
++HRESULT
++d3dadapter9_new( Display *gdi_display,
++                 boolean ex,
++                 IDirect3D9Ex **ppOut )
++{
++    struct d3dadapter9 *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                                         sizeof(struct d3dadapter9));
++    HRESULT hr;
++    unsigned i, j, k;
++
++    if (!This) {
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    This->vtable = &d3dadapter9_vtable;
++    This->refs = 1;
++    This->ex = ex;
++    This->gdi_display = gdi_display;
++
++    if (!has_d3dadapter(gdi_display)) {
++        ERR("Your display driver doesn't support native D3D9 adapters.\n");
++        d3dadapter9_Release(This);
++        return D3DERR_NOTAVAILABLE;
++    }
++
++    hr = fill_groups(This);
++    if (FAILED(hr)) {
++        d3dadapter9_Release(This);
++        return hr;
++    }
++
++    /* map absolute adapter IDs with internal adapters */
++    for (i = 0; i < This->ngroups; ++i) {
++        for (j = 0; j < This->groups[i].noutputs; ++j) {
++            This->nadapters++;
++        }
++    }
++    if (This->nadapters == 0) {
++        ERR("No available native adapters in system.\n");
++        d3dadapter9_Release(This);
++        return D3DERR_NOTAVAILABLE;
++    }
++
++    This->map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                          This->nadapters*sizeof(struct adapter_map));
++    if (!This->map) {
++        d3dadapter9_Release(This);
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++    for (i = k = 0; i < This->ngroups; ++i) {
++        for (j = 0; j < This->groups[i].noutputs; ++j, ++k) {
++            This->map[k].master = k-j;
++            This->map[k].group = i;
++        }
++    }
++
++    *ppOut = (IDirect3D9Ex *)This;
++    FIXME("\033[1;32m\nNative Direct3D 9 is active."
++          "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++    return D3D_OK;
++}
+diff -urN wine-1.9.1/dlls/d3d9-nine/d3dadapter9.h wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3dadapter9.h
+--- wine-1.9.1/dlls/d3d9-nine/d3dadapter9.h    1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/d3dadapter9.h       2016-01-18 06:33:43.828613767 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/dri3.c wine-1.9.1-staging+d3d9/dlls/d3d9-nine/dri3.c
+--- wine-1.9.1/dlls/d3d9-nine/dri3.c   1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/dri3.c      2016-01-18 06:33:43.830613767 -0500
+@@ -0,0 +1,1345 @@
++/*
++ * 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 <fcntl.h>
++#include <unistd.h>
++#include <pthread.h>
++
++#include "dri3.h"
++
++#include <X11/Xlib-xcb.h>
++#include <xcb/dri3.h>
++#include <xcb/present.h>
++
++#include "winbase.h" /* for Sleep */
++
++#ifdef D3DADAPTER9_DRI2
++#include <sys/ioctl.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>
++#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 = 0;
++    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 = 0;
++#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 -urN wine-1.9.1/dlls/d3d9-nine/dri3.h wine-1.9.1-staging+d3d9/dlls/d3d9-nine/dri3.h
+--- wine-1.9.1/dlls/d3d9-nine/dri3.h   1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/dri3.h      2016-01-18 06:33:43.830613767 -0500
+@@ -0,0 +1,101 @@
++/*
++ * 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>
++
++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 -urN wine-1.9.1/dlls/d3d9-nine/libd3d9-nine.def wine-1.9.1-staging+d3d9/dlls/d3d9-nine/libd3d9-nine.def
+--- wine-1.9.1/dlls/d3d9-nine/libd3d9-nine.def 1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/libd3d9-nine.def    2016-01-18 06:33:43.830613767 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/Makefile.in wine-1.9.1-staging+d3d9/dlls/d3d9-nine/Makefile.in
+--- wine-1.9.1/dlls/d3d9-nine/Makefile.in      1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/Makefile.in 2016-01-18 06:33:43.830613767 -0500
+@@ -0,0 +1,12 @@
++MODULE    = d3d9-nine.dll
++IMPORTS   = dxguid uuid advapi32 gdi32 user32
++EXTRAINCL = $(X_CFLAGS) $(D3D_CFLAGS)
++EXTRALIBS = $(D3DADAPTER9_LIBS)
++
++C_SRCS = \
++        d3d9_main.c \
++        d3dadapter9.c \
++        present.c \
++        dri3.c
++
++RC_SRCS = version.rc
+diff -urN wine-1.9.1/dlls/d3d9-nine/present.c wine-1.9.1-staging+d3d9/dlls/d3d9-nine/present.c
+--- wine-1.9.1/dlls/d3d9-nine/present.c        1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/present.c   2016-01-18 06:33:43.831613767 -0500
+@@ -0,0 +1,1332 @@
++/*
++ * 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 <X11/Xutil.h>
++
++#include "dri3.h"
++
++#include "wine/library.h" // for wine_dl*
++#include "wine/unicode.h" // for strcpyW
++
++#ifndef D3DPRESENT_DONOTWAIT
++#define D3DPRESENT_DONOTWAIT      0x00000001
++#endif
++
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR 1
++#ifdef ID3DPresent_GetWindowOccluded
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 1
++#else
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 0
++#endif
++
++static const struct D3DAdapter9DRM *d3d9_drm = NULL;
++#ifdef D3DADAPTER9_DRI2
++static int is_dri2_fallback = 0;
++#endif
++
++#define X11DRV_ESCAPE 6789
++enum x11drv_escape_codes
++{
++    X11DRV_SET_DRAWABLE,     /* set current drawable for a DC */
++    X11DRV_GET_DRAWABLE,     /* get current drawable for a DC */
++    X11DRV_START_EXPOSURES,  /* start graphics exposures */
++    X11DRV_END_EXPOSURES,    /* end graphics exposures */
++    X11DRV_FLUSH_GL_DRAWABLE /* flush changes made to the gl drawable */
++};
++
++struct x11drv_escape_get_drawable
++{
++    enum x11drv_escape_codes code;         /* escape code (X11DRV_GET_DRAWABLE) */
++    Drawable                 drawable;     /* X drawable */
++    Drawable                 gl_drawable;  /* GL drawable */
++    int                      pixel_format; /* internal GL pixel format */
++    RECT                     dc_rect;      /* DC rectangle relative to drawable */
++};
++
++static XContext d3d_hwnd_context;
++static CRITICAL_SECTION context_section;
++static CRITICAL_SECTION_DEBUG critsect_debug =
++{
++    0, 0, &context_section,
++    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
++      0, 0, { (DWORD_PTR)(__FILE__ ": context_section") }
++};
++static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 };
++
++const GUID IID_ID3DPresent = { 0x77D60E80, 0xF1E6, 0x11DF, { 0x9E, 0x39, 0x95, 0x0C, 0xDF, 0xD7, 0x20, 0x85 } };
++const GUID IID_ID3DPresentGroup = { 0xB9C3016E, 0xF32A, 0x11DF, { 0x9C, 0x18, 0x92, 0xEA, 0xDE, 0xD7, 0x20, 0x85 } };
++
++struct d3d_drawable
++{
++    Drawable drawable; /* X11 drawable */
++    RECT dc_rect; /* rect relative to the X11 drawable */
++    HDC hdc;
++    HWND wnd; /* HWND (for convenience) */
++};
++
++#ifdef ID3DPresent_GetWindowOccluded
++static HHOOK hhook;
++
++struct d3d_wnd_hooks
++{
++    HWND focus_wnd;
++    struct DRI3Present *present;
++    struct d3d_wnd_hooks *prev;
++    struct d3d_wnd_hooks *next;
++};
++
++static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This );
++static HRESULT dri3_present_register_window_hook( struct DRI3Present *This );
++
++static struct d3d_wnd_hooks d3d_hooks;
++#endif
++
++struct DRI3Present
++{
++    /* COM vtable */
++    void *vtable;
++    /* IUnknown reference count */
++    LONG refs;
++
++    D3DPRESENT_PARAMETERS params;
++    HWND focus_wnd;
++    PRESENTpriv *present_priv;
++#ifdef D3DADAPTER9_DRI2
++    struct DRI2priv *dri2_priv;
++#endif
++
++    WCHAR devname[32];
++    HCURSOR hCursor;
++
++    DEVMODEW initial_mode;
++    BOOL device_needs_reset;
++    BOOL occluded;
++    Display *gdi_display;
++    struct d3d_drawable *d3d;
++    boolean ex;
++    boolean no_window_changes;
++    boolean mode_changed;
++    long style;
++    long style_ex;
++    boolean drop_wnd_messages;
++};
++
++struct D3DWindowBuffer
++{
++    PRESENTPixmapPriv *present_pixmap_priv;
++};
++
++static void
++free_d3dadapter_drawable(struct d3d_drawable *d3d)
++{
++    ReleaseDC(d3d->wnd, d3d->hdc);
++    HeapFree(GetProcessHeap(), 0, d3d);
++}
++
++void
++destroy_d3dadapter_drawable(Display *gdi_display, HWND hwnd)
++{
++    struct d3d_drawable *d3d;
++
++    EnterCriticalSection(&context_section);
++    if (!XFindContext(gdi_display, (XID)hwnd,
++                      d3d_hwnd_context, (char **)&d3d)) {
++        XDeleteContext(gdi_display, (XID)hwnd, d3d_hwnd_context);
++        free_d3dadapter_drawable(d3d);
++    }
++    LeaveCriticalSection(&context_section);
++}
++
++static struct d3d_drawable *
++create_d3dadapter_drawable(HWND hwnd)
++{
++    struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++    struct d3d_drawable *d3d;
++
++    d3d = HeapAlloc(GetProcessHeap(), 0, sizeof(*d3d));
++    if (!d3d) {
++        ERR("Couldn't allocate d3d_drawable.\n");
++        return NULL;
++    }
++
++    d3d->hdc = GetDCEx(hwnd, 0, DCX_CACHE | DCX_CLIPSIBLINGS);
++    if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++                  sizeof(extesc), (LPSTR)&extesc) <= 0) {
++        ERR("Unexpected error in X Drawable lookup (hwnd=%p, hdc=%p)\n",
++            hwnd, d3d->hdc);
++        ReleaseDC(hwnd, d3d->hdc);
++        HeapFree(GetProcessHeap(), 0, d3d);
++        return NULL;
++    }
++
++    d3d->drawable = extesc.drawable;
++    d3d->wnd = hwnd;
++    d3d->dc_rect = extesc.dc_rect;
++
++    return d3d;
++}
++
++static struct d3d_drawable *
++get_d3d_drawable(Display *gdi_display, HWND hwnd)
++{
++    struct d3d_drawable *d3d, *race;
++
++    EnterCriticalSection(&context_section);
++    if (!XFindContext(gdi_display, (XID)hwnd,
++                      d3d_hwnd_context, (char **)&d3d)) {
++        struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++
++        /* check if the window has moved since last we used it */
++        if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++                      sizeof(extesc), (LPSTR)&extesc) <= 0) {
++            WARN("Window update check failed (hwnd=%p, hdc=%p)\n",
++                 hwnd, d3d->hdc);
++        }
++
++        if (!EqualRect(&d3d->dc_rect, &extesc.dc_rect))
++            d3d->dc_rect = extesc.dc_rect;
++
++        return d3d;
++    }
++    LeaveCriticalSection(&context_section);
++
++    TRACE("No d3d_drawable attached to hwnd %p, creating one.\n", hwnd);
++
++    d3d = create_d3dadapter_drawable(hwnd);
++    if (!d3d) { return NULL; }
++
++    EnterCriticalSection(&context_section);
++    if (!XFindContext(gdi_display, (XID)hwnd,
++                      d3d_hwnd_context, (char **)&race)) {
++        /* apparently someone beat us to creating this d3d drawable. Let's not
++           waste more time with X11 calls and just use theirs instead. */
++        free_d3dadapter_drawable(d3d);
++        return race;
++    }
++    XSaveContext(gdi_display, (XID)hwnd, d3d_hwnd_context, (char *)d3d);
++    return d3d;
++}
++
++static void
++release_d3d_drawable(struct d3d_drawable *d3d)
++{
++    if (d3d) { LeaveCriticalSection(&context_section); }
++}
++
++static ULONG WINAPI
++DRI3Present_AddRef( struct DRI3Present *This )
++{
++    ULONG refs = InterlockedIncrement(&This->refs);
++    TRACE("%p increasing refcount to %u.\n", This, refs);
++    return refs;
++}
++
++static ULONG WINAPI
++DRI3Present_Release( struct DRI3Present *This )
++{
++    ULONG refs = InterlockedDecrement(&This->refs);
++    TRACE("%p decreasing refcount to %u.\n", This, refs);
++    if (refs == 0) {
++        /* dtor */
++#ifdef ID3DPresent_GetWindowOccluded
++        dri3_present_unregister_window_hook(This);
++#endif
++        if (This->d3d)
++            destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
++        ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
++
++        PRESENTDestroy(This->gdi_display, This->present_priv);
++#ifdef D3DADAPTER9_DRI2
++        if (is_dri2_fallback)
++            DRI2FallbackDestroy(This->dri2_priv);
++#endif
++        HeapFree(GetProcessHeap(), 0, This);
++    }
++    return refs;
++}
++
++static HRESULT WINAPI
++DRI3Present_QueryInterface( struct DRI3Present *This,
++                            REFIID riid,
++                            void **ppvObject )
++{
++    if (!ppvObject) { return E_POINTER; }
++
++    if (IsEqualGUID(&IID_ID3DPresent, riid) ||
++        IsEqualGUID(&IID_IUnknown, riid)) {
++        *ppvObject = This;
++        DRI3Present_AddRef(This);
++        return S_OK;
++    }
++
++    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++    *ppvObject = NULL;
++
++    return E_NOINTERFACE;
++}
++
++static HRESULT
++DRI3Present_ChangePresentParameters( struct DRI3Present *This,
++                                    D3DPRESENT_PARAMETERS *params);
++
++static HRESULT WINAPI
++DRI3Present_SetPresentParameters( struct DRI3Present *This,
++                                  D3DPRESENT_PARAMETERS *pPresentationParameters,
++                                  D3DDISPLAYMODEEX *pFullscreenDisplayMode )
++{
++    if (pFullscreenDisplayMode)
++        ERR("Ignoring pFullscreenDisplayMode\n");
++    return DRI3Present_ChangePresentParameters(This, pPresentationParameters);
++}
++
++static HRESULT WINAPI
++DRI3Present_D3DWindowBufferFromDmaBuf( struct DRI3Present *This,
++                       int dmaBufFd,
++                       int width,
++                       int height,
++                       int stride,
++                       int depth,
++                       int bpp,
++                       struct D3DWindowBuffer **out)
++{
++    Pixmap pixmap;
++
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback) {
++        *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                    sizeof(struct D3DWindowBuffer));
++        DRI2FallbackPRESENTPixmap(This->present_priv, This->dri2_priv,
++                                  dmaBufFd, width, height, stride, depth,
++                                  bpp,
++                                  &((*out)->present_pixmap_priv));
++        return D3D_OK;
++    }
++#endif
++    if (!DRI3PixmapFromDmaBuf(This->gdi_display, DefaultScreen(This->gdi_display),
++                              dmaBufFd, width, height, stride, depth,
++                              bpp, &pixmap ))
++        return D3DERR_DRIVERINTERNALERROR;
++
++    *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                    sizeof(struct D3DWindowBuffer));
++    PRESENTPixmapInit(This->present_priv, pixmap, &((*out)->present_pixmap_priv));
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_DestroyD3DWindowBuffer( struct DRI3Present *This,
++                           struct D3DWindowBuffer *buffer )
++{
++    /* the pixmap is managed by the PRESENT backend.
++     * But if it can delete it right away, we may have
++     * better performance */
++    PRESENTTryFreePixmap(This->gdi_display, buffer->present_pixmap_priv);
++    HeapFree(GetProcessHeap(), 0, buffer);
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_WaitBufferReleased( struct DRI3Present *This,
++                                struct D3DWindowBuffer *buffer)
++{
++    PRESENTWaitPixmapReleased(buffer->present_pixmap_priv);
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_FrontBufferCopy( struct DRI3Present *This,
++                             struct D3DWindowBuffer *buffer )
++{
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback)
++        return D3DERR_DRIVERINTERNALERROR;
++#endif
++    /* TODO: use dc_rect */
++    if (PRESENTHelperCopyFront(This->gdi_display, buffer->present_pixmap_priv))
++        return D3D_OK;
++    else
++        return D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_PresentBuffer( struct DRI3Present *This,
++                           struct D3DWindowBuffer *buffer,
++                           HWND hWndOverride,
++                           const RECT *pSourceRect,
++                           const RECT *pDestRect,
++                           const RGNDATA *pDirtyRegion,
++                           DWORD Flags )
++{
++    struct d3d_drawable *d3d;
++    RECT dest_translate;
++
++    if (hWndOverride) {
++        d3d = get_d3d_drawable(This->gdi_display, hWndOverride);
++    } else if (This->params.hDeviceWindow) {
++        d3d = get_d3d_drawable(This->gdi_display, This->params.hDeviceWindow);
++    } else {
++        d3d = get_d3d_drawable(This->gdi_display, This->focus_wnd);
++    }
++    if (!d3d) { return D3DERR_DRIVERINTERNALERROR; }
++
++    /* TODO: should we use a list here instead ? */
++    if (This->d3d && (This->d3d->wnd != d3d->wnd)) {
++        destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
++    }
++    This->d3d = d3d;
++
++    if (d3d->dc_rect.top != 0 &&
++        d3d->dc_rect.left != 0) {
++        if (!pDestRect)
++            pDestRect = (const RECT *) &(d3d->dc_rect);
++        else {
++            dest_translate.top = pDestRect->top + d3d->dc_rect.top;
++            dest_translate.left = pDestRect->left + d3d->dc_rect.left;
++            dest_translate.bottom = pDestRect->bottom + d3d->dc_rect.bottom;
++            dest_translate.right = pDestRect->right + d3d->dc_rect.right;
++            pDestRect = (const RECT *) &dest_translate;
++        }
++    }
++
++    if (!PRESENTPixmap(This->gdi_display, d3d->drawable, buffer->present_pixmap_priv,
++                       &This->params, pSourceRect, pDestRect, pDirtyRegion))
++        return D3DERR_DRIVERINTERNALERROR;
++
++    release_d3d_drawable(d3d);
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetRasterStatus( struct DRI3Present *This,
++                             D3DRASTER_STATUS *pRasterStatus )
++{
++    FIXME("(%p, %p), stub!\n", This, pRasterStatus);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetDisplayMode( struct DRI3Present *This,
++                            D3DDISPLAYMODEEX *pMode,
++                            D3DDISPLAYROTATION *pRotation )
++{
++    DEVMODEW dm;
++
++    ZeroMemory(&dm, sizeof(dm));
++    dm.dmSize = sizeof(dm);
++
++    EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &dm, 0);
++    pMode->Width = dm.dmPelsWidth;
++    pMode->Height = dm.dmPelsHeight;
++    pMode->RefreshRate = dm.dmDisplayFrequency;
++    pMode->ScanLineOrdering = (dm.dmDisplayFlags & DM_INTERLACED) ?
++                                  D3DSCANLINEORDERING_INTERLACED :
++                                  D3DSCANLINEORDERING_PROGRESSIVE;
++
++    /* XXX This is called "guessing" */
++    switch (dm.dmBitsPerPel) {
++        case 32: pMode->Format = D3DFMT_X8R8G8B8; break;
++        case 24: pMode->Format = D3DFMT_R8G8B8; break;
++        case 16: pMode->Format = D3DFMT_R5G6B5; break;
++        default:
++            WARN("Unknown display format with %u bpp.\n", dm.dmBitsPerPel);
++            pMode->Format = D3DFMT_UNKNOWN;
++    }
++
++    switch (dm.dmDisplayOrientation) {
++        case DMDO_DEFAULT: *pRotation = D3DDISPLAYROTATION_IDENTITY; break;
++        case DMDO_90:      *pRotation = D3DDISPLAYROTATION_90; break;
++        case DMDO_180:     *pRotation = D3DDISPLAYROTATION_180; break;
++        case DMDO_270:     *pRotation = D3DDISPLAYROTATION_270; break;
++        default:
++            WARN("Unknown display rotation %u.\n", dm.dmDisplayOrientation);
++            *pRotation = D3DDISPLAYROTATION_IDENTITY;
++    }
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetPresentStats( struct DRI3Present *This,
++                             D3DPRESENTSTATS *pStats )
++{
++    FIXME("(%p, %p), stub!\n", This, pStats);
++    return D3DERR_INVALIDCALL;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetCursorPos( struct DRI3Present *This,
++                          POINT *pPoint )
++{
++    BOOL ok;
++    HWND draw_window;
++
++    if (!pPoint)
++        return D3DERR_INVALIDCALL;
++
++    draw_window = This->params.hDeviceWindow ?
++        This->params.hDeviceWindow : This->focus_wnd;
++
++    ok = GetCursorPos(pPoint);
++    ok = ok && ScreenToClient(draw_window, pPoint);
++    return ok ? S_OK : D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_SetCursorPos( struct DRI3Present *This,
++                          POINT *pPoint )
++{
++    BOOL ok;
++    POINT real_pos;
++
++    if (!pPoint)
++        return D3DERR_INVALIDCALL;
++
++    ok = SetCursorPos(pPoint->x, pPoint->y);
++    if (!ok)
++        goto error;
++
++    ok = GetCursorPos(&real_pos);
++    if (!ok || real_pos.x != pPoint->x || real_pos.y != pPoint->y)
++        goto error;
++
++    return D3D_OK;
++
++error:
++    SetCursor(NULL); /* Hide cursor rather than put wrong pos */
++    return D3DERR_DRIVERINTERNALERROR;
++}
++
++
++/* Note: assuming 32x32 cursor */
++static HRESULT WINAPI
++DRI3Present_SetCursor( struct DRI3Present *This,
++                       void *pBitmap,
++                       POINT *pHotspot,
++                       BOOL bShow )
++{
++   if (pBitmap) {
++      ICONINFO info;
++      HCURSOR cursor;
++
++      DWORD mask[32];
++      memset(mask, ~0, sizeof(mask));
++
++      if (!pHotspot)
++         return D3DERR_INVALIDCALL;
++      info.fIcon = FALSE;
++      info.xHotspot = pHotspot->x;
++      info.yHotspot = pHotspot->y;
++      info.hbmMask = CreateBitmap(32, 32, 1, 1, mask);
++      info.hbmColor = CreateBitmap(32, 32, 1, 32, pBitmap);
++
++      cursor = CreateIconIndirect(&info);
++      if (info.hbmMask) DeleteObject(info.hbmMask);
++      if (info.hbmColor) DeleteObject(info.hbmColor);
++      if (cursor)
++         DestroyCursor(This->hCursor);
++      This->hCursor = cursor;
++   }
++   SetCursor(bShow ? This->hCursor : NULL);
++
++   return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3Present_SetGammaRamp( struct DRI3Present *This,
++                          const D3DGAMMARAMP *pRamp,
++                          HWND hWndOverride )
++{
++    HWND hWnd = hWndOverride ? hWndOverride : This->focus_wnd;
++    HDC hdc;
++    BOOL ok;
++    if (!pRamp) {
++        return D3DERR_INVALIDCALL;
++    }
++    hdc = GetDC(hWnd);
++    ok = SetDeviceGammaRamp(hdc, (void *)pRamp);
++    ReleaseDC(hWnd, hdc);
++    return ok ? D3D_OK : D3DERR_DRIVERINTERNALERROR;
++}
++
++static HRESULT WINAPI
++DRI3Present_GetWindowInfo( struct DRI3Present *This,
++                           HWND hWnd,
++                           int *width, int *height, int *depth )
++{
++    HRESULT hr;
++    RECT pRect;
++
++    if (!hWnd)
++        hWnd = This->focus_wnd;
++    hr = GetClientRect(hWnd, &pRect);
++    if (!hr)
++        return D3DERR_INVALIDCALL;
++    *width = pRect.right - pRect.left;
++    *height = pRect.bottom - pRect.top;
++    *depth = 24; //TODO
++    return D3D_OK;
++}
++
++static LONG fullscreen_style(LONG style)
++{
++    /* Make sure the window is managed, otherwise we won't get keyboard input. */
++    style |= WS_POPUP | WS_SYSMENU;
++    style &= ~(WS_CAPTION | WS_THICKFRAME);
++
++    return style;
++}
++
++static LONG fullscreen_exstyle(LONG exstyle)
++{
++    /* Filter out window decorations. */
++    exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
++
++    return exstyle;
++}
++
++static HRESULT
++DRI3Present_ChangeDisplaySettingsIfNeccessary( struct DRI3Present *This, DEVMODEW *new_mode ) {
++    DEVMODEW current_mode;
++    LONG hr;
++
++    ZeroMemory(&current_mode, sizeof(DEVMODEW));
++    /* Only change the mode if necessary. */
++    if (!EnumDisplaySettingsW(This->devname, ENUM_CURRENT_SETTINGS, &current_mode))
++    {
++       ERR("Failed to get current display mode.\n");
++    } else if (current_mode.dmPelsWidth != new_mode->dmPelsWidth
++           || current_mode.dmPelsHeight != new_mode->dmPelsHeight
++           || (current_mode.dmDisplayFrequency != new_mode->dmDisplayFrequency
++           && (new_mode->dmFields & DM_DISPLAYFREQUENCY)))
++    {
++        hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
++        if (hr != DISP_CHANGE_SUCCESSFUL) {
++            /* try again without display RefreshRate */
++            if (new_mode->dmFields & DM_DISPLAYFREQUENCY) {
++                new_mode->dmFields &= ~DM_DISPLAYFREQUENCY;
++                new_mode->dmDisplayFrequency = 0;
++                hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
++                if (hr != DISP_CHANGE_SUCCESSFUL) {
++                    ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++                    return D3DERR_INVALIDCALL;
++                }
++            } else {
++                ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++                return D3DERR_INVALIDCALL;
++            }
++        }
++    }
++    return D3D_OK;
++}
++
++#ifdef ID3DPresent_GetWindowOccluded
++static struct d3d_wnd_hooks *get_last_hook(void) {
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++    while (hook->next) {
++        hook = hook->next;
++    }
++    return hook;
++}
++
++LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
++{
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++    boolean drop_wnd_messages;
++
++    if (nCode < 0) {
++        return CallNextHookEx(hhook, nCode, wParam, lParam);
++    }
++
++    if (lParam) {
++        CWPSTRUCT wndprocparams = *((CWPSTRUCT*)lParam);
++        while (hook->next) {
++            hook = hook->next;
++
++            /* skip messages for other hwnds */
++            if (hook->focus_wnd != wndprocparams.hwnd)
++                continue;
++            if (!hook->present)
++                continue;
++
++            switch (wndprocparams.message) {
++                case WM_ACTIVATEAPP:
++                    if (hook->present->drop_wnd_messages)
++                        return -1;
++
++                    drop_wnd_messages = hook->present->drop_wnd_messages;
++                    hook->present->drop_wnd_messages = TRUE;
++                    if (wndprocparams.wParam == WA_INACTIVE) {
++                            hook->present->occluded = TRUE;
++
++                            DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &(hook->present->initial_mode));
++
++                            if (!hook->present->no_window_changes &&
++                                    IsWindowVisible(hook->present->params.hDeviceWindow))
++                                ShowWindow(hook->present->params.hDeviceWindow, SW_MINIMIZE);
++                    } else {
++                            hook->present->device_needs_reset |= hook->present->occluded;
++                            hook->present->occluded = FALSE;
++
++                            if (!hook->present->no_window_changes) {
++                                /* restore window */
++                                SetWindowPos(hook->present->params.hDeviceWindow, NULL, 0, 0,
++                                             hook->present->params.BackBufferWidth, hook->present->params.BackBufferHeight,
++                                             SWP_NOACTIVATE | SWP_NOZORDER);
++                            }
++
++                            if (hook->present->ex) {
++                                DEVMODEW new_mode;
++
++                                ZeroMemory(&new_mode, sizeof(DEVMODEW));
++                                new_mode.dmPelsWidth = hook->present->params.BackBufferWidth;
++                                new_mode.dmPelsHeight = hook->present->params.BackBufferHeight;
++                                new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++                                if (hook->present->params.FullScreen_RefreshRateInHz) {
++                                    new_mode.dmFields |= DM_DISPLAYFREQUENCY;
++                                    new_mode.dmDisplayFrequency = hook->present->params.FullScreen_RefreshRateInHz;
++                                }
++                                new_mode.dmSize = sizeof(DEVMODEW);
++                                DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &new_mode);
++                            }
++                    }
++                    hook->present->drop_wnd_messages = drop_wnd_messages;
++                break;
++                case WM_DISPLAYCHANGE:
++                    hook->present->mode_changed = TRUE;
++                    hook->present->device_needs_reset = TRUE;
++                break;
++                /* TODO: handle other window messages here */
++                default:
++                break;
++            }
++        }
++    }
++
++    return CallNextHookEx(hhook, nCode, wParam, lParam);
++}
++
++static HRESULT dri3_present_register_window_hook( struct DRI3Present *This ) {
++    struct d3d_wnd_hooks *lasthook;
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++
++    HWND hWnd = This->focus_wnd;
++
++    /* let's see if already hooked */
++    while (hook->next) {
++        hook = hook->next;
++        if (hook->focus_wnd == hWnd && hook->present == This)
++            return D3DERR_INVALIDCALL;
++    }
++    /* create single WindowsHook in this process */
++    if (!hhook) {
++        // TODO: do we need to handle different threadIDs ?
++        DWORD threadID = GetWindowThreadProcessId(hWnd, NULL);
++        hhook = SetWindowsHookExW(WH_CALLWNDPROC, HookCallback, NULL, threadID);
++        if (!hhook) {
++            ERR("SetWindowsHookEx failed with 0x%08x\n", GetLastError());
++            return D3DERR_DRIVERINTERNALERROR;
++        }
++    }
++    lasthook = get_last_hook();
++    hook = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++            sizeof(struct d3d_wnd_hooks));
++    if (!hook)
++        return E_OUTOFMEMORY;
++    /* add window hwnd to list */
++    lasthook->next = hook;
++    hook->prev = lasthook;
++    hook->focus_wnd = hWnd;
++    hook->present = This;
++    return D3D_OK;
++}
++
++static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This ) {
++    struct d3d_wnd_hooks *hook = &d3d_hooks;
++
++    HWND hWnd = This->focus_wnd;
++
++    /* find hook and remove it */
++    while (hook->next) {
++        hook = hook->next;
++        if(hook->focus_wnd == hWnd && hook->present == This) {
++            /* remove hook */
++            hook->prev->next = hook->next;
++            HeapFree(GetProcessHeap(), 0, hook);
++            /* start again at list head */
++            hook = &d3d_hooks;
++        }
++    }
++    /* remove single process WindowsHook */
++    if (get_last_hook() == &d3d_hooks && hhook) {
++       if (!UnhookWindowsHookEx(hhook)) {
++           ERR("UnhookWindowsHookEx failed with 0x%08x\n", GetLastError());
++       }
++       hhook = NULL;
++    }
++
++    return D3D_OK;
++}
++
++static BOOL WINAPI
++DRI3Present_GetWindowOccluded( struct DRI3Present *This )
++{
++    /* we missed to poll occluded */
++    if (This->device_needs_reset) {
++        This->device_needs_reset = FALSE;
++        return TRUE;
++    }
++
++    return This->occluded;
++}
++#endif
++/*----------*/
++
++
++static ID3DPresentVtbl DRI3Present_vtable = {
++    (void *)DRI3Present_QueryInterface,
++    (void *)DRI3Present_AddRef,
++    (void *)DRI3Present_Release,
++    (void *)DRI3Present_SetPresentParameters,
++    (void *)DRI3Present_D3DWindowBufferFromDmaBuf,
++    (void *)DRI3Present_DestroyD3DWindowBuffer,
++    (void *)DRI3Present_WaitBufferReleased,
++    (void *)DRI3Present_FrontBufferCopy,
++    (void *)DRI3Present_PresentBuffer,
++    (void *)DRI3Present_GetRasterStatus,
++    (void *)DRI3Present_GetDisplayMode,
++    (void *)DRI3Present_GetPresentStats,
++    (void *)DRI3Present_GetCursorPos,
++    (void *)DRI3Present_SetCursorPos,
++    (void *)DRI3Present_SetCursor,
++    (void *)DRI3Present_SetGammaRamp,
++    (void *)DRI3Present_GetWindowInfo,
++#ifdef ID3DPresent_GetWindowOccluded
++    (void *)DRI3Present_GetWindowOccluded
++#endif
++};
++
++static HRESULT
++DRI3Present_ChangePresentParameters( struct DRI3Present *This,
++                                    D3DPRESENT_PARAMETERS *params )
++{
++    HWND draw_window = params->hDeviceWindow;
++    RECT rect;
++    DEVMODEW new_mode;
++
++    if (!GetClientRect(draw_window, &rect)) {
++        WARN("GetClientRect failed.\n");
++        rect.right = 640;
++        rect.bottom = 480;
++    }
++
++    if (params->BackBufferWidth == 0) {
++        params->BackBufferWidth = rect.right - rect.left;
++    }
++    if (params->BackBufferHeight == 0) {
++        params->BackBufferHeight = rect.bottom - rect.top;
++    }
++
++    if ((This->params.BackBufferWidth != params->BackBufferWidth) ||
++        (This->params.BackBufferHeight != params->BackBufferHeight)) {
++        This->mode_changed = TRUE;
++    }
++
++    if (This->mode_changed || (This->params.Windowed != params->Windowed)) {
++        if (!params->Windowed) {
++            /* switch display mode */
++            ZeroMemory(&new_mode, sizeof(DEVMODEW));
++            new_mode.dmPelsWidth = params->BackBufferWidth;
++            new_mode.dmPelsHeight = params->BackBufferHeight;
++            new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++            if (params->FullScreen_RefreshRateInHz) {
++                new_mode.dmFields |= DM_DISPLAYFREQUENCY;
++                new_mode.dmDisplayFrequency = params->FullScreen_RefreshRateInHz;
++            }
++            new_mode.dmSize = sizeof(DEVMODEW);
++            DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &new_mode);
++        } else {
++            DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &This->initial_mode);
++        }
++        This->mode_changed = FALSE;
++
++        if (This->params.Windowed) {
++            if (!params->Windowed) {
++                LONG style, style_ex;
++                boolean drop_wnd_messages;
++
++                /* switch from window to fullscreen */
++#ifdef ID3DPresent_GetWindowOccluded
++                if (dri3_present_register_window_hook(This)) {
++                    SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
++                }
++#else
++                SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
++#endif
++                This->style = GetWindowLongW(draw_window, GWL_STYLE);
++                This->style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++                style = fullscreen_style(This->style);
++                style_ex = fullscreen_exstyle(This->style_ex);
++
++                drop_wnd_messages = This->drop_wnd_messages;
++                This->drop_wnd_messages = TRUE;
++
++                SetWindowLongW(draw_window, GWL_STYLE, style);
++                SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++                SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth,
++                             params->BackBufferHeight,
++                             SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++                This->drop_wnd_messages = drop_wnd_messages;
++            }
++        } else {
++            if (!params->Windowed) {
++                /* switch from fullscreen to fullscreen */
++                MoveWindow(draw_window, 0, 0,
++                        params->BackBufferWidth,
++                        params->BackBufferHeight,
++                        TRUE);
++            } else {
++                LONG style, style_ex;
++                boolean drop_wnd_messages;
++
++                /* switch from fullscreen to window */
++                style = GetWindowLongW(draw_window, GWL_STYLE);
++                style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++                /* These flags are set by wined3d_device_setup_fullscreen_window, not the
++                 * application, and we want to ignore them in the test below, since it's
++                 * not the application's fault that they changed. Additionally, we want to
++                 * preserve the current status of these flags (i.e. don't restore them) to
++                 * more closely emulate the behavior of Direct3D, which leaves these flags
++                 * alone when returning to windowed mode. */
++                This->style ^= (This->style ^ style) & WS_VISIBLE;
++                This->style_ex ^= (This->style_ex ^ style_ex) & WS_EX_TOPMOST;
++
++                /* Only restore the style if the application didn't modify it during the
++                 * fullscreen phase. Some applications change it before calling Reset()
++                 * when switching between windowed and fullscreen modes (HL2), some
++                 * depend on the original style (Eve Online). */
++                drop_wnd_messages = This->drop_wnd_messages;
++                This->drop_wnd_messages = TRUE;
++                if (style == fullscreen_style(This->style) && style_ex == fullscreen_exstyle(This->style_ex))
++                {
++                    SetWindowLongW(draw_window, GWL_STYLE, style);
++                    SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++                }
++                SetWindowPos(draw_window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED |
++                             SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
++                             SWP_NOACTIVATE);
++                This->drop_wnd_messages = drop_wnd_messages;
++
++#ifdef ID3DPresent_GetWindowOccluded
++        dri3_present_unregister_window_hook(This);
++#endif
++                This->style = 0;
++                This->style_ex = 0;
++            }
++        }
++    } else if (!params->Windowed) {
++        LONG style, style_ex;
++        /* move draw window back to place */
++
++        style = GetWindowLongW(draw_window, GWL_STYLE);
++        style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE);
++
++        style = fullscreen_style(style);
++        style_ex = fullscreen_exstyle(style_ex);
++
++        SetWindowLongW(draw_window, GWL_STYLE, style);
++        SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex);
++        SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth,
++                     params->BackBufferHeight,
++                     SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++    }
++
++    This->params = *params;
++    return D3D_OK;
++}
++
++static HRESULT
++DRI3Present_new( Display *gdi_display,
++                 const WCHAR *devname,
++                 D3DPRESENT_PARAMETERS *params,
++                 HWND focus_wnd,
++                 struct DRI3Present **out,
++                 boolean ex,
++                 boolean no_window_changes )
++{
++    struct DRI3Present *This;
++
++    if (!focus_wnd) { focus_wnd = params->hDeviceWindow; }
++    if (!focus_wnd) {
++        ERR("No focus HWND specified for presentation backend.\n");
++        return D3DERR_INVALIDCALL;
++    }
++
++    This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                     sizeof(struct DRI3Present));
++    if (!This) {
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    This->gdi_display = gdi_display;
++    This->vtable = &DRI3Present_vtable;
++    This->refs = 1;
++    This->focus_wnd = focus_wnd;
++    This->params.Windowed = TRUE;
++    This->ex = ex;
++    This->no_window_changes = no_window_changes;
++
++    strcpyW(This->devname, devname);
++
++    ZeroMemory(&(This->initial_mode), sizeof(This->initial_mode));
++    This->initial_mode.dmSize = sizeof(This->initial_mode);
++
++    EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &(This->initial_mode), 0);
++
++    PRESENTInit(gdi_display, &(This->present_priv));
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback)
++        DRI2FallbackInit(gdi_display, &(This->dri2_priv));
++#endif
++    *out = This;
++
++    return D3D_OK;
++}
++
++struct DRI3PresentGroup
++{
++    /* COM vtable */
++    void *vtable;
++    /* IUnknown reference count */
++    LONG refs;
++
++    struct DRI3Present **present_backends;
++    unsigned npresent_backends;
++    Display *gdi_display;
++    boolean ex;
++    boolean no_window_changes;
++};
++
++static ULONG WINAPI
++DRI3PresentGroup_AddRef( struct DRI3PresentGroup *This )
++{
++    ULONG refs = InterlockedIncrement(&This->refs);
++    TRACE("%p increasing refcount to %u.\n", This, refs);
++    return refs;
++}
++
++static ULONG WINAPI
++DRI3PresentGroup_Release( struct DRI3PresentGroup *This )
++{
++    ULONG refs = InterlockedDecrement(&This->refs);
++    TRACE("%p decreasing refcount to %u.\n", This, refs);
++    if (refs == 0) {
++        unsigned i;
++        if (This->present_backends) {
++            for (i = 0; i < This->npresent_backends; ++i) {
++                if (This->present_backends[i])
++                    DRI3Present_Release(This->present_backends[i]);
++            }
++            HeapFree(GetProcessHeap(), 0, This->present_backends);
++        }
++        HeapFree(GetProcessHeap(), 0, This);
++    }
++    return refs;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_QueryInterface( struct DRI3PresentGroup *This,
++                                 REFIID riid,
++                                 void **ppvObject )
++{
++    if (!ppvObject) { return E_POINTER; }
++    if (IsEqualGUID(&IID_ID3DPresentGroup, riid) ||
++        IsEqualGUID(&IID_IUnknown, riid)) {
++        *ppvObject = This;
++        DRI3PresentGroup_AddRef(This);
++        return S_OK;
++    }
++
++    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
++    *ppvObject = NULL;
++
++    return E_NOINTERFACE;
++}
++
++static UINT WINAPI
++DRI3PresentGroup_GetMultiheadCount( struct DRI3PresentGroup *This )
++{
++    FIXME("(%p), stub!\n", This);
++    return 1;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_GetPresent( struct DRI3PresentGroup *This,
++                             UINT Index,
++                             ID3DPresent **ppPresent )
++{
++    if (Index >= DRI3PresentGroup_GetMultiheadCount(This)) {
++        ERR("Index >= MultiHeadCount\n");
++        return D3DERR_INVALIDCALL;
++    }
++    DRI3Present_AddRef(This->present_backends[Index]);
++    *ppPresent = (ID3DPresent *)This->present_backends[Index];
++
++    return D3D_OK;
++}
++
++static HRESULT WINAPI
++DRI3PresentGroup_CreateAdditionalPresent( struct DRI3PresentGroup *This,
++                                          D3DPRESENT_PARAMETERS *pPresentationParameters,
++                                          ID3DPresent **ppPresent )
++{
++    HRESULT hr;
++    hr = DRI3Present_new(This->gdi_display, This->present_backends[0]->devname,
++                         pPresentationParameters, 0, (struct DRI3Present **)ppPresent,
++                         This->ex, This->no_window_changes);
++    return hr;
++}
++
++static void WINAPI
++DRI3PresentGroup_GetVersion( struct DRI3PresentGroup *This,
++                             int *major,
++                             int *minor)
++{
++    *major = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR;
++    *minor = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR;
++}
++
++static ID3DPresentGroupVtbl DRI3PresentGroup_vtable = {
++    (void *)DRI3PresentGroup_QueryInterface,
++    (void *)DRI3PresentGroup_AddRef,
++    (void *)DRI3PresentGroup_Release,
++    (void *)DRI3PresentGroup_GetMultiheadCount,
++    (void *)DRI3PresentGroup_GetPresent,
++    (void *)DRI3PresentGroup_CreateAdditionalPresent,
++    (void *)DRI3PresentGroup_GetVersion
++};
++
++HRESULT
++present_create_present_group( Display *gdi_display,
++                           const WCHAR *device_name,
++                           UINT adapter,
++                           HWND focus_wnd,
++                           D3DPRESENT_PARAMETERS *params,
++                           unsigned nparams,
++                           ID3DPresentGroup **group,
++                           boolean ex,
++                           boolean no_window_changes )
++{
++    struct DRI3PresentGroup *This =
++        HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                  sizeof(struct DRI3PresentGroup));
++    DISPLAY_DEVICEW dd;
++    HRESULT hr;
++    unsigned i;
++
++    if (!This) {
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    This->gdi_display = gdi_display;
++    This->vtable = &DRI3PresentGroup_vtable;
++    This->refs = 1;
++    This->ex = ex;
++    This->no_window_changes = no_window_changes;
++    This->npresent_backends = nparams;
++    This->present_backends = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++                                       This->npresent_backends *
++                                       sizeof(struct DRI3Present *));
++    if (!This->present_backends) {
++        DRI3PresentGroup_Release(This);
++        ERR("Out of memory.\n");
++        return E_OUTOFMEMORY;
++    }
++
++    if (nparams != 1) { adapter = 0; }
++    for (i = 0; i < This->npresent_backends; ++i) {
++        ZeroMemory(&dd, sizeof(dd));
++        dd.cb = sizeof(dd);
++        /* find final device name */
++        if (!EnumDisplayDevicesW(device_name, adapter+i, &dd, 0)) {
++            WARN("Couldn't find subdevice %d from `%s'\n",
++                 i, debugstr_w(device_name));
++        }
++
++        /* create an ID3DPresent for it */
++        hr = DRI3Present_new(gdi_display, dd.DeviceName, &params[i],
++                             focus_wnd, &This->present_backends[i],
++                             This->ex, This->no_window_changes);
++        if (FAILED(hr)) {
++            DRI3PresentGroup_Release(This);
++            return hr;
++        }
++    }
++
++    *group = (ID3DPresentGroup *)This;
++    TRACE("Returning %p\n", *group);
++
++    return D3D_OK;
++}
++
++HRESULT
++present_create_adapter9( Display *gdi_display,
++                      HDC hdc,
++                      ID3DAdapter9 **out )
++{
++    struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
++    HRESULT hr;
++    int fd;
++
++    if (!d3d9_drm) {
++        ERR("DRM drivers are not supported on your system.\n");
++        return D3DERR_DRIVERINTERNALERROR;
++    }
++
++    if (ExtEscape(hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
++                  sizeof(extesc), (LPSTR)&extesc) <= 0) {
++        ERR("X11 drawable lookup failed (hdc=%p)\n", hdc);
++    }
++
++#ifdef D3DADAPTER9_DRI2
++    if (!is_dri2_fallback && !DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) {
++#else
++    if (!DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) {
++#endif
++        ERR("DRI3Open failed (fd=%d)\n", fd);
++        return D3DERR_DRIVERINTERNALERROR;
++    }
++#ifdef D3DADAPTER9_DRI2
++    if (is_dri2_fallback && !DRI2FallbackOpen(gdi_display, DefaultScreen(gdi_display), &fd)) {
++        ERR("DRI2Open failed (fd=%d)\n", fd);
++        return D3DERR_DRIVERINTERNALERROR;
++    }
++#endif
++    hr = d3d9_drm->create_adapter(fd, out);
++    if (FAILED(hr)) {
++        ERR("Unable to create ID3DAdapter9 (fd=%d)\n", fd);
++        return hr;
++    }
++
++    TRACE("Created ID3DAdapter9 with fd %d\n", fd);
++
++    return D3D_OK;
++}
++
++BOOL
++has_d3dadapter( Display *gdi_display )
++{
++    static const void * WINAPI (*pD3DAdapter9GetProc)(const char *);
++    static void *handle = NULL;
++    static int done = 0;
++
++    char errbuf[256];
++
++#if !defined(SONAME_D3DADAPTER9)
++    return FALSE;
++#endif
++
++    /* like in opengl.c (single threaded assumption OK?) */
++    if (done) { return handle != NULL; }
++    done = 1;
++
++    handle = wine_dlopen(D3D_MODULE_DIR "/" SONAME_D3DADAPTER9,
++                         RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf));
++    if (!handle) {
++        ERR("Failed to load %s: %s\n", SONAME_D3DADAPTER9, errbuf);
++        goto cleanup;
++    }
++
++    /* find our entry point in d3dadapter9 */
++    pD3DAdapter9GetProc = wine_dlsym(handle, "D3DAdapter9GetProc",
++                                     errbuf, sizeof(errbuf));
++    if (!pD3DAdapter9GetProc) {
++        ERR("Failed to get the entry point from %s: %s",
++            SONAME_D3DADAPTER9, errbuf);
++        goto cleanup;
++    }
++
++    /* get a handle to the drm backend struct */
++    d3d9_drm = pD3DAdapter9GetProc(D3DADAPTER9DRM_NAME);
++    if (!d3d9_drm) {
++        ERR("%s doesn't support the `%s' backend.\n",
++            SONAME_D3DADAPTER9, D3DADAPTER9DRM_NAME);
++        goto cleanup;
++    }
++
++    /* verify that we're binary compatible */
++    if (d3d9_drm->major_version != D3DADAPTER9DRM_MAJOR) {
++        ERR("Version mismatch. %s has %d.%d, was expecting %d.x\n",
++            SONAME_D3DADAPTER9, d3d9_drm->major_version,
++            d3d9_drm->minor_version, D3DADAPTER9DRM_MAJOR);
++        goto cleanup;
++    }
++
++    /* this will be used to store d3d_drawables */
++    d3d_hwnd_context = XUniqueContext();
++
++    if (!PRESENTCheckExtension(gdi_display, 1, 0)) {
++        ERR("Unable to query PRESENT.\n");
++        goto cleanup;
++    }
++
++    if (!DRI3CheckExtension(gdi_display, 1, 0)) {
++#ifndef D3DADAPTER9_DRI2
++        ERR("Unable to query DRI3.\n");
++        goto cleanup;
++#else
++        ERR("Unable to query DRI3. Trying DRI2 fallback (slower performance).\n");
++        is_dri2_fallback = 1;
++        if (!DRI2FallbackCheckSupport(gdi_display)) {
++            ERR("DRI2 fallback unsupported\n");
++            goto cleanup;
++        }
++#endif
++    }
++
++    return TRUE;
++
++cleanup:
++    ERR("\033[1;31m\nNative Direct3D 9 will be unavailable."
++        "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++    if (handle) {
++        wine_dlclose(handle, NULL, 0);
++        handle = NULL;
++    }
++
++    return FALSE;
++}
+diff -urN wine-1.9.1/dlls/d3d9-nine/present.h wine-1.9.1-staging+d3d9/dlls/d3d9-nine/present.h
+--- wine-1.9.1/dlls/d3d9-nine/present.h        1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/present.h   2016-01-18 06:33:43.831613767 -0500
+@@ -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 -urN wine-1.9.1/dlls/d3d9-nine/version.rc wine-1.9.1-staging+d3d9/dlls/d3d9-nine/version.rc
+--- wine-1.9.1/dlls/d3d9-nine/version.rc       1969-12-31 19:00:00.000000000 -0500
++++ wine-1.9.1-staging+d3d9/dlls/d3d9-nine/version.rc  2016-01-18 06:33:43.832613767 -0500
+@@ -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 -urN wine-1.9.1/dlls/ntdll/loadorder.c wine-1.9.1-staging+d3d9/dlls/ntdll/loadorder.c
+--- wine-1.9.1/dlls/ntdll/loadorder.c  2016-01-18 06:51:05.362592514 -0500
++++ wine-1.9.1-staging+d3d9/dlls/ntdll/loadorder.c     2016-01-18 06:33:43.833613767 -0500
+@@ -644,3 +644,46 @@
+     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 -urN wine-1.9.1/dlls/winex11.drv/init.c wine-1.9.1-staging+d3d9/dlls/winex11.drv/init.c
+--- wine-1.9.1/dlls/winex11.drv/init.c 2016-01-18 06:51:03.053592561 -0500
++++ wine-1.9.1-staging+d3d9/dlls/winex11.drv/init.c    2016-01-18 06:33:43.834613767 -0500
+@@ -365,6 +365,7 @@
+                 {
+                     struct x11drv_escape_get_drawable *data = out_data;
+                     data->drawable = physDev->drawable;
++                    data->dc_rect = physDev->dc_rect;
+                     return TRUE;
+                 }
+                 break;
+diff -urN wine-1.9.1/dlls/winex11.drv/x11drv.h wine-1.9.1-staging+d3d9/dlls/winex11.drv/x11drv.h
+--- wine-1.9.1/dlls/winex11.drv/x11drv.h       2016-01-18 06:51:08.257592455 -0500
++++ wine-1.9.1-staging+d3d9/dlls/winex11.drv/x11drv.h  2016-01-18 06:33:43.834613767 -0500
+@@ -293,6 +293,7 @@
+     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 -urN wine-1.9.1/include/config.h.in wine-1.9.1-staging+d3d9/include/config.h.in
+--- wine-1.9.1/include/config.h.in     2016-01-18 06:51:11.000000000 -0500
++++ wine-1.9.1-staging+d3d9/include/config.h.in        2016-01-18 06:33:43.835613767 -0500
+@@ -4,6 +4,12 @@
+ #define __WINE_CONFIG_H
+ #ifndef WINE_CROSSTEST
++/* Whether d3dadapter9 DRI2 fallback is compiled */
++#undef D3DADAPTER9_DRI2
++
++/* "module dir" */
++#undef D3D_MODULE_DIR
++
+ /* Define to a function attribute for Microsoft hotpatch assembly prefix. */
+ #undef DECLSPEC_HOTPATCH
+@@ -1362,6 +1368,9 @@
+ /* Define to the soname of the libcairo library. */
+ #undef SONAME_LIBCAIRO
++/* "temporary hack" */
++#undef SONAME_D3DADAPTER9
++
+ /* Define to the soname of the libcapi20 library. */
+ #undef SONAME_LIBCAPI20
+@@ -1374,6 +1383,9 @@
+ /* Define to the soname of the libdbus-1 library. */
+ #undef SONAME_LIBDBUS_1
++/* Define to the soname of the libEGL library. */
++#undef SONAME_LIBEGL
++
+ /* Define to the soname of the libfontconfig library. */
+ #undef SONAME_LIBFONTCONFIG
+diff -urN wine-1.9.1/programs/winecfg/resource.h wine-1.9.1-staging+d3d9/programs/winecfg/resource.h
+--- wine-1.9.1/programs/winecfg/resource.h     2016-01-18 06:51:03.839592545 -0500
++++ wine-1.9.1-staging+d3d9/programs/winecfg/resource.h        2016-01-18 06:44:19.169600803 -0500
+@@ -218,6 +218,7 @@
+ #define IDC_ENABLE_EAX                  9003
+ #define IDC_ENABLE_HIDEWINE             9004
+ #define IDC_ENABLE_GTK3                 9005
++#define IDC_ENABLE_NATIVE_D3D9          9006 /* Manually corrected. */
+ /* About tab */
+ #define IDC_ABT_OWNER                8432
+diff -urN wine-1.9.1/programs/winecfg/staging.c wine-1.9.1-staging+d3d9/programs/winecfg/staging.c
+--- wine-1.9.1/programs/winecfg/staging.c      2016-01-18 06:51:03.839592545 -0500
++++ wine-1.9.1-staging+d3d9/programs/winecfg/staging.c 2016-01-18 06:48:46.029595357 -0500
+@@ -34,6 +34,23 @@
+ 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);
++}
++
++/*
+  * Command stream multithreading
+  */
+ static BOOL csmt_get(void)
+@@ -132,6 +149,7 @@
+     CheckDlgButton(dialog, IDC_ENABLE_EAX, eax_get() ? BST_CHECKED : BST_UNCHECKED);
+     CheckDlgButton(dialog, IDC_ENABLE_HIDEWINE, hidewine_get() ? BST_CHECKED : BST_UNCHECKED);
+     CheckDlgButton(dialog, IDC_ENABLE_GTK3, gtk3_get() ? BST_CHECKED : BST_UNCHECKED);
++    CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, nine_get() ? BST_CHECKED : BST_UNCHECKED);
+ #ifndef HAVE_VAAPI
+     disable(IDC_ENABLE_VAAPI);
+@@ -139,6 +157,10 @@
+ #ifndef HAVE_GTK3
+     disable(IDC_ENABLE_GTK3);
+ #endif
++#if !defined(SONAME_D3DADAPTER9)
++    disable(IDC_ENABLE_NATIVE_D3D9);
++#endif
++
+ }
+ INT_PTR CALLBACK StagingDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+@@ -184,6 +206,10 @@
+             gtk3_set(IsDlgButtonChecked(hDlg, IDC_ENABLE_GTK3) == BST_CHECKED);
+             SendMessageW(GetParent(hDlg), PSM_CHANGED, 0, 0);
+             return TRUE;
++        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;
+     }
+diff -urN wine-1.9.1/programs/winecfg/winecfg.rc wine-1.9.1-staging+d3d9/programs/winecfg/winecfg.rc
+--- wine-1.9.1/programs/winecfg/winecfg.rc     2016-01-18 06:51:03.839592545 -0500
++++ wine-1.9.1-staging+d3d9/programs/winecfg/winecfg.rc        2016-01-18 06:42:54.270602535 -0500
+@@ -314,12 +314,13 @@
+ 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.",IDC_STATIC,16,16,230,16
++    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 &CSMT for better graphic performance",IDC_ENABLE_CSMT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,40,230,8
+     CONTROL     "Enable &VAAPI as backend for DXVA2 GPU decoding",IDC_ENABLE_VAAPI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,55,230,8
+     CONTROL     "Enable Environmental Audio E&xtensions (EAX)",IDC_ENABLE_EAX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,70,230,8
+     CONTROL     "&Hide Wine version from applications",IDC_ENABLE_HIDEWINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,85,230,8
+     CONTROL     "Enable &GTK3 Theming",IDC_ENABLE_GTK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,100,230,8
++    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